DIRECTORY Basics USING [BITAND, BITOR, Card16FromH, Card32FromF, Comparison, FWORD, HWORD], BasicTime USING [GMT, Now], CCTypes USING[CCError, CCErrorCase], CirioTypes USING [zeroBA], Commander USING [Register, CommandProc], CommanderOps USING [ArgumentVector, Parse], Convert USING[IntFromRope, RopeFromChar], IO USING[card, EndOf, GetChar, GetFWord, GetHWord, PeekChar, PutF, PutFR, SetIndex, STREAM, time, UnsafeGetBlock], List USING[LORA, CompareProc, Sort], ObjectFiles USING [BracketNest, BracketPairKind, CNameOfStab, CreateParsed, FileSegmentPC, GlobalVarLoc, MakeUnknownVarLoc, RopeForStabType, SimpleSeg, Stab, StabBody, StabType, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo], ObjectFilesPrivate USING [AlterFunStabType, BracketPair, BracketPairBody, CheckStaticVar, FunStabInfo, FunStabSet, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, Module, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, RaiseUnreadableObjectFileForFun, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, ReadStabRope, RegisterObjectFileFlavor, ScanSymbolStabs, SLineData, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType], PFS USING [PathFromRope, RopeFromPath, StreamFromOpenFile, OpenFileFromStream], PFSNames USING [PATH], Random USING [ChooseInt, Create, RandomStream], RCTW USING [GetTokenRope, RCTWData, RCTWDataBody], Rope USING[Concat, Equal, Fetch, FromChar, Index, IsEmpty, Length, Match, ROPE], SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, ReleaseStreamForFile]; XCOFFFiles: CEDAR MONITOR IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, RCTW, Rope, SystemInterface EXPORTS ObjectFiles = BEGIN CCError: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE ¬ NIL] ¬ CCTypes.CCError; ROPE: TYPE ~ Rope.ROPE; PATH: TYPE ~ PFSNames.PATH; Stab: TYPE = ObjectFiles.Stab; StabBody: TYPE = ObjectFiles.StabBody; StabType: TYPE = ObjectFiles.StabType; FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC; VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo; Block: BYTE = 64H; Brac: BYTE = 65H; Fun: BYTE = 8eH; STSym: BYTE = 85H; GSym: BYTE = 80H; PSym: BYTE = 82H; LSym: BYTE = 81H; RSym: BYTE = 83H; SO: BYTE = 67H; HidEnt: BYTE = 6bH; XTYSD: BYTE = 1; -- CSECT Section Definition -- XMCRW: BYTE = 5; -- Read Write Data -- Parsed: TYPE = REF ParsedBody; ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody; Header: TYPE = REF HeaderBody; HeaderBody: PUBLIC TYPE = ObjectFilesPrivate.HeaderBody; Module: TYPE = REF ModuleBody; ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody; StabList: TYPE = ObjectFilesPrivate.StabList; StabSet: TYPE = ObjectFilesPrivate.StabSet; StabRange: TYPE = ObjectFilesPrivate.StabRange; MemorySegmentInfo: TYPE ~ ObjectFilesPrivate.MemorySegmentInfo; unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize; MOldsun2: CARD = 0; M68010: CARD = 1; M68020: CARD = 2; MSparc: CARD = 3; OMagic: CARD16 = 0407B; NMagic: CARD16 = 0410B; ZMagic: CARD16 = 0413B; PageSize: CARD32 = 02000H; OldPageSize: CARD32 = 00800H; FRelFlg: CARD16 = 0001H; FExec: CARD16 = 0002H; FLnNo: CARD16 = 0004H; FLSyms: CARD16 = 0008H; FAr16WR: CARD16 = 0080H; FAr32WR: CARD16 = 0100H; FAr32W: CARD16 = 0200H; FDynLoad: CARD16 = 1000H; FShrObj: CARD16 = 2000H; FLdMinusR: CARD16 = 8000H; WireHeader: TYPE = REF WireHeaderBody; WireHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ magic: Basics.HWORD, numSections: Basics.HWORD, timeDate: Basics.FWORD, symPtr: Basics.FWORD, numSyms: Basics.FWORD, sizeOptHdr: Basics.HWORD, flags: Basics.HWORD]; SectionList: TYPE = REF SectionListBody; SectionListBody: TYPE = RECORD[ list: SEQUENCE length: CARD OF SectionHeader]; SectionHeader: TYPE = REF SectionHeaderBody; SectionHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ name: Rope.ROPE ¬ NIL, pAddr: CARD32, vAddr: CARD32, size: CARD32, dataPtr: CARD32, relocPtr: CARD32, lnnoPtr: CARD32, numRelocEntries: CARD16, numLnnoEntries: CARD16, flags: CARD32]; WireSectionHeader: TYPE = REF WireSectionHeaderBody; WireSectionHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ name: PACKED ARRAY [0..7] OF BYTE, pAddr: Basics.FWORD, vAddr: Basics.FWORD, size: Basics.FWORD, dataPtr: Basics.FWORD, relocPtr: Basics.FWORD, lnnoPtr: Basics.FWORD, numRelocEntries: Basics.HWORD, numLnnoEntries: Basics.HWORD, flags: Basics.FWORD]; WireAuxHeader: TYPE = REF WireAuxHeaderBody; WireAuxHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ magic: Basics.HWORD, vStamp: Basics.HWORD, textSize: Basics.FWORD, dataSize: Basics.FWORD, bssSize: Basics.FWORD, entryPtr: Basics.FWORD, textBase: Basics.FWORD, dataBase: Basics.FWORD, tocAddress: Basics.FWORD, entryPtSectionNum: Basics.HWORD, textSectionNum: Basics.HWORD, dataSectionNum: Basics.HWORD, tocSectionNum: Basics.HWORD, loaderSectionNum: Basics.HWORD, bssSectionNum: Basics.HWORD, maxAlignmentForText: Basics.HWORD, maxAlignmentForData: Basics.HWORD, moduleTypeField: ARRAY [0..1] OF BYTE, reservedField: ARRAY [0..1] OF BYTE, maxStackSize: Basics.FWORD, reservedFields: ARRAY [0..3] OF Basics.FWORD ]; ByteEntry: TYPE = REF ByteEntryBody; ByteEntryBody: TYPE = MACHINE DEPENDENT RECORD[ val(0:0..7): BYTE]; TwoByteEntry: TYPE = REF TwoByteEntryBody; TwoByteEntryBody: TYPE = MACHINE DEPENDENT RECORD[ val(0:0..15): Basics.HWORD]; StabSize: CARD ¬ 18; WireSTEntry: TYPE = REF WireSTEntryBody; WireSTEntryBody: TYPE = MACHINE DEPENDENT RECORD[ name(0: 0..63): PACKED ARRAY [0..7] OF BYTE, value(0: 64..95): Basics.FWORD, sectionNumber(0: 96..111): Basics.HWORD, derivedType(0: 112..119): BYTE, type(0: 120..127): BYTE, storageClass(0: 128..135): BYTE, numAuxEntries(0: 136..143): BYTE, pad(0: 144..159): Basics.HWORD ]; AuxType: TYPE = {symbol, file, csect}; WireSTAuxEntry: TYPE = REF WireSTAuxEntryBody; WireSTAuxEntryBody: TYPE = MACHINE DEPENDENT RECORD[ aux(0: 0..159): SELECT OVERLAID AuxType FROM symbol => [ name(0: 0..63): PACKED ARRAY [0..7] OF BYTE, pad(0: 64..159): Basics.HWORD], file => [ fileName(0: 0..111): PACKED ARRAY [0..13] OF BYTE, pad(0: 112..159): Basics.HWORD], csect => [ csectLength(0: 0..31): Basics.FWORD, parameterType(0: 32..63): Basics.FWORD, snParameterType(0: 64..79): Basics.HWORD, alignment(0: 80..84): [0..31], symbolType(0: 85..87): [0..7], storageMappingClass(0: 88..95): BYTE, stab(0: 96..127): Basics.FWORD, snStab(0: 128..143): Basics.HWORD, pad(0: 144..159): Basics.HWORD] ENDCASE]; ReadHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED { wHeader: WireHeader ¬ NEW[WireHeaderBody]; wAuxHeader: WireAuxHeader ¬ NEW[WireAuxHeaderBody]; nBytes: INT ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader­], 0, BYTES[WireHeaderBody]]]; nBytes2: INT ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wAuxHeader­], 0, Basics.Card16FromH[wHeader.sizeOptHdr]]]; magic: CARD ¬ Basics.Card16FromH[wHeader.magic]; nBadMagic: BOOLEAN ¬ (magic # OMagic) AND (magic # NMagic)AND (magic # ZMagic); flags: CARD ¬ Basics.Card16FromH[wHeader.flags]; nPageSize: CARD ¬ 01000H; SymbolSize: CARD ¬ 18; RelocEntrySize: CARD ¬ 10; LnnoEntrySize: CARD ¬ 6; textOffset: CARD ¬ Basics.Card32FromF[wAuxHeader.textBase]; textSize: CARD ¬ Basics.Card32FromF[wAuxHeader.textSize]; iDataSeg: MemorySegmentInfo ¬ [Basics.Card32FromF[wAuxHeader.dataBase], Basics.Card32FromF[wAuxHeader.dataSize]]; symsSeg: MemorySegmentInfo ¬ [Basics.Card32FromF[wHeader.symPtr], Basics.Card32FromF[wHeader.numSyms] * SymbolSize]; textLoadOffset: CARD32 ¬ 0; linnoSeg, debugSeg, textRelocSeg, dataRelocSeg: MemorySegmentInfo ¬ [0, 0]; numSects: CARD ¬ Basics.Card16FromH[wHeader.numSections]; sectionList: SectionList ¬ NEW[SectionListBody[numSects]]; debugIndex, textIndex, dataIndex: CARD ¬ LAST[CARD]; header: Header; FOR i: CARD IN [0..numSects) DO wSectionHeader: WireSectionHeader ¬ NEW[WireSectionHeaderBody]; nBytes: INT ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader­], 0, BYTES[WireSectionHeaderBody]]]; sectionList[i] ¬ NEW[SectionHeaderBody]; FOR j: CARD IN [0..8) DO c: CARD ¬ wSectionHeader.name[j]; ch: CHAR ¬ VAL[c]; IF c = 0 THEN EXIT; sectionList[i].name ¬ sectionList[i].name.Concat[Convert.RopeFromChar[from: ch, quote: FALSE]]; ENDLOOP; sectionList[i].pAddr ¬ Basics.Card32FromF[wSectionHeader.pAddr]; sectionList[i].vAddr ¬ Basics.Card32FromF[wSectionHeader.vAddr]; sectionList[i].size ¬ Basics.Card32FromF[wSectionHeader.size]; sectionList[i].dataPtr ¬ Basics.Card32FromF[wSectionHeader.dataPtr]; sectionList[i].relocPtr ¬ Basics.Card32FromF[wSectionHeader.relocPtr]; sectionList[i].lnnoPtr ¬ Basics.Card32FromF[wSectionHeader.lnnoPtr]; sectionList[i].numRelocEntries ¬ Basics.Card16FromH[wSectionHeader.numRelocEntries]; sectionList[i].numLnnoEntries ¬ Basics.Card16FromH[wSectionHeader.numLnnoEntries]; sectionList[i].flags ¬ Basics.Card32FromF[wSectionHeader.flags]; ENDLOOP; FOR i: CARD IN [0..numSects) DO IF Rope.Equal[sectionList[i].name, ".debug", TRUE] THEN debugIndex ¬ i; IF Rope.Equal[sectionList[i].name, ".text", TRUE] THEN textIndex ¬ i; IF Rope.Equal[sectionList[i].name, ".data", TRUE] THEN dataIndex ¬ i; IF Rope.Equal[sectionList[i].name, ".loader", TRUE] THEN flags ¬ Basics.BITOR[flags, FLdMinusR]; ENDLOOP; IF debugIndex # LAST[CARD] THEN { debugSeg ¬ [sectionList[debugIndex].dataPtr, sectionList[debugIndex].size]; }; IF textIndex # LAST[CARD] THEN { linnoSeg ¬ [sectionList[textIndex].lnnoPtr, sectionList[textIndex].numLnnoEntries * LnnoEntrySize]; textOffset ¬ sectionList[textIndex].dataPtr; textRelocSeg ¬ [sectionList[textIndex].relocPtr, sectionList[textIndex].numRelocEntries * RelocEntrySize]; }; IF dataIndex # LAST[CARD] THEN { iDataSeg.byteOffset ¬ sectionList[dataIndex].dataPtr; dataRelocSeg ¬ [sectionList[dataIndex].relocPtr, sectionList[dataIndex].numRelocEntries * RelocEntrySize]; }; header ¬ NEW[HeaderBody ¬ [ dynamic: FALSE, toolversion: BYTE[0], machtype: BYTE[0], magic: magic, flags: flags, text: [textOffset, textSize], iData: iDataSeg, textReloc: textRelocSeg, dataReloc: dataRelocSeg, syms: symsSeg, debug: debugSeg, linno: linnoSeg, textLoadOffset: textLoadOffset, bssSize: Basics.Card32FromF[wAuxHeader.bssSize], entryPoint: Basics.Card32FromF[wAuxHeader.entryPtr], nPageSize: nPageSize, nEntries: Basics.Card32FromF[wHeader.numSyms], stringOffset: symsSeg.byteOffset+symsSeg.byteLength ]]; RETURN[header]; }; XCOFFModuleFromParsedAndPC: ObjectFilesPrivate.ModuleFromParsedAndPCProcType ~ { IF whole = NIL THEN RETURN[NIL] ELSE { stabRange, pcRange: StabRange; firstX, limitX: CARD; stream: IO.STREAM; [stabRange, pcRange] ¬ AlternativeFindModuleStabRange[whole, spc.relPC, moduleRope]; IF stabRange.count = 0 THEN RETURN[NIL]; firstX ¬ stabRange.first; limitX ¬ stabRange.first+stabRange.count; stream ¬ SystemInterface.GetStreamForFile[whole.file]; { ENABLE UNWIND => { SystemInterface.ReleaseStreamForFile[whole.file, stream]; }; firstSO: Stab; firstPC: CARD32 ¬ pcRange.first; lag: LIST OF Module ¬ NIL; [firstSO, ] ¬ BasicReadStab[whole, stream, firstX]; FOR modules: LIST OF Module ¬ whole.modules, modules.rest WHILE modules # NIL DO IF modules.first.firstPC = firstPC THEN -- we already have it { SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[modules.first] }; IF firstPC < modules.first.firstPC THEN -- we should have found it by now { newModule: Module ¬ CreateModule[whole, stream, stabRange, pcRange]; cell: LIST OF Module ¬ LIST[newModule]; cell.rest ¬ modules; IF lag # NIL THEN lag.rest ¬ cell ELSE whole.modules ¬ cell; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[newModule]; }; lag ¬ modules; ENDLOOP; { newModule: Module ¬ CreateModule[whole, stream, stabRange, pcRange]; cell: LIST OF Module ¬ LIST[newModule]; IF lag # NIL THEN lag.rest ¬ cell ELSE whole.modules ¬ cell; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[newModule]; }; }; }; }; CreateModule: PROC[parsed: Parsed, stream: IO.STREAM, stabRange, pcRange: StabRange ¬ [0, 0]] RETURNS[Module] = { module: Module ¬ NEW[ModuleBody]; rctw: RCTW.RCTWData ¬ NEW[RCTW.RCTWDataBody]; sizes: REF KnownSizeList ¬ NEW[KnownSizeList ¬ CopyList[KnownSizes]]; firstSO: Stab; nStabs: CARD; [firstSO, ] ¬ BasicReadStab[parsed, stream, stabRange.first, sizes]; nStabs ¬ stabRange.count; module.whole ¬ parsed; module.firstStabX ¬ 0; module.limitStabX ¬ stabRange.count; module.firstPC ¬ pcRange.first; -- firstSO.value; module.limitPC ¬ parsed.header.text.byteLength; -- (bogus, but it will suffice for reasons given earlier) module.stabs ¬ NEW[StabSet[nStabs]]; rctw.module ¬ module; {I: CARD ¬ 0; current: CARD ¬ 0; tmp: REF StabSet ¬ NIL; auxCount: CARD ¬ 0; funFlag: BOOLEAN ¬ FALSE; WHILE I SystemInterface.ReleaseStreamForFile[whole.file, stream]; stream ¬ SystemInterface.GetStreamForFile[whole.file]; [sr, pcRange] ¬ AlternativeFindModuleStabRangeInner[whole, relativePC, moduleRope, stream]; SystemInterface.ReleaseStreamForFile[whole.file, stream]; }; }; LastStabX: CARD = 0ffffffffH; AlternativeFindModuleStabRangeInner: PROC[whole: ObjectFilesPrivate.Parsed, relativePC: CARD, moduleRope: Rope.ROPE, stream: IO.STREAM] RETURNS[sr: StabRange, pcRange: StabRange ¬ [0, 0]] = { firstStabX: CARD ¬ 0; checkWholeFile: BOOL ¬ moduleRope.IsEmpty; pattern: Rope.ROPE ¬ Rope.Concat[moduleRope, ".*"]; baseSO: Stab ¬ BasicReadStab[whole, stream, firstStabX].stab; nextStabX: CARD ¬ IF baseSO.value = 0 OR baseSO.value = LastStabX THEN whole.stabLimit ELSE baseSO.value; name: Rope.ROPE ¬ baseSO.rope; IF baseSO.stabType # SO THEN RETURN[[0, 0]]; WHILE firstStabX < whole.stabLimit DO maxPC: CARD ¬ 0; minPC: CARD ¬ LAST[CARD]; highDbx: CARD ¬ baseSO.stabX; IF checkWholeFile OR (~name.IsEmpty AND Rope.Match[pattern, name]) THEN { FOR x: CARD ¬ baseSO.stabX, highDbx WHILE x < nextStabX DO info: StabIndexTypeAndValue ¬ CheckStab[whole, stream, x]; IF info.stabType = Fun OR info.stabType = SLine OR info.stabType = LBrac OR info.stabType = RBrac -- OR info.stabType = SO -- THEN { maxPC ¬ MAX[maxPC, info.value]; minPC ¬ MIN[minPC, info.value]; }; highDbx ¬ info.stabXTo + 1; ENDLOOP; IF minPC <= relativePC AND relativePC <= maxPC THEN RETURN[[baseSO.stabX, nextStabX-baseSO.stabX], [minPC, maxPC]]; }; firstStabX ¬ nextStabX; baseSO ¬ BasicReadStab[whole, stream, firstStabX].stab; nextStabX ¬ IF baseSO.value = 0 OR baseSO.value = LastStabX THEN whole.stabLimit ELSE baseSO.value; name ¬ baseSO.rope; ENDLOOP; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[[0, 0]]; }; CheckStab: ENTRY PROC[whole: Parsed, stream: IO.STREAM, stabX: CARD] RETURNS[StabIndexTypeAndValue] = { ENABLE UNWIND => NULL; rope: Rope.ROPE ¬ NIL; GetRope: PROC [] RETURNS [rope: Rope.ROPE] ~ { IF stream#previousStream THEN { cloneStream¬PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]]; previousStream ¬ stream; }; rope ¬ RopeFromData[whole, stream, wireStabBuffer.name, wireStabBuffer.sectionNumber, wireStabBuffer.storageClass, IF wireStabBuffer.numAuxEntries = 0 THEN wireStabBuffer.name ELSE wsAux.name]; }; GetSymTypeAndClass: PROC [] RETURNS [symType, class: CARD] ~ { RETURN[wsAux.symbolType, wsAux.storageMappingClass] }; IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*StabSize]; TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer­], 0, StabSize]]}; IF wireStabBuffer.numAuxEntries # 0 THEN { TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wsAux­], 0, StabSize]]}; }; RETURN[[stabX, stabX + wireStabBuffer.numAuxEntries, TypeFromData[wireStabBuffer.storageClass, GetRope, GetSymTypeAndClass, wireStabBuffer.type], Basics.Card32FromF[wireStabBuffer.value]]]; }; XCOFFVarLocFromStab: ObjectFilesPrivate.VarLocFromStabProcType ~ { header: Header ~ stab.module.whole.header; MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ { segRope:Rope.ROPE; segBase: CARD ~ SELECT kind FROM text => 0, data => header.iData.byteOffset, --header.text.byteLength,-- bss => header.textReloc.byteOffset, --header.text.byteLength + header.iData.byteLength,-- ENDCASE => ERROR; SELECT kind FROM text => segRope ¬ "text"; data => segRope ¬ "data"; bss => segRope ¬ "bss"; ENDCASE => ERROR; RETURN [NEW [ObjectFiles.VarLocBody ¬ [ bitSize: IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: fSegment[ [0, segRope], (stab.value-- - segBase--)*8, stab.value + segBase] ]]]}; SELECT stab.stabType FROM Fun => RETURN MkSegment[text]; STSym => RETURN MkSegment[data]; LCSym => RETURN MkSegment[bss]; LSym, PSym => { byteOffset: INT ~ LOOPHOLE[stab.value]; vLB: ObjectFiles.VarLoc; IF stab.stabType=PSym AND stab.size>4 AND stab.size#LAST[CARD] THEN vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [ bitSize: stab.size*8, where: indirect[ base: NEW[ObjectFiles.VarLocBody ¬ [ bitSize: 32, where: frame[bitOffset: 8*byteOffset]]], offset: CirioTypes.zeroBA]]] ELSE vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [ bitSize: IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: frame[bitOffset: 8*byteOffset]]]; RETURN[vLB]}; RSym => { vLB: ObjectFiles.VarLoc; IF stab.size>4 AND stab.size#LAST[CARD] THEN vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [ bitSize: stab.size*8, where: indirect[ base: NEW[ObjectFiles.VarLocBody ¬ [ bitSize: 32, where: register[regNum: stab.value]]], offset: CirioTypes.zeroBA]]] ELSE vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [ bitSize: IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: register[regNum: stab.value]]]; RETURN[vLB] }; GSym => RETURN [NEW [ObjectFiles.VarLocBody ¬ [ bitSize: IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: namedCommon[Rope.Concat["_", ObjectFiles.CNameOfStab[stab]], 0, 0, FALSE, FALSE] ]]]; ENDCASE => RETURN ObjectFiles.MakeUnknownVarLoc[IO.PutFR["unrecognized stabType (%02xH) for %g", [cardinal[stab.size]], [rope[ObjectFiles.CNameOfStab[stab]]] ]]; }; PCtoLineNumMap: TYPE = REF PCtoLineNumMapBody; PCtoLineNumMapBody: TYPE = ObjectFilesPrivate.PCtoLineNumMapBody; LineNumToPCMap: TYPE = REF LineNumToPCMapBody; LineNumToPCMapBody: TYPE = ObjectFilesPrivate.LineNumToPCMapBody; SLineData: TYPE = ObjectFilesPrivate.SLineData; FMap: TYPE ~ LIST OF FMapData; FMapBody: TYPE ~ RECORD [ seq: SEQUENCE len: CARD OF FMapData]; FMapData: TYPE ~ REF FMapDataBody; FMapDataBody: TYPE ~ RECORD[ fName: Rope.ROPE, stabOffset: CARD]; InstallPCLineNumMaps: PROC[module: Module, stabRange: StabRange] = { fMap, fMapTmp: FMap ¬ NIL; firstStabX: CARD ¬ stabRange.first; limitStabX: CARD ¬ stabRange.first + stabRange.count; CompareByCLineNum: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = BEGIN info1: REF SLineData ¬ NARROW[ref1]; info2: REF SLineData ¬ NARROW[ref2]; IF info1.cLineNum < info2.cLineNum THEN RETURN[less]; IF info1.cLineNum > info2.cLineNum THEN RETURN[greater]; IF info1.parsedRelPC.relPC < info2.parsedRelPC.relPC THEN RETURN[less]; IF info1.parsedRelPC.relPC > info2.parsedRelPC.relPC THEN RETURN[greater]; RETURN[equal]; END; CompareByPC: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = BEGIN info1: REF SLineData ¬ NARROW[ref1]; info2: REF SLineData ¬ NARROW[ref2]; IF info1.parsedRelPC.relPC < info2.parsedRelPC.relPC THEN RETURN[less]; IF info1.parsedRelPC.relPC > info2.parsedRelPC.relPC THEN RETURN[greater]; IF info1.cLineNum < info2.cLineNum THEN RETURN[less]; IF info1.cLineNum > info2.cLineNum THEN RETURN[greater]; RETURN[equal]; END; IF module.pcToLineNum # NIL OR module.lineNumToPC # NIL THEN { IF module.pcToLineNum = NIL OR module.lineNumToPC = NIL THEN ERROR; RETURN; }; { nItems: INTEGER ¬ 0; list1: LIST OF REF ANY ¬ NIL; -- LIST OF REF SLineData list2: LIST OF REF ANY ¬ NIL; -- LIST OF REF SLineData sortedList: LIST OF REF ANY ¬ NIL; linno, relPC, pOffset: CARD ¬ 0; inCurrentModule: BOOLEAN ¬ FALSE; stream: IO.STREAM ¬ SystemInterface.GetStreamForFile[module.whole.file]; IO.SetIndex[stream, module.whole.header.linno.byteOffset]; FOR I: CARD IN [0..module.whole.header.linno.byteLength / 6) DO IO.SetIndex[stream, module.whole.header.linno.byteOffset + I*6]; relPC ¬ Basics.Card32FromF[IO.GetFWord[stream]]; linno ¬ Basics.Card16FromH[IO.GetHWord[stream]]; IF linno = 0 THEN IF relPC <= limitStabX AND relPC >= firstStabX THEN { inCurrentModule ¬ TRUE; IO.SetIndex[stream, module.whole.header.syms.byteOffset + 18 * relPC + 18 * 5 + 4]; pOffset ¬ Basics.Card16FromH[IO.GetHWord[stream]]; } ELSE inCurrentModule ¬ FALSE ELSE IF inCurrentModule THEN { info: REF SLineData ¬ NEW[SLineData ¬ [cLineNum: linno + pOffset - 1, parsedRelPC: [[0 --??--, PFS.RopeFromPath[module.fileName]], relPC]]]; list1 ¬ CONS[info, list1]; list2 ¬ CONS[info, list2]; nItems¬nItems + 1; }; ENDLOOP; SystemInterface.ReleaseStreamForFile[module.whole.file, stream]; sortedList ¬ List.Sort[list1, CompareByCLineNum]; module.lineNumToPC ¬ NEW[LineNumToPCMapBody[nItems]]; FOR I: INTEGER IN [0..nItems) DO info: REF SLineData ¬ NARROW[sortedList.first]; module.lineNumToPC[I] ¬ info­; sortedList ¬ sortedList.rest; ENDLOOP; sortedList ¬ List.Sort[list2, CompareByPC]; module.pcToLineNum ¬ NEW[PCtoLineNumMapBody[nItems]]; FOR I: INTEGER IN [0..nItems) DO info: REF SLineData ¬ NARROW[sortedList.first]; module.pcToLineNum[I] ¬ info­; sortedList ¬ sortedList.rest; ENDLOOP; }; }; BasicReadStab: ENTRY PROC[parsed: Parsed, stream: IO.STREAM, stabX: CARD, sizes: REF KnownSizeList ¬ NIL] RETURNS[stab: Stab, nAux: CARD ¬ 0] ~ { ENABLE UNWIND => NULL; stab ¬ NEW[StabBody]; [stab­, nAux] ¬ ReadStabBody[parsed, stream, stabX, sizes]; RETURN }; TypeFromData: PROC [data: BYTE, getName: PROC RETURNS [Rope.ROPE], getSymTypeAndClass: PROC RETURNS [symType, class: CARD], typ: BYTE ¬ 0] RETURNS [stabType: StabType] ~ { dataVal: CARD ¬ data; typeVal: CARD ¬ typ; IF typeVal = 20H THEN stabType ¬ Fun ELSE SELECT dataVal FROM Block => { name: Rope.ROPE ¬ getName[]; SELECT TRUE FROM Rope.Equal[".bb", name] => stabType ¬ LBrac; Rope.Equal[".eb", name] => stabType ¬ RBrac; ENDCASE => ERROR; }; Brac => { name: Rope.ROPE ¬ getName[]; SELECT TRUE FROM Rope.Equal[".bf", name] => stabType ¬ LBrac; Rope.Equal[".ef", name] => stabType ¬ RBrac; ENDCASE => ERROR; }; PSym => stabType ¬ PSym; LSym => stabType ¬ LSym; RSym => stabType ¬ RSym; STSym => stabType ¬ STSym; GSym => stabType ¬ GSym; HidEnt => { symType, class: CARD; [symType, class] ¬ getSymTypeAndClass[]; IF symType = XTYSD AND class = XMCRW THEN stabType ¬ Invalid ELSE stabType ¬ Unspecified; }; SO => stabType ¬ SO; ENDCASE => stabType ¬ Unspecified }; DebugStab: CARD = 0fffeH; previousStream: IO.STREAM ¬ NIL; cloneStream: IO.STREAM ¬ NIL; ReadStabBody: PROC [parsed: Parsed, stream: IO.STREAM, stabX: CARD, sizes: REF KnownSizeList] RETURNS [stab: StabBody, nAux: CARD ¬ 0] ~ { size: CARD; rope: Rope.ROPE ¬ NIL; GetRope: PROC [] RETURNS [Rope.ROPE] ~ { RETURN[rope] }; GetSymTypeAndClass: PROC [] RETURNS [symType, class: CARD] ~ { RETURN[wsAux.symbolType, wsAux.storageMappingClass] }; IO.SetIndex[stream, parsed.header.syms.byteOffset+stabX*StabSize]; TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer­], 0, StabSize]]}; IF wireStabBuffer.numAuxEntries # 0 THEN { TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wsAux­], 0, StabSize]]}; }; nAux ¬ wireStabBuffer.numAuxEntries; IF stream#previousStream THEN { cloneStream¬PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]]; previousStream ¬ stream; }; rope ¬ RopeFromData[parsed, cloneStream, wireStabBuffer.name, wireStabBuffer.sectionNumber, wireStabBuffer.storageClass, IF wireStabBuffer.numAuxEntries = 0 THEN wireStabBuffer.name ELSE wsAux.name]; IF sizes # NIL THEN [size, sizes­] ¬ SizeFromName[rope, sizes­] ELSE size ¬ 0; stab ¬ [ module: NIL, stabX: stabX, stabType: TypeFromData[wireStabBuffer.storageClass, GetRope, GetSymTypeAndClass, wireStabBuffer.type], --wireStabBuffer.type, value: Basics.Card32FromF[wireStabBuffer.value], size: size, rope: rope ]; RETURN}; dataChar: ByteEntry ¬ NEW[ByteEntryBody]; RopeFromData: PROC [parsed: Parsed, stream: IO.STREAM, data: PACKED ARRAY [0..7] OF BYTE, sn: Basics.HWORD, storeClass: BYTE, auxData: PACKED ARRAY [0..7] OF BYTE] RETURNS [name: Rope.ROPE ¬ NIL] ~ TRUSTED { len: TwoByteEntry ¬ NEW[TwoByteEntryBody]; dbg: BOOL ¬ IF Basics.Card16FromH[sn] = DebugStab THEN TRUE ELSE FALSE; sum, offset: CARD ¬ 0; IF dbg AND storeClass = 67H THEN { data ¬ auxData; dbg ¬ FALSE; }; offset ¬ IF dbg THEN parsed.header.debug.byteOffset ELSE parsed.header.stringOffset; FOR i: CARD IN [0..4) DO n: CARD ¬ data[i]; sum ¬ sum + n; ENDLOOP; IF sum = 0 THEN { FOR i: CARD IN [4..8) DO n: CARD ¬ data[i]; sum ¬ sum * 256 + n; ENDLOOP; IO.SetIndex[stream, offset + sum]; IF IO.EndOf[stream] THEN RETURN[""]; DO c: CHAR ¬ ' ; c ¬ IO.GetChar[stream]; IF c = VAL[0] THEN EXIT; name ¬ name.Concat[Convert.RopeFromChar[from: c, quote: FALSE]]; ENDLOOP; } ELSE FOR i: CARD IN [0..8) DO num: CARD ¬ data[i]; IF num = 0 THEN EXIT; name ¬ name.Concat[Convert.RopeFromChar[from: VAL[num], quote: FALSE]]; ENDLOOP; RETURN }; wireStabBuffer: WireSTEntry ¬ NEW[WireSTEntryBody]; wsAux: WireSTAuxEntry ¬ NEW[WireSTAuxEntryBody]; RandomTestFindStabRange: Commander.CommandProc = { args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; path: PATH ¬ PFS.PathFromRope[args[1]]; fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[]; { ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet]; file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path]; nextSeed: INT ¬ IF args.argc < 3 THEN 4466 ELSE Convert.IntFromRope[args[2]]; start: BasicTime.GMT ¬ BasicTime.Now[]; WHILE TRUE DO rs: Random.RandomStream ¬ Random.Create[seed: nextSeed]; whole: Parsed ¬ ObjectFiles.CreateParsed[file, "XCOFF"]; IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed], IO.time[start]]; FOR I: INT IN [0..100) DO range: StabRange; pc: CARD ¬ Random.ChooseInt[rs, 0, whole.header.text.byteLength]; [range, ] ¬ AlternativeFindModuleStabRange[whole, pc]; IO.PutF[cmd.out, "\Tpc = %g gives firstX: %g count: %g\N", IO.card[pc], IO.card[range.first], IO.card[range.count]]; ENDLOOP; ENDLOOP; }; SystemInterface.CloseFileSet[fileSet]; }; SizeFromName: PROC[name:ROPE, sizes: KnownSizeList ¬ NIL] RETURNS [size: CARD ¬ 0, newSizes: KnownSizeList] ~ { c: CHAR; newID: CARD; where: CARD ¬ 0; IF sizes = NIL THEN RETURN; newSizes ¬ sizes; where ¬ Rope.Index[name, 0, ":"] + 1; IF where = ABS[name.Length[]]+ 1 THEN RETURN; IF (c ¬ name.Fetch[where]) # 't AND c # 'T THEN { typeID: INT; IF IsDigit[c] OR c = '- THEN [typeID, ] ¬ GetNum[name, where] ELSE [typeID, ] ¬ GetNum[name, where+1]; RETURN[FindInList[typeID, sizes], newSizes]; }; [newID, where] ¬ GetNum[name, where+ 1]; IF name.Fetch[where] # '= THEN ERROR; where ¬ where + 1; SELECT name.Fetch[where] FROM 'f => { type: INT; [type, where] ¬ GetNum[name, where+ 1]; size ¬ FindInList[type, sizes]; }; '*, 'e => size ¬ 4; 'u, 's => { [size, where] ¬ GetNum[name, where +1]}; 'a => { garb, start, end, type: INT; baseSize: CARD; c: CHAR ¬ name.Fetch[where + 1]; IF c# 'r THEN ERROR; [garb, where] ¬ GetNum[name, where+2]; IF name.Fetch[where] # '; THEN ERROR; [start, where] ¬ GetNum[name, where+1]; IF name.Fetch[where] # '; THEN ERROR; [end, where] ¬ GetNum[name, where+1]; IF name.Fetch[where] # '; THEN ERROR; [type, where] ¬ GetNum[name, where+1]; baseSize ¬ FindInList[type, sizes]; size ¬ (end - start + 1) * baseSize; }; ENDCASE => size ¬ 0; newSizes ¬ CONS[[newID, size], newSizes]; size ¬ 0; }; GetNum: PROC [rope: ROPE, index: CARD] RETURNS [num: INT ¬ 0, newIndex: CARD ¬ 0] ~ { len: CARD ¬ rope.Length[]; i: CARD; negFlag: BOOL ¬ FALSE; FOR i ¬ index, i + 1 UNTIL i = len DO c: CHAR ¬ rope.Fetch[i]; IF ~IsDigit[c] AND c # '- THEN { newIndex ¬ i; EXIT; }; IF c = '- THEN negFlag ¬ TRUE ELSE num ¬ num * 10 + (c - '0); ENDLOOP; IF i = len THEN newIndex ¬ i; IF negFlag THEN num ¬ -num; }; KnownSize: TYPE ~ RECORD[typeID: INT, size: CARD]; KnownSizeList: TYPE ~ LIST OF KnownSize; KnownSizes: KnownSizeList ¬ LIST[[-1, 4], [-2, 1], [-3, 2], [-4, 4], [-5, 1], [-6, 1], [-7, 2], [-8, 4], [-9, 4], [-10, 4], [-11, 0], [-12, 4], [-13, 8], [-14, 10], [-15, 4], [-16, 1], [-17, 4], [-18, 8], [-19, 1], [-20, 1], [-21, 1], [-22, 2], [-23, 1], [-24, 1], [-25, 8], [-26, 16], [-27, 1], [-28, 2], [-29, 4], [-30, 2]]; CopyList: PROC [l: KnownSizeList] RETURNS [n: KnownSizeList ¬ NIL] ~ { n ¬ NIL; FOR i: KnownSizeList ¬ l, i.rest WHILE i # NIL DO n ¬ CONS[i.first, n]; ENDLOOP; }; FindInList: PROC [i: INT, l: KnownSizeList] RETURNS [s: CARD ¬ LAST[CARD]] ~ { FOR loop: KnownSizeList ¬ l, loop.rest WHILE loop # NIL DO IF loop.first.typeID = i THEN RETURN[loop.first.size]; ENDLOOP; ERROR; }; IsDigit: PROC [c: CHAR] RETURNS [BOOL] = INLINE { RETURN [c IN ['0 .. '9]] }; XCOFFGetTypeRef: ObjectFilesPrivate.GetTypeRefProcType ~ { typeRef: Rope.ROPE; lastChar: CHAR; IF IsDigit[lastChar ¬ IO.PeekChar[sourceStream]] OR lastChar = '- THEN { typeRef ¬ RCTW.GetTokenRope[sourceStream]; RETURN[typeRef]} ELSE DO lastChar ¬ IO.GetChar[sourceStream]; typeRef ¬ Rope.Concat[typeRef, Rope.FromChar[lastChar]]; IF lastChar = ') THEN RETURN[typeRef] ENDLOOP }; XCOFFInstallBracketPairsForOneFunStab: PROC[module: Module, funStabIndex: CARD] = { funStab: Stab ¬ module.funStabs[funStabIndex].stab; paramNames, lastParamName: LIST OF Rope.ROPE ¬ NIL; paramStabs, lastParamStab: LIST OF Stab ¬ NIL; -- includes param mod stabs x: CARD ¬ funStab.stabX+1; good: BOOL ¬ TRUE; module.funStabs[funStabIndex].brackets ¬ NEW[BracketPairBody¬[ module: module, kind: syntheticFun, firstX: funStab.stabX, limitX: 0, firstPC: funStab.value, pcLimit: 0, funStab: funStab, funIndex: funStabIndex, symbols: NIL, innerBrackets: NIL]]; WHILE x < module.limitStabX DO stab: Stab ¬ ObjectFilesPrivate.ReadStab[module, x]; TakeBP: PROC ~ { finalRBracX: CARD; [finalRBracX, module.funStabs[funStabIndex].brackets.innerBrackets, paramStabs] ¬ ScanOneBracketPairSequence[module, funStab, funStabIndex, x, paramStabs, lastParamStab]; IF good THEN module.funStabs[funStabIndex].brackets.limitX ¬ finalRBracX+1; module.funStabs[funStabIndex].brackets.pcLimit ¬ IF finalRBracX { stabCell: LIST OF Stab ¬ LIST[stab]; name: Rope.ROPE ¬ ObjectFiles.CNameOfStab[stab]; nameCell: LIST OF Rope.ROPE ¬ LIST[name]; IF paramStabs#NIL AND stab=paramStabs.first THEN ERROR; IF paramNames = NIL THEN paramNames ¬ nameCell ELSE lastParamName.rest ¬ nameCell; lastParamName ¬ nameCell; IF paramStabs = NIL THEN paramStabs ¬ stabCell ELSE lastParamStab.rest ¬ stabCell; lastParamStab ¬ stabCell}; RSym, LSym => { stabCell: LIST OF Stab ¬ LIST[stab]; name: Rope.ROPE ¬ ObjectFiles.CNameOfStab[stab]; isAParam: BOOLEAN ¬ FALSE; -- initial value FOR pNames: LIST OF Rope.ROPE ¬ paramNames, pNames.rest WHILE pNames # NIL DO IF Rope.Equal[name, pNames.first] THEN {isAParam ¬ TRUE; EXIT}; ENDLOOP; IF isAParam THEN { IF paramStabs = NIL THEN paramStabs ¬ stabCell ELSE lastParamStab.rest ¬ stabCell; lastParamStab ¬ stabCell} ELSE -- we are facing the first symbol of a nested block {TakeBP[]; EXIT}; }; GSym, LCSym, STSym => IF good THEN { module.funStabs[funStabIndex].brackets.limitX ¬ stab.stabX; good ¬ FALSE}; SLine, Unspecified => NULL; LBrac => {TakeBP[]; EXIT}; Fun => { IF good THEN module.funStabs[funStabIndex].brackets.limitX ¬ stab.stabX; module.funStabs[funStabIndex].brackets.pcLimit ¬ stab.value; EXIT}; ENDCASE => ObjectFilesPrivate.RaiseUnreadableObjectFileForFun[ IO.PutFR["Unexpected stab (of stabType %02xH) in intro to %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]] ], module, funStab]; x ¬ x + 1; REPEAT FINISHED => { IF good THEN module.funStabs[funStabIndex].brackets.limitX ¬ module.limitStabX; module.funStabs[funStabIndex].brackets.pcLimit ¬ module.limitPC; }; ENDLOOP; module.funStabs[funStabIndex].brackets.symbols ¬ paramStabs; RETURN}; BracketPair: TYPE ~ ObjectFilesPrivate.BracketPair; BracketPairBody: TYPE ~ ObjectFilesPrivate.BracketPairBody; ScanOneBracketPairSequence: PROC[module: Module, fun: Stab, funIndex: CARD, firstX: CARD, symHead, symTail: StabList] RETURNS[--finalRBracX-- CARD, --innerBrackets-- LIST OF BracketPair, --symbols-- StabList] = { innerBrackets: LIST OF BracketPair ¬ NIL; lastInnerBracket: LIST OF BracketPair ¬ NIL; x: CARD ¬ firstX; DO xAfterSymbs: CARD; stabAfterSymbs: Stab; [xAfterSymbs, symHead, symTail] ¬ ObjectFilesPrivate.ScanSymbolStabs[module, x, symHead, symTail]; IF xAfterSymbs >= module.limitStabX THEN RETURN[xAfterSymbs, innerBrackets, symHead]; stabAfterSymbs ¬ ObjectFilesPrivate.ReadStab[module, xAfterSymbs]; SELECT stabAfterSymbs.stabType FROM LBrac => { finalRBracX: CARD; nestedInnerBrackets: LIST OF BracketPair; bracket: BracketPair; bracketCell: LIST OF BracketPair; [finalRBracX, nestedInnerBrackets, symHead] ¬ ScanOneBracketPairSequence[module, fun, funIndex, xAfterSymbs+1, symHead, symTail]; bracket ¬ NEW[BracketPairBody¬[ module: module, kind: actual, firstX: stabAfterSymbs.stabX, limitX: finalRBracX+1, firstPC: stabAfterSymbs.value, pcLimit: IF finalRBracX RETURN[xAfterSymbs, innerBrackets, symHead]; ENDCASE => ERROR; -- can't happen ENDLOOP}; GlobalPreDefinedTypes: REF PDTType ¬ NIL; GPTDs: LIST OF Rope.ROPE ¬ LIST [ "int:t-1=r-1;-2147483648;2147483647", "char:t-2=@s8;r-2;0;255", "short:t-3=@s16;r-3;-32768;32767", "long:t-4=-1", "unsigned char:t-5=@s8;r-5;0;255", "signed char:t-6=@s8;r-6;-128;127", "unsigned short:t-7=@s16;r-7;0;65535", "unsigned int:t-8=r-8;0;4294967295", "unsigned:t-9=-8", "unsigned long:t-10=-8", "void:t-11=r-11;0;0", "float:t-12=g-12;4", "double:t-13=g-12;8", "long double:t-14=g-12;10", "integer:t-15=-1", "boolean:t-16=efalse:0,true:1,", "shortreal:t-17=g-12;4", "real:t-18=g-12;8", "stringptr:t-19=N-19", "character:t-20=@s8;r-20;0;255", "logical*1:t-21=@s8;r-21;0;255", "logical*2:t-22=@s16;r-22;0;65535", "logical*4:t-23=r-23;0;4294967295", "logical:t-24=-23", "complex:t-25=c-25;8", "double complex:t-26=c-25;16", "integer*1:t-27=-6", "integer*2:t-28=-3", "integer*4:t-29=-1", "wchar:t-30=@s16;r-30;0;65535"]; PDTType: TYPE ~ RECORD [body: SEQUENCE length: CARD OF Rope.ROPE]; IntallPreDefinedTypes: PROC ~ { count: CARD ¬ 0; l: LIST OF Rope.ROPE ¬ NIL; FOR l ¬ GPTDs, l.rest UNTIL l = NIL DO count ¬ count + 1; ENDLOOP; GlobalPreDefinedTypes ¬ NEW[PDTType[count]]; l ¬ GPTDs; FOR index: CARD IN [0..count) DO GlobalPreDefinedTypes[index] ¬ l.first; l ¬ l.rest; ENDLOOP; }; GetDataSectionOffset: PROC[module: Module] RETURNS[CARD] ~ { IsDotO: PROC RETURNS[BOOL] ~ { RETURN[Basics.BITAND[module.whole.header.flags, (FLdMinusR+FShrObj+FDynLoad+FExec)] = 0]; }; IF IsDotO[] THEN RETURN [0]; FOR x: CARD DECREASING IN [module.firstStabX..module.limitStabX) DO stab: Stab ¬ ObjectFilesPrivate.ReadStab[module, x]; IF stab.stabType = Invalid THEN RETURN [stab.value]; ENDLOOP; RETURN [0]; }; XCOFFInstallStaticVars: ObjectFilesPrivate.InstallStaticVarsType ~ { numFuns: INT ¬ 1; dataStabOffset: CARD ¬ 0; -- globalFrame stab seems to be offset from versionStringStab, which has to be searched for at times... IF NOT module.staticVarsInstalled THEN FOR y: CARD IN [module.firstStabX..module.limitStabX) DO x: CARD ¬ module.firstStabX + module.limitStabX - 1 - y; stab: Stab ¬ ObjectFilesPrivate.ReadStab[module, x]; IF stab = NIL THEN LOOP; IF stab.stabType = Fun THEN { IF numFuns = 0 THEN EXIT; numFuns ¬ numFuns - 1; }; IF stab.stabType = STSym OR stab.stabType = LCSym THEN { IF module.versionStampStab = NIL THEN { gvi: ObjectFiles.GlobalVarLoc ¬ NIL; gvi ¬ NARROW[ObjectFilesPrivate.CheckStaticVar[stab, "versionStamp", TRUE]]; IF gvi # NIL THEN { stream: IO.STREAM ¬ NIL; dataRope: Rope.ROPE; module.versionStampStab ¬ stab; dataStabOffset ¬ GetDataSectionOffset[module]; dataRope ¬ ObjectFilesPrivate.ReadInitialDataAsRope[module, gvi.fileByteOffset + dataStabOffset]; IF dataRope.IsEmpty[] THEN { ENABLE UNWIND => SystemInterface.ReleaseStreamForFile [module.whole.file, stream]; searchFor: Rope.ROPE ¬ "@(#)"; c: CHAR; searchForIndex: INT ¬ 0; found: BOOL ¬ FALSE; stream ¬ SystemInterface.GetStreamForFile[module.whole.file]; IO.SetIndex[stream, gvi.fileByteOffset + dataStabOffset]; dataRope ¬ ""; WHILE ~found DO tmpOffset: CARD ¬ 0; WHILE ((c ¬ IO.GetChar[stream]) # searchFor.Fetch[searchForIndex]) DO dataStabOffset ¬ dataStabOffset + 1; ENDLOOP; tmpOffset ¬ tmpOffset + 1; searchForIndex ¬ searchForIndex + 1; WHILE (searchForIndex < searchFor.Length[] AND (c ¬ IO.GetChar[stream]) = searchFor.Fetch[searchForIndex]) DO tmpOffset ¬ tmpOffset + 1; searchForIndex ¬ searchForIndex + 1; ENDLOOP; tmpOffset ¬ tmpOffset + 1; IF searchForIndex = searchFor.Length[] THEN found ¬ TRUE ELSE dataStabOffset ¬ dataStabOffset + tmpOffset; ENDLOOP; dataRope ¬ searchFor; WHILE ((c ¬ IO.GetChar[stream]) # '\000) DO dataRope ¬ dataRope.Concat[Rope.FromChar[c]]; ENDLOOP; SystemInterface.ReleaseStreamForFile [module.whole.file, stream]; }; stab.value ¬ stab.value+dataStabOffset; IF module.globalFrameStab # NIL THEN module.globalFrameStab.value ¬ module.globalFrameStab.value + dataStabOffset; IF module.globalFrameStab # NIL THEN { module.globalFrameGvl.bitOffset ¬ module.globalFrameGvl.bitOffset + dataStabOffset * 8; module.globalFrameGvl.fileByteOffset ¬ module.globalFrameGvl.fileByteOffset + dataStabOffset; }; module.versionStampInfo ¬ NEW[ObjectFiles.VersionStampInfo¬[gvi, dataRope]]; LOOP; }; }; IF module.globalFrameStab = NIL THEN { gvi: ObjectFiles.GlobalVarLoc ¬ NIL; gvi ¬ NARROW[ObjectFilesPrivate.CheckStaticVar[stab, "globalframe", TRUE]]; IF gvi # NIL THEN { module.globalFrameStab ¬ stab; module.globalFrameGvl ¬ gvi; LOOP; }; }; }; ENDLOOP; module.staticVarsInstalled ¬ TRUE; }; XCOFFAlterFunStab: ObjectFilesPrivate.AlterFunStabType ~ { RETURN [module.funStabs[funStabX].stab]; }; XCOFFGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ { RETURN [0]; }; transTable: ObjectFilesPrivate.TranslationTable; IntallPreDefinedTypes[]; transTable ¬NEW[ObjectFilesPrivate.TranslationTableBody[1]]; Commander.Register["xcoffRandomTestFindStabRange", RandomTestFindStabRange]; transTable[0] ¬ [0, 2, 479, "XCOFF"]; ObjectFilesPrivate.RegisterObjectFileFlavor[NEW [ObjectFilesPrivate.ObjectFileFlavorBody ¬ [ "XCOFF", XCOFF, ReadHeader, XCOFFModuleFromParsedAndPC, XCOFFVarLocFromStab, XCOFFGetTypeRef, XCOFFInstallBracketPairsForOneFunStab, NIL, NIL, NIL, FALSE, XCOFFInstallStaticVars, XCOFFAlterFunStab, XCOFFGetSPOffset ]], transTable]; END. &¦ XCOFFFiles.mesa Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Modified from DotOAccessImpl.mesa Laurie Horton, June 24, 1992 6:07 pm PDT Philip James, February 24, 1992 11:40 am PST Last tweaked by Mike Spreitzer October 2, 1992 1:27 pm PDT Chauser, March 24, 1992 5:25 pm PST Katsuyuki Komatsu June 21, 1992 1:55 pm PDT Useful types Following types are defined in ObjectFiles some Stab types LBrac: BYTE = 00H; RBrac: BYTE = 00H; SLine: BYTE = 00H; LCSym: BYTE = 00H; Decl: BYTE = 8cH; interesting symbol type interesting storage mapping class Following types are defined in ObjectFilesPrivate Following values are of global interest pj theContStab: Stab ~ [edo: NIL, stabX: CARD.LAST, stringX: CARD32.LAST, type: BYTE.LAST, other: BYTE.LAST, desc: CARD16.LAST, value: CARD32.LAST, rope: "don't look at me, I'm a continuation of an earlier stab", dx: CARD.LAST]; This stab is put in edo.stabs[i] wherever continuation stabs would appear. DotOCookies The following computations are adapted from /usr/include/sys/exec.h, obtained by: REdit cartiff -f /usr/include/sys/exec.h The following computations are adapted from /usr/include/sun4/a.out.h, obtained by: REdit cartiff -f /usr/include/sun4/a.out.h The following symbols are adapted from /usr/include/filehdr.h The following record type was constructed based on page 1339 of the Sun Release 4.0 documentation (A.OUT documentation) PROC[stream: IO.STREAM] RETURNS[Header] = TRUSTED { The following computations are adapted from /usr/include/sun4/a.out.h, obtained by: REdit cartiff -f /usr/include/sun4/a.out.h IF wHeader.machtype = MOldsun2 THEN OldPageSize ELSE PageSize; IF wHeader.machtype = MOldsun2 THEN (IF magic = ZMagic THEN nPageSize ELSE BYTES[WireHeaderBody]) ELSE (IF magic = ZMagic THEN 0 ELSE BYTES[WireHeaderBody]); iDataSeg: SegmentInfo _ [textOffset + textSize, Basics.Card32FromF[wHeader.iDataSize]]; dataRelocSeg.byteOffset+dataRelocSeg.byteLength, Basics.Card32FromF[wHeader.symsSize]]; debugSeg: MemorySegmentInfo _ [Basics.Card32FromF[wHeader.symPtr], Basics.Card32FromF[wHeader.numSyms] * SymbolSize]; IF magic = ZMagic THEN 02000H ELSE 0; text segment is loaded into memory at nominal 0 + textLoadOffset the 02000H is the largest page size on certain machines, and allows the first page of memory to remain unmapped. iDataSeg.byteOffset+iDataSeg.byteLength, Basics.Card32FromF[wHeader.trSize]]; textRelocSeg.byteOffset+textRelocSeg.byteLength, Basics.Card32FromF[wHeader.drSize]] EmbeddedDotOs We assume that there are dbx stabs located in the dotO in the symbol table entry range [firstX..limitX). We assume that the first stab is a SO stab whose value is the next module symbol table entry of the embedded dotO. We assume that this stab is a SO stab containing the file name. The first and limitX have presumably been obtained by other means. For example, at this writing the CirioNub will provide access to a table of pc ranges located in the target world. (In addition, we provide a rather crude mechanism below to use when the CirioNub approach is not available. (e.g., when examining a file that is not part of a PCedar load state.) We are unable to define a legitimate limitPC. We assume that when, later, an attempt is made to look up a pc in the bracket structure, we have already determined that that pc definitely belongs to this EmbeddedDotO. Thus, we can use header.textSize as a (bogus) limitPC. PROC[whole: Parsed, spc: FileSegmentPC, moduleRope: ROPE _ NIL] RETURNS[Module] = { nest so that we can catch unwinds and release the stream first, see if we already have it prepare the embeddedDotO for a call on BuildBrackets lets read the all stabs now (without their ropes) (I did some timing tests on a Dorado for RopeImpl. It took about 6 seconds to perform this loop, including the allocates. On the other hand, it takes about 4 seconds to spin through the entries without allocating the stab records. So, since at some point I have to traverse all the entries to find the Fun stabs, I might as well allocate them.) (we also relocate the pc value of bracket stabs.) now lets finish up module.firstSO _ module.stabs[0]; module.secondSO _ IF module.stabs[module.stabs[0].dx].stabType = SO THEN module.stabs[module.stabs[0].dx] ELSE NIL; module.fileName _ PFS.PathFromRope[IF module.secondSO = NIL THEN ReadStabRope[module.firstSO] ELSE ReadStabRope[module.secondSO]]; Finding Embedded dotOs This procedure should only be used when examining a dotO which is not in the load state. If we are given a pc in a running PCR, it is far faster to use procedures in LoadStateAccess to obtain the stab range for an embedded dot O. Those procedures use a table available from the nub to find the stab range, then produce the embedded dotO through a call on CreateEmbeddedDotO. baseSO.value points the next baseSO on AIX. baseSO.value points the next baseSO on AIX. PROC [stab: Stab] RETURNS [DotOAccess.VarLoc] ~ { PJames 1/31/92: Doesn't look appropriate for XCoff...stab.value has a different type of value... IF stab.value < segBase THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["value (%xH) less than segment base (%xH) for symbol %g in %g", [cardinal[stab.value]], [cardinal[segBase]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]] ]]; C Line-Number to Relative-PC maps sorted by PC sorted by Line Num CompareBySI: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = BEGIN info1: FMapData _ NARROW[ref1]; info2: FMapData _ NARROW[ref2]; IF info1.stabOffset < info2.stabOffset THEN RETURN[less]; IF info1.stabOffset > info2.stabOffset THEN RETURN[greater]; RETURN[equal]; END; we have to create them FOR I: CARD IN [module.firstStabX..module.limitStabX) DO stab: Stab _ ReadStab[module, I]; IF stab.stabType = SLine THEN { info: REF SLineData _ NEW[SLineData_[cLineNum: --pj fill this in! stab.desc-- 0, parsedRelPC: [[2, ".text"], stab.value]]]; list1 _ CONS[info, list1]; list2 _ CONS[info, list2]; nItems _ nItems+1}; ENDLOOP; Stabs This routine treats stabX as relative to the entire containing dotO file. warning: does NOT relocate LBrac or RBrac stabs. warning: does NOT read the associated rope Also: the edo field is set to NIL; 00000H => SLine; -- no SLine s in XCOFF Fun => stabType _ Fun; -- gets in the way. 00000H => LCSym; -- ? 00000H => Main; -- not used? 00000H => BIncl; 00000H => EIncl; 00000H => SOL; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@dataChar^], 0, 1]]}; c _ dataChar.val; all users should be in the monitor typeID: INT _ -1; IF IsDigit[c] THEN typeID _ Convert.IntFromRope[name.Substr[where]] ELSE typeID _ Convert.IntFromRope[name.Substr[where + 1]]; These sizes were determined from /usr/include/dbxstclass.h (no guarantees though) PROC [sourceStream:IO.STREAM] RETURNS [Rope.ROPE] The function stab is module.funStabs[funStabIndex].stab The following loop finds the limitX and pcLimit. These might be at different X values if there are global symbols between procedures (which can happen with Sun's cc). good goes false once we've found the limitX and are just looking for the pcLimit. The loop also accumulates innerBrackets, if any. We make a feeble attempt to distinguish parameters from local variables; this attempt will fail for Gnu cc; it it's important to get this right, look at the `symbol descriptor' in a variable's stab. We assume the following structure: some param stabs some stabs that modify the param stabs symbol stabs for the first inner block (if any) Note that both C compilers feels free to omit the LBrac and RBrac of a procedure with no local variables. Gnu cc further feels free to omit the L&RBrac of procedures with no non-trivial nested scopes. this is coded to expect the symbols before the LBrac. We have discovered that the Sun C compiler places local variables symbols in the symbol table before their enclosing left bracket.!! This is confirmed by the example in "Dbx and Dbxtool Interfaces, Second Edition, Revised, 7 January 1988. See lines 46 and 47 on page 28. It is also confirmed by some comments in /import/gdb/dbxread.c. See source position 90236. This is in the vicinity of "case N_RBRAC". On the positive side, the code in /import/gdb/dbxread.c confirms that the local variables symbols are expected to be properly sorted in some way with respect to the RBrac/LBrac stabs. The comment in /import/gdb/dbxread.c also suggests that there are some C compilers that place the symbols inside the LBrac/RBrac pair. It shouldn't be difficult to recode this to handle the second case. One will have to collect the symbols during the scan. For full generality, one might expect to receive the symbols anytime one is outside an inner pair. We assume that firstX is pointing at the first symbol of the first bracket pair. (If the enclosing bracket pair is an innermost pair, then firstX is pointing at either an RBrac, a Fun, or is an attempt to go past the end of the symbol table.) Upon return, nextX will point to an unmatched RBrac, a Fun, or will be an attempt to go past the end of the symbol table. It seems AIX ld doesn't relocate static symbol (STSym) offset. So, we get data section's base offset and add the offset to local symbol offset. Section's base offset doesn't correct if file is .o. PROC[module: Module] = this procedure examines all stabs up to the first Fun stab, looking for certain expected stabs. These are recorded in the whole. Force find the version stamp mob Before ld, the version stamp mob is further into the .data section than usual, and the stab entry shows no indication of this, so if no rope was found at the correct location, walk through until @(#) is found. rope assignement has been done in CreateModule. module.funStabs[funStabX].stab.rope _ module.stabs[module.funStabs[funStabX].firstX+1].rope; On AIX, SP offset from FP is always 0 (SP = FP). Main code Ê6–"cedarcode" style•NewlineDelimiter ™codešœ™Kšœ ÏeœC™NK™!K™(K™,K™:K™#K™+—K˜šÏk ˜ Kš œžœžœžœ(žœžœ˜QKšœ žœžœ˜Kšœžœ˜$Kšœ žœ ˜Kšœ žœ˜(Kšœ žœ˜+Kšœžœ˜)KšžœžœLžœ˜rKšœžœžœ˜$Kšœ žœ×˜èKšœžœ³˜ËKšžœžœF˜OKšœ žœžœ˜Kšœžœ#˜/Kšžœžœ(˜2Kšœžœ@žœ˜PKšœžœh˜}—K˜K˜K˜šÏn œžœž˜Kšžœ?žœ)žœ žœ˜™Kšžœ ˜—Kšœž˜K˜KšŸœžœ&žœžœ˜RK˜™ Kšžœžœžœ˜Kšžœžœ žœ˜—K˜™*K˜Kšœžœ˜K˜Kšœ žœ˜&Kšœ žœ˜&K˜Kšœžœ˜0Kšœžœ ˜6K˜Kšœ™K˜KšŸœžœ˜KšŸœžœ˜KšŸœžœ™KšŸœžœ™KšŸœžœ˜KšŸœžœ™KšŸœžœ˜KšŸœžœ™KšŸœžœ™KšŸœžœ˜KšŸœžœ˜KšŸœžœ˜KšŸœžœ˜KšÐbkœžœ˜šŸœžœ˜K™Kš œžœÏc˜/K™!Kš œžœ¡˜&—K˜—K˜™1K™Kšœžœžœ ˜Kšœ žœžœ!˜8K˜Kšœžœžœ ˜Kšœ žœžœ!˜8K˜Kšœžœžœ ˜Kšœ žœžœ!˜8K˜Kšœ žœ˜-Kšœ žœ˜+Kšœ žœ ˜/K˜Kšœžœ(˜?K˜—™'K™Kšœžœ˜2K˜šœžœ žœžœ žœžœžœžœ žœžœžœžœ žœžœGžœžœ™äK™J——K˜™ K˜šœD™DKšœ5™5—K˜KšŸœžœ˜Kšžœžœ˜Kšžœžœ˜KšŸœžœ˜K˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜K˜šœF™FKšœ7™7—K˜KšŸœžœ ˜KšŸ œžœ ˜K˜Kšœ=™=KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜KšŸœžœ ˜šŸ œžœ ˜K™Kšœežœ™w—K˜Kšœ žœžœ˜&š œžœžœž œžœ˜0Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜K˜—Kšœ žœžœ˜(šœžœžœ˜Kšœžœ žœžœ˜.K˜—Kšœžœžœ˜,š œžœžœž œžœ˜3Kšœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜K˜—Kšœžœžœ˜4š œžœžœž œžœ˜7Kš œžœžœžœžœ˜"Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜K˜—Kšœžœžœ˜,š œžœžœž œžœ˜3Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜ Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜"Kšœžœ˜"Kšœžœžœžœ˜&Kšœžœžœžœ˜$Kšœžœ˜Kšœžœžœž˜,Kšœ˜—K˜Kšœ žœžœ˜$š œžœžœž œžœ˜/Kšœ žœ˜K˜—Kšœžœžœ˜*š œžœžœž œžœ˜2Kšœžœ˜K˜—KšŸœžœ˜Kšœ žœžœ˜(š œžœžœž œžœ˜1Kš œžœžœžœžœ˜,Kšœžœ˜Kšœ"žœ˜(Kšœžœ˜Kšœžœ˜Kšœžœ˜ Kšœžœ˜!Kšœž˜Kšœ˜K˜—Kšœ žœ˜&Kšœžœžœ˜.š œžœžœž œžœ˜4šœžœžœ ž˜,šœ ˜ Kš œžœžœžœžœ˜,Kšœžœ˜—šœ ˜ Kš œžœžœ žœžœ˜2Kšœžœ˜ —šœ ˜ Kšœžœ˜$Kšœ!žœ˜'Kšœ#žœ˜)Kšœ˜Kšœ˜Kšœ žœ˜%Kšœžœ˜Kšœžœ˜"Kšœžœ˜—Kšžœ˜ ——K˜šŸ œ*žœ˜=Kš žœ žœžœžœ žœ™3Kšœžœ˜*Kšœžœ˜3Kš œžœžœžœžœ˜YKšœ žœžœžœ<˜nKšœžœ%˜0Kšœ žœžœžœ˜OKšœžœ%˜0šœF™FKšœ7™7—šœ žœ ˜Kšžœžœ žœ ™>—KšÐbn œžœ˜Kš¢œžœ˜Kš¢ œžœ˜šœ žœ+˜;šžœž™#š œžœžœ žœžœ™=Kšž™Kš œžœžœžœžœ™6———Kšœ žœ+˜9˜qKšœW™W—šœhÏb œ˜tKšœW™W—Kšœi£ œ™ušœžœ˜Kšžœžœžœ™%Kšœ@™@Kšœp™p—˜KKšœM™MKšœT™T—Kšœ žœ+˜9Kšœžœ˜:Kšœ"žœžœžœ˜4K˜šžœžœžœž˜Kšœ$žœ˜?Kš œžœžœžœžœ˜gKšœžœ˜(šžœžœžœž˜Kšœžœ˜!Kšœžœžœ˜Kšžœžœžœ˜KšœWžœ˜_Kšžœ˜—K˜@K˜@K˜>K˜DK˜FK˜DK˜TK˜RK˜@Kšžœ˜—šžœžœžœž˜Kšžœ+žœžœ˜GKšžœ*žœžœ˜EKšžœ*žœžœ˜EKšžœ,žœžœžœ˜`Kšžœ˜—šžœžœžœžœ˜!K˜KK˜—šžœ žœžœžœ˜ KšœT£ œ˜cK˜,KšœZ£œ˜jK˜—šžœ žœžœžœ˜ K˜5KšœZ£œ˜jK˜—šœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ˜K˜Kšœ0˜0Kšœ4˜4Kšœ˜Kšœ.˜.Kšœ3˜3Kšœ˜—Kšžœ ˜Kšœ˜——K˜™ ™K™hK™³K™ëK™—K˜šŸœ7˜QKšžœ0žœžœžœ ™Sš žœ žœžœžœžœž˜$Kšœ˜K˜Kšœžœ˜Kšœžœžœ˜K˜K˜TKšžœžœžœžœ˜(K˜K˜K˜)K˜6K˜™8Kšœ˜šžœžœ˜Kšœ9˜9K˜—Kšœ˜Kšœ žœ˜ Kšœžœžœ žœ˜K˜K˜3K™ š žœ žœžœ&žœ žœž˜Pšžœ!žœ¡˜=šœ˜Kšœ:˜:Kšžœ˜Kšœ˜——šžœ!žœ¡!˜IKšœ˜K˜DKšœžœžœ žœ ˜'K˜Kšžœžœžœžœ˜Kšžœ-˜3K˜—K˜Kšžœ?˜AK˜Kšžœžœžœ#˜Sšžœ"žœ˜*Kšžœžœžœ˜JK˜—K˜Kšžœ·˜½Kšœ˜K˜——™šŸœ/˜BKšžœžœ™1Kšœ*˜*šŸ œžœžœ˜NKšœ žœ˜šœ žœžœž˜ K˜ Kšœ!¡˜šžœžœ˜)Kšœ˜šœ˜šœžœ˜$K˜ Kšœ(˜(—Kšœ˜——šžœžœ˜)Kš œ žœ žœžœžœ žœ žœ˜VKšœ(˜(—Kšžœ˜ —šœ ˜ Kšœ˜Kšžœ žœ žœžœ˜'šžœžœ˜)Kšœ˜šœ˜šœžœ˜$Kšœ ˜ Kšœ&˜&—Kšœ˜——šžœžœ˜)Kš œ žœ žœžœžœ žœ žœ˜VKšœ&˜&—Kšžœ˜ K˜—šœžœžœ˜/Kš œ žœ žœžœžœ žœ žœ˜VKšœJžœžœ˜\—Kšžœžœžœo˜¡—K˜K˜——™!K˜Kšœžœžœ˜.šœžœ)˜AK™ —K˜Kšœžœžœ˜.šœžœ)˜AK™—K˜Kšœ žœ ˜/K˜Kšœžœžœžœ ˜šœ žœžœ˜Kšœžœžœžœ ˜%—Kšœ žœžœ˜"šœžœžœ˜Kšœ žœ˜Kšœ žœ˜K˜—šŸœžœ*˜DK˜Kšœžœ˜Kšœ žœ˜#Kšœ žœ%˜5K˜šŸœžœžœžœžœžœžœ˜SKšž˜Kšœžœ žœ˜$Kšœžœ žœ˜$Kšžœ!žœžœ˜5Kšžœ!žœžœ ˜8Kšžœ3žœžœ˜GKšžœ3žœžœ ˜JKšžœ˜Kšžœ˜K˜—šŸ œžœžœžœžœžœžœ˜MKšž˜Kšœžœ žœ˜$Kšœžœ žœ˜$Kšžœ3žœžœ˜GKšžœ3žœžœ ˜JKšžœ!žœžœ˜5Kšžœ!žœžœ ˜8Kšžœ˜Kšžœ˜K˜—šŸ œžœžœžœžœžœžœ™MJšž™Jšœžœ™Jšœžœ™Jšžœ%žœžœ™9Jšžœ%žœžœ ™Kš žœžœžœžœžœžœ˜CKšžœ˜Kšœ˜K˜—™Kšœ˜Kšœžœ˜Kš œžœžœžœžœžœ¡˜6Kš œžœžœžœžœžœ¡˜6Kš œ žœžœžœžœžœ˜"Kšœžœ˜ Kšœžœžœ˜!Kšœžœžœ7˜HK˜Kšžœ8˜:š žœŸœžœžœ/ž˜?Kšžœ9£œ˜@Kšœžœ˜0Kšœžœ˜0šžœ ž˜šžœžœžœ˜5Kšœžœ˜KšžœQ˜SKšœžœ˜2K˜—šž˜Kšœž˜——šžœ˜šžœžœ˜Kš œžœ žœ>¡œžœ*˜ŒKšœžœ˜Kšœžœ˜K˜K˜——Kšžœ˜—Kšœ@˜@K˜š žœŸœžœžœ(ž™8Kšœ!™!šžœžœ™Kšœžœ žœ¡œ.™|Kšœžœ™Kšœžœ™Kšœ™—šžœ™K™——K˜1Kšœžœ˜5š žœŸœžœžœ ž˜ Kšœžœ žœ˜/Kšœ£œ ˜K˜Kšžœ˜—K˜K˜+Kšœžœ˜5š žœŸœžœžœ ž˜ Kšœžœ žœ˜/K˜K˜Kšžœ˜K˜—Kšœ˜—Kšœ˜——K™™K™˜K™IK˜Kšœ0™0K™*K™"—šŸ œžœžœžœžœ žœ žœžœžœžœ ˜‘Kšžœžœžœ˜Kšœžœ ˜K˜;Kšž˜Kšœ˜—K˜šŸ œžœžœ žœžœžœžœžœžœžœžœ˜«Kšœ žœ˜Kšœ žœ˜šžœžœ˜K˜—šž˜šžœ žœ˜š£œ˜ ˜Kšœ žœ ˜šžœžœž˜K˜,K˜,Kšžœžœ˜—K˜——š£œ˜˜Kšœ žœ ˜šžœžœž˜K˜,K˜,Kšžœžœ˜—K˜——Kšœ'™'KšŸœ'™*K˜K˜K˜K˜Kšœ™K˜˜ ˜Kšœžœ˜K˜(Kš žœ žœžœ žœžœžœ˜YK˜——Kšœ™Kš œžœ˜Kšœ™Kšœ™Kšœ žœ™Kšžœ˜!——K˜K˜—KšŸ œžœ ˜Kšœžœžœžœ˜ Kšœ žœžœžœ˜šŸ œžœžœžœ žœ žœžœžœ ˜ŠKšœžœ˜ Kšœ žœžœ˜šŸœžœžœžœ˜(Kšžœ˜ K˜—šŸœžœžœžœ˜>Kšžœ-˜3K˜—Kšžœ@˜BKšžœžœžœ#˜Sšžœ"žœ˜*Kšžœžœžœ˜JKšœ˜—K˜$šžœžœ˜Kšœ žœžœ˜LK˜K˜—Kšœyžœ"žœžœ ˜Çšžœ žœž˜K˜+—šž˜K˜ —˜Kšœžœ˜ K˜ Kšœg¡˜}Kšœ0˜0K˜ Kšœ ˜ Kšœ˜—Kšžœ˜—K˜Kšœžœ˜)š$Ÿ œžœžœžœžœžœžœžœ žœžœ žœžœžœžœžœ žœžœžœ˜ÏKšœžœ˜*Kš œžœžœ$žœžœžœžœ˜GKšœ žœ˜šžœžœžœ˜"K˜Kšœžœ˜ K˜—Kšœ žœžœ žœ˜Tšžœžœžœž˜Kšœžœ ˜K˜Kšžœ˜—šžœ žœ˜šžœžœžœž˜Kšœžœ ˜K˜Kšžœ˜—Kšžœ ˜"Kšžœžœžœžœ˜$šž˜Kšœžœ˜ Kšœžœ˜Kšžœžœžœ™FK™Kšžœžœžœžœ˜Kšœ8žœ˜@Kšžœ˜—K˜—šž˜šžœžœžœž˜Kšœžœ ˜Kšžœ žœžœ˜Kšœ.žœžœ˜GKšžœ˜——Kšž˜Kšœ˜—K˜Kšœžœ˜3šœžœ˜0KšÏt"™"—K˜šŸœ˜1Kšœ˜K˜Kšœ˜Kšœ˜Kšœ˜K˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ žœ˜ Kšœžœ˜—K˜KšœœœzœÇ™ôK˜™"K™K™&K™/K™—K™ÉK™šžœž˜K˜4šŸœžœ˜Kšœ žœ˜K˜ªKšžœžœ?˜K˜0Kšžœ˜ Kšžœ7˜;Kšžœ˜—Kšžœ˜—Kšžœžœžœžœ˜šžœž˜šœ ˜ Kšœ žœžœžœ˜$Kšœ žœ!˜0Kš œ žœžœžœžœ˜)Kš žœ žœžœžœžœ˜7Kšžœžœžœžœ˜RK˜Kšžœžœžœžœ˜RK˜—šœ˜Kšœ žœžœžœ˜$Kšœ žœ!˜0Kšœ žœžœ¡˜+š žœ žœžœžœžœ žœž˜Mšžœ ž˜&Kšœ žœžœ˜—Kšžœ˜—šžœ žœ˜Kšžœžœžœžœ˜RK˜—šœžœ¡3˜9Kšœ žœ˜—Kšœ˜—šœžœžœ˜$K˜;Kšœžœ˜—Kšœžœ˜Kšœžœ˜šœ˜Kšžœžœ<˜HK˜šžœ<˜>Kšœ3˜3Kšœ+˜+—Kšœ˜—K˜ Kšž˜šžœ˜ KšžœžœC˜OK˜@Kšœ˜—Kšžœ˜—K˜<šžœ˜K˜——™7K™ÒK™æK™óK™y—Kšœ žœ"˜3Kšœžœ&˜;šŸœžœ&žœ žœžœ¡œžœ¡œžœžœ¡ œ ˜ÒKšœ˜Kšœžœžœžœ˜)Kšœžœžœžœ˜,Kšœžœ ˜šž˜Kšœ žœ˜Kšœ˜K˜bšžœ"ž˜(Kšžœ&˜,—K˜Bšžœž˜#˜Kšœ˜Kšœ žœ˜Kšœžœžœ ˜)Kšœ˜Kšœ žœžœ ˜!K˜šœ žœ˜Kšœ˜Kšœ ˜ Kšœ˜K˜Kšœ˜Kšœ žœžœ8žœ˜zK˜Kšœ˜Kšœ%˜%—Kšœžœ ˜Kšžœžœžœžœ%˜aK˜Kšœžœ˜K˜Kšœ˜—Kšœ"žœ&˜NKšžœžœ¡˜!—Kšžœ˜ ——K˜K˜KšŸœžœ žœ˜*š Ÿœžœžœžœžœ˜!Kšœ&˜&Kšœ˜Kšœ#˜#Kšœ˜Kšœ#˜#Kšœ$˜$Kšœ'˜'Kšœ%˜%Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!Kšœ!˜!Kšœ$˜$Kšœ$˜$Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ ——˜Kš œ žœžœžœ žœžœžœ˜B—˜šŸœžœ˜Kšœžœ˜Kš œžœžœžœžœ˜šžœžœžœž˜&K˜Kšžœ˜—Kšœžœ˜,K˜ šžœžœžœ ž˜ K˜'K˜ Kšžœ˜—K˜K˜—Kšœ™šŸœžœžœžœ˜<šŸœžœžœžœ˜KšžœžœE˜YKšœ˜K˜—K™4Kšžœ žœžœ˜š žœžœž œžœ(ž˜CK˜4Kšžœžœžœ˜4Kšžœ˜—Kšžœ˜ K˜K˜—šŸœ-˜CKšžœ™K™Kšœ˜Kšœ žœ˜Kšœžœ¡g˜‚šžœžœž˜&šžœžœžœ'˜5Kšž˜Kšœžœ1˜8K˜4Kšžœžœžœžœ˜šžœžœ˜Kšžœ žœžœ˜K˜Kšœ˜—šžœžœž˜6Kšœ˜šžœžœž˜%Kšœ˜Kšœ žœ˜$Kšœžœ9žœ˜Lšžœžœž˜Kšœ˜Kšœžœžœžœ˜Kšœžœ˜K˜K˜.K˜ašžœžœ˜KšžœžœE˜RKšœ ™ Kšœ4™4Kšœ2™2Kšœ1™1K™7Kšœžœ ˜Kšœžœ˜Kšœžœ˜Kšœžœžœ˜K˜=Kšžœ7˜9K˜šžœž˜Kšœ žœ˜šžœžœ5žœ˜FK˜$Kšžœ˜—K˜K˜$šžœ&žœžœ5ž˜mK˜K˜$Kšžœ˜—K˜šžœ%ž˜+Kšœž˜ —šž˜K˜,—Kšžœ˜—K˜šžœžœž˜+K˜-Kšžœ˜—KšœA˜AK˜—K˜'šžœžœžœ˜%K˜M—šžœžœžœ˜&K˜WK˜]K˜—Kšœžœ/˜LKšžœ˜Kšœ˜—Kšœ˜—šžœžœž˜$Kšœ˜Kšœ žœ˜$Kšœžœ8žœ˜Kšžœžœž˜Kšœ˜K˜K˜Kšžœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšžœ˜——K˜Kšœžœ˜"Kšœ˜K˜—šŸœ)˜:Kšœ/™/K™\Kšžœ%˜+K˜—šŸœ(˜8K™0Kšžœ˜ Kšœ˜—˜K˜——K™ ™Kšœ0˜0Kšœ˜Kšœ žœ-˜