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], CommanderOps USING [ArgumentVector, Parse], Convert USING [IntFromRope, RopeFromChar], IO, 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 [CString, Create]; SGIFiles: CEDAR MONITOR IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, 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.CString; 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.CString; [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.PutFLR["value (%xH) less than segment base (%xH) for symbol %g in %g", LIST[[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: CommanderOps.ArgumentVector ฌ CommanderOps.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 Willie-s, March 2, 1993 4:24 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) สIŒ•NewlineDelimiter –"cedarcode" style™šœ ™ Jšœ ฯeœC™NJšœ!™!Jšœ#™#Jšœ ™ J™.J™#—Icode˜šฯk ˜ Kšœžœ(ž œž œžœžœžœžœ˜gKšœ žœžœ˜Kšœžœ˜%Kšœ žœ ˜Kšœ žœ˜#Kšœ žœ˜+Kšœžœ˜*Kšžœ˜Kšœžœ˜Kšœ žœม˜าKšœžœแ˜๙Kšžœžœ˜'Kšœ žœžœ˜Kšœžœ#˜/Kšœžœžœ˜+Kšœ˜Kšœžœ„˜™Kšœ žœ˜"K˜—K˜K˜šฯnœžœž˜Kšžœ?žœ)žœ*˜žKšžœ˜—Kšž˜K˜KšŸœžœ!žœžœ˜MK˜šœ™Kšžœžœžœ˜Kšžœžœ žœ˜Kšœ žœ˜%Kšžœžœ žœ˜Kšžœžœ žœ˜—K˜šœ*™*Kšœžœ˜Kšœ žœ˜&Kšœ žœ˜&Kšœžœ˜.Kšœ žœ˜$Kšœ žœ˜*Kšœ žœ˜,Kšœ žœ˜,Kšœžœ˜4—˜šœžœ ˜6K˜——šœ1™1K˜Kšœžœžœ ˜Kšœ žœžœ!˜8K˜Kšœžœžœ ˜Kšœ žœžœ!˜8K˜šœ žœ˜*K˜—Kšœ žœ˜+šœ žœ ˜/K˜—Kšœžœ(˜?Kšœžœ˜0K˜Kšœ žœžœ˜(Kšœžœ&˜;K˜Kšœ žœ!˜1Kšœžœ%˜9Kšœ žœ"˜3K˜Jšœ!™!Kšœžœžœ˜.Kšœžœ)˜AJšœ ™ Kšœžœžœ˜.Kšœžœ)˜AK˜Kšœžœžœ ˜šœ žœžœ!˜8K˜—Kšœ žœžœ˜$Kšœžœ$˜7—K˜šœ™K˜Kšœ žœžœ˜*Kšœžœžœ˜0Kšœžœžœ˜8Kšœžœžœ˜0Kšœžœžœ˜8Kšœžœžœ˜:Kšœžœžœ˜6Kšœžœžœ˜:Kšœ žœžœ˜,Kšœžœžœ˜2Kšœžœžœ˜.Kšœžœžœ˜.Kšœžœžœ˜2Kšœžœžœ˜.Kšœžœžœ˜2Kšœžœžœ˜.Kšœžœžœ˜2Kšœžœžœ˜0Kšœžœžœ˜>Kšœ žœžœ˜,Kšœ žœžœ˜,Kšœžœžœ˜:Kšœ žœžœ˜,Kšœ žœžœ˜*J™šœžœž˜$K˜Kšœžœ˜ K˜Kšœž˜ K˜—K˜Kšœ žœ˜-Kšœžœžœžœ˜AK˜Kšœžœžœžœ ˜šœ žœž˜Kšœžœ žœžœ ˜&—Kšœ žœžœ˜"šœžœž˜K˜Kšœ žœ˜Kšœ ž˜K˜—K˜Kšœ žœžœ˜K˜Kš œ žœžœžœ žœžœžœ˜>K˜Kšœžœžœ˜*šœžœž˜Kš œžœ žœžœžœ˜"——K˜JšœH™HJšœH™HJšœ ™ JšœH™HJšœH™H˜KšŸœžœ ฯc"˜<—K˜šœ ™ K˜KšŸ œžœ˜—K˜™J™Kšœ žœ  %˜?KšŸ œžœ "˜:KšŸ œžœ ˜1KšŸ œžœ ˜0KšŸœžœ˜KšŸ œžœ˜šŸ œžœ #˜=Jšœ™—KšŸ œžœ˜K˜KšŸ œžœ žœžœ”˜ตK˜KšŸ œžœ˜KšŸ œžœ˜—J™™ K˜KšŸœžœ ž œž œžœž œžœ žœ˜tJ™KšŸ œžœ˜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˜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šœžœ˜ Kšœžœ˜Kšœžœ˜ Kšœžœ˜Kšœžœ˜ Kšœžœ˜ Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜K˜—Kšœžœžœ˜:š œžœžœž œžœ˜:Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜——K˜JšœH™HJšœH™HJšœ™JšœH™HJšœH™HK˜Kšœžœ˜2K˜KšŸœ*˜CK˜JšœH™HJšœH™HJšœ ™ JšœH™HJšœH™HK˜Kšœ žœžœžœžœžœžœžœžœ˜@K˜šŸœžœžœžœNž œžœžœžœžœž˜คKšœ˜—K˜š ŸœžœžœEž œž˜uKšœ˜Kšœ žœN˜bKšœ˜—K˜š Ÿ œžœžœžœž˜&K˜K˜K˜—K˜JšœH™HJšœH™HJšœH™HJšœH™HJšœH™HK˜šŸœžœžœ žœ˜LKšžœžœžœ˜9Kšœ+žœ$˜WKšœžœ(˜GKšœžœžœ˜Kšœžœ˜Kšœžœ(˜EKšœ žœ-˜>K˜OK˜Kšžœ žœžœ˜(J™K˜Jšœk™kK˜šžœ ž˜K˜Kšžœžœžœ˜/šžœ0ž˜6K˜—šž˜K˜ —Kšžœ˜—K˜Kšžœžœ˜*K˜K˜—K˜šŸœžœ žœ9˜}Kšœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜ K˜šžœžœž˜K˜ K˜K˜šžœžœž˜K˜jKšžœ˜—Kšžœ˜—K˜K˜—K˜š Ÿœžœžœ žœžœ˜0Kšžœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜1K˜Kšœžœ˜#Kšžœ /˜Gšœ žœ˜"Kšœžœžœ˜8—Kšžœ ˜"K˜Kšœ žœ˜&K˜šžœž˜Kšžœ ˜!—K˜J™,šžœžœžœž˜JKšžœžœ˜ —š žœžœžœžœž˜OKšžœžœ˜—šž˜Kšžœ ˜%—K˜K˜—K˜šŸœžœ1žœ žœžœ žœžœžœžœ˜ฤK˜Kšœ žœžœžœ˜ Kšœžœ˜K˜Kšœ žœžœ˜2Kšœ˜Kšœ˜K˜J™'šž˜šžœ"ž˜(Kšžœ˜—K˜.K˜"šžœ"ž˜(Kšžœ˜—K˜.K˜"šžœ"ž˜(Kšžœ˜—K˜.K˜"šžœ"ž˜(Kšžœ˜—K˜.K˜"šžœ"ž˜(Kšžœ˜—K˜.K˜"šžœ"ž˜(Kšžœ˜—K˜.K˜"šžœž˜Kšžœ˜——Kšžœ˜K˜J™šžœžœžœž˜#K˜Kšœžœ˜šžœž˜Kšœ žœ˜šœ ˜ Kšœ˜Kšœ˜Kšžœ˜K˜—Kšœžœ &˜:Kšœ žœ %˜9šœ˜K˜Kšœžœ,˜:Kšœ ˜ Kšœžœ-˜Kšœ#žœ&˜LKšœ žœ˜Kšœžœ˜%Kšœžœ˜Kšœ(žœ˜2Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ ˜Kšœžœ˜Kš œžœžœžœžœžœ ˜6Kš œžœžœžœžœžœ ˜6Kš œ žœžœžœžœžœ˜"Kšœžœ:˜UKšœ žœ˜Kšœ žœ˜K˜K˜Jšœ>™>Kšžœ:˜šœžœ˜Kšœ%˜%K˜ ˜Kšœ œžœ ˜.Kšœ˜—K˜K˜—Kšœžœ˜Kšœžœ˜Kšžœ˜—K˜Kšœ1˜1Kšœžœ>˜V—˜š žœŸœžœžœ.ž˜AKšœžœ žœ˜/K˜K˜Kšžœ˜——˜K˜+Kšœžœ>˜V—˜š žœŸœžœžœ.ž˜AKšœžœ žœ˜/K˜K˜Kšžœ˜——˜Kšœ,˜,Kšœ,˜,—˜Kšžœ˜Kšžœ˜Kšžœ˜K˜—K˜šŸœžœžœžœ žœ&žœžœ žœžœ˜’K˜J™J™Kšœ˜Kšœ žœ˜Kšœ$žœ˜-Kšœ˜Kšœžœ˜Kšœ žœžœ˜Kšœžœ˜Kšœ žœ˜K˜šžœ ž˜K˜Kšœ žœ'˜9Kšœ9˜9K˜—šž˜K˜Kšœ žœ%˜7K˜K˜—Kšœ˜K˜šžœ ž˜Kšœ ˜ šœ˜K˜Kšœ˜Kšžœ˜K˜—Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ ˜ šœ ˜ Kšžœ˜—Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜šœ˜Kšœ˜Kšœ˜Kšžœ˜K˜—Kšžœžœ˜—K˜J™K˜Bšžœž˜Kšœ˜Kšœ˜Kšžœ˜K˜—Kšœ1˜1Kšœžœ˜0K˜šžœž˜Kšžœ˜—K˜J™$šžœžœž˜AK˜Kšœžœ˜Kšœžœ˜Kšœžœ˜KšœI˜Išžœ$ž˜*K˜Kšœ;˜;K˜—šž˜K˜Kšœ*˜*Kšœ˜—KšœE˜Ešžœž˜Kšœ-˜-—Kšœ˜Kšœ6˜6Kšœ'˜'Kšœ2˜2Kšœ˜Kšœ˜—šžœžœžœž˜JK˜J™=Kšœ˜Kšœ˜—šžœžœžœž˜'Kšœ˜—šž˜šžœ-ž˜3Kšœ.˜.——šž˜Kšœ ˜ K˜K˜—J™'šžœ ž˜K˜Kšœl˜lšžœ ž˜Kšœ1˜1—Kšœ˜Kšžœ˜—K˜šžœž˜K˜K˜K˜—K˜K˜—K˜š Ÿœžœ žœžœžœž˜PKšœ˜Kšœžœ˜0Kš œžœžœžœžœ˜\Kšœžœ˜ Kšœžœ-˜@Kšœ žœ*˜:Kšœžœ˜ K˜Kšžœ!˜#šžœžœžœž˜!Kšœ'žœ˜EKš œžœžœžœžœ˜jK˜/šžœž˜K˜Kšœžœ-˜9Kšœ žœ˜(K˜3Kšžœ ˜K˜—Kšžœ˜—K˜Kšžœ ˜K˜—K˜š Ÿœžœ žœžœž˜HK˜K˜Kšœžœ˜1Kšœžœ˜ Kšœžœ˜ K˜Kšœ˜Kšœ$žœ˜)Kšœ,žœ˜1K˜Kšœžœ;˜ZJšœ-™-K˜Kšžœ˜Kšœ žœžœ˜=šžœž˜K˜K˜Kšžœ˜K˜5K˜—šž˜Kšœ˜Kšœž œžœžœ˜4šžœž˜Kšœ˜J™*Kšœ/žœ˜4Kšœ2žœ˜7KšœMžœ˜RKšœ˜—šž˜Kšœ˜Kšœ1žœ˜7K˜—K˜—J™K˜"J™Kšžœ*˜,K˜.Kšœžœ(˜Bšžœžœžœž˜$Kšœ$žœ˜HKšžœ˜—K˜J™Kšžœ-˜/K˜)Kšœžœ%˜>Kšœ žœžœžœžœžœžœžœ˜K˜J™#Kšžœ6˜8K˜.Kšœžœ(˜Bšžœžœžœž˜$Kšœ$žœ˜HKšžœ˜—K˜J™~Kšœ\˜\K˜J™Kšžœ$˜&K˜#Kšœžœ"˜<šžœžœžœž˜Kšœžœ˜AKšžœ˜—K˜J™Kšžœ'˜)K˜)Kšœžœ#˜;šžœžœžœž˜"Kšœ žœ˜BKšžœ˜—K˜Jšœ?™?JšœA™AJšœ4™4Kšžœ'˜)K˜)Kšœžœ#˜;Kš œ žœžœžœžœžœžœ#˜}K˜J™Kšžœ*˜,Kšœžœ5˜RKš œ žœžœžœžœžœžœ'˜†K˜J™Kšžœ-˜/Kšœžœ8˜SKš œ žœžœžœžœžœžœ*˜‡K˜K˜ K˜K˜—K˜š Ÿœžœ žœžœ žœ˜6Kšžœ žœžœ˜!—Kšž˜˜Kšœžœ˜K˜Kšžœ˜šžœžœž˜Kšžœ˜ —šž˜K˜Kšœžœ˜šžœžœž˜Kšžœ˜—Kšœ8žœ˜@Kšžœ˜—K˜J™=J™6Kšœ9žœ˜AK˜Kšž˜—K˜K˜š Ÿœžœžœžœžœ(˜cK˜Kšœ žœ˜Kšœ žœ˜J™šžœ ž˜K˜ K˜šœ˜K˜š žœžœžœžœž˜5K˜ —šž˜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˜š Ÿ œžœžœ žœžœ˜cKšœžœžœ˜"Kšžœ˜—Kšž˜˜Kšœžœ˜ Kšœ žœžœ˜K˜Kšœ žœ)˜:K˜K˜K˜Kšžœž˜˜Kšœžœ'˜AK˜U—K˜Kšž˜˜Kšœžœ%˜?K˜]—K˜K˜J™/K˜Fšœ%žœ˜LKšžœ˜&—˜Kšœžœ˜ Kšœ˜K˜K˜K˜ K˜K˜ K˜K˜K˜K˜—K˜Kšž˜—K˜K˜š Ÿ œžœžœ žœ žœžœ˜dKšœžœžœ˜"Kšžœ˜—˜Kšžœžœžœ˜K˜Kšœžœ ˜K˜MK˜Kšž˜—K˜K˜š Ÿœžœ žœžœžœžœ˜RKšžœž˜K˜Kšœžœ˜ K˜šžœ žœž˜Kšœ žœ˜"—K˜Kšžœ˜Kšœ žœžœžœ˜XK˜Kšžœ ˜K˜—K˜š Ÿœžœ žœžœžœ˜LKšžœž˜!K˜Kšœžœ˜ K˜šžœžœž˜Kšœ žœ˜(—K˜Jšœt™tKšœ žœžœžœ˜^Kšžœ˜K˜—K˜š Ÿœžœ žœžœ#žœ˜UKšžœž˜%—˜Kšœžœ˜ K˜šžœžœž˜Kšœžœ˜-—K˜šœ žœžœ˜?Kšžœ˜#—K˜Kšžœ˜—K˜K˜š Ÿœžœ žœžœžœžœ˜WKšžœž˜!K˜Kšœžœ˜ K˜šžœžœž˜Kšœ žœ˜(—K˜Kšžœ˜šœ žœžœ˜>Kšžœ˜—K˜Kšžœ˜—K˜K˜š Ÿœžœ žœžœ(žœ˜[Kšžœ˜—Kšž˜˜Kšœžœ˜ K˜šžœžœž˜Kšœžœ˜2—K˜šœ žœžœ˜CKšžœ˜$—K˜Kšžœ˜—K˜K˜š Ÿœžœ žœžœ(žœ˜[Kšžœ˜—Kšž˜˜Kšœžœ˜ K˜šžœžœž˜Kšœžœ˜2—K˜šœ žœžœ˜CKšžœ˜$—K˜Kšžœ˜—K˜K˜š Ÿœžœ žœžœžœ˜FKšžœ˜—Kšž˜˜Kšœžœ˜ K˜šžœ žœž˜Kšœ žœ˜$—K˜šœ žœžœ˜K˜@K˜>K˜BK˜>K˜>K˜>K˜HK˜HKšžœ˜—Kšžœ3˜5šžœžœžœž˜!šžœžœž˜šœ$žœ,˜Sšžœžœ(žœ˜4šžœ žœžœžœ˜ K˜7K˜K˜—šž˜K˜>—Kšœ˜—šžœ˜šžœ žœžœžœ˜ K˜8K˜K˜—šž˜K˜@—Kšœ˜—K˜—šœ"žœ,˜Qšžœ žœžœžœ˜K˜(K˜ K˜6K˜—Kšœ˜—šœ žœ$˜Fšžœ!ž˜'K˜;—šžœžœ!ž˜,K˜<—Kšœ˜—šœ)˜)K™!K˜BK˜9Kšœ˜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˜OK˜Kšœ žœ˜Kšœ˜Kšœ žœžœ˜Kšœžœ˜ J™J™Kšžœ˜Kšœ žœžœ˜=šžœžœ˜Kšžœ˜Kšžœ˜K˜—Kšœž œžœžœ˜4šžœž˜Kšžœ˜—K˜Kšœ$žœ˜)Kšœ'žœ˜,Kšœ žœ˜(K˜K˜K˜Kšœžœ!˜3K˜Jšœ ™ šžœžœžœž˜Jšœ™Kšœ#žœ˜?Kšžœ˜—K˜Jšœ7™7šžœžœžœž˜šžœžœžœž˜šžœž˜%Kšžœ˜—Kšœžœ˜"K˜4Kšžœ˜—šžœ"žœž˜.K˜K˜>K˜[K˜—šžœžœ"žœž˜3K˜K˜>K˜YKšœ˜—šžœžœ!žœž˜2K˜K˜=˜K˜——Kšžœ˜Kšœžœ˜Kšžœ˜—K˜K˜;K˜J™Jšœ%™%šœ žœ ˜˜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šœH™HJšœ<™™>Jšœ'™'JšœC™CJšœ5™5JšœH™HK˜šŸœžœ'žœ žœ*žœ œžœ œžœžœ œ ˜๒Kšœ˜Kšœžœžœžœ˜)Kšœžœžœžœ˜,Kšœžœ ˜Kšœžœ˜!šž˜Kšœ žœ˜Kšœ˜K˜bšžœ"žœ˜*Kšžœžœžœžœ˜TKšžœ-˜3—K˜Bšžœž˜#˜Kšœ˜Kšœ žœ˜Kšœžœžœ ˜)Kšœ˜Kšœ žœžœ ˜!K˜šœ žœ˜Kšœ˜Kšœ ˜ Kšœ˜K˜Kšœ˜Kšœ žœžœ8žœ˜zK˜Kšœ˜Kšœ%˜%—Kšœžœ ˜Kšžœžœžœžœ%˜aK˜Kšœžœ˜K˜Kšœ˜—šœ#˜#Kšžœžœžœžœ˜TKšžœ-˜3—Kšžœžœ ˜!—Kšž˜Kšœ˜—K˜—šŸ#œžœ˜:Kšœžœ˜K˜Kšœ žœ1˜DKšœ0žœ 0˜fšžœžœ ž˜Kšœ˜K˜3Kš œžœžœžœžœ˜3Kšœžœžœžœ ˜JKšœžœ˜Kšœžœžœ˜K™šœ)žœ˜>Kšœ˜Kšœ˜Kšœ˜K˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ žœ˜ Kšœžœ˜—K˜Kšœœœzœว™๔K™™"K™K™&K™/K™—K™ษK˜šžœž˜K˜4šŸœžœ˜Kšœ žœ˜K˜ชKšžœžœ?˜K˜0Kšžœ˜ Kšžœ7˜;Kšžœ˜—Kšžœ˜—Kšžœžœžœžœ˜šžœž˜šœ ˜ Kšœ žœžœžœ˜$Kšœ žœ!˜0Kš œ žœžœžœžœ˜)Kš žœ žœžœžœžœ˜7Kšžœžœžœžœ˜RK˜Kšžœžœžœžœ˜RK˜—šœ˜Kšœ žœžœžœ˜$Kšœ žœ!˜0Kšœ žœžœ ˜+š žœ žœžœžœžœ žœž˜Mšžœ ž˜&Kšœ žœžœ˜—Kšžœ˜—šžœ žœ˜Kšžœžœžœžœ˜RK˜—šœžœ 3˜9Kšœ žœ˜—Kšœ˜—šœžœžœ˜$K˜;Kšœžœ˜—Kšœžœ˜Kšœžœ˜šœ˜Kšžœžœ<˜HK˜šžœ<˜>Kšœ3˜3Kšœ+˜+—Kšœ˜——K˜ Kšž˜šžœ˜ KšžœžœC˜OK˜@Kšœ˜—Kšžœ˜—K˜˜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˜—˜K˜—JšœH™HJšœC™CJšœ=™=J™JšœF™FJšœ?™?JšœH™HK˜šŸœžœ˜-K˜šžœžœž˜&šžœžœžœ'˜5Kšž˜K˜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šœžœ˜"—˜K˜—K˜JšœH™HJšœ;™;JšœH™HK˜šŸœžœžœžœ ˜IK˜Kšžœ"˜(K˜K˜—šŸœ'žœ˜>Kšœ+žœ ˜K˜G—šžœ9˜;Kšžœ žœžœ˜9—Kšžœ˜—Kšžœ˜K˜K˜K˜&—K˜K˜K˜šœ ™ J™Kšœ2žœ.˜cJ™J™*Jšœ$ (™LJ™J™.Kšœ+ (˜SK˜Kšœ0 ˜MK˜-K˜K˜JK˜˜,Kšžœ,˜/˜Kšœ˜Kšžœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšžœ˜Kšžœ˜K˜K˜K˜Kšžœ˜K˜K˜K˜—K˜K˜ ——K˜Kšžœ˜K˜—…—๋v[ภ