DIRECTORY Basics USING [Card16FromH, Card32FromF, Comparison, BITLSHIFT, BITRSHIFT, BITAND, BITOR, FWORD, HWORD], BasicTime USING [GMT, Now], CCTypes USING [CCError, CCErrorCase], CirioTypes USING [zeroBA], Commander USING [Register, Handle], CommandTool USING [ArgumentVector, Parse], Convert USING [IntFromRope, RopeFromChar], IO USING [card, EndOf, GetChar, GetIndex, PutF, PutFR, SetIndex, STREAM, time, UnsafeGetBlock], List USING [CompareProc, Sort], ObjectFiles USING [BracketNest, BracketPairKind, BracketProc, CNameOfStab, CreateParsed, DescribeModule, FileSegmentPC, FunInfo, GlobalVarLoc, MakeUnknownVarLoc, ModuleInfo, Parsed, RopeForStabType, SimpleSeg, Stab, StabBody, StorageClass, StabType, SymbolProc, UnreadableObjectFile, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo], ObjectFilesPrivate USING [AlterFunStabType, BracketConsumer, BracketPair, BracketPairBody, CheckStaticVar, FnConsumer, FunStabSet, FunStabInfo, FunHandleBody, FunStabSetBody, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, Module, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, RegisterObjectFileFlavor, RaiseUnreadableObjectFileForFun, SLineData, ScanSymbolStabs, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType], PFS USING [PathFromRope, RopeFromPath], PFSNames USING [PATH], Random USING [ChooseInt, Create, RandomStream], Rope USING [Concat, Equal, FromChar, ROPE], SGI, SystemInterface USING [CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, GetNameOfFile, ReleaseStreamForFile, ShowReport], UXStrings USING [UnixString, Create]; SGIFiles: CEDAR MONITOR IMPORTS Basics, BasicTime, CCTypes, Commander, CommandTool, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, Rope, SystemInterface, UXStrings EXPORTS ObjectFiles, SGI = BEGIN CCError: ERROR[case: CCTypes.CCErrorCase, msg: ROPE _ NIL] _ CCTypes.CCError; ROPE: TYPE = Rope.ROPE; PATH: TYPE = PFSNames.PATH; Comparison: TYPE = Basics.Comparison; FWORD: TYPE = Basics.FWORD; HWORD: TYPE = Basics.HWORD; Stab: TYPE = ObjectFiles.Stab; StabBody: TYPE = ObjectFiles.StabBody; StabType: TYPE = ObjectFiles.StabType; StorageClass: TYPE = ObjectFiles.StorageClass; FunInfo: TYPE = ObjectFiles.FunInfo; SymbolProc: TYPE = ObjectFiles.SymbolProc; BracketProc: TYPE = ObjectFiles.BracketProc; BracketNest: TYPE = ObjectFiles.BracketNest; BracketPairKind: TYPE = ObjectFiles.BracketPairKind; VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo; Parsed: TYPE = REF ParsedBody; ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody; Module: TYPE = REF ModuleBody; ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody; ModuleInfo: TYPE = ObjectFiles.ModuleInfo; StabSet: TYPE = ObjectFilesPrivate.StabSet; StabRange: TYPE = ObjectFilesPrivate.StabRange; MemorySegmentInfo: TYPE = ObjectFilesPrivate.MemorySegmentInfo; FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC; BracketPair: TYPE = REF BracketPairBody; BracketPairBody: TYPE = ObjectFilesPrivate.BracketPairBody; FunStabSet: TYPE = ObjectFilesPrivate.FunStabSet; FunStabSetBody: TYPE = ObjectFilesPrivate.FunStabSetBody; FunStabInfo: TYPE = ObjectFilesPrivate.FunStabInfo; PCtoLineNumMap: TYPE = REF PCtoLineNumMapBody; PCtoLineNumMapBody: TYPE = ObjectFilesPrivate.PCtoLineNumMapBody; LineNumToPCMap: TYPE = REF LineNumToPCMapBody; LineNumToPCMapBody: TYPE = ObjectFilesPrivate.LineNumToPCMapBody; Header: TYPE = REF HeaderBody; HeaderBody: PUBLIC TYPE = ObjectFilesPrivate.HeaderBody; FunHandle: TYPE = REF FunHandleBody; FunHandleBody: TYPE = ObjectFilesPrivate.FunHandleBody; WireHeader: TYPE = REF SGI.WireHeaderBody; WireAuxHeader: TYPE = REF SGI.WireAuxHeaderBody; WireSectionHeader: TYPE = REF SGI.WireSectionHeaderBody; WireSymHeader: TYPE = REF SGI.WireSymHeaderBody; WirePackedLineNum: TYPE = REF SGI.WirePackedLineNumBody; WireProcDescriptor: TYPE = REF SGI.WireProcDescriptorBody; WireRelFileTable: TYPE = REF SGI.WireRelFileTableBody; WireFileDescriptor: TYPE = REF SGI.WireFileDescriptorBody; WireSTEntry: TYPE = REF SGI.WireSTEntryBody; WireExtSTEntry: TYPE = REF SGI.WireExtSTEntryBody; WireTypeInfo: TYPE = REF SGI.WireTypeInfoBody; WireRelIndex: TYPE = REF SGI.WireRelIndexBody; WireAuxSTEntry: TYPE = REF SGI.WireAuxSTEntryBody; SectionTable: TYPE = REF SGI.SectionTableBody; FileDescrTable: TYPE = REF SGI.FileDescrTableBody; RelFileTable: TYPE = REF SGI.RelFileTableBody; ProcDescrTable: TYPE = REF SGI.ProcDescrTableBody; LocalSymTable: TYPE = REF SGI.LocalSymTableBody; IndexedLocalSymTable: TYPE = REF SGI.IndexedLocalSymTableBody; ExtSymTable: TYPE = REF SGI.ExtSymTableBody; AuxSymTable: TYPE = REF SGI.AuxSymTableBody; IndexedAuxSymTable: TYPE = REF SGI.IndexedAuxSymTableBody; StringTable: TYPE = REF SGI.StringTableBody; WireTables: TYPE = REF SGI.WireTablesBody; StabIndexTypeAndValue: TYPE = RECORD [ stabX: CARD, type: StabType, value: CARD ]; StabList: TYPE = ObjectFilesPrivate.StabList; ScannedBracketPair: TYPE = RECORD[bpi: BracketPair, nextX: CARD]; FMap: TYPE = LIST OF FMapData; FMapBody: TYPE = RECORD [SEQUENCE maxIndex: CARD OF FMapData]; FMapData: TYPE = REF FMapDataBody; FMapDataBody: TYPE = RECORD [ fName: Rope.ROPE, stabOffset: CARD ]; DotOType: TYPE = Rope.ROPE; PDTType: TYPE = RECORD [SEQUENCE maxIndex: CARD OF Rope.ROPE]; ByteSequence: TYPE = REF ByteSequenceBody; ByteSequenceBody: TYPE = RECORD [SEQUENCE maxIndex: CARD OF BYTE]; IndexNil: CARD = 0FFFFFH; -- max valid index for aux entries ECOFFMagic: CARD16 = 352; nPageSize: CARD = 01000H; -- this is according to getpagesize() SymbolSize: CARD = 12; -- this is the size of a local sym ExtSymbolSize: CARD = 16; -- this is ext sym size AuxSymbolSize: CARD = 4; -- this is aux sym size RelocEntrySize: CARD = 8; LnnoEntrySize: CARD = 4; FileDescrSize: CARD = 72; -- Need to check this...may be some ProcDescrSize: CARD = 56; BasicSizes: ARRAY [0..64) OF BYTE = [0,32,8,8,16,16,32,32,32,32,32,64,0,0,32,0,32,32,64,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]; WordByteSize: CARD = 4; WordBitSize: CARD = 32; ElfMagic: CARD = (Basics.BITLSHIFT[177B, 24] + Basics.BITLSHIFT['E.ORD, 16] + Basics.BITLSHIFT['L.ORD, 8] + 'F.ORD); ElfClassNone: CARD = 0; ElfClass32: CARD = 1; ElfClass64: CARD = 2; ElfDataNone: CARD = 0; ElfData2LSB: CARD = 1; ElfData2MSB: CARD = 2; ETNone: CARD = 0; ETRelocatable: CARD = 1; ETExecutable: CARD = 2; ETDynamicLib: CARD = 3; ETCore: CARD = 4; EMNone: CARD = 0; EMM32: CARD = 1; EMSparc: CARD = 2; EM386: CARD = 3; EM68K: CARD = 4; EM88K: CARD = 5; EM486: CARD = 6; EM860: CARD = 7; EMMips: CARD = 8; EMS370: CARD = 9; SHTNull: CARD = 0; SHTProgBits: CARD = 1; SHTSymTab: CARD = 2; SHTStrTab: CARD = 3; SHTRela: CARD = 4; SHTHash: CARD = 5; SHTDynamic: CARD = 6; SHTNote: CARD = 7; SHTNoBits: CARD = 8; SHTRel: CARD = 9; SHTShLib: CARD = 10; SHTDynSym: CARD = 11; SHTLoProc: CARD = 70000000H; SHTMipsDebug: CARD = SHTLoProc+5; SHFWrite: CARD = 1; SHFAlloc: CARD = 2; SHFExecInStr: CARD = 4; ElfWireHeader: TYPE = REF ElfWireHeaderBody; ElfWireHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ magic: Basics.FWORD, elfClass: BYTE, elfData: BYTE, elfVersion: BYTE, elfPad1: BYTE, elfPad2: PACKED ARRAY [8..15] OF BYTE, type: Basics.HWORD, machine: Basics.HWORD, version: Basics.FWORD, entry: Basics.FWORD, progHdrOffset: Basics.FWORD, sectHdrOffset: Basics.FWORD, flags: Basics.FWORD, elfHdrSize: Basics.HWORD, progHdrSize: Basics.HWORD, progHdrNum: Basics.HWORD, sectHdrSize: Basics.HWORD, sectHdrNum: Basics.HWORD, sectStrTblX: Basics.HWORD]; SectionList: TYPE = REF SectionListBody; SectionListBody: TYPE = RECORD[ list: SEQUENCE length: CARD OF SectionHeader]; SectionHeader: TYPE = REF SectionHeaderBody; SectionHeaderBody: TYPE = RECORD[ name: ROPE _ NIL, nameIndex: CARD32, type: CARD32, flags: CARD32, addr: CARD32, offset: CARD32, size: CARD32, link: CARD32, info: CARD32, alignment: CARD32, entrySize: CARD32]; ElfWireSectionHeader: TYPE = REF ElfWireSectionHeaderBody; ElfWireSectionHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ nameIndex: Basics.FWORD, type: Basics.FWORD, flags: Basics.FWORD, addr: Basics.FWORD, offset: Basics.FWORD, size: Basics.FWORD, link: Basics.FWORD, info: Basics.FWORD, alignment: Basics.FWORD, entrySize: Basics.FWORD]; unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize; NullStabIndexTypeAndValue: StabIndexTypeAndValue = [0, Invalid, 0]; RawBytes: TYPE = RECORD [PACKED SEQUENCE COMPUTED CARD OF BYTE]; Printf: PROC [fmt: POINTER TO RawBytes, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10: UNSPECIFIED _ 0] RETURNS [INTEGER] = TRUSTED MACHINE CODE { "xr_printf" }; Print: PROC [s: STRING, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10: UNSPECIFIED _ 0] = TRUSTED { [] _ Printf[LOOPHOLE[@s.text], arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10]; }; DebugProc: PROC = TRUSTED MACHINE CODE { "XR_CallDebugger"; }; FindMatchingProcDescr: PUBLIC PROC [relPC: CARD, parsed: ObjectFiles.Parsed] RETURNS [SGI.WireProcDescriptorBody, BOOLEAN] = TRUSTED { privateParsed: ObjectFilesPrivate.Parsed _ LOOPHOLE[parsed, ObjectFilesPrivate.Parsed]; wireTables: WireTables _ NARROW[privateParsed.privateInfo, WireTables]; found: BOOLEAN _ FALSE; high, low, mid: INT32; procDescrStartingAddr: CARD32 _ wireTables.procDescr[0].startAddress; numOfProcs: INT32 _ wireTables.wSymHeader.procDescrIndexLimit; dummy: SGI.WireProcDescriptorBody _ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; IF relPC = 0 THEN RETURN [dummy, found]; low _ 0; high _ numOfProcs; WHILE low < high DO mid _ (low+high+1)/2; IF mid = numOfProcs THEN RETURN [dummy, found]; IF relPC < wireTables.procDescr[mid].startAddress THEN high _ mid - 1 ELSE low _ mid; ENDLOOP; RETURN [wireTables.procDescr[high], TRUE]; }; FixUpProcedureDescrAddrs: PROC [header: Header, numFileDescr: CARD32, fileDescr: FileDescrTable, procDescr: ProcDescrTable] = { numProcDescr: INT32; j, jStart, jStop: CARD32; i: CARD32; FOR i IN [0..numFileDescr) DO numProcDescr _ fileDescr[i].cpd; jStart _ fileDescr[i].ipdFirst; jStop _ jStart + numProcDescr; FOR j IN [jStart..jStop) DO procDescr[j].startAddress _ fileDescr[i].startAddress + procDescr[j].startAddress - header.textLoadOffset; ENDLOOP; ENDLOOP; }; IsSameEndianSGI: PUBLIC PROC [stream: IO.STREAM] RETURNS [BOOLEAN] = TRUSTED { magicNum: Basics.HWORD; nBytes, oldFileIndex: INT; fileHeader: WireHeader ¬ NEW[SGI.WireHeaderBody]; oldFileIndex ¬ IO.GetIndex[stream]; IO.SetIndex[stream, 0]; -- SGI magic number is 2 bytes at start of file nBytes ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@fileHeader^], 0, BYTES[SGI.WireHeaderBody]]]; IO.SetIndex[stream, oldFileIndex]; magicNum ¬ LOOPHOLE[fileHeader.magic]; IF (nBytes = 0) THEN ERROR; -- something is very wrong IF (magicNum.hi = 01H) AND (magicNum.lo = 062H OR magicNum.lo = 060H) THEN RETURN [TRUE] ELSE IF (magicNum.hi = 062H OR magicNum.hi = 060H) AND (magicNum.lo = 01H) THEN RETURN [FALSE] ELSE ERROR; -- this is not a MIPS SGI file }; ProcessQualifierSizes: PROC [typeInfo: SGI.WireTypeInfoBody, qualifiedSize: CARD, auxIndex: INT32, wireTables: WireTables] RETURNS [continued: BOOLEAN, size: CARD, nextAuxIndex: INT32] ~ TRUSTED { qualifier: ARRAY [0..5) OF BYTE; numQualifiers: CARD ¬ 0; continued ¬ LOOPHOLE[typeInfo.continued, INT] = 1; size ¬ qualifiedSize; nextAuxIndex ¬ auxIndex; DO IF (typeInfo.typeQual0 = SGI.TQNil) THEN EXIT; qualifier[numQualifiers] ¬ typeInfo.typeQual0; numQualifiers ¬ numQualifiers + 1; IF (typeInfo.typeQual1 = SGI.TQNil) THEN EXIT; qualifier[numQualifiers] ¬ typeInfo.typeQual1; numQualifiers ¬ numQualifiers + 1; IF (typeInfo.typeQual2 = SGI.TQNil) THEN EXIT; qualifier[numQualifiers] ¬ typeInfo.typeQual2; numQualifiers ¬ numQualifiers + 1; IF (typeInfo.typeQual3 = SGI.TQNil) THEN EXIT; qualifier[numQualifiers] ¬ typeInfo.typeQual3; numQualifiers ¬ numQualifiers + 1; IF (typeInfo.typeQual4 = SGI.TQNil) THEN EXIT; qualifier[numQualifiers] ¬ typeInfo.typeQual4; numQualifiers ¬ numQualifiers + 1; IF (typeInfo.typeQual5 = SGI.TQNil) THEN EXIT; qualifier[numQualifiers] ¬ typeInfo.typeQual5; numQualifiers ¬ numQualifiers + 1; IF numQualifiers > 5 THEN EXIT; ENDLOOP; FOR i: INT IN (numQualifiers..0] DO { low, high, bitWidth: INT32; SELECT qualifier[i] FROM SGI.TQNil => NULL; SGI.TQPtr => { size ¬ WordBitSize; RETURN; }; SGI.TQProc => NULL; -- size info is redundant with pointer SGI.TQVol => NULL; -- volatile doesnt have any size info SGI.TQArray => { low ¬ LOOPHOLE[wireTables.auxSyms[nextAuxIndex].lowIndex]; nextAuxIndex ¬ nextAuxIndex + 1; high ¬ LOOPHOLE[wireTables.auxSyms[nextAuxIndex].highIndex]; nextAuxIndex ¬ nextAuxIndex + 1; bitWidth ¬ LOOPHOLE[wireTables.auxSyms[nextAuxIndex].bitWidth]; nextAuxIndex ¬ nextAuxIndex + 1; size ¬ (high+1)*bitWidth; RETURN; } ENDCASE => NULL; }; ENDLOOP; RETURN; }; SLineData: TYPE = ObjectFilesPrivate.SLineData; LineNum: TYPE = REF LineNumSeqBody; LineNumSeqBody: TYPE = RECORD [SEQUENCE maxIndex: CARD OF LineNumRecBody]; LineNumRecBody: TYPE = RECORD [ lineNumber: INT32, relativePC: CARD ]; UnPackLineNumbers: PUBLIC PROC [stream: IO.STREAM, module: Module, wireTables: WireTables] = TRUSTED { CompareByCLineNum: PROC [ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = TRUSTED { 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]; }; CompareByPC: PROC [ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = TRUSTED { 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]; }; header: Header ¬ module.whole.header; fileDescr: FileDescrTable ¬ wireTables.fileDescr; procDescr: ProcDescrTable ¬ wireTables.procDescr; numBytes: CARD ¬ wireTables.wSymHeader.numBytesPackedLineNums; packedLineNum: WirePackedLineNum ¬ NEW[SGI.WirePackedLineNumBody[numBytes]]; l, count: BYTE; signedShort, absOfSignedShort: INT16; delta, lowByte: INT32; packedIndex, stopIndex, lineTableIndex: INT32 ¬ 0; k, numProcDescr: INT32; j, jStart, jStop: CARD32; numBytesRead: INT32; currentSrcLine: CARD; info: REF SLineData; startAddress: CARD32; 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; unpackedNums: LineNum ¬ NEW[LineNumSeqBody[wireTables.wSymHeader.lineNumIndexLimit]]; instrCount: CARD32; fdIndex: INT32; IO.SetIndex[stream, wireTables.wSymHeader.packedLineNumPtr]; numBytesRead ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[packedLineNum, CARD]+BYTES[CARD]], 0, numBytes]]; fdIndex ¬ module.fdIndex; numProcDescr ¬ fileDescr[fdIndex].cpd; jStart ¬ fileDescr[fdIndex].ipdFirst; jStop ¬ jStart + numProcDescr; FOR j IN [jStart..jStop) DO IF (procDescr[j].iline # -1) AND (procDescr[j].lnLow # -1) AND (procDescr[j].lnHigh # -1) THEN { stopIndex ¬ fileDescr[fdIndex].ilineBase + fileDescr[fdIndex].cline; FOR k IN [j+1..numProcDescr) DO IF procDescr[k].iline # -1 THEN { stopIndex ¬ fileDescr[fdIndex].ilineBase + procDescr[k].iline; EXIT; }; ENDLOOP; IF (stopIndex - procDescr[j].iline) > 0 THEN { startAddress ¬ procDescr[j].startAddress; instrCount ¬ 0; lineTableIndex ¬ fileDescr[fdIndex].ilineBase + procDescr[j].iline; currentSrcLine ¬ procDescr[j].lnLow; packedIndex ¬ fileDescr[fdIndex].cbLineOffset + procDescr[j].cbLineOffset; WHILE lineTableIndex < stopIndex DO delta ¬ packedLineNum[packedIndex]; IF delta > 127 THEN delta ¬ LOOPHOLE[Basics.BITOR[delta, 0FFFF00H]]; delta ¬ LOOPHOLE[Basics.BITRSHIFT[delta, 4]]; count ¬ Basics.BITAND[packedLineNum[packedIndex], 0FH] + 1; packedIndex ¬ packedIndex + 1; signedShort ¬ LOOPHOLE[delta, INT16]; absOfSignedShort ¬ ABS[signedShort]; IF absOfSignedShort > 7 THEN { delta ¬ Basics.BITLSHIFT[packedLineNum[packedIndex], 8]; packedIndex ¬ packedIndex + 1; lowByte ¬ Basics.BITAND[packedLineNum[packedIndex], 0FFH]; delta ¬ Basics.BITOR[delta, lowByte]; packedIndex ¬ packedIndex + 1; signedShort ¬ LOOPHOLE[delta, INT16]; }; currentSrcLine ¬ currentSrcLine + signedShort; FOR l IN [0..count) DO unpackedNums[lineTableIndex].lineNumber ¬ currentSrcLine; unpackedNums[ lineTableIndex].relativePC ¬ instrCount*4+startAddress; instrCount ¬ instrCount + 1; lineTableIndex ¬ lineTableIndex + 1; ENDLOOP; ENDLOOP; }; }; ENDLOOP; FOR I: CARD IN [0..wireTables.wSymHeader.lineNumIndexLimit) DO info ¬ NEW[SLineData ¬ [ cLineNum: unpackedNums[I].lineNumber, parsedRelPC: [ [0 --??--, PFS.RopeFromPath[module.fileName]], unpackedNums[I].relativePC ] ]]; list1 ¬ CONS[info, list1]; list2 ¬ CONS[info, list2]; ENDLOOP; sortedList ¬ List.Sort[list1, CompareByCLineNum]; module.lineNumToPC ¬ NEW[LineNumToPCMapBody[wireTables.wSymHeader.lineNumIndexLimit]]; FOR I: INTEGER IN [0..wireTables.wSymHeader.lineNumIndexLimit) DO info: REF SLineData ¬ NARROW[sortedList.first]; module.lineNumToPC[I] ¬ info^; sortedList ¬ sortedList.rest; ENDLOOP; sortedList ¬ List.Sort[list2, CompareByPC]; module.pcToLineNum ¬ NEW[PCtoLineNumMapBody[wireTables.wSymHeader.lineNumIndexLimit]]; FOR I: INTEGER IN [0..wireTables.wSymHeader.lineNumIndexLimit) DO info: REF SLineData ¬ NARROW[sortedList.first]; module.pcToLineNum[I] ¬ info^; sortedList ¬ sortedList.rest; ENDLOOP; wireTables.pcToLineNum ¬ module.pcToLineNum; wireTables.lineNumToPC ¬ module.lineNumToPC; FREE[@packedLineNum]; FREE[@unpackedNums]; RETURN; }; CalcSymbolSize: PUBLIC PROC [symTabIndex: CARD, fdIndex: INT32, wireTables: WireTables, isExternal: BOOLEAN] RETURNS [size : CARD ¬ 0] = TRUSTED { thisSym: WireSTEntry; auxIndex: CARD; symIndex, basicType, qualifiedSize: CARD ¬ 0; typeInfo: SGI.WireTypeInfoBody; nonStandardWidth: BOOLEAN; continued: BOOLEAN ¬ TRUE; symBaseIndex: CARD; symType: CARD; IF isExternal THEN { thisSym ¬ LOOPHOLE[@wireTables.extSyms[symTabIndex].sym]; fdIndex ¬ wireTables.extSyms[symTabIndex].fileDescrIndex; } ELSE { thisSym ¬ LOOPHOLE[@wireTables.localSyms[symTabIndex]]; }; symType ¬ thisSym.symbolType; SELECT symType FROM SGI.STStruct, SGI.STUnion => { size ¬ thisSym.value*8; RETURN; }; SGI.STFile, SGI.STProc, SGI.STStaticProc, SGI.STBlock, SGI.STEnd => RETURN; SGI.STConstant, SGI.STLabel, SGI.STRegReloc, SGI.STForward, SGI.STStaParam => { size ¬ WordBitSize; RETURN; }; ENDCASE => NULL; auxIndex ¬ wireTables.fileDescr[fdIndex].iauxBase + thisSym.index; IF auxIndex >= IndexNil THEN { size ¬ WordBitSize; RETURN; }; typeInfo ¬ wireTables.auxSyms[auxIndex].typeInfo; nonStandardWidth ¬ LOOPHOLE[typeInfo.fBitField]; basicType ¬ typeInfo.basicType; IF (basicType = SGI.BTNil) THEN RETURN; IF ((basicType = SGI.BTStruct) OR (basicType = SGI.BTUnion)) THEN { currentIndex: CARD; relFileIndex: INT32; relFileOffset: INT32; relIndex: SGI.WireRelIndexBody ¬ wireTables.auxSyms[auxIndex+1].relIndex; IF relIndex.relFileDescrIndex = 0FFFH THEN { relFileIndex ¬ wireTables.auxSyms[auxIndex+2].relFileIndex; } ELSE { relFileIndex ¬ relIndex.relFileDescrIndex; }; relFileOffset ¬ wireTables.fileDescr[fdIndex].rfdBase + relFileIndex; IF relFileOffset # 0 THEN fdIndex ¬ wireTables.relFiles[relFileOffset]; symIndex ¬ relIndex.index; symBaseIndex ¬ wireTables.fileDescr[fdIndex].isymBase; currentIndex ¬ symIndex + symBaseIndex; size ¬ wireTables.localSyms[currentIndex].value*8; auxIndex ¬ auxIndex + 2; } ELSE IF ((basicType = SGI.BTTypedef) OR (basicType = SGI.BTIndirect)) THEN { size ¬ WordBitSize; } ELSE IF (nonStandardWidth = FALSE) THEN size ¬ BasicSizes[basicType] ELSE IF wireTables.auxSyms[auxIndex+1].bitWidth # 0 THEN size ¬ wireTables.auxSyms[auxIndex+1].bitWidth ELSE size ¬ 0; WHILE continued DO { [continued, qualifiedSize, auxIndex] ¬ ProcessQualifierSizes[typeInfo, qualifiedSize, auxIndex, wireTables]; IF continued THEN typeInfo ¬ wireTables.auxSyms[auxIndex].typeInfo; }; ENDLOOP; IF (qualifiedSize # 0) THEN { size ¬ qualifiedSize; }; }; ReadElfWireSymHeader: PROC [stream: IO.STREAM] RETURNS [WireSymHeader] = TRUSTED { wHeader: ElfWireHeader _ NEW[ElfWireHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[ElfWireHeaderBody]]]; wSymHeader: WireSymHeader _ NIL; sectHdrOffset: CARD _ Basics.Card32FromF[wHeader.sectHdrOffset]; sectHdrNum: CARD _ Basics.Card16FromH[wHeader.sectHdrNum]; type: CARD; IO.SetIndex[stream, sectHdrOffset]; FOR i: CARD IN [0..sectHdrNum) DO wSectionHeader: ElfWireSectionHeader _ NEW[ElfWireSectionHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[ElfWireSectionHeaderBody]]]; type _ Basics.Card32FromF[wSectionHeader.type]; IF type = SHTMipsDebug THEN { offset: CARD _ Basics.Card32FromF[wSectionHeader.offset]; wSymHeader _ NEW[SGI.WireSymHeaderBody]; [] _ ReadWireSymHeader[stream, offset, wSymHeader]; RETURN[wSymHeader]; }; ENDLOOP; RETURN[wSymHeader]; }; InitParsedWireTables: PROC [stream: IO.STREAM, parsed: Parsed] = TRUSTED { filename: UXStrings.UnixString; wireTables: WireTables _ NEW[SGI.WireTablesBody]; nBytes: CARD; magic: CARD; header: Header _ parsed.header; symHeader: WireSymHeader; symLimit, extSymLimit, auxSymLimit: CARD; procDescLimit, fileDescLimit, relFileLimit: CARD; filename _ UXStrings.Create[PFS.RopeFromPath[SystemInterface.GetNameOfFile[parsed.file]]]; IO.SetIndex[stream, 0]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@magic], 0, 4]]; IF magic = ElfMagic THEN { Print["Found an ELF object\n"]; IO.SetIndex[stream, 0]; wireTables.wSymHeader _ ReadElfWireSymHeader[stream]; } ELSE { magic _ Basics.BITRSHIFT[LOOPHOLE[magic, WORD], 16]; IF magic = ECOFFMagic THEN { wireTables.wHeader _ ReadWireHeader[stream, 0, NIL]; wireTables.wAuxHeader _ ReadWireAuxHeader[stream, NIL]; wireTables.wSymHeader _ ReadWireSymHeader[stream, wireTables.wHeader.symPtr, NIL]; } ELSE { Print["Found unknown magic number %d\n", magic]; ERROR; }; }; symHeader _ wireTables.wSymHeader; IO.SetIndex[stream, symHeader.fileDescrPtr]; fileDescLimit _ symHeader.fileDescrIndexLimit; wireTables.fileDescr _ NEW[SGI.FileDescrTableBody[fileDescLimit]]; FOR i: CARD IN [0..fileDescLimit) DO [] _ ReadWireFileDescriptor[stream, LOOPHOLE[@wireTables.fileDescr[i]]]; ENDLOOP; IO.SetIndex[stream, symHeader.relFileDescrPtr]; relFileLimit _ symHeader.numRelFileDescr; wireTables.relFiles _ NEW[SGI.RelFileTableBody[relFileLimit]]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.relFiles, CARD]+BYTES[CARD]], 0, relFileLimit*BYTES[SGI.RelFileTableBody]]]; IO.SetIndex[stream, wireTables.wSymHeader.procDescrPtr]; procDescLimit _ symHeader.procDescrIndexLimit; wireTables.procDescr _ NEW[SGI.ProcDescrTableBody[procDescLimit]]; FOR i: CARD IN [0..procDescLimit) DO [] _ ReadWireProcDescriptor[stream, LOOPHOLE[@wireTables.procDescr[i]]]; ENDLOOP; FixUpProcedureDescrAddrs[header, fileDescLimit, wireTables.fileDescr, wireTables.procDescr]; IO.SetIndex[stream, symHeader.symPtr]; symLimit _ symHeader.symIndexLimit; wireTables.localSyms _ NEW[SGI.LocalSymTableBody[symLimit]]; FOR i: CARD IN [0..symLimit) DO [] _ ReadWireSTEntry[stream, LOOPHOLE[@wireTables.localSyms[i]]]; ENDLOOP; IO.SetIndex[stream, symHeader.extSymPtr]; extSymLimit _ symHeader.extSymIndexLimit; wireTables.extSyms _ NEW[SGI.ExtSymTableBody[extSymLimit]]; FOR i: CARD IN [0..extSymLimit) DO [] _ ReadWireExtSTEntry[stream, LOOPHOLE[@wireTables.extSyms[i]]]; ENDLOOP; IO.SetIndex[stream, symHeader.auxSymPtr]; auxSymLimit _ symHeader.auxSymIndexLimit; wireTables.auxSyms _ NEW[SGI.AuxSymTableBody[auxSymLimit]]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.auxSyms, CARD]+BYTES[CARD]], 0, auxSymLimit*AuxSymbolSize]]; IO.SetIndex[stream, symHeader.symStringPtr]; wireTables.localStrings _ NEW[SGI.StringTableBody[symHeader.symStringIndexLimit]]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.localStrings, CARD]+BYTES[CARD]], 0, symHeader.symStringIndexLimit]]; IO.SetIndex[stream, symHeader.extSymStringPtr]; wireTables.extStrings _ NEW[SGI.StringTableBody[symHeader.extSymStringIndexLimit]]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.extStrings, CARD]+BYTES[CARD]], 0, symHeader.extSymStringIndexLimit]]; parsed.privateInfo _ wireTables; }; RopeFromStream: PROC [stream: IO.STREAM, offset: CARD] RETURNS [name: Rope.ROPE _ NIL] = TRUSTED { c: CHAR; IO.SetIndex[stream, offset]; IF IO.EndOf[stream] THEN RETURN[""]; DO c _ ' ; c _ IO.GetChar[stream]; IF (c = VAL[0]) THEN EXIT; name _ name.Concat[Convert.RopeFromChar[from: c, quote: FALSE]]; ENDLOOP; name _ name.Concat[Convert.RopeFromChar[from: ':, quote: FALSE]]; RETURN }; TypeAndClassFromData: PROC [sc: BYTE, st: BYTE _ 0] RETURNS [type: StabType, class: StorageClass] = { classVal: CARD _ sc; typeVal: CARD _ st; SELECT typeVal FROM SGI.STNil => type _ Unspecified; SGI.STGlobal => type _ GSym; SGI.STStatic => { IF classVal = SGI.SCBSS OR classVal = SGI.SCSBSS THEN type _ LCSym ELSE type _ STSym; }; SGI.STParam => type _ PSym; SGI.STLocal => type _ LSym; SGI.STLabel => type _ Unspecified; SGI.STStaticProc, SGI.STProc => type _ Fun; SGI.STBlock => type _ LBrac; SGI.STEnd => type _ RBrac; SGI.STMember => type _ LSym; SGI.STTypeDef => type _ LSym; SGI.STFile => type _ SO; SGI.STConstant => type _ Unspecified; ENDCASE => type _ Unspecified; SELECT classVal FROM SGI.SCNIL => class _ SCNil; SGI.SCTEXT => class _ SCText; SGI.SCDATA => class _ SCData; SGI.SCBSS => class _ SCBss; SGI.SCREGISTER => class _ SCRegister; SGI.SCABS => class _ SCAbs; SGI.SCUNDEFINED => class _ SCUnspecified; SGI.SCBITS => class _ SCBits; SGI.SCDBX => class _ SCInvalid; SGI.SCREGIMAGE => class _ SCRegImage; SGI.SCINFO => class _ SCUserStruct; SGI.SCUSERSTRUCT => class _ SCUserStruct; SGI.SCSDATA => class _ SCSData; SGI.SCSBSS => class _ SCSBss; SGI.SCRDATA => class _ SCRData; SGI.SCVAR => class _ SCCommon; SGI.SCCOMMON => class _ SCCommon; SGI.SCSCOMMON => class _ SCSCommon; SGI.SCVARREGISTER => class _ SCVerRegister; SGI.SCVARIANT => class _ SCVariant; SGI.SCUNDEFINE => class _ SCSUndefined; ENDCASE => class _ SCInvalid }; ReadStabBody: PROC [symTabIndex: CARD, fdIndex: INT32, isExternal: BOOLEAN, wireTables: WireTables, header: Header, stream: IO.STREAM] RETURNS [stab: StabBody] = TRUSTED { size: CARD; rope: Rope.ROPE _ NIL; wireSymTabEntry: WireSTEntry; stringBase: INT32 _ wireTables.fileDescr[fdIndex].issBase; type: StabType; class: StorageClass; IF (isExternal) THEN { wireSymTabEntry _ LOOPHOLE[@wireTables.extSyms[symTabIndex].sym]; rope _ RopeFromStream[stream, header.extStringOffset+wireSymTabEntry.symStringIndex]; } ELSE { wireSymTabEntry _ LOOPHOLE[@wireTables.localSyms[symTabIndex]]; rope _ RopeFromStream[stream, header.stringOffset+stringBase+wireSymTabEntry.symStringIndex]; }; size _ CalcSymbolSize[symTabIndex, fdIndex, wireTables, isExternal]/8; [type, class] _ TypeAndClassFromData[LOOPHOLE[wireSymTabEntry.storageClass], LOOPHOLE[wireSymTabEntry.symbolType]]; stab _ [ module: NIL, stabX: symTabIndex, stabType: type, stabStorClass: class, size: size, value: wireSymTabEntry.value, rope: rope, index: wireSymTabEntry.index, extRef: isExternal, fdIndex: fdIndex ]; RETURN }; BasicReadStab: ENTRY PROC [stabX: CARD, fdIndex: INT32, isExternal: BOOLEAN, wireTables: WireTables, header: Header, stream: IO.STREAM] RETURNS[stab: Stab] = { ENABLE UNWIND => NULL; stab _ NEW[StabBody]; stab^ _ ReadStabBody[stabX, fdIndex, isExternal, wireTables, header, stream]; RETURN }; ReadWireHeader: PROC [stream: IO.STREAM, pos: CARD _ 0, wHeader: WireHeader _ NIL] RETURNS [WireHeader] = TRUSTED { nBytes: INT; IF (wHeader = NIL) THEN wHeader _ NEW[SGI.WireHeaderBody]; IO.SetIndex[stream, pos]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[SGI.WireHeaderBody]]]; RETURN [wHeader]; }; ReadWireAuxHeader: PROC [stream: IO.STREAM, wAuxHeader: WireAuxHeader _ NIL] RETURNS [WireAuxHeader] = TRUSTED { nBytes: INT; IF (wAuxHeader = NIL) THEN wAuxHeader _ NEW[SGI.WireAuxHeaderBody]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wAuxHeader^], 0, BYTES[SGI.WireAuxHeaderBody]]]; RETURN [wAuxHeader]; }; ReadWireSectionHeader: PROC [stream: IO.STREAM, wSectHeader: WireSectionHeader _ NIL] RETURNS [WireSectionHeader] = TRUSTED { nBytes: INT; IF (wSectHeader = NIL) THEN wSectHeader _ NEW[SGI.WireSectionHeaderBody]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectHeader^], 0, BYTES[SGI.WireSectionHeaderBody]]]; RETURN [wSectHeader]; }; ReadWireSymHeader: PROC [stream: IO.STREAM, pos: CARD, wSymHeader: WireSymHeader _ NIL] RETURNS [WireSymHeader] = TRUSTED { nBytes: INT; IF (wSymHeader = NIL) THEN wSymHeader _ NEW[SGI.WireSymHeaderBody]; IO.SetIndex[stream, pos]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSymHeader^], 0, BYTES[SGI.WireSymHeaderBody]]]; RETURN [wSymHeader]; }; ReadWireProcDescriptor: PROC [stream: IO.STREAM, wProcDescriptor: WireProcDescriptor _ NIL] RETURNS [WireProcDescriptor] = TRUSTED { nBytes: INT; IF (wProcDescriptor = NIL) THEN wProcDescriptor _ NEW[SGI.WireProcDescriptorBody]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wProcDescriptor^], 0, BYTES[SGI.WireProcDescriptorBody]]]; RETURN [wProcDescriptor]; }; ReadWireFileDescriptor: PROC [stream: IO.STREAM, wFileDescriptor: WireFileDescriptor _ NIL] RETURNS [WireFileDescriptor] = TRUSTED { nBytes: INT; IF (wFileDescriptor = NIL) THEN wFileDescriptor _ NEW[SGI.WireFileDescriptorBody]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wFileDescriptor^], 0, BYTES[SGI.WireFileDescriptorBody]]]; RETURN [wFileDescriptor]; }; ReadWireSTEntry: PROC [stream: IO.STREAM, wSTEntry: WireSTEntry _ NIL] RETURNS [WireSTEntry] = TRUSTED { nBytes: INT; IF (wSTEntry = NIL) THEN wSTEntry _ NEW[SGI.WireSTEntryBody]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSTEntry^], 0, BYTES[SGI.WireSTEntryBody]]]; RETURN [wSTEntry]; }; ReadWireExtSTEntry: PROC [stream: IO.STREAM, wExtSTEntry: WireExtSTEntry _ NIL] RETURNS [WireExtSTEntry] = TRUSTED { nBytes: INT; IF (wExtSTEntry = NIL) THEN wExtSTEntry _ NEW[SGI.WireExtSTEntryBody]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wExtSTEntry^], 0, BYTES[SGI.WireExtSTEntryBody]]]; RETURN [wExtSTEntry]; }; BitsOn: PROC [flags: CARD, mask: CARD] RETURNS [on: BOOL] ~ INLINE { RETURN [Basics.BITAND[flags, mask] # 0] }; ReadELFHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED { wHeader: ElfWireHeader _ NEW[ElfWireHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[ElfWireHeaderBody]]]; magic: CARD _ Basics.Card32FromF[wHeader.magic]; shortMagic: CARD _ Basics.BITRSHIFT[LOOPHOLE[magic, WORD], 16]; objType: CARD _ Basics.Card16FromH[wHeader.type]; machine: CARD _ Basics.Card16FromH[wHeader.machine]; nBadMagic: BOOLEAN _ (magic # ElfMagic) OR (wHeader.elfClass # ElfClass32) OR (wHeader.elfData # ElfData2MSB) OR ((objType # ETRelocatable) AND (objType # ETExecutable)) OR (machine # EMMips); nPageSize: CARD _ 1000H; textSeg: MemorySegmentInfo _ [0, 0]; iDataSeg: MemorySegmentInfo _ [0, 0]; symHdrSeg: MemorySegmentInfo _ [0, 0]; textRelocSeg: MemorySegmentInfo _ [0, 0]; dataRelocSeg: MemorySegmentInfo _ [0, 0]; bssSeg: MemorySegmentInfo _ [0, 0]; bssSize: CARD32 _ 0; sectHdrOffset: CARD _ Basics.Card32FromF[wHeader.sectHdrOffset]; sectHdrNum: CARD _ Basics.Card16FromH[wHeader.sectHdrNum]; sectionList: SectionList _ NEW[SectionListBody[sectHdrNum]]; sectStrTblX: CARD _ Basics.Card16FromH[wHeader.sectStrTblX]; textIndex, dataIndex, bssIndex, symtabIndex, symsIndex: CARD _ LAST[CARD]; header: Header; wSymHeader: WireSymHeader _ NEW[SGI.WireSymHeaderBody]; textLoadOffset: CARD32 _ Basics.Card32FromF[wHeader.entry]; IF nBadMagic THEN ERROR; IO.SetIndex[stream, sectHdrOffset]; FOR i: CARD IN [0..sectHdrNum) DO wSectionHeader: ElfWireSectionHeader _ NEW[ElfWireSectionHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[ElfWireSectionHeaderBody]]]; sectionList[i] _ NEW[SectionHeaderBody]; sectionList[i].nameIndex _ Basics.Card32FromF[wSectionHeader.nameIndex]; sectionList[i].type _ Basics.Card32FromF[wSectionHeader.type]; sectionList[i].flags _ Basics.Card32FromF[wSectionHeader.flags]; sectionList[i].addr _ Basics.Card32FromF[wSectionHeader.addr]; sectionList[i].offset _ Basics.Card32FromF[wSectionHeader.offset]; sectionList[i].size _ Basics.Card32FromF[wSectionHeader.size]; sectionList[i].link _ Basics.Card32FromF[wSectionHeader.link]; sectionList[i].info _ Basics.Card32FromF[wSectionHeader.info]; sectionList[i].alignment _ Basics.Card32FromF[wSectionHeader.alignment]; sectionList[i].entrySize _ Basics.Card32FromF[wSectionHeader.entrySize]; ENDLOOP; IO.SetIndex[stream, sectionList[sectStrTblX].offset]; FOR i: CARD IN [0..sectHdrNum) DO SELECT TRUE FROM (sectionList[i].type = SHTProgBits) AND BitsOn[sectionList[i].flags, SHFAlloc] => { IF NOT BitsOn[sectionList[i].flags, SHFWrite] THEN { IF textIndex = LAST[CARD] THEN { textSeg _ [sectionList[i].offset, sectionList[i].size]; textIndex _ i; } ELSE textSeg.byteLength _ textSeg.byteLength + sectionList[i].size; } ELSE { IF dataIndex = LAST[CARD] THEN { iDataSeg _ [sectionList[i].offset, sectionList[i].size]; dataIndex _ i; } ELSE iDataSeg.byteLength _ iDataSeg.byteLength + sectionList[i].size; }; }; (sectionList[i].type = SHTNoBits) AND BitsOn[sectionList[i].flags, SHFWrite] => { IF bssIndex = LAST[CARD] THEN { bssSize _ bssSize + sectionList[i].size; bssIndex _ i; bssSeg _ [sectionList[i].offset, sectionList[i].size]; }; }; (sectionList[i].type = SHTRela) OR (sectionList[i].type = SHTRel) => { IF sectionList[i].info = textIndex THEN textRelocSeg _ [sectionList[i].offset, sectionList[i].size] ELSE IF sectionList[i].info = dataIndex THEN dataRelocSeg _ [sectionList[i].offset, sectionList[i].size]; }; (sectionList[i].type = SHTMipsDebug) => { [] _ ReadWireSymHeader[stream, sectionList[i].offset, wSymHeader]; symHdrSeg _ [sectionList[i].offset, sectionList[i].size]; }; ENDCASE; ENDLOOP; header _ NEW[HeaderBody _ [ dynamic: objType = ETDynamicLib, toolversion: BYTE[0] -- wHeader.version --, machtype: machine, magic: shortMagic, text: textSeg, iData: iDataSeg, textReloc: textRelocSeg, dataReloc: dataRelocSeg, syms: symHdrSeg, debug: [0, 0], linno: [0, 0], textLoadOffset: textLoadOffset, bssSize: bssSize, entryPoint: Basics.Card32FromF[wHeader.entry], nPageSize: nPageSize, nEntries: wSymHeader.symIndexLimit, stringOffset: wSymHeader.symStringPtr, extStringOffset: wSymHeader.extSymStringPtr ]]; RETURN[header]; }; ReadHeader: PROC [stream: IO.STREAM] RETURNS [Header] = TRUSTED { wHeader: WireHeader; wAuxHeader: WireAuxHeader; wSymHeader: WireSymHeader; magic: CARD; nBytes: CARD; dataRelocSeg: MemorySegmentInfo _ [0, 0]; bssRelocSeg: MemorySegmentInfo _ [0, 0]; textRawData, dataRawData, bssRawData, textRelocSeg: MemorySegmentInfo _ [0, 0]; header: Header; numSects: CARD; sectionTable: SectionTable; sectionName: ROPE _ NIL; ch: CHAR; IO.SetIndex[stream, 0]; nBytes _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@magic], 0, 4]]; IF magic = ElfMagic THEN { IO.SetIndex[stream, 0]; RETURN[ReadELFHeader[stream]]}; magic _ Basics.BITRSHIFT[LOOPHOLE[magic, WORD], 16]; IF magic # ECOFFMagic THEN ERROR; wHeader _ ReadWireHeader[stream, 0, NIL]; wAuxHeader _ ReadWireAuxHeader[stream, NIL]; wSymHeader _ NEW[SGI.WireSymHeaderBody]; magic _ wHeader.magic; numSects _ wHeader.numSections; sectionTable _ NEW[SGI.SectionTableBody[numSects]]; FOR i: CARD IN [0..numSects) DO [] _ ReadWireSectionHeader[stream, LOOPHOLE[@sectionTable[i]]]; ENDLOOP; FOR i: CARD IN [0..numSects) DO FOR j: CARD IN [0..8) DO IF (sectionTable[i].name[j] = 0) THEN EXIT; ch _ VAL[sectionTable[i].name[j]]; sectionName _ sectionName.Concat[Rope.FromChar[ch]]; ENDLOOP; IF Rope.Equal[sectionName, ".text", TRUE] THEN { textRawData _ [sectionTable[i].dataPtr, sectionTable[i].size]; textRelocSeg _ [sectionTable[i].relocPtr, sectionTable[i].numRelocEntries * RelocEntrySize] } ELSE IF Rope.Equal[sectionName, ".data", TRUE] THEN { dataRawData _ [sectionTable[i].dataPtr, sectionTable[i].size]; dataRelocSeg _ [sectionTable[i].vAddr, sectionTable[i].numRelocEntries * RelocEntrySize]; } ELSE IF Rope.Equal[sectionName, ".bss", TRUE] THEN { bssRawData _ [sectionTable[i].dataPtr, sectionTable[i].size]; }; FREE[@sectionName]; sectionName _ NIL; ENDLOOP; [] _ ReadWireSymHeader[stream, wHeader.symPtr, wSymHeader]; header _ NEW[HeaderBody _ [ dynamic: FALSE, toolversion: BYTE[0], machtype: BYTE[0], magic: magic, text: textRawData, iData: dataRawData, textReloc: textRelocSeg, dataReloc: dataRelocSeg, syms: [0, 0], debug: [0, 0], linno: [0, 0], textLoadOffset: wAuxHeader.textBase, bssSize: wAuxHeader.bssSize, entryPoint: wAuxHeader.entryPtr, nPageSize: nPageSize, nEntries: wSymHeader.symIndexLimit, stringOffset: wSymHeader.symStringPtr, extStringOffset: wSymHeader.extSymStringPtr ]]; RETURN[header]; }; AlternativeFindModuleStabRange: PROC [header: Header, fileDescr: FileDescrTable, procDescr: ProcDescrTable, symHeader: WireSymHeader, relativePC: CARD] RETURNS [sr: StabRange, pcRange: StabRange _ [0, 0], fdIndex: INT32 _ 0] = { IF header = NIL THEN RETURN[[0, 0], [0, 0], 0] ELSE { pcCount: CARD _ 0; minPC: CARD _ LAST[CARD]; indexFirstSym, numSyms, numInstructions: INT32; i, indexFirstProc: INT16; startAddress, textOffset: CARD32; absolutePC: CARD _ 0; numFileDescr: INT32 _ symHeader.fileDescrIndexLimit; textOffset _ header.textLoadOffset; absolutePC _ textOffset + relativePC; FOR i IN [0..numFileDescr) DO startAddress _ fileDescr[i].startAddress; IF absolutePC < startAddress THEN { IF i = 0 THEN RETURN[[0, 0], [0, 0], 0]; fdIndex _ i - 1; startAddress _ fileDescr[fdIndex].startAddress; WHILE fdIndex > 1 AND startAddress = fileDescr[fdIndex-1].startAddress AND fileDescr[fdIndex].fMerge # 0 DO fdIndex _ fdIndex - 1; ENDLOOP; EXIT; } ENDLOOP; IF (fdIndex > numFileDescr) THEN RETURN[[0, 0], [0, 0], 0]; startAddress _ fileDescr[fdIndex].startAddress; indexFirstProc _ fileDescr[fdIndex].ipdFirst; minPC _ procDescr[indexFirstProc].startAddress + textOffset; numInstructions _ fileDescr[fdIndex].cline; pcCount _ 4 * numInstructions; indexFirstSym _ fileDescr[fdIndex].isymBase; numSyms _ fileDescr[fdIndex].csym; IF (absolutePC < (minPC + pcCount)) THEN RETURN[[ indexFirstSym, numSyms], [minPC-textOffset, pcCount], fdIndex]; RETURN[[0, 0], [0, 0], 0]; }; }; GetExtStabList: PROC [fdIndex: INT32, wireTables: WireTables, header: Header, stream: IO.STREAM] RETURNS [extStabList: LIST OF Stab, numExtSyms: CARD] = TRUSTED { i: CARD; totNumExtSyms: CARD _ wireTables.wSymHeader.extSymIndexLimit; lastElem: LIST OF Stab _ NIL; newStab: Stab; numExtSyms _ 0; extStabList _ NIL; FOR i IN [0..totNumExtSyms) DO IF (wireTables.extSyms[i].fileDescrIndex = CARD16[fdIndex]) THEN { newStab _ BasicReadStab[i, fdIndex, TRUE, wireTables, header, stream]; IF (extStabList = NIL) THEN { extStabList _ LIST[newStab]; -- make one element list holding new Stab lastElem _ extStabList; } ELSE { lastElem.rest _ LIST[newStab]; lastElem _ lastElem.rest; }; lastElem.rest _ NIL; numExtSyms _ numExtSyms + 1; }; ENDLOOP; }; CreateModule: PROC [parsed: Parsed, fdIndex: INT32, wireTables: WireTables, stream: IO.STREAM, stabRange, pcRange: StabRange _ [0, 0]] RETURNS [Module] = TRUSTED { module: Module _ NEW[ModuleBody]; nStabs: CARD _ stabRange.count; currentIndex: CARD; I: CARD _ 0; nExtStabs: CARD; extStabList, thisExtStab: LIST OF Stab _ NIL; stab: Stab; lineNumbers: LineNum _ NIL; stringBase: INT32 _ wireTables.fileDescr[fdIndex].issBase; fileNameOffset: INT32 _ wireTables.fileDescr[fdIndex].rss; filename: UXStrings.UnixString; [extStabList, nExtStabs] _ GetExtStabList[fdIndex, wireTables, parsed.header, stream]; module.whole _ parsed; module.firstStabX _ stabRange.first; module.limitStabX _ stabRange.first + nStabs + nExtStabs; module.firstPC _ pcRange.first; module.limitPC _ pcRange.first + pcRange.count; module.stabs _ NEW[StabSet[nStabs + nExtStabs]]; module.fdIndex _ fdIndex; currentIndex _ 0; I _ 0; WHILE (I < nStabs) DO module.stabs[currentIndex] _ BasicReadStab[stabRange.first+I, fdIndex, FALSE, wireTables, parsed.header, stream]; stab _ module.stabs[currentIndex]; stab.module _ module; IF (stab.stabType = LBrac) OR (stab.stabType = RBrac) THEN -- relocate bracket pcs stab.value _ stab.value + module.firstPC; IF (stab.stabType = Fun) THEN stab.value _ stab.value - parsed.header.textLoadOffset; currentIndex _ currentIndex + 1; I _ I + 1; ENDLOOP; FOR thisExtStab _ extStabList, thisExtStab.rest WHILE (thisExtStab # NIL) DO module.stabs[currentIndex] _ thisExtStab.first; currentIndex _ currentIndex + 1 ENDLOOP; module.fileName _ PFS.PathFromRope[RopeFromStream[stream, parsed.header.stringOffset+stringBase+fileNameOffset]]; filename _ UXStrings.Create[PFS.RopeFromPath[module.fileName]]; module.staticVarsInstalled _ FALSE; module.versionStampInfo _ NIL; module.outerBracket _ NEW[BracketPairBody _ [ module: module, kind: syntheticOuter, firstX: 0, limitX: module.whole.header.nEntries, firstPC: module.firstPC, pcLimit: module.limitPC, funIndex: 0, symbols: NIL, innerBrackets: NIL ]]; RETURN[module]; }; SGIModuleFromParsedAndPC: PROC [whole: Parsed, spc: FileSegmentPC, moduleRope: Rope.ROPE _ NIL] RETURNS [newModule: Module _ NIL] = TRUSTED { stabRange, pcRange: StabRange; stream: IO.STREAM; nBytes, fdIndex: INT32 _ 0; firstPC: CARD32; newElem, prevElem, modules: LIST OF Module; wireTables: WireTables _ NIL; IF whole = NIL THEN RETURN ELSE { stream _ SystemInterface.GetStreamForFile [whole.file]; IF (whole.privateInfo = NIL) THEN InitParsedWireTables [stream, whole]; wireTables _ NARROW [whole.privateInfo, WireTables]; [stabRange, pcRange, fdIndex] _ AlternativeFindModuleStabRange [whole.header, wireTables.fileDescr, wireTables.procDescr, wireTables.wSymHeader, spc.relPC]; stream _ SystemInterface.GetStreamForFile[whole.file]; { ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[whole.file, stream]; firstPC _ pcRange.first; prevElem _ NIL; IF whole.modules = NIL THEN { newModule _ CreateModule[whole, fdIndex, wireTables, stream, stabRange, pcRange]; newElem _ LIST[newModule]; -- make one element list holding new module newElem.rest _ modules; IF (prevElem = NIL) THEN whole.modules _ newElem ELSE prevElem.rest _ newElem; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN; }; FOR modules _ whole.modules, modules.rest WHILE (modules # NIL) DO IF (modules.first.firstPC = firstPC) THEN -- we already have it { SystemInterface.ReleaseStreamForFile[whole.file, stream]; newModule _ modules.first; RETURN }; IF (firstPC < modules.first.firstPC) THEN { -- we should have found it by now newModule _ CreateModule[whole, fdIndex, wireTables, stream, stabRange, pcRange]; newElem _ LIST[newModule]; -- make one element list holding new module newElem.rest _ modules; IF (prevElem = NIL) THEN whole.modules _ newElem ELSE prevElem.rest _ newElem; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN; }; prevElem _ modules; ENDLOOP; }; { newModule: Module _ CreateModule[whole, fdIndex, wireTables, stream, stabRange, pcRange]; cell: LIST OF Module _ LIST[newModule]; IF prevElem # NIL THEN prevElem.rest _ cell ELSE whole.modules _ cell; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[newModule]; }; }; }; SGIVarLocFromStab: PROC [stab: Stab] RETURNS [ObjectFiles.VarLoc] = { header: Header ~ stab.module.whole.header; wireTables: WireTables _ NARROW[stab.module.whole.privateInfo, WireTables]; MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ { segRope: Rope.ROPE; fileByteOffset: CARD; bitOffset: CARD; segBase: CARD ~ SELECT kind FROM text => 0, data => header.dataReloc.byteOffset, bss => wireTables.wAuxHeader.bssBase, ENDCASE => ERROR; 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]]] ]]; SELECT kind FROM text => { segRope _ "text"; bitOffset _ (stab.value-segBase)*8; fileByteOffset _ stab.value-segBase+header.text.byteOffset; }; data => { segRope _ "data"; bitOffset _ (stab.value-segBase)*8; fileByteOffset _ stab.value-segBase+header.iData.byteOffset; }; bss => { segRope _ "bss"; bitOffset _ (stab.value-segBase)*8; fileByteOffset _ stab.value-segBase+header.iData.byteOffset; }; ENDCASE => ERROR; RETURN [NEW [ObjectFiles.VarLocBody _ [ bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: fSegment[ [0, segRope], bitOffset, fileByteOffset] ]]]}; 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#0 THEN stab.size*8 ELSE unspecdBitSize, where: frame[bitOffset: 8*byteOffset]]]; RETURN[vLB]}; RSym => { sz: CARD ~ IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize; vLB: ObjectFiles.VarLoc; IF stab.size>4 AND stab.size # LAST[CARD] THEN vLB _ NEW[ObjectFiles.VarLocBody _ [ bitSize: sz, where: indirect[ base: NEW[ObjectFiles.VarLocBody _ [ bitSize: 32, where: register[regNum: stab.value]]], offset: CirioTypes.zeroBA]]] ELSE vLB _ NEW[ObjectFiles.VarLocBody _ [ bitSize: sz, where: register[regNum: stab.value]]]; RETURN[vLB] }; GSym => RETURN [NEW [ObjectFiles.VarLocBody _ [ bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: namedCommon[ObjectFiles.CNameOfStab[stab], 0, 0, FALSE, FALSE] ]]]; ENDCASE => RETURN ObjectFiles.MakeUnknownVarLoc[IO.PutFR["unrecognized stabType (%02xH) for %g", [cardinal[ORD[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[stab]]] ]]; }; ScanOneBracketPairSequence: PROC [module: Module, fun: Stab, funIndex: CARD, firstX: CARD, unclaimedHead, unclaimedTail: StabList] RETURNS [--finalRBracX-- CARD, --innerBrackets-- LIST OF BracketPair, --head of unclaimed symbols-- StabList] = { innerBrackets: LIST OF BracketPair _ NIL; lastInnerBracket: LIST OF BracketPair _ NIL; x: CARD _ firstX; symHead, symTail: StabList _ NIL; DO xAfterSymbs: CARD; stabAfterSymbs: Stab; [xAfterSymbs, symHead, symTail] _ ObjectFilesPrivate.ScanSymbolStabs[module, x, symHead, symTail]; IF xAfterSymbs >= module.limitStabX THEN { IF unclaimedTail#NIL THEN unclaimedTail.rest _ symHead ELSE unclaimedHead _ symHead; RETURN[xAfterSymbs, innerBrackets, unclaimedHead]}; 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 { IF unclaimedTail#NIL THEN unclaimedTail.rest _ symHead ELSE unclaimedHead _ symHead; RETURN[xAfterSymbs, innerBrackets, unclaimedHead]}; ENDCASE => ERROR; -- can't happen ENDLOOP }; SGIInstallBracketPairsForOneFunStab: PROC [module: Module, funStabIndex: CARD] = { wasScanned: BOOLEAN _ module.funStabs[funStabIndex].bracketsScanned; module.funStabs[funStabIndex].bracketsScanned _ TRUE; -- if error occurs, then we won't do this again. IF NOT wasScanned THEN { 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; }; SGIScanModuleStructure: PROC [module: Module, perFn: ObjectFilesPrivate.FnConsumer] ~ { I: CARD _ 0; WHILE I < module.stabs.nStabs DO stab: Stab ¬ module.stabs[I]; IF stab.module = NIL THEN I _ I+1 ELSE SELECT stab.stabType FROM GSym, LCSym, STSym, LSym => I _ I + 1; Fun => {funStab: Stab ~ stab; firstLocal: Stab _ NIL; WHILE I+1 < module.stabs.nStabs DO I _ I + 1; stab _ module.stabs[I]; IF stab.module = NIL THEN LOOP; SELECT stab.stabType FROM PSym => NULL; LBrac => {firstLocal _ module.stabs[I]; EXIT}; Invalid, Unspecified , SO => NULL; ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab while scanning the arguments for function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; ENDLOOP; I _ perFn[funStab, firstLocal, I+module.firstStabX] - module.firstStabX}; Invalid, Unspecified, SO => I _ I + 1; RBrac, LBrac => {I _ I + 1;}; ENDCASE => { SystemInterface.ShowReport[IO.PutFR["Found %g stab while scanning in the global space of %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; I _ I + 1}; ENDLOOP; RETURN}; SGIScanFnStructure: PROC [module: Module, funStab: Stab, firstLocal: Stab _ NIL, nextX: CARD, perParm: PROC [Stab] _ NIL, perBracket: ObjectFilesPrivate.BracketConsumer _ NIL] RETURNS [limitX, limitPc: CARD] ~ { IF perParm#NIL THEN PassParams[module, funStab, funStab.stabX+1, nextX, perParm]; IF firstLocal=NIL THEN limitX _ nextX ELSE limitX _ DoBrack[module, funStab, firstLocal, perBracket]; FOR K: CARD _ limitX-module.firstStabX, K+1 WHILE K < module.stabs.nStabs DO stab: Stab _ module.stabs[K]; IF stab.module = NIL THEN LOOP; SELECT stab.stabType FROM Fun => RETURN [limitX, stab.value]; ENDCASE => NULL; ENDLOOP; RETURN [limitX, module.limitPC]}; DoBrack: PROC [module: Module, funStab, first: Stab, perSubBracket: ObjectFilesPrivate.BracketConsumer] RETURNS [limitX: CARD] ~ { IF perSubBracket#NIL THEN limitX _ perSubBracket[first] ELSE limitX _ SGIScanBktStructure[module, funStab, first, NIL, NIL].limitX; RETURN}; SGIScanBktStructure: PROC [module: Module, funStab, first: Stab, perLocal: PROC [Stab] _ NIL, perSubBracket: ObjectFilesPrivate.BracketConsumer _ NIL] RETURNS [limitX, firstPc, limitPc: CARD] ~ { I: CARD _ first.stabX - module.firstStabX; stab: Stab; FOR I _ I, I+1 WHILE I < module.stabs.nStabs DO stab ¬ module.stabs[I]; IF stab.module = NIL THEN LOOP; SELECT stab.stabType FROM STSym, LSym => IF perLocal#NIL THEN perLocal[stab]; LBrac => { J: CARD _ I+1; firstPc _ stab.value+funStab.value; WHILE J < module.stabs.nStabs DO stab ¬ module.stabs[J]; IF stab.module = NIL THEN J _ J+1 ELSE SELECT stab.stabType FROM RBrac => RETURN [J+1+module.firstStabX, firstPc, stab.value+funStab.value]; STSym, LSym, LBrac => J _ DoBrack[module, funStab, stab, perSubBracket] - module.firstStabX; Invalid, Unspecified, SO => J _ J +1; Fun => {--Since we're debugging C, which has no nested functions, this shouldn't happen; if it does, we assume the bracket parsing has failed and re-synch with top level enumeration of functions SystemInterface.ShowReport[IO.PutFR["Found FUN stab after an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; RETURN [J+module.firstStabX, firstPc, stab.value]}; ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab after an LBRAC in function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; ENDLOOP; SystemInterface.ShowReport[IO.PutFR["Missed an RBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; RETURN[J+module.firstStabX, firstPc, module.limitPC]}; Fun => {--shouldn't happen, but ... SystemInterface.ShowReport[IO.PutFR["Found FUN stab before an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; }; Invalid, Unspecified, SO => NULL; RBrac => { firstPc _ first.value+funStab.value; RETURN[I+module.firstStabX, firstPc, stab.value+funStab.value]; }; ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab before an LBRAC in function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; ENDLOOP; SystemInterface.ShowReport[IO.PutFR["Missed an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; RETURN[I+module.firstStabX, module.limitPC, module.limitPC]}; PassParams: PROC [module: Module, funStab: Stab, firstX, limitX: CARD, to: PROC [Stab]] ~ { FOR I: CARD IN [firstX - module.firstStabX .. limitX-module.firstStabX) DO stab: Stab _ module.stabs[I]; IF stab.module#NIL THEN SELECT stab.stabType FROM PSym, RSym, LSym, STSym => to[stab]; Invalid, Unspecified, SO => NULL; RBrac => RETURN; ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab in parms of %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; ENDLOOP; RETURN}; SGIInstallStaticVars: PROC [module: Module] = { IF NOT module.staticVarsInstalled THEN FOR x: CARD IN [module.firstStabX..module.limitStabX) DO stab: Stab _ ObjectFilesPrivate.ReadStab[module, x]; IF stab = NIL THEN LOOP; IF stab.stabType = Fun THEN EXIT; 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 { dataRope: Rope.ROPE _ ObjectFilesPrivate.ReadInitialDataAsRope[module, gvi.fileByteOffset]; module.versionStampStab _ stab; 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; }; SGIAlterFunStab: PROC [module: Module, funStabX: CARD] RETURNS [Stab] = { RETURN [module.funStabs[funStabX].stab]; }; SGIGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ TRUSTED { privateModule: ObjectFilesPrivate.Module _ LOOPHOLE[module]; parsed: ObjectFiles.Parsed _ LOOPHOLE[privateModule.whole, ObjectFiles.Parsed]; absPC: CARD _ spc.relPC + parsed.header.textLoadOffset; currentPDR: SGI.WireProcDescriptorBody; found: BOOLEAN; spOffset: INT; [currentPDR, found] _ FindMatchingProcDescr [absPC, parsed]; IF found = FALSE THEN spOffset _ 0 ELSE spOffset _ LOOPHOLE[currentPDR.frameoffset]; RETURN[spOffset]; }; RandomTestFindStabRange: PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] = { args: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; path: PATH _ PFS.PathFromRope[args[1]]; range: StabRange; pc: CARD; fileSet: SystemInterface.FileSet _ SystemInterface.CreateFileSet[]; wireTables: WireTables _ NIL; { 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, "SGI"]; wireTables _ NARROW[whole.privateInfo, WireTables]; IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed], IO.time[start]]; FOR I: INT IN [0..100) DO pc _ Random.ChooseInt[rs, 0, whole.header.text.byteLength]; [range, [, ], ] _ AlternativeFindModuleStabRange[whole.header, wireTables.fileDescr, wireTables.procDescr, wireTables.wSymHeader, 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]; }; transTable: ObjectFilesPrivate.TranslationTable _ NEW[ ObjectFilesPrivate.TranslationTableBody[3]]; transTable[0] _ [0, 2, ECOFFMagic, "SGI"]; -- byteOffset,length,compareValue,format transTable[1] _ [0, 4, ElfMagic, "SGI", first]; -- the SGI elf magic sequence transTable[2] _ [18, 2, EMMips, "SGI", last]; Commander.Register["sgiRandomTestFindStabRange", RandomTestFindStabRange]; ObjectFilesPrivate.RegisterObjectFileFlavor[ NEW [ ObjectFilesPrivate.ObjectFileFlavorBody _ [ "SGI", SGIOBJ, ReadHeader, SGIModuleFromParsedAndPC, SGIVarLocFromStab, NIL, NIL, SGIScanModuleStructure, SGIScanFnStructure, SGIScanBktStructure, TRUE, SGIInstallStaticVars, SGIAlterFunStab, SGIGetSPOffset ]], transTable]; END.. &˜SGIFiles.mesa Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Modified from DotOAccessImpl.mesa Edwards, June 16, 1992 12:05 pm PDT Jas, January 8, 1993 1:30 pm PST Katsuyuki Komatsu January 25, 1993 4:15 pm PST Useful type definitions Following types are defined in ObjectFiles Following types are defined in ObjectFilesPrivate C Line-Number to Relative-PC maps sorted by PC Type defs for this module ======================================================================== ======================================================================== Constants ======================================================================== ======================================================================== Magic nums Sizes based on Chapter 10 padding problems Elf stuff ======================================================================== ======================================================================== Global Variables ======================================================================== ======================================================================== ======================================================================== ======================================================================== Basic Low Level Support Routines ======================================================================== ======================================================================== ======================================================================== ======================================================================== Low Level Support Functions for Reading and Finding Symbol Table Entries ======================================================================== ======================================================================== A simple binary search through the procedure descriptor records to find the matching procedure information. Check either majic numbers MIPSEL and MIPSEB collect the qualifiers if there are any return the size C Line-Number to Relative-PC maps first we read in all of packed line numbers into an array - - Even though we allocated for all of the line numbers we're only interested in the current files line numbers. unpack line numbers for each procedure in this file - - find out how many instructions there are in this procedure - - find the next procedure that contains instructions - - unpack the line numbers for this procedure - - watch out for sign problems here SIze is returned in bits the first aux symbol is the TI calculate the size of the basic type I've never seen a basic type typedef in SGI, but just in case process the qualifiers if there are any Print["InitParsedWireTables %s\n", filename]; read the file, optional and symbol headers read the file descriptor table read the relative file table read the procedure descriptor table Add the file start address to each of the procedure descriptor addrs so that the procedure descriptor addrs are dotO relative. read the local symbols read the external symbols Aux's are problematic as far as byte/bit reversing is concerned because they are a union of bitfields and integers, so we read in as un twiddled here and play with the bits as needed read the local strings read the external strings Add a colon to the end of the name to be compatible with Sun, this is so the CheckStaticStab routine will match, jas size is in bits, stab size needs to be in bytes This routine must follow a call to the ReadWireHeader function to ensure that the proper offset is set for the read. PROC [stream: IO.STREAM] RETURNS [Header] = TRUSTED Print["Found the Debug section"]; Print["Reading Header ...\n"]; Fill in array of section headers Read in raw section header data Find index of section headers for .text, .data segments Fill in the header for this file - - ======================================================================== Used by SGIModuleFromParsedAndPC and RandomTestFindStabRange search through file descriptors until you find one that contains the pc... this will give us max and min symtab entry range then once we know the file we can use proc descriptors to find max and min pc symtab entries range ======================================================================== ======================================================================== Used only by CreateModule search though the external stabs and make a list of those that are associated with a particular file ======================================================================== strangely enough, in ext syms the fdindex is a half word but in the symbolic header the max fdindex is a full word ======================================================================== Used only by SGIModuleFromParsedAndPC ======================================================================== prepare the embeddedDotO for a call on BuildBrackets I'm puzzled as to why stabX info is kept...we read all our stabs into the stabs array...so we shouldnt ever have to go back to the file... and in any case .limitStabX includes the ext syms making it useless for file access lets read all the local stabs now (we also relocate the pc value of bracket stabs.) read in a sym table entry tack on the external symbols that belong to this module ... I think external symbols really should be in the parsed structure but that probably would require wholesale changes Print["CreateModule for file %s\n", filename]; only unpack line numbers that haven't already been unpacked I've changed the unpacking line numbers to be on demand, and the call is in ObjectFilesImpl.GetLineNumForPC and ObjectFilesImpl.GetPCForLineNum IF wireTables.pcToLineNum = NIL THEN UnPackLineNumbers[module.whole.header, wireTables.fileDescr, wireTables.procDescr, stream, module, wireTables]; ======================================================================== 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 first pc of the embedded dotO. We assume that this or the next 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 ======================================================================== IF stabRange.count = 0 THEN RETURN; nest so that we can catch unwinds and release the stream if some outer block leaves us dangling clean up insert new element containing module in the list first, see if we already have it insert new element containing module in the list ======================================================================== Given a symbol table entry return a VarLoc record which contains a storage class string, address, the size of the variable in bits, and any bit offset ======================================================================== the dataReloc in the header is always the start of the data section where the wireTables.wAuxHeader.dataBase is the start of rdata if there was one. ======================================================================== Used only by SGIInstallBracketPairsForOneFunStab This is coded so that symbols both before and after LBracs are saved with the appropriate bracket pair 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. ======================================================================== 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 procedure examines all stabs up to the first Fun stab, looking for certain expected stabs. These are recorded in the whole. it fills in the global frame sym table entry pointer, the global frame varloc pointer and a pointer to the version stamp in the module ======================================================================== ======================================================================== No need to alter function sym tab entries with MIPS e-coff. ======================================================================== Functions for testing ======================================================================== testing ... see if we can parse a symtab entry for a random PC? ======================================================================== Main Code The magic number for MIPSEL is 354 (0x162) transTable[0] _ [0, 2, 354, "SGI"]; -- byteOffset,length,compareValue,format The magic number for the MIPSEB is 352 (0x160) ÊK˜šœ ™ JšœN™NJšœ!™!Jšœ#™#Jšœ ™ J™.—J˜šÏk ˜ Icodešœœ( œ œœœœœ˜gJšœ œœ˜Jšœœ˜%Jšœ œ ˜Jšœ œ˜#Jšœ œ˜*Jšœœ˜*Kšœœ9œ˜_Jšœœ˜Kšœ œÁ˜ÒKšœœá˜ùJšœœ˜'Jšœ œœ˜Jšœœ#˜/Jšœœœ˜+Jšœ˜Kšœœ„˜™Jšœ œ˜%J˜—J˜J˜šÏnœœ˜Jšœ>œ)œ*˜Jšœ˜—Jš˜J˜Kšžœœ!œœ˜MJ˜šœ™Jšœœœ˜Jšœœ œ˜Jšœ œ˜%Jšœœ œ˜Jšœœ œ˜—J˜šœ*™*Jšœœ˜Jšœ œ˜&Jšœ œ˜&Jšœœ˜.Jšœ œ˜$Jšœ œ˜*Jšœ œ˜,Jšœ œ˜,Jšœœ˜4—˜šœœ ˜6J˜——šœ1™1J˜Jšœœœ ˜Jšœ œœ!˜8J˜Jšœœœ ˜Jšœ œœ!˜8J˜šœ œ˜*J˜—Jšœ œ˜+šœ œ ˜/J˜—Jšœœ(˜?Jšœœ˜0J˜Jšœ œœ˜(Jšœœ&˜;J˜Jšœ œ!˜1Jšœœ%˜9Jšœ œ"˜3J˜Jšœ!™!Jšœœœ˜.Jšœœ)˜AJšœ ™ Jšœœœ˜.Jšœœ)˜AJ˜Jšœœœ ˜šœ œœ!˜8J˜—Jšœ œœ˜$Jšœœ$˜7—J˜šœ™J˜Jšœ œœ˜*Jšœœœ˜0Jšœœœ˜8Jšœœœ˜0Jšœœœ˜8Jšœœœ˜:Jšœœœ˜6Jšœœœ˜:Jšœ œœ˜,Jšœœœ˜2Jšœœœ˜.Jšœœœ˜.Jšœœœ˜2Jšœœœ˜.Jšœœœ˜2Jšœœœ˜.Jšœœœ˜2Jšœœœ˜0Jšœœœ˜>Jšœ œœ˜,Jšœ œœ˜,Jšœœœ˜:Jšœ œœ˜,Jšœ œœ˜*J™šœœ˜$J˜Jšœœ˜ J˜Jšœ˜ J˜—J˜Kšœ œ˜-Jšœœœœ˜AJ˜Jšœœœœ ˜šœ œ˜Jšœœ œœ ˜&—Jšœ œœ˜"šœœ˜J˜Jšœ œ˜Jšœ ˜J˜—J˜Jšœ œœ˜J˜Jš œ œœœ œœœ˜>J˜Jšœœœ˜*šœœ˜Jš œœ œœœ˜"——J˜JšœH™HJšœH™HJšœ ™ JšœH™HJšœH™H˜Jšžœœ Ïc"˜<—J˜šœ ™ J˜Jšž œœ˜—J˜™J™Jšœ œ Ÿ%˜?Jšž œœŸ"˜:Jšž œœŸ˜1Jšž œœŸ˜0Jšžœœ˜Jšž œœ˜šž œœŸ#˜=Jšœ™—Jšž œœ˜J˜Jšž œœ œœ”˜µK˜Kšž œœ˜Kšž œœ˜—J™™ K˜Kšžœœ œ œœ œœ œ˜tJ™Jšž œœ˜Kšž œœ˜Kšž œœ˜K˜Kšž œœ˜Kšž œœ˜Kšž œœ˜K˜Kšžœœ˜Kšž œœ˜Kšž œœ˜Kšž œœ˜Kšžœœ˜K˜Kšžœœ˜KšÐbkœœ˜Kšžœœ˜Kš œœ˜Kš œœ˜Kš œœ˜Kš œœ˜Kš œœ˜KšÐbnœœ˜Kš œœ˜K˜Kšžœœ˜Kšž œœ˜Kšž œœ˜Kšž œœ˜Kšžœœ˜Kšžœœ˜Kšž œœ˜Kšžœœ˜Kšž œœ˜Kšžœœ˜Kšžœœ˜Kšž œœ˜Kšž œœ ˜Kšž œœ˜!K˜Kšžœœ˜Kšžœœ˜Kšž œœ˜K˜Jšœœœ˜,š œœœ œœ˜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šœœ˜ Kšœœ˜Kšœœ˜ Kšœœ˜Kšœœ˜ Kšœœ˜ Kšœœ˜ Kšœ œ˜Kšœ œ˜K˜—Kšœœœ˜:š œœœ œœ˜:Kšœœ˜Kšœ œ˜Kšœœ˜Kšœ œ˜Kšœœ˜Kšœ œ˜Kšœ œ˜Kšœ œ˜Kšœœ˜Kšœœ˜——J˜JšœH™HJšœH™HJšœ™JšœH™HJšœH™HJ˜Kšœœ˜2J˜Jšžœ*˜CJ˜JšœH™HJšœH™HJšœ ™ JšœH™HJšœH™HJ˜Jšœ œœœœœœœœ˜@J˜šžœœœœN œœœœœ˜¤Jšœ˜—J˜š žœœœE œ˜uJšœ˜Jšœ œN˜bJšœ˜—J˜š ž œœœœ˜&J˜J˜J˜—J˜JšœH™HJšœH™HJšœH™HJšœH™HJšœH™HJ˜šžœœœ œ˜LJšœœœ˜9Jšœ+œ$˜WJšœœ(˜GJšœœœ˜Jšœœ˜Jšœœ(˜EJšœ œ-˜>JšœO˜OJ˜Jšœ œœ˜(J™J˜Jšœk™kJ˜šœ ˜Jšœ˜Jšœœœ˜/šœ0˜6J˜—š˜J˜ —Jšœ˜—J˜Jšœœ˜*J˜J˜—J˜šžœœ œ9˜}Jšœ˜Jšœœ˜Jšœœ˜Jšœœ˜ J˜šœœ˜J˜ J˜J˜šœœ˜Jšœj˜jJšœ˜—Jšœ˜—J˜J˜—J˜š žœœœ œœ˜0Jšœœœ˜Jšœœ˜Jšœœ˜Jšœœ˜1J˜Jšœœ˜#JšœŸ/˜Gšœ œ˜"Jšœœœ˜8—Jšœ ˜"J˜Jšœ œ˜&J˜šœ˜JšœŸ˜!—J˜J™,šœœœ˜JJšœœ˜ —š œœœœ˜OJšœœ˜—š˜JšœŸ˜%—J˜J˜—J˜šžœœ1œ œœ œœœœ˜ÄJ˜Jšœ œœœ˜ Jšœœ˜J˜Jšœ œœ˜2Jšœ˜Jšœ˜J˜J™'š˜šœ"˜(Jšœ˜—J˜.J˜"šœ"˜(Jšœ˜—J˜.J˜"šœ"˜(Jšœ˜—J˜.J˜"šœ"˜(Jšœ˜—J˜.J˜"šœ"˜(Jšœ˜—J˜.J˜"šœ"˜(Jšœ˜—J˜.J˜"šœ˜Jšœ˜——Jšœ˜J˜J™šœœœ˜#J˜Jšœœ˜šœ˜Jšœ œ˜šœ ˜ Jšœ˜Jšœ˜Jšœ˜J˜—JšœœŸ&˜:Jšœ œŸ%˜9šœ˜J˜Jšœœ,˜:Jšœ ˜ Jšœœ-˜Jšœ#œ&˜LJšœ œ˜Jšœœ˜%Jšœœ˜Jšœ(œ˜2Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ ˜Jšœœ˜Jš œœœœœœŸ˜6Jš œœœœœœŸ˜6Jš œ œœœœœ˜"Jšœœ:˜UJšœ œ˜Jšœ œ˜J˜J˜Jšœ>™>Jšœ:˜šœœ˜Jšœ%˜%J˜ ˜JšœŸœœ ˜.Jšœ˜—J˜J˜—Jšœœ˜Jšœœ˜Jšœ˜—J˜Jšœ1˜1Jšœœ>˜V—˜š œžœœœ.˜AJšœœ œ˜/J˜J˜Jšœ˜——˜J˜+Jšœœ>˜V—˜š œžœœœ.˜AJšœœ œ˜/J˜J˜Jšœ˜——˜Jšœ,˜,Jšœ,˜,—˜Jšœ˜Jšœ˜Jšœ˜J˜—J˜šžœœœœ œ&œœ œœ˜’J˜J™J™Jšœ˜Jšœ œ˜Jšœ$œ˜-Jšœ˜Jšœœ˜Jšœ œœ˜Jšœœ˜Jšœ œ˜J˜šœ ˜J˜Jšœ œ'˜9Jšœ9˜9J˜—š˜J˜Jšœ œ%˜7J˜J˜—Jšœ˜J˜šœ ˜Jšœ ˜ šœ˜J˜Jšœ˜Jšœ˜J˜—Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ ˜ šœ ˜ Jšœ˜—Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜šœ˜Jšœ˜Jšœ˜Jšœ˜J˜—Jšœœ˜—J˜J™J˜Bšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—Jšœ1˜1Jšœœ˜0J˜šœ˜Jšœ˜—J˜J™$šœœ˜AJ˜Jšœœ˜Jšœœ˜Jšœœ˜JšœI˜Išœ$˜*J˜Jšœ;˜;J˜—š˜J˜Jšœ*˜*Jšœ˜—JšœE˜Ešœ˜Jšœ-˜-—Jšœ˜Jšœ6˜6Kšœ'˜'Jšœ2˜2Jšœ˜Jšœ˜—šœœœ˜JJ˜J™=Jšœ˜Jšœ˜—šœœœ˜'Jšœ˜—š˜šœ-˜3Jšœ.˜.——š˜Jšœ ˜ J˜J˜—J™'šœ ˜J˜Jšœl˜lšœ ˜Jšœ1˜1—Jšœ˜Jšœ˜—J˜šœ˜J˜J˜J˜—J˜J˜—J˜š žœœ œœœ˜PJšœ˜Kšœœ˜0Kš œœœœœ˜\Kšœœ˜ Kšœœ-˜@Kšœ œ*˜:Kšœœ˜ K˜Kšœ!˜#šœœœ˜!Kšœ'œ˜EKš œœœœœ˜jKšœ/˜/šœ˜K˜Kšœœ-˜9Kšœ œ˜(Jšœ3˜3Jšœ ˜K˜—Kšœ˜—K˜Kšœ ˜J˜—J˜š žœœ œœ˜HJ˜Jšœ˜Jšœœ˜1Jšœœ˜ Jšœœ˜ J˜Jšœ˜Jšœ$œ˜)Jšœ,œ˜1J˜Jšœœ;˜ZJšœ-™-J˜Jšœ˜Jšœ œœ˜=šœ˜J˜J˜Jšœ˜Jšœ5˜5J˜—š˜Jšœ˜Jšœ œœœ˜4šœ˜Jšœ˜J™*Jšœ/œ˜4Jšœ2œ˜7JšœMœ˜RJšœ˜—š˜Jšœ˜Jšœ1œ˜7J˜—J˜—J™Jšœ"˜"J™Jšœ*˜,Jšœ.˜.Jšœœ(˜Bšœœœ˜$Jšœ$œ˜HJšœ˜—J˜J™Jšœ-˜/Jšœ)˜)Jšœœ%˜>Jšœ œœœœœœœ˜J˜J™#Jšœ6˜8Jšœ.˜.Jšœœ(˜Bšœœœ˜$Jšœ$œ˜HJšœ˜—J˜J™~Jšœ\˜\J˜J™Jšœ$˜&Jšœ#˜#Jšœœ"˜<šœœœ˜Jšœœ˜AJšœ˜—J˜J™Jšœ'˜)Jšœ)˜)Jšœœ#˜;šœœœ˜"Jšœ œ˜BJšœ˜—J˜Jšœ?™?JšœA™AJšœ4™4Jšœ'˜)Jšœ)˜)Jšœœ#˜;Jš œ œœœœœœ#˜}J˜J™Jšœ*˜,Jšœœ5˜RJš œ œœœœœœ'˜†J˜J™Jšœ-˜/Jšœœ8˜SJš œ œœœœœœ*˜‡J˜Jšœ ˜ J˜J˜—J˜š žœœ œœ œ˜6Jšœ œœ˜!—Jš˜˜Jšœœ˜J˜Jšœ˜šœœ˜Jšœ˜ —š˜J˜Jšœœ˜šœœ˜Jšœ˜—Jšœ8œ˜@Jšœ˜—J˜J™=J™6Jšœ9œ˜AJ˜Jš˜—J˜J˜š žœœœœœ(˜cJ˜Jšœ œ˜Jšœ œ˜J™šœ ˜Jšœ ˜ Jšœ˜šœ˜J˜š œœœœ˜5J˜ —š˜J˜ —J˜—Jšœ˜Jšœ˜Jšœ"˜"Jšœ+˜+Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜Jšœ%˜%Jšœ˜—J˜šœ ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœ œ˜%Jšœœ˜Jšœ œ˜)Jšœœ˜Jšœœ˜Jšœ œ˜%Jšœœ˜#Jšœ œ˜)Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜!Jšœ œ˜#Jšœ œ˜+Jšœ œ˜#Jšœ œ˜'Jšœ˜J˜—J˜—J˜š ž œœœ œœ˜cJšœœœ˜"Jšœ˜—Jš˜˜Jšœœ˜ Jšœ œœ˜J˜Jšœ œ)˜:J˜J˜J˜Jšœ˜˜Jšœœ'˜AJ˜U—J˜Jš˜˜Jšœœ%˜?J˜]—J˜J˜J™/JšœF˜Fšœ%œ˜LJšœ˜&—˜Jšœœ˜ Jšœ˜J˜J˜J˜ J˜J˜ J˜J˜J˜J˜—J˜Jš˜—J˜J˜š ž œœœ œ œœ˜dJšœœœ˜"Jšœ˜—˜Jšœœœ˜J˜Jšœœ ˜J˜MJ˜Jš˜—J˜J˜š žœœ œœœœ˜RJšœ˜J˜Jšœœ˜ J˜šœ œ˜Jšœ œ˜"—J˜Jšœ˜Jšœ œœœ˜XJ˜Jšœ ˜J˜—J˜š žœœ œœœ˜LJšœ˜!J˜Jšœœ˜ J˜šœœ˜Jšœ œ˜(—J˜Jšœt™tJšœ œœœ˜^Jšœ˜J˜—J˜š žœœ œœ#œ˜UJšœ˜%—˜Jšœœ˜ J˜šœœ˜Jšœœ˜-—J˜šœ œœ˜?Jšœ˜#—J˜Jšœ˜—J˜J˜š žœœ œœœœ˜WJšœ˜!J˜Jšœœ˜ J˜šœœ˜Jšœ œ˜(—J˜Jšœ˜šœ œœ˜>Jšœ˜—J˜Jšœ˜—J˜J˜š žœœ œœ(œ˜[Jšœ˜—Jš˜˜Jšœœ˜ J˜šœœ˜Jšœœ˜2—J˜šœ œœ˜CJšœ˜$—J˜Jšœ˜—J˜J˜š žœœ œœ(œ˜[Jšœ˜—Jš˜˜Jšœœ˜ J˜šœœ˜Jšœœ˜2—J˜šœ œœ˜CJšœ˜$—J˜Jšœ˜—J˜J˜š žœœ œœœ˜FJšœ˜—Jš˜˜Jšœœ˜ J˜šœ œ˜Jšœ œ˜$—J˜šœ œœ˜˜>Kšœ@˜@Kšœ>˜>KšœB˜BKšœ>˜>Kšœ>˜>Kšœ>˜>KšœH˜HKšœH˜HKšœ˜—Kšœ3˜5šœœœ˜!šœœ˜šœ$œ,˜Sšœœ(œ˜4šœ œœœ˜ Kšœ7˜7Kšœ˜K˜—š˜Kšœ>˜>—Kšœ˜—šœ˜šœ œœœ˜ Kšœ8˜8Kšœ˜K˜—š˜Kšœ@˜@—Kšœ˜—K˜—šœ"œ,˜Qšœ œœœ˜Kšœ(˜(Kšœ ˜ Kšœ6˜6K˜—Kšœ˜—šœ œ$˜Fšœ!˜'Kšœ;˜;—šœœ!˜,Kšœ<˜<—Kšœ˜—šœ)˜)K™!JšœB˜BKšœ9˜9Kšœ˜K˜K˜—Kšœ˜—Kšœ˜—šœ œ˜Kšœ ˜ Kšœ œŸœ˜+Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜J˜J˜K˜Kšœ˜Kšœ.˜.Kšœ˜Kšœ#˜#Kšœ&˜&K˜+Kšœ˜—Kšœ ˜Kšœ˜K˜—šž œœ œœ˜$Jšœ ˜—Jš˜˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜ Jšœœ˜ J˜)J˜(J˜OJ˜Jšœ œ˜Jšœ˜Jšœ œœ˜Jšœœ˜ J™J™Jšœ˜Jšœ œœ˜=šœœ˜Jšœ˜Jšœ˜J˜—Jšœ œœœ˜4šœ˜Jšœ˜—J˜Jšœ$œ˜)Jšœ'œ˜,Jšœ œ˜(J˜Jšœ˜Jšœ˜Jšœœ!˜3J˜Jšœ ™ šœœœ˜Jšœ™Jšœ#œ˜?Jšœ˜—J˜Jšœ7™7šœœœ˜šœœœ˜šœ˜%Jšœ˜—Jšœœ˜"J˜4Jšœ˜—šœ"œ˜.J˜J˜>J˜[J˜—šœœ"œ˜3J˜J˜>J˜YJšœ˜—šœœ!œ˜2J˜J˜=˜J˜——Jšœ˜Jšœœ˜Jšœ˜—J˜Jšœ;˜;J˜J™Jšœ%™%šœ œ ˜˜Jšœ œ˜Jšœ œ˜Jšœ œ˜J˜ J˜J˜J˜J˜J˜ J˜J˜J˜$J˜J˜ J˜Jšœ#˜#J˜&J˜+—J˜—J˜J˜Jšœ ˜—J˜J˜JšœH™HJšœ<™™>Jšœ'™'JšœC™CJšœ5™5JšœH™HJ˜šžœœ'œ œ*œŸœœŸœœœŸœ ˜òKšœ˜Kšœœœœ˜)Kšœœœœ˜,Kšœœ ˜Kšœœ˜!š˜Kšœ œ˜Kšœ˜Kšœb˜bšœ"œ˜*Kšœœœœ˜TKšœ-˜3—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šœœœœ˜TKšœ-˜3—KšœœŸ˜!—Kš˜Kšœ˜—J˜—šž#œœ˜:Jšœœ˜J˜Jšœ œ1˜DKšœ0œŸ0˜fšœœ ˜Kšœ˜Kšœ3˜3Kš œœœœœ˜3KšœœœœŸ˜JKšœœ˜Kšœœœ˜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šœ<˜˜QKšœ œœ˜%Kšœ;˜?š œžœœ!œ˜LK˜Kšœœœœ˜šœ˜Kšœœ˜#Kšœœ˜—Kšœ˜—Kšœ˜!K˜—šžœœ[œ œ˜‚Kšœœœ˜7Kšœ6œœ ˜KKšœ˜K˜—šžœœ2œ œ6œœœ˜ÃKšžœœ#˜*K˜ šœ œ˜/K˜Kšœœœœ˜šœ˜Kšœœ œœ˜3šœ ˜ Kšžœœ˜Kšœ#˜#šœ˜ K˜Kšœœœ˜!šœœ˜Kšœ œ<˜KKšœ\˜\Kšœœ ˜%šœŸº˜ÂKšœœž˜»Kšœ-˜3—KšœœÑ˜ù—Kšœ˜—Kšœœ˜­Kšœ0˜6—šœŸ˜#Kšœœ¢˜¿—Kšœœœ˜!šœ ˜ Kšœ$˜$Kšœ<˜B—KšœœÒ˜ú—Kšœ˜—Kšœœ˜­Kšœ7˜=K˜—K˜šž œœ1œœ ˜[š œžœœœ:˜JK˜š œ œœœ˜1Kšœ$˜$Kšœœœ˜!Kšœ œ˜KšœœÂ˜ê—Kšœ˜—Kšœ˜K˜—˜J˜—JšœH™HJšœC™CJšœ=™=J™JšœF™FJšœ?™?JšœH™HJ˜šžœœ˜-J˜šœœ˜&šœœœ'˜5Kš˜Kšœ4˜4Kšœœœœ˜Kšœœœ˜!šœœ˜6Kšœ˜šœœ˜%Kšœ˜Kšœ œ˜$Kšœœ9œ˜Lšœœ˜Kšœ˜KšœœH˜[Kšœ˜Kšœœ/˜LKšœ˜Kšœ˜—Kšœ˜—šœœ˜$Kšœ˜Kšœ œ˜$Kšœœ8œ˜Kšœœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—Kšœ˜—Kšœ˜——K˜Kšœœ˜"—˜J˜—J˜JšœH™HJšœ;™;JšœH™HJ˜šžœœœœ ˜IK˜Jšœ"˜(J˜J˜—šžœ'œ˜>Kšœ+œ ˜J˜G—šœ9˜;Jšœ œœ˜9—Jšœ˜—Jšœ˜J˜J˜J˜&—J˜J˜J˜šœ ™ J™Jšœ2œ.˜cJ™J™*Jšœ$Ÿ(™LJ™J™.Jšœ+Ÿ(˜SJ˜Jšœ0Ÿ˜MJšœ-˜-J˜J˜JJ˜˜,Jšœ,˜/˜Jšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Jšœ˜Kšœ˜J˜J˜J˜Kšœ˜J˜J˜K˜—J˜J˜ ——J˜Jšœ˜J˜—…—ëÒ]m