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 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 Ê7É•NewlineDelimiter ™codešœ™K™HK™!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šœq˜qKšœW™W—šœhÏb œ˜tKšœW™W—Kšœi¢ œ™ušœœ˜Kšœœœ™%Kšœ@™@Kšœp™p—šœK˜KKšœM™MKšœT™T—Kšœ œ+˜9Kšœœ˜:Kšœ"œœœ˜4K˜šœœœ˜Kšœ$œ˜?Kš œœœœœ˜gKšœœ˜(šœœœ˜Kšœœ˜!Kšœœœ˜Kšœœœ˜KšœWœ˜_Kšœ˜—Kšœ@˜@Kšœ@˜@Kšœ>˜>KšœD˜DKšœF˜FKšœD˜DKšœT˜TKšœR˜RKšœ@˜@Kšœ˜—šœœœ˜Kšœ+œœ˜GKšœ*œœ˜EKšœ*œœ˜EKšœ,œœœ˜`Kšœ˜—šœœœœ˜!KšœK˜KK˜—šœ œœœ˜ KšœT¢ œ˜cKšœ,˜,KšœZ¢œ˜jK˜—šœ œœœ˜ Kšœ5˜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šœT˜TKšœœœœ˜(K˜Kšœ˜Kšœ)˜)Kšœ6˜6K˜™8Kšœ˜šœœ˜Kšœ9˜9K˜—Kšœ˜Kšœ œ˜ Kšœœœ œ˜K˜Kšœ3˜3K™ š œ œœ&œ œ˜Pšœ!œ ˜=šœ˜Kšœ:˜:Kšœ˜Kšœ˜——šœ!œ !˜IKšœ˜KšœD˜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˜šžœœœœœœœ˜SJš˜Jšœœ œ˜$Jšœœ œ˜$Jšœ!œœ˜5Jšœ!œœ ˜8Jšœ3œœ˜GJšœ3œœ ˜JJšœ˜Jšœ˜J˜—šž œœœœœœœ˜MJš˜Jšœœ œ˜$Jšœœ œ˜$Jšœ3œœ˜GJšœ3œœ ˜JJšœ!œœ˜5Jšœ!œœ ˜8Jšœ˜Jšœ˜J˜—šž œœœœœœœ™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šœ1˜1Kšœœ˜5š œžœœœ ˜ Jšœœ œ˜/Jšœ¢œ ˜Jšœ˜Jšœ˜—J˜Jšœ+˜+Kšœœ˜5š œžœœœ ˜ Jšœœ œ˜/Jšœ˜Jšœ˜Jšœ˜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šœÏeœ¤œz¤œÇ™ôK˜™"K™K™&K™/K™—K™ÉK™šœ˜Kšœ4˜4šžœœ˜Kšœ œ˜Kšœª˜ªKšœœ?˜Kšœ0˜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˜bšœ"˜(Kšœ&˜,—KšœB˜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šœ4˜4Kšœœœ˜4Kšœ˜—Kšœ˜ K˜K˜—šžœ-˜CKšœ™K™Kšœ˜Kšœ œ˜Kšœœ g˜‚šœœ˜&šœœœ'˜5Kš˜Kšœœ1˜8Kšœ4˜4Kšœœœœ˜šœœ˜Kšœ œœ˜Kšœ˜Kšœ˜—šœœ˜6Kšœ˜šœœ˜%Kšœ˜Kšœ œ˜$Kšœœ9œ˜Lšœœ˜Kšœ˜Kšœœœœ˜Kšœœ˜Kšœ˜Kšœ.˜.Kšœa˜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˜M—šœœœ˜&KšœW˜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šœ œ-˜