DIRECTORY Basics USING [BITAND, BITLSHIFT, BITSHIFT, Card16FromH, Card32FromF, Comparison, FWORD, HWORD, Int32FromF], BasicTime USING [GMT, Now], CCTypes USING[CCError, CCErrorCase], CirioTypes USING [zeroBA], Commander USING [Register, CommandProc], CommanderOps USING [ArgumentVector, Parse], Convert USING [IntFromRope], IO, List USING [Sort], ObjectFiles USING[BracketPairKind, CNameOfStab, CreateParsed, DescribeModule, FileSegmentPC, GlobalVarLoc, MakeUnknownVarLoc, ReadInstruction, RopeForStabType, SimpleSeg, Stab, StabBody, StabType, UnreadableObjectFile, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo], ObjectFilesPrivate USING[AlterFunStabType, BracketConsumer, BracketPair, BracketPairBody, CheckStaticVar, FnConsumer, FunStabSetBody, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, RegisterObjectFileFlavor, SLineData, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType], PFS USING [PathFromRope, RopeFromPath, StreamFromOpenFile, OpenFileFromStream], PFSNames USING [PATH], Random USING[ChooseInt, Create, RandomStream], RMTWBackdoor USING [GetDotO], Rope, SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, ReleaseStreamForFile, ShowReport]; SunELFFiles: CEDAR MONITOR IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, RMTWBackdoor, Rope, SystemInterface EXPORTS ObjectFiles = BEGIN CCError: ERROR[case: CCTypes.CCErrorCase, msg: ROPE _ NIL] _ CCTypes.CCError; ROPE: TYPE ~ Rope.ROPE; PATH: TYPE ~ PFSNames.PATH; Stab: TYPE = ObjectFiles.Stab; StabList: TYPE = ObjectFilesPrivate.StabList; StabBody: TYPE = ObjectFiles.StabBody; StabType: TYPE = ObjectFiles.StabType; StabRange: TYPE = ObjectFilesPrivate.StabRange; FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC; VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo; LBrac: BYTE = 0c0H; RBrac: BYTE = 0e0H; SLine: BYTE = 044H; Fun: BYTE = 024H; PSym: BYTE = 0a0H; LSym: BYTE = 080H; RSym: BYTE = 040H; STSym: BYTE = 026H; LCSym: BYTE = 028H; GSym: BYTE = 020H; Main: BYTE = 02aH; SO: BYTE = 064H; BIncl: BYTE = 082H; EIncl: BYTE = 0a2H; Excl: BYTE = 0c2H; SOL: BYTE = 084H; Parsed: TYPE = REF ParsedBody; ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody; Module: TYPE = REF ModuleBody; ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody; Header: TYPE = REF HeaderBody; HeaderBody: TYPE = ObjectFilesPrivate.HeaderBody; MemorySegmentInfo: TYPE ~ ObjectFilesPrivate.MemorySegmentInfo; StabSet: TYPE = ObjectFilesPrivate.StabSet; BracketPair: TYPE ~ ObjectFilesPrivate.BracketPair; BracketPairBody: TYPE ~ ObjectFilesPrivate.BracketPairBody; unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize; 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; SHFWrite: CARD = 1; SHFAlloc: CARD = 2; SHFExecInstr: CARD = 4; STBLocal: CARD = 0; STBGlobal: CARD = 1; STBWeak: CARD = 2; STTNoType: CARD = 0; STTObject: CARD = 1; STTFunc: CARD = 2; STTSection: CARD = 3; STTFile: CARD = 4; RSparcNone: CARD = 0; RSparc8: CARD = 1; RSparc16: CARD = 2; RSparc32: CARD = 3; RSparcDisk8: CARD = 4; RSparcDisk16: CARD = 5; RSparcDisk32: CARD = 6; RSparcWDisp30: CARD = 7; RSparcWDisp22: CARD = 8; RSparcHi22: CARD = 9; RSparc22: CARD = 10; RSparc13: CARD = 11; RSparcLo10: CARD = 12; RSparcGot10: CARD = 13; RSparcGot13: CARD = 14; RSparcGot22: CARD = 15; RSparcPc10: CARD = 16; RSparcPc22: CARD = 17; RSparcWPlt30: CARD = 18; RSparcCopy: CARD = 19; RSparcGlobDat: CARD = 20; RSparcJmpSlot: CARD = 21; RSparcRelative: CARD = 22; RSparcUa32: CARD = 23; WireHeader: TYPE = REF WireHeaderBody; WireHeaderBody: 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]; WireSectionHeader: TYPE = REF WireSectionHeaderBody; WireSectionHeaderBody: 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]; WireStabEntry: TYPE = REF WireStabEntryBody; WireStabEntryBody: TYPE = MACHINE DEPENDENT RECORD[ stringX(0: 0..31): Basics.FWORD, type(0: 32..39): BYTE, other(0: 40..47): BYTE, desc(0: 48..63): Basics.HWORD, value(0: 64..95): Basics.FWORD]; WireSymtabEntry: TYPE = REF WireSymtabEntryBody; WireSymtabEntryBody: TYPE = MACHINE DEPENDENT RECORD[ name(0: 0..31): Basics.FWORD, value(0: 32..63): Basics.FWORD, size(0: 64..95): Basics.FWORD, bind(0: 96..99): [0..15], type(0: 100..103): [0..15], other(0: 104..111): BYTE, sectionIndex(0: 112..127): Basics.HWORD]; SymtabRange: TYPE = RECORD[first, count: CARD]; SymtabBind: TYPE ~ { Local, Global, Weak }; SymtabType: TYPE ~ { NoType, Object, Func, Section, File }; WireRelocEntry: TYPE = REF WireRelocEntryBody; WireRelocEntryBody: TYPE = MACHINE DEPENDENT RECORD[ offset(0: 0..31): Basics.FWORD, sym(0: 32..55): [0..16777215], type(0: 56..63): BYTE, addend(0: 64..95): Basics.FWORD]; BitsOn: PROC [flags: CARD, mask: CARD] RETURNS [on: BOOL] ~ INLINE { RETURN [Basics.BITAND[flags, mask] # 0] }; IsDataSection: PROC [section: SectionHeader] RETURNS [BOOL] ~ INLINE { RETURN [(section.type = SHTProgBits OR section.type = SHTNoBits) AND BitsOn[section.flags, SHFAlloc] AND NOT BitsOn[section.flags, SHFExecInstr]] }; ReadHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED { wHeader: WireHeader _ NEW[WireHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[WireHeaderBody]]]; magic: CARD _ Basics.Card32FromF[wHeader.magic]; 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 # EMSparc); nPageSize: CARD _ 1000H; textSeg: MemorySegmentInfo _ [0, 0]; iDataSeg: MemorySegmentInfo _ [0, 0]; bssSeg: MemorySegmentInfo _ [0, 0]; symtabSeg: MemorySegmentInfo _ [0, 0]; symtabStrSeg: MemorySegmentInfo _ [0, 0]; symsSeg: MemorySegmentInfo _ [0, 0]; symsStrSeg: MemorySegmentInfo _ [0, 0]; textRelocSeg: MemorySegmentInfo _ [0, 0]; dataRelocSeg: MemorySegmentInfo _ [0, 0]; symsRelocSeg: MemorySegmentInfo _ [0, 0]; textLoadOffset: 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]; maxSymsSize: CARD _ 0; header: Header; IO.SetIndex[stream, sectHdrOffset]; FOR i: CARD IN [0..sectHdrNum) DO wSectionHeader: WireSectionHeader _ NEW[WireSectionHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[WireSectionHeaderBody]]]; 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; FOR i: CARD IN [0..sectHdrNum) DO IO.SetIndex[stream, sectionList[sectStrTblX].offset+sectionList[i].nameIndex]; sectionList[i].name _ ReadRope[stream]; 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; IF objType = ETRelocatable THEN sectionList[i].addr _ sectionList[i].offset - textSeg.byteOffset; } ELSE { IF dataIndex = LAST[CARD] THEN { iDataSeg _ [sectionList[i].offset, sectionList[i].size]; dataIndex _ i; } ELSE iDataSeg.byteLength _ iDataSeg.byteLength + sectionList[i].size; IF objType = ETRelocatable THEN sectionList[i].addr _ sectionList[i].offset - iDataSeg.byteOffset; }; }; (sectionList[i].type = SHTNoBits) AND BitsOn[sectionList[i].flags, SHFWrite] => { IF bssIndex = LAST[CARD] THEN { bssSeg _ [sectionList[i].offset, sectionList[i].size]; bssIndex _ i; } ELSE bssSeg.byteLength _ bssSeg.byteLength + sectionList[i].size; IF objType = ETRelocatable THEN sectionList[i].addr _ sectionList[i].offset - bssSeg.byteOffset; }; (sectionList[i].type = SHTSymTab) => { IF symtabIndex = LAST[CARD] THEN { symtabSeg _ [sectionList[i].offset, sectionList[i].size]; symtabIndex _ i; IF sectionList[i].entrySize # BYTES[WireSymtabEntryBody] THEN ERROR; symtabStrSeg _ [sectionList[sectionList[i].link].offset, sectionList[sectionList[i].link].size]; }; }; (sectionList[i].type = SHTProgBits) AND sectionList[i].flags = 0 => { IF sectionList[i].entrySize = BYTES[WireStabEntryBody] THEN { IF maxSymsSize < sectionList[i].size THEN { symsSeg _ [sectionList[i].offset, sectionList[i].size]; symsIndex _ i; maxSymsSize _ 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] ELSE IF sectionList[i].info = symsIndex THEN symsRelocSeg _ [sectionList[i].offset, sectionList[i].size]; }; ENDCASE; ENDLOOP; IF symsIndex # 0 THEN { symsStrName: ROPE _ Rope.Concat[sectionList[symsIndex].name, "str"]; symsRelocName: ROPE _ Rope.Concat[".rela", sectionList[symsIndex].name]; FOR i: CARD IN [0..sectHdrNum) DO IF Rope.Equal[symsStrName, sectionList[i].name] THEN symsStrSeg _ [sectionList[i].offset, sectionList[i].size]; IF Rope.Equal[symsRelocName, sectionList[i].name] THEN symsRelocSeg _ [sectionList[i].offset, sectionList[i].size]; ENDLOOP; }; header _ NEW[HeaderBody _ [ dynamic: objType = ETDynamicLib, toolversion: BYTE[0] -- wHeader.version --, machtype: machine, magic: 0 -- wHeader.magic --, text: textSeg, iData: iDataSeg, textReloc: textRelocSeg, dataReloc: dataRelocSeg, symsReloc: symsRelocSeg, syms: symsSeg, extSyms: symtabSeg, textLoadOffset: textLoadOffset, bssSize: bssSeg.byteLength, entryPoint: Basics.Card32FromF[wHeader.entry], nPageSize: nPageSize, nEntries: symsSeg.byteLength/BYTES[WireStabEntryBody], nExtEntries: symtabSeg.byteLength/BYTES[WireSymtabEntryBody], stringOffset: symsStrSeg.byteOffset, stringIndexLimit: symsStrSeg.byteLength, extStringOffset: symtabStrSeg.byteOffset, extStringIndexLimit: symtabStrSeg.byteLength, clientData: sectionList ]]; RETURN[header]; }; SunELFModuleFromParsedAndPC: ObjectFilesPrivate.ModuleFromParsedAndPCProcType ~ { IF whole = NIL THEN RETURN [NIL] ELSE { symtabRange: SymtabRange; minFuncX: CARD; minPC: CARD; dataReloc: CARD; [symtabRange, minFuncX, minPC, dataReloc] _ AlternativeFindModuleSymtabRange[whole, spc.relPC]; IF symtabRange = [0, 0] THEN RETURN [NIL]; IF symtabRange = [1, whole.header.nExtEntries-1] THEN { RETURN [ModuleFromParsedInner[whole]]; }; { moduleWhole: Parsed _ NIL; sourceRope: Rope.ROPE _ NIL; funcRope: Rope.ROPE _ NIL; dotOPathRope, dotORope: Rope.ROPE _ NIL; dotOId: CARD _ 0; lag: LIST OF Module _ NIL; newModule: Module _ NIL; cell: LIST OF Module _ NIL; sourceRope _ ReadSymtabRope[whole, symtabRange.first]; FOR modules: LIST OF Module _ whole.modules, modules.rest WHILE modules # NIL DO IF minPC < modules.first.firstPC THEN EXIT; -- we should have found it by now IF Rope.Equal[PFS.RopeFromPath[modules.first.fileName], sourceRope] THEN { -- we already have it RETURN[modules.first] }; lag _ modules; ENDLOOP; IF whole.targetData = NIL THEN RETURN [NIL]; funcRope _ ReadSymtabRope[whole, minFuncX]; [dotOPathRope, dotORope, dotOId] _ GetFileNameAndID[whole, sourceRope]; IF dotOId = 0 THEN RETURN [NIL]; moduleWhole _ RMTWBackdoor.GetDotO[whole.targetData, dotOPathRope, dotORope, dotOId, GetDotOId]; newModule _ ModuleFromParsedInner[moduleWhole, funcRope, minPC, dataReloc]; IF newModule = NIL THEN RETURN [NIL]; cell _ LIST[newModule]; IF lag # NIL THEN lag.rest _ cell ELSE whole.modules _ cell; newModule.whole _ whole; newModule.moduleWhole _ moduleWhole; RETURN [newModule]; }; }; }; ModuleFromParsedInner: PROC[whole: Parsed, funcRope: Rope.ROPE _ NIL, funcPC, dataReloc: CARD _ 0] RETURNS[Module] = { IF whole = NIL THEN RETURN [NIL] ELSE { stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; IF whole = NIL THEN RETURN [NIL] ELSE { ENABLE UNWIND => { SystemInterface.ReleaseStreamForFile[whole.file, stream]; }; stabRange: StabRange _ [0, whole.header.nEntries]; firstPC: CARD _ 0; lag: LIST OF Module _ NIL; FOR modules: LIST OF Module _ whole.modules, modules.rest WHILE modules # NIL DO IF modules.first.firstPC = firstPC THEN { -- we already have it SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[modules.first] }; IF firstPC < modules.first.firstPC THEN { -- we should have found it by now newModule: Module _ CreateModule[whole, stream, stabRange]; cell: LIST OF Module _ LIST[newModule]; cell.rest _ modules; IF lag # NIL THEN lag.rest _ cell ELSE whole.modules _ cell; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[newModule]; }; lag _ modules; ENDLOOP; { newModule: Module _ CreateModule[whole, stream, stabRange, funcRope, funcPC, dataReloc]; cell: LIST OF Module _ LIST[newModule]; IF lag # NIL THEN lag.rest _ cell ELSE whole.modules _ cell; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[newModule]; }; }; }; }; GetFileNameAndID: PROC [whole: Parsed, sourceRope: Rope.ROPE] RETURNS [dotOPathRope, dotORope: Rope.ROPE _ NIL, dotOId: CARD _ 0] = { stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; { ENABLE UNWIND => { SystemInterface.ReleaseStreamForFile[whole.file, stream]; }; nStabs: CARD _ whole.header.nEntries; stabX, nextStabX: CARD _ 0; strIndex, nextStrIndex: CARD _ whole.header.stringOffset; source: Rope.ROPE _ NIL; dotOPath, dotO: Rope.ROPE _ NIL; ropeStream: IO.STREAM _ PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]]; WHILE stabX < nStabs DO IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireStabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]}; SELECT wireStabBuffer.type FROM 00H => { stabX _ stabX + 1; nextStabX _ stabX + Basics.Card16FromH[wireStabBuffer.desc]; strIndex _ nextStrIndex; nextStrIndex _ nextStrIndex + Basics.Card32FromF[wireStabBuffer.value]; IO.SetIndex[ropeStream, strIndex+Basics.Card32FromF[wireStabBuffer.stringX]]; source _ ReadRope[ropeStream]; dotOPath _ NIL; }; 38H => { stabX _ stabX + 1; IO.SetIndex[ropeStream, strIndex+Basics.Card32FromF[wireStabBuffer.stringX]]; dotO _ ReadRope[ropeStream]; dotOPath _ Rope.Concat[dotOPath, dotO]; }; 3cH => { stabX _ nextStabX; IF Rope.Equal[source, sourceRope] THEN RETURN [dotOPathRope: dotOPath, dotORope: dotO, dotOId: Basics.Card32FromF[wireStabBuffer.value]]; }; ENDCASE => stabX _ stabX + 1; ENDLOOP; }; }; GetDotOId: PROC [whole: Parsed] RETURNS [dotOId: CARD _ 0] = { stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; { ENABLE UNWIND => { SystemInterface.ReleaseStreamForFile[whole.file, stream]; }; nStabs: CARD _ whole.header.nEntries; stabX, nextStabX: CARD _ 0; WHILE stabX < nStabs DO IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireStabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]}; SELECT wireStabBuffer.type FROM 00H => { stabX _ stabX + 1; nextStabX _ stabX + Basics.Card16FromH[wireStabBuffer.desc]; }; 3cH => { stabX _ nextStabX; RETURN [Basics.Card32FromF[wireStabBuffer.value]]; }; ENDCASE => stabX _ stabX + 1; ENDLOOP; }; }; LineNumList: TYPE = REF LineNumListBody; LineNumListBody: TYPE = RECORD [nLines: CARD, lines: LIST OF REF ANY _ NIL]; CreateModule: PROC[whole: Parsed, stream: IO.STREAM, stabRange: StabRange _ [0, 0], funcRope: Rope.ROPE _ NIL, funcPC, dataReloc: CARD _ 0] RETURNS[Module] = BEGIN module: Module _ NEW[ModuleBody]; lineNums: LineNumList _ NEW [LineNumListBody _ [0, NIL]]; lineNums2: LineNumList _ NEW [LineNumListBody _ [0, NIL]]; nStabs: CARD _ stabRange.count; module.whole _ whole; module.firstStabX _ stabRange.first; module.limitStabX _ stabRange.first+stabRange.count; module.firstPC _ 0; module.limitPC _ whole.header.text.byteLength; module.dataReloc _ dataReloc; module.stabs _ NEW[StabSet[nStabs]]; {I: CARD _ 0; WHILE I 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, "SunELF"]; IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed], IO.time[start]]; FOR I: INT IN [0..100) DO pc: CARD _ Random.ChooseInt[rs, 0, whole.header.text.byteLength]; range: SymtabRange _ AlternativeFindModuleSymtabRange[whole, pc].symtabRange; 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]; }; SymtabBody: TYPE ~ RECORD[symtabX: CARD, value: CARD, size: CARD, symtabBind: SymtabBind, symtabType: SymtabType, symtabSection: CARD]; nullSymtabBody: SymtabBody ~ [0, 0, 0, Local, NoType, 0]; AlternativeFindModuleSymtabRange: PROC[whole: Parsed, relativePC: CARD] RETURNS[symtabRange: SymtabRange _ [0, 0], minFuncX, minPC: CARD _ 0, dataReloc: CARD _ 0] = { baseFile: SymtabBody _ nullSymtabBody; maxPC: CARD _ 0; highSymtabX: CARD _ 0; foundDataReloc: BOOLEAN _ FALSE; FindModuleSymtabRange: PROC [nominalX: CARD] RETURNS [failed: BOOL] = { IF nominalX >= whole.header.nExtEntries THEN RETURN[failed: TRUE]; baseFile _ nullSymtabBody; maxPC _ 0; highSymtabX _ 0; foundDataReloc _ FALSE; minPC _ LAST[CARD]; FOR x: CARD DECREASING IN [0..nominalX] DO info: SymtabBody _ ReadSymtabBody[whole, x]; SELECT info.symtabType FROM Func => IF info.symtabSection # 0 THEN { maxPC _ MAX[maxPC, info.value + info.size]; IF info.symtabBind = Local AND info.value < minPC THEN { minFuncX _ x; minPC _ info.value}}; File => {baseFile _ info; EXIT}; NoType => {dataReloc _ info.value; foundDataReloc _ TRUE}; ENDCASE; highSymtabX _ MAX[highSymtabX, info.symtabX]; ENDLOOP; IF baseFile.symtabType # File THEN { RETURN[failed: TRUE]}; FOR x: CARD IN (nominalX..whole.header.nExtEntries) DO info: SymtabBody _ ReadSymtabBody[whole, x]; SELECT info.symtabType FROM Func => IF info.symtabSection # 0 THEN { maxPC _ MAX[maxPC, info.value + info.size]; IF info.symtabBind = Local AND info.value < minPC THEN { minFuncX _ x; minPC _ info.value}}; File => EXIT; NoType => IF NOT foundDataReloc THEN { dataReloc _ info.value; foundDataReloc _ TRUE}; ENDCASE; highSymtabX _ MAX[highSymtabX, info.symtabX]; ENDLOOP; RETURN[failed: FALSE]; }; IF whole = NIL THEN RETURN[[0, 0], 0, 0, 0] ELSE { nominalX: CARD _ SearchForPCSymtab[whole, relativePC]; DO IF FindModuleSymtabRange[nominalX].failed THEN RETURN[[0, 0], 0, 0, 0]; IF minPC <= relativePC AND relativePC < maxPC THEN { RETURN[[baseFile.symtabX, highSymtabX-baseFile.symtabX+1], minFuncX, minPC, dataReloc]}; IF minPC > relativePC THEN EXIT; nominalX _ highSymtabX + 1; ENDLOOP; RETURN[[0, 0], 0, 0, 0]; }; }; SearchForPCSymtab: PROC[whole: Parsed, pc: CARD] RETURNS[CARD] = BEGIN x: CARD _ 0; y: CARD _ whole.header.nExtEntries; WHILE x+1 < y DO mid: CARD _ (x+y)/2; midSymtab: SymtabBody _ SearchFwdForPCSymtab[whole, mid, y]; SELECT TRUE FROM midSymtab.symtabX = y => y _ mid; pc < midSymtab.value => y _ mid; midSymtab.value = pc => RETURN[midSymtab.symtabX]; midSymtab.value < pc => x _ mid; ENDCASE => ERROR; ENDLOOP; RETURN[x]; END; SearchFwdForPCSymtab: PROC[whole: Parsed, start: CARD, limit: CARD] RETURNS[SymtabBody] = BEGIN FOR x: CARD _ start, x+1 WHILE x < limit DO info: SymtabBody _ ReadSymtabBody[whole, x]; IF info.symtabType = Func AND info.symtabBind = Local THEN RETURN[info]; IF info.symtabBind = Global THEN EXIT; ENDLOOP; RETURN[[limit, 0, 0, Local, NoType, 0]]; END; SymtabBindFromData: PROC [data: [0..15]] RETURNS [symtabType: SymtabBind] ~ { val: CARD _ data; symtabType _ SELECT val FROM STBLocal => Local, STBGlobal => Global, STBWeak => Weak, ENDCASE => ERROR; }; SymtabTypeFromData: PROC [data: [0..15]] RETURNS [symtabType: SymtabType] ~ { val: CARD _ data; symtabType _ SELECT val FROM STTNoType => NoType, STTObject => Object, STTFunc => Func, STTSection => Section, STTFile => File, ENDCASE => ERROR; }; ReadSymtabBody: ENTRY PROC[whole: Parsed, symtabX: CARD] RETURNS[SymtabBody] = BEGIN ENABLE UNWIND => NULL; stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; IO.SetIndex[stream, whole.header.extSyms.byteOffset+symtabX*BYTES[WireSymtabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireSymtabBuffer^], 0, BYTES[WireSymtabEntryBody]]]}; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[[symtabX, Basics.Card32FromF[wireSymtabBuffer.value], Basics.Card32FromF[wireSymtabBuffer.size], SymtabBindFromData[wireSymtabBuffer.bind], SymtabTypeFromData[wireSymtabBuffer.type], Basics.Card16FromH[wireSymtabBuffer.sectionIndex]]]; END; ReadSymtabRope: ENTRY PROC[whole: Parsed, symtabX: CARD] RETURNS[rope: Rope.ROPE _ NIL] = BEGIN ENABLE UNWIND => NULL; stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; IO.SetIndex[stream, whole.header.extSyms.byteOffset+symtabX*BYTES[WireSymtabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireSymtabBuffer^], 0, BYTES[WireSymtabEntryBody]]]}; IO.SetIndex[stream, whole.header.extStringOffset+Basics.Card32FromF[wireSymtabBuffer.name]]; rope _ ReadRope[stream]; SystemInterface.ReleaseStreamForFile[whole.file, stream]; END; SunELFVarLocFromStab: ObjectFilesPrivate.VarLocFromStabProcType ~ { header: Header ~ stab.module.whole.header; MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ { segRope: ROPE; segBase: CARD ~ SELECT kind FROM text => 0, data => header.text.byteLength, bss => header.text.byteLength + header.iData.byteLength, ENDCASE => ERROR; segSize: CARD ~ SELECT kind FROM text => header.text.byteLength, data => header.iData.byteLength, bss => header.bssSize, ENDCASE => ERROR; IF stab.value >= segSize THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["value (%xH) greater than segment size (%xH) for symbol %g in %g", [cardinal[stab.value]], [cardinal[segSize]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]] ]]; SELECT kind FROM text => segRope _ "text"; data => segRope _ "data"; bss => segRope _ "bss"; ENDCASE => ERROR; RETURN [NEW [ObjectFiles.VarLocBody _ [ bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize, where: fSegment[ [0, segRope], stab.value*8, stab.value + segBase + header.text.byteOffset - header.textLoadOffset] ]]]}; 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[Rope.Concat["_", 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]]] ]]; }; SunELFInstallStaticVars: ObjectFilesPrivate.InstallStaticVarsType ~ { 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 _ 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; }; PCtoLineNumMap: TYPE = REF PCtoLineNumMapBody; PCtoLineNumMapBody: TYPE = ObjectFilesPrivate.PCtoLineNumMapBody; LineNumToPCMap: TYPE = REF LineNumToPCMapBody; LineNumToPCMapBody: TYPE = ObjectFilesPrivate.LineNumToPCMapBody; SLineData: TYPE = ObjectFilesPrivate.SLineData; InstallPCLineNumMaps: PROC[module: Module, lineNums, lineNums2: LineNumList] = { CompareByCLineNum: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = { 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] = { 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]; }; sortedList: LIST OF REF ANY _ NIL; IF module.pcToLineNum # NIL OR module.lineNumToPC # NIL THEN { IF module.pcToLineNum = NIL OR module.lineNumToPC = NIL THEN ERROR; RETURN; }; sortedList _ List.Sort[lineNums.lines, CompareByCLineNum]; module.lineNumToPC _ NEW[LineNumToPCMapBody[lineNums.nLines]]; FOR I: INTEGER IN [0..lineNums.nLines) DO info: REF SLineData _ NARROW[sortedList.first]; module.lineNumToPC[I] _ info^; sortedList _ sortedList.rest; ENDLOOP; sortedList _ List.Sort[lineNums2.lines, CompareByPC]; module.pcToLineNum _ NEW[PCtoLineNumMapBody[lineNums2.nLines]]; FOR I: INTEGER IN [0..lineNums2.nLines) DO info: REF SLineData _ NARROW[sortedList.first]; module.pcToLineNum[I] _ info^; sortedList _ sortedList.rest; ENDLOOP; }; TypeFromData: PROC [data: BYTE] RETURNS [stabType: ObjectFiles.StabType] ~ { val: CARD _ data; stabType _ SELECT val FROM LBrac => LBrac, RBrac => RBrac, SLine => SLine, Fun => Fun, PSym => PSym, LSym => LSym, RSym => RSym, STSym => STSym, LCSym => LCSym, GSym => GSym, Main => Main, SO => SO, BIncl => BIncl, EIncl => EIncl, Excl => Excl, SOL => SOL, ENDCASE => Unspecified }; BasicReadStab: ENTRY PROC[whole: Parsed, stream: IO.STREAM, stabX: CARD] RETURNS[stab: Stab, numStabsRead: CARD] ~ { ENABLE UNWIND => NULL; stab _ NEW [StabBody]; [stab^, numStabsRead] _ ReadStabBody[whole, stream, stabX]; RETURN }; previousStream: IO.STREAM _ NIL; cloneStream: IO.STREAM _ NIL; ReadStabBody: PROC [whole: Parsed, stream: IO.STREAM, stabX: CARD] RETURNS [stab: StabBody, numStabsRead: CARD] ~ { rope: ROPE _ "\\"; size, rLen, offset: CARD16 _ 0; value: CARD32; stabType: ObjectFiles.StabType; IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireStabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]}; stabType _ TypeFromData[wireStabBuffer.type]; size _ Basics.Card16FromH[wireStabBuffer.desc]; value _ Basics.Card32FromF[wireStabBuffer.value]; IF stream#previousStream THEN { cloneStream _ PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]]; previousStream _ stream; }; rope _ ReadStringX[cloneStream, whole, Basics.Card32FromF[wireStabBuffer.stringX]]; rLen _ rope.Length[]; numStabsRead _ 1; IF ~rope.IsEmpty[] THEN WHILE rope.Fetch[rLen-1] = '\\ DO offset _ offset + 1; IO.SetIndex[stream, whole.header.syms.byteOffset+(stabX + offset)*BYTES[WireStabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]}; rope _ rope.Substr[len:rLen-1].Concat[ReadStringX[cloneStream, whole, Basics.Card32FromF[wireStabBuffer.stringX]]]; rLen _ rope.Length[]; numStabsRead _ numStabsRead + 1; ENDLOOP; stab _ [ module: NIL, stabX: stabX, stabType: stabType, size: size, value: value, rope: rope ]; RETURN}; RelocateStabAndLineNum: PROC [whole: Parsed, stream: IO.STREAM, module: Module, nStabs: CARD, funcRope: Rope.ROPE _ NIL, funcPC, dataReloc: CARD _ 0, lineNum, lineNum2: LineNumList] ~ { sectionList: SectionList _ NARROW[whole.header.clientData]; nRelocEntries: INT _ whole.header.symsReloc.byteLength / BYTES[WireRelocEntryBody]; symtabStream: IO.STREAM _ PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]]; previousSymtabX: CARD _ LAST[CARD]; symtabX: CARD; sectionIndex: CARD; baseValue: CARD; value: CARD; stabX: CARD; stabRope: Rope.ROPE _ Rope.Concat[funcRope, ":f("]; -- local function FOR I: CARD IN [0..nRelocEntries) DO IO.SetIndex[stream, whole.header.symsReloc.byteOffset+I*BYTES[WireRelocEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireRelocBuffer^], 0, BYTES[WireRelocEntryBody]]]}; symtabX _ wireRelocBuffer.sym; IF symtabX # previousSymtabX THEN { IO.SetIndex[symtabStream, whole.header.extSyms.byteOffset+symtabX*BYTES[WireSymtabEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[symtabStream, [LOOPHOLE[@wireSymtabBuffer^], 0, BYTES[WireSymtabEntryBody]]]}; sectionIndex _ Basics.Card16FromH[wireSymtabBuffer.sectionIndex]; baseValue _ Basics.Card32FromF[wireSymtabBuffer.value] + sectionList[sectionIndex].addr; IF IsDataSection[sectionList[sectionIndex]] THEN baseValue _ baseValue + dataReloc; previousSymtabX _ symtabX; }; value _ baseValue + Basics.Int32FromF[wireRelocBuffer.addend]; stabX _ Basics.Card32FromF[wireRelocBuffer.offset] / BYTES[WireStabEntryBody]; SELECT wireRelocBuffer.type FROM RSparc32 => module.stabs[stabX].value _ value; ENDCASE => ERROR; IF module.stabs[stabX].stabType = Fun AND Rope.IsPrefix[stabRope, module.stabs[stabX].rope] THEN { module.firstPC _ module.firstPC + (funcPC - module.stabs[stabX].value); module.limitPC _ module.limitPC + (funcPC - module.stabs[stabX].value); }; ENDLOOP; FOR I: CARD IN [0..nStabs) DO SELECT module.stabs[I].stabType FROM Fun => IF Rope.Find[module.stabs[I].rope, ":P("] = -1 THEN value _ module.stabs[I].value _ module.stabs[I].value + module.firstPC; SLine => { info: REF SLineData _ NEW[SLineData_[cLineNum: module.stabs[I].size, parsedRelPC: [[1, ".text"], module.stabs[I].value + value]]]; lineNum.lines _ CONS[info, lineNum.lines]; lineNum.nLines _ lineNum.nLines + 1; lineNum2.lines _ CONS[info, lineNum2.lines]; lineNum2.nLines _ lineNum2.nLines + 1; module.stabs[I].value _ module.stabs[I].value + value; }; LBrac, RBrac => module.stabs[I].value _ module.stabs[I].value + value; ENDCASE; ENDLOOP; RETURN}; wireStabBuffer: WireStabEntry _ NEW[WireStabEntryBody]; wireSymtabBuffer: WireSymtabEntry _ NEW[WireSymtabEntryBody]; wireRelocBuffer: WireRelocEntry _ NEW[WireRelocEntryBody]; ReadStringX: PROC[stream: IO.STREAM, whole: Parsed, stringX: CARD] RETURNS[rope: ROPE] ~ { IO.SetIndex[stream, whole.header.stringOffset+stringX]; rope _ ReadRope[stream]}; RopeBufferSize: CARD = 100; ropeBuffer: REF PACKED ARRAY [0..RopeBufferSize) OF CHAR _ NEW[PACKED ARRAY [0..RopeBufferSize) OF CHAR]; ReadRope: PROC[s: IO.STREAM] RETURNS[rope: ROPE] = BEGIN ENABLE UNWIND => NULL; rope: ROPE _ NIL; WHILE TRUE DO nChars: CARD _ RopeBufferSize; -- tentative rt: Rope.Text; TRUSTED{[] _ IO.UnsafeGetBlock[s, [LOOPHOLE[@ropeBuffer^], 0, RopeBufferSize]]}; FOR I: CARD IN [0..RopeBufferSize) DO IF ropeBuffer[I] = '\000 THEN {nChars _ I; EXIT}; ENDLOOP; rt _ Rope.NewText[nChars]; FOR I: CARD IN [0..nChars) DO rt[I] _ ropeBuffer[I] ENDLOOP; rope _ IF rope = NIL THEN (IF nChars = 0 THEN "" ELSE rt) ELSE (IF nChars = 0 THEN rope ELSE Rope.Concat[rope, rt]); IF nChars < RopeBufferSize THEN EXIT; ENDLOOP; RETURN[rope]; END; IsExternalFun: PROC [stab: Stab] RETURNS [BOOL] ~ { RETURN[Rope.Find[stab.rope, ":P", 0, TRUE] # -1]}; SunELFScanModuleStructure: 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 => IF IsExternalFun[stab] THEN I _ I + 1 ELSE { 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, RSym => NULL; LBrac => { SELECT module.stabs[I+1].stabType FROM STSym, LSym, RSym => firstLocal _ module.stabs[I+1]; ENDCASE; EXIT}; Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => 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]; REPEAT FINISHED => SystemInterface.ShowReport[IO.PutFR["Missed an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; ENDLOOP; I _ perFn[funStab, firstLocal, I+module.firstStabX] - module.firstStabX}; SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => 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}; SunELFScanFnStructure: 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 PassLocals[module, funStab, funStab.stabX+1, nextX, perParm]; limitX _ DoBrack[module, funStab, module.stabs[nextX-module.firstStabX], 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 => IF stab.value > funStab.value THEN 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 _ SunELFScanBktStructure[module, funStab, first, NIL, NIL].limitX; RETURN}; SunELFScanBktStructure: 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 + 1; stab: Stab; IF first.stabType # LBrac THEN ERROR; firstPc _ first.value; 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 RBrac => RETURN [I+1+module.firstStabX, firstPc, stab.value]; STSym, LSym, RSym => IF perLocal#NIL THEN perLocal[stab]; LBrac => I _ DoBrack[module, funStab, stab, perSubBracket] - 1 - module.firstStabX; Fun => IF NOT IsExternalFun[stab] THEN {--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]; RETURN [I+module.firstStabX, stab.value, stab.value]}; SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL; ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab before an RBRAC 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[I+module.firstStabX, module.limitPC, module.limitPC]}; PassLocals: 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]; SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL; ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab in parms/locals of %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal]; ENDLOOP; RETURN}; SunELFGetTypeRef: ObjectFilesPrivate.GetTypeRefProcType ~ { typeRef: Rope.ROPE; lastChar: CHAR _ IO.PeekChar[sourceStream]; IF IsDigit[lastChar] THEN { typeRef _ IO.GetTokenRope[sourceStream, NumTok].token; RETURN[typeRef]} ELSE IF lastChar='( THEN DO lastChar _ IO.GetChar[sourceStream]; typeRef _ Rope.Concat[typeRef, Rope.FromChar[lastChar]]; IF lastChar = ') THEN RETURN[typeRef] ENDLOOP ELSE CCError[cirioError, IO.PutFR1["malformed type rep (starts with %q)", [character[lastChar]] ]]; }; IsDigit: PROC [c:CHAR] RETURNS [BOOL] = INLINE { RETURN [c IN ['0 .. '9]] }; NumTok: PROC [char: CHAR] RETURNS [IO.CharClass] ~ { SELECT char FROM IN ['0..'9] => RETURN [other]; ENDCASE => RETURN [break]}; SunELFAlterFunStab: ObjectFilesPrivate.AlterFunStabType ~ {RETURN [module.funStabs[funStabX].stab]; }; SunELFGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ { entryRelativePC: CARD _ spc.relPC; inst0: CARD _ ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC]]; inst1: CARD _ ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC+4]]; inst2: CARD _ ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC+8]]; spOffset: INT _ SaveProtocol1[inst0, inst1, inst2]; IF spOffset = 0 THEN spOffset _ SaveProtocol2[inst0]; RETURN[spOffset]; }; SaveProtocol1: PROC[inst0, inst1, inst2: CARD] RETURNS[spOffset: INT] ~ { decoded0: DecodedSparcInstruction _ DecodeSparcInstruction[inst0]; decoded1: DecodedSparcInstruction _ DecodeSparcInstruction[inst1]; decoded2: DecodedSparcInstruction _ DecodeSparcInstruction[inst2]; IF decoded0.op # 0 THEN RETURN[0]; IF decoded0.op2 # 4 THEN RETURN[0]; IF decoded0.rd # 1 THEN RETURN[0]; -- this is %g1 IF decoded1.op # 2 THEN RETURN[0]; IF decoded1.op3 # 0 THEN RETURN[0]; IF decoded1.i # 1 THEN RETURN[0]; IF decoded1.rs1 # 1 THEN RETURN[0]; -- this is %g1 IF decoded1.rd # 1 THEN RETURN[0]; -- this is %g1 IF decoded2.op # 2 THEN RETURN[0]; IF decoded2.op3 # 74B THEN RETURN[0]; IF decoded2.i # 0 THEN RETURN[0]; IF decoded2.rs1 # 16B THEN RETURN[0]; -- this is %sp IF decoded2.rs2 # 1 THEN RETURN[0]; -- this is %g1 IF decoded2.rd # 16B THEN RETURN[0]; -- this is %sp spOffset _ LOOPHOLE[Basics.BITSHIFT[decoded0.imm22, 10] + decoded1.simm13]; }; SaveProtocol2: PROC[inst0: CARD] RETURNS[spOffset: INT] ~ { decoded0: DecodedSparcInstruction _ DecodeSparcInstruction[inst0]; IF decoded0.op # 2 THEN RETURN[0]; IF decoded0.op3 # 74B THEN RETURN[0]; IF decoded0.i # 0 THEN RETURN[0]; IF decoded0.rs1 # 16B THEN RETURN[0]; -- this is %sp IF decoded0.rd # 16B THEN RETURN[0]; -- this is %sp spOffset _ decoded0.simm13; }; DecodedSparcInstruction: TYPE = RECORD[ op, disp30, rd, a, cond, op2, imm22, disp22, op3, rs1, i, asi, rs2, simm13, opf: CARD]; DecodeSparcInstruction: PROC[inst: CARD] RETURNS[DecodedSparcInstruction] ~ { RETURN[[ op: Basics.BITAND[3, Basics.BITSHIFT[inst, -30]], disp30: Basics.BITAND[7777777777B, inst], rd: Basics.BITAND[37B, Basics.BITSHIFT[inst, -25]], a: Basics.BITAND[1, Basics.BITSHIFT[inst, -29]], cond: Basics.BITAND[17B, Basics.BITSHIFT[inst, -25]], op2: Basics.BITAND[7, Basics.BITSHIFT[inst, -22]], imm22: Basics.BITAND[17777777B, inst], disp22: Basics.BITAND[17777777B, inst], op3: Basics.BITAND[77B, Basics.BITSHIFT[inst, -19]], rs1: Basics.BITAND[37B, Basics.BITSHIFT[inst, -14]], i: Basics.BITAND[1, Basics.BITSHIFT[inst, -13]], asi: Basics.BITAND[377B, Basics.BITSHIFT[inst, -5]], rs2: Basics.BITAND[37B, inst], simm13: Basics.BITAND[17777B, inst], opf: Basics.BITAND[777B, Basics.BITSHIFT[inst, -5]]]]; }; transTable: ObjectFilesPrivate.TranslationTable _ NEW[ObjectFilesPrivate.TranslationTableBody[2]]; Commander.Register["SunELFRandomTestFindSymtabRange", RandomTestFindSymtabRange]; transTable[0] _ [0, 4, ElfMagic, "SunELF", first]; transTable[1] _ [18, 2, EMSparc, "SunELF", last]; ObjectFilesPrivate.RegisterObjectFileFlavor[NEW[ObjectFilesPrivate.ObjectFileFlavorBody _ [ "SunELF", SunADotOut, ReadHeader, SunELFModuleFromParsedAndPC, SunELFVarLocFromStab, SunELFGetTypeRef, NIL, SunELFScanModuleStructure, SunELFScanFnStructure, SunELFScanBktStructure, TRUE, SunELFInstallStaticVars, SunELFAlterFunStab, SunELFGetSPOffset ]], transTable]; END. Þ SunELFFiles.mesa Copyright Ó 1992, 1993 by Xerox Corporation. All rights reserved. Katsuyuki Komatsu January 25, 1993 4:07 pm PST Useful types Following types are defined in ObjectFiles some Stab types Following types are defined in ObjectFilesPrivate Following values are of global interest The following computations are adapted from /usr/include/sys/elf.h of the SunOS Release 5.x. The following computations are adapted from /usr/include/sys/elf_SPARC.h of the SunOS Release 5.x. The following record type was constructed based on /usr/include/sys/elf.h of the SunOS Release 5.x. Header PROC[stream: IO.STREAM] RETURNS[Header] = TRUSTED ignore .comment section that is (sectionList[i].entrySize = 0) symsStrSeg _ [sectionList[sectionList[i].link].offset, sectionList[sectionList[i].link].size]; -- Unfotunately, the link field of stab section is not reliable. Module We assume that there are dbx stabs located in the whole in the stab table entry range [firstX..limitX). We assume that the first stab is a special stab whose type is the Undefined (0x00), whose size is the count of stabs and whose value is the size of string table. We also assume that this stab containing the file name. PROC [whole: Parsed, spc: FileSegmentPC, moduleRope: ROPE _ NIL] RETURNS [Module] We are fortunate, single module ! first, see if we already have it nest so that we can catch unwinds and release the stream first, see if we already have it nest so that we can catch unwinds and release the stream nest so that we can catch unwinds and release the stream prepare the Module for a call on BuildBrackets lets read the all stabs now (WITH their ropes) now lets finish up usage: RandomTestFindStabRange /dir/.../dir/[sun4/]foo[.c2c].o Finding Modules by Symtab retry because SearchForPCSymtab may return wrong range Variables PROC [stab: Stab] RETURNS [ObjectFiles.VarLoc] PROC[module: Module] = this procedure examines all stabs up to the first Fun stab, looking for certain expected stabs. These are recorded in the whole. C Line-Number to Relative-PC maps sorted by PC sorted by Line Num Stabs warning: does NOT relocate stabs. Also: the module field is set to NIL; hack to avoid messing up the stream buffering all users should be in the monitor all users should be in the monitor all users should be in the monitor WARNING: the rope reading code causes random repositioning of the stream. That is CRUDE and expensive. Simply for this experiment. I need to do something better. Read in the whole string table? read in the symbols, sort them, then read in string table and pick out the interesting strings? What? Symbol ropes we assume that the stream has been positioned at the beginning of a sequence of chars terminated by a '\000 char. Stab Structure PROC [sourceStream:IO.STREAM] RETURNS [Rope.ROPE] Instruction decoder Following procedures compute the SP offset from FP by examining the entry protocol to a procedure. SPoffset = 0 means that the instructions do not form the expected protocol. protocol 1 is sethi %hi(Offset),%g1 add %g1,%lo(Offset),%g1 save %sp,%g1,%sp check for sethi %hi(spOffset),%g1 check for add %g1,%lo(spOffset),%g1 check for save %sp,%g1,%sp protocol 2 is save %sp, spOffset,%sp check for save %sp, spOffset, %sp Main code �Ê9•NewlineDelimiter ™codešœ™K™BK™.—K˜šÏk ˜ Kš œ�œ�œ� œ�œ(�œ�œ˜kKšœ �œ�œ˜Kšœ�œ˜$Kšœ �œ ˜Kšœ �œ˜(Kšœ �œ˜+Kšœ�œ˜Kš�œ˜Kšœ�œ˜Kšœ �œ€˜‘Kšœ�œþ˜–Kš�œ�œF˜OKšœ �œ�œ˜Kšœ�œ"˜.Kšœ �œ ˜Kšœ˜Kšœ�œt˜‰K˜—K˜šÏn œ�œ�˜Kš�œ?�œ)�œ-˜¡Kš�œ ˜—Kšœ�˜K˜Kšžœ�œ!�œ�œ˜MK˜™ Kš�œ�œ�œ˜Kš�œ�œ �œ˜—K˜™*K˜Kšœ�œ˜Kšœ �œ˜-Kšœ �œ˜&Kšœ �œ˜&Kšœ �œ ˜/Kšœ�œ˜0Kšœ�œ ˜6K˜Kšœ™K™Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜KšÐbkœ�œ˜Kšžœ�œ˜Kšžœ�œ˜Kšžœ�œ˜KšŸœ�œ˜K˜—™1K™Kšœ�œ�œ ˜Kšœ �œ�œ!˜8K˜Kšœ�œ�œ ˜Kšœ �œ�œ!˜8K™Kšœ�œ�œ ˜Kšœ �œ!˜1K˜Kšœ�œ(˜?K˜Kšœ �œ˜+K˜Kšœ �œ"˜3Kšœ�œ&˜;K˜—™'K™Kšœ�œ˜2K˜Kšœ\™\K˜Kšžœ�œ � œ� œ�œ� œ�œ �œ˜tK˜Kšž œ�œ˜Kšž œ�œ˜Kšž œ�œ˜K˜Kšž œ�œ˜Kšž œ�œ˜Kšž œ�œ˜K˜Kšžœ�œ˜Kšž œ�œ˜Kšž œ�œ˜Kšž œ�œ˜Kšžœ�œ˜K˜Kšžœ�œ˜KšŸœ�œ˜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šžœ�œ˜K˜Kšž œ�œ˜Kšž œ�œ˜Kšžœ�œ˜Kšž œ�œ˜Kšžœ�œ˜K˜Kšœb™bK™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šœc™cKšœ �œ�œ˜&š œ�œ�œ� œ�œ˜0Kšœ�œ˜Kšœ �œ˜Kšœ �œ˜Kšœ �œ˜Kšœ �œ˜Kš œ �œ�œ �œ�œ˜&Kšœ �œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜—K˜Kšœ �œ�œ˜(šœ�œ�œ˜Kšœ�œ �œ�œ˜.K˜—Kšœ�œ�œ˜,šœ�œ�œ˜!Kšœ�œ�œ˜Kšœ �œ˜Kšœ�œ˜ Kšœ�œ˜Kšœ�œ˜ Kšœ�œ˜Kšœ�œ˜ Kšœ�œ˜ Kšœ�œ˜ Kšœ �œ˜Kšœ �œ˜K˜—Kšœ�œ�œ˜4š œ�œ�œ� œ�œ˜7Kšœ�œ˜Kšœ �œ˜Kšœ�œ˜Kšœ �œ˜Kšœ�œ˜Kšœ �œ˜Kšœ �œ˜Kšœ �œ˜Kšœ�œ˜Kšœ�œ˜K˜—Kšœ�œ�œ˜,š œ�œ�œ� œ�œ˜3Kšœ�œ˜ Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜ K˜—Kšœ�œ�œ˜0š œ�œ�œ� œ�œ˜5Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ˜Kšœ˜Kšœ�œ˜Kšœ"�œ˜)K˜—Kšœ �œ�œ�œ˜/šœ �œ˜K˜K˜Kšœ˜Kšœ˜K˜—šœ �œ˜K˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—Kšœ�œ�œ˜.š œ�œ�œ� œ�œ˜4Kšœ�œ˜Kšœ˜Kšœ�œ˜Kšœ�œ˜!——K˜™K˜šžœ�œ �œ�œ�œ�œ�œ˜DKš�œ �œ˜*K˜—š ž œ�œ�œ�œ�œ˜FKš �œ�œ�œ!�œ�œ(˜”K˜—šž œ*�œ˜>Kš �œ �œ�œ�œ �™1Kšœ�œ˜*Kš œ�œ�œ�œ�œ˜YKšœ�œ%˜0Kšœ �œ$˜1Kšœ �œ'˜4Kš œ �œ�œ!�œ!�œ�œ�œ˜ÁKšœ �œ ˜Kšœ$˜$Kšœ%˜%Kšœ#˜#Kšœ&˜&Kšœ)˜)Kšœ$˜$Kšœ'˜'Kšœ)˜)Kšœ)˜)Kšœ)˜)Kšœ�œ˜Kšœ�œ-˜@Kšœ �œ*˜:Kšœ�œ˜˜>Kšœ@˜@Kšœ>˜>KšœB˜BKšœ>˜>Kšœ>˜>Kšœ>˜>KšœH˜HKšœH˜HKš�œ˜—š�œ�œ�œ�˜!Kš�œL˜NKšœ'˜'š�œ�œ�˜šœ$�œ,˜Sš�œ�œ(�œ˜4š�œ �œ�œ�œ˜ Kšœ7˜7Kšœ˜K˜—š�˜Kšœ>˜>—š�œ�˜KšœA˜A—Kšœ˜—š�œ˜š�œ �œ�œ�œ˜ Kšœ8˜8Kšœ˜K˜—š�˜Kšœ@˜@—š�œ�˜KšœB˜B—Kšœ˜—K˜—šœ"�œ,˜Qš�œ �œ�œ�œ˜Kšœ6˜6Kšœ ˜ K˜—š�˜Kšœ<˜<—š�œ�˜Kšœ@˜@—Kšœ˜—šœ&˜&š�œ�œ�œ�œ˜"Kšœ9˜9Kšœ˜Kš�œ�œ�œ�œ˜DKšœ`˜`K˜—Kšœ˜—šœ$�œ˜EKšœ>™>š�œ�œ�œ˜=š�œ#�œ˜+Kšœ7˜7Kšœ˜KšœŸ™ŸKšœ"˜"K˜—Kšœ˜—Kšœ˜—šœ �œ$˜Fš�œ!�˜'Kšœ;˜;—š�œ�œ!�˜,Kšœ;˜;—š�œ�œ!�˜,Kšœ<˜<—Kšœ˜—Kš�œ˜—Kš�œ˜—š�œ�œ˜Kšœ �œ3˜DKšœ�œ5˜Hš�œ�œ�œ�˜!š�œ.�˜4Kšœ:˜:—š�œ0�˜6Kšœ<˜<—Kš�œ˜—K˜—šœ �œ˜Kšœ ˜ Kšœ �œÏcœ˜+Kšœ˜Kšœ ¡œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜Kšœ˜Kšœ.˜.Kšœ˜Kšœ�œ˜6Kšœ"�œ˜=Kšœ$˜$Kšœ(˜(Kšœ)˜)Kšœ-˜-Kšœ˜Kšœ˜—Kš�œ ˜Kšœ˜K˜——K™™™K™gK™¡K™7K™—šžœ6˜QKš�œ1�œ�œ�œ ™Qš �œ �œ�œ�œ�œ�œ˜'Kšœ˜Kšœ �œ˜Kšœ�œ˜ Kšœ �œ˜K˜Kšœ_˜_Kš�œ�œ�œ�œ˜*š�œ/�œ˜7Kšœ!™!Kš�œ ˜&K˜—˜Kšœ�œ˜Kšœ�œ�œ˜Kšœ�œ�œ˜Kšœ�œ�œ˜(Kšœ�œ˜Kšœ�œ�œ �œ˜Kšœ�œ˜Kšœ�œ�œ �œ˜K˜Kšœ6˜6K™ š �œ �œ�œ&�œ �œ�˜PKš�œ�œ�œ¡!˜Mš�œ �œ3�œ¡˜`Kš�œ˜Kšœ˜—K˜Kš�œ˜—Kš �œ�œ�œ�œ�œ˜,Kšœ+˜+KšœG˜GKš�œ �œ�œ�œ˜ Kšœ`˜`K˜KšœK˜KKš �œ �œ�œ�œ�œ˜%Kšœ�œ ˜Kš�œ�œ�œ�œ˜Kšœ�œ�œ0˜AK™K™8šœ˜š�œ�œ˜Kšœ9˜9K˜K˜—Kšœ�œ˜%Kšœ�œ˜K˜š�œ�˜Kš�œ5�œ˜QKš�œ�œ�œ�œ˜cš�œ�˜šœ˜Kšœ˜Kšœ<˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ%˜%Kšœ˜Kšœ˜Kšœ �œ˜ K˜ Kšœ �œ˜ Kšœ�œ˜K˜—Kš�œ ˜Kš�œ˜K™—K™>šžœ˜4Kšœ<˜š �œžœ�œ�œ�˜)Jšœ�œ �œ˜/Jšœ˜Jšœ˜Jš�œ˜—J˜Jšœ5˜5Kšœ�œ'˜?š �œžœ�œ�œ�˜*Jšœ�œ �œ˜/Jšœ˜Jšœ˜Jš�œ˜—Kšœ˜K˜——K™™K™šž œ�œ�œ�œ%˜LKšœ�œ˜šœ �œ�œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kš�œ�œ˜ Kšœ˜Kšœ˜Kšœ ˜ Kš�œ�œ˜ Kš�œ˜—K˜K˜—šž œ�œ�œ�œ�œ �œ�œ�œ˜tK˜Kšœ!™!K™%K™Kš�œ�œ�œ˜Kšœ�œ ˜Kšœ;˜;Kš�˜Kšœ˜K˜—K™-Kšœ�œ�œ�œ˜ Kšœ �œ�œ�œ˜K˜šž œ�œ�œ�œ �œ�œ �œ˜sKšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ˜Kš�œ5�œ˜QKš�œ�œ�œ�œ˜cKšœ-˜-Kšœ/˜/Kšœ1˜1š�œ�œ˜Kšœ�œ�œ˜NK˜K˜—KšœS˜SK˜Kšœ˜š�œ�˜š�œ�˜!K˜š�œ@�œ˜\Kš�œ�œ�œ�œ˜cKšœs˜sK˜Kšœ ˜ Kš�œ˜———šœ˜Kšœ�œ˜ Kšœ ˜ Kšœ˜K˜ Kšœ ˜ Kšœ ˜ Kšœ˜—Kš�œ˜K˜—šžœ�œ�œ�œ�œ�œ�œ�œ)˜¹Kšœ�œ˜;Kšœ�œ'�œ˜SKš œ�œ�œ�œ�œ˜ZKšœ�œ�œ�œ˜#Kšœ �œ˜Kšœ�œ˜Kšœ �œ˜Kšœ�œ˜ Kšœ�œ˜ Kšœ�œ!¡˜EK˜š �œžœ�œ�œ�˜$Kš�œ6�œ˜SKš�œ�œ�œ�œ˜eKšœ˜š�œ�œ˜#Kš�œ@�œ˜^Kš�œ�œ�œ�œ˜mKšœA˜AKšœX˜XKš�œ*�œ#˜SKšœ˜K˜—Kšœ>˜>Kšœ5�œ˜Nš�œ�˜ Kšœ.˜.Kš�œ�œ˜—š�œ$�œ3�œ˜bKšœG˜GKšœG˜GKšœ˜—Kš�œ˜—K˜š �œžœ�œ�œ �˜š�œ�˜$šœ�œ-�˜:KšœG˜G—šœ ˜ Kšœ�œ �œi˜‚Kšœ�œ˜*Kšœ$˜$Kšœ�œ˜,Kšœ&˜&Kšœ6˜6Kšœ˜—KšœF˜FKš�œ˜—Kš�œ˜—Kš�œ˜K˜—šœ �œ˜7KšÏt"™"—šœ$�œ˜=Kš¢"™"—šœ"�œ˜:Kš¢"™"—K™šž œ�œ �œ�œ�œ�œ�œ˜ZKš�œ5˜7Kšœ˜Kš�œL�œÕ™­—K˜—K˜™ K™Kšžœ�œ˜Kšœ �œ�œ�œ�œ�œ�œ�œ�œ�œ�œ˜iK˜˜Kšœq™q—š žœ�œ�œ�œ�œ�œ˜2Kš�˜Kš�œ�œ�œ˜Kšœ�œ�œ˜š�œ�œ�˜ Kšœ�œ¡ ˜+K˜K˜Kš�œ�œ�œ%˜PK˜š �œžœ�œ�œ�˜%Kš�œ�œ�œ˜1Kš�œ˜K˜—K˜Kš �œžœ�œ�œ �œ�œ˜<š œ�œ�œ�œ�œ �œ�œ˜9Kš�œ�œ �œ�œ˜:—Kš�œ�œ�œ˜%Kš�œ˜—Kš�œ˜ Kš�œ˜K™——K˜™K˜šž œ�œ�œ�œ˜3Kš�œ�œ ˜2K˜—šžœ�œ;˜ZKšžœ�œ˜ š�œ�˜ K˜Kš�œ�œ�œ˜!š�œ�œ�˜Kšœ&˜&šœ�œ�œ �œ˜3Kšœ˜Kšœ�œ˜š�œ�˜"Kšœ ˜ K˜Kš�œ�œ�œ�œ˜š�œ�˜Kšœ�œ˜šœ ˜ š�œ�˜&Kšœ4˜4Kš�œ˜—Kš�œ˜—Kšœ�œ�œ�œ˜@Kš�œ�œà˜ˆ—Kš�œ�œ�œ�˜ÀKš�œ˜—KšœI˜I—Kšœ#�œ�œ˜Lš�œ˜ Kšœ�œ¬˜ÉKšœ ˜ ——Kš�œ˜—Kš�œ˜—K˜šžœ�œ4�œ �œ �œ �œ3�œ�œ�œ˜ÖKš�œ �œ�œ>˜QKšœU˜Uš �œžœ�œ!�œ�˜LK˜Kš�œ�œ�œ�œ˜š�œ�˜Kšœ�œ�œ�œ˜FKš�œ�œ˜—Kš�œ˜—Kš�œ˜!K˜—šžœ�œ[�œ �œ˜‚Kš�œ�œ�œ˜7Kš�œ9�œ�œ ˜NKš�œ˜K˜—šžœ�œ2�œ �œ6�œ�œ�œ˜ÆKšžœ�œ'˜.K˜ Kš�œ�œ�œ˜%Kšœ˜š�œ �œ�˜/K˜Kš�œ�œ�œ�œ˜š�œ�˜Kšœ �œ.˜=Kšœ�œ �œ�œ˜9KšœS˜Sšœ�œ�œ�œ¡˜CKšœ�œŸ˜¼Kš�œ0˜6—Kšœ#�œ�œ�œ˜GKš�œ�œÒ˜ú—Kš�œ˜—Kšœ�œ�˜­Kš�œ7˜=K˜—šž œ�œ1�œ�œ ˜[š �œžœ�œ�œ:�˜JK˜š �œ �œ�œ�œ�˜1Kšœ$˜$Kšœ#�œ�œ�œ˜GKš�œ�œÉ˜ñ—Kš�œ˜—Kš�œ˜K˜—šžœ+˜;Kš �œ�œ�œ�œ�œ™1K˜Kšœ�œ˜Kšœ �œ�œ˜+š�œ�œ˜Kšœ �œ*˜6Kš�œ ˜—š�œ�œ �œ�˜Kšœ �œ˜$K˜8Kš�œ�œ�œ ˜%Kš�˜—Kš�œ�œH˜cK˜K˜š  œ�œ�œ�œ�œ˜%Kšœ�œ�œ�œ˜&K˜—š žœ�œ�œ�œ�œ˜4š�œ�˜Kš�œ �œ ˜Kš�œ�œ ˜——K˜—Kšžœ)�œ%˜fK˜—K˜™K˜šžœ(˜9Kšœ�œ ˜"Kšœ�œ>˜IKšœ�œ@˜KKšœ�œ@˜KKšœ �œ&˜3Kš�œ�œ!˜5Kš�œ ˜Kšœ˜—˜Kšœ!�œ �œ0™bK™K—™™ K™K™K™——š ž œ�œ�œ�œ �œ˜IKšœB˜BKšœB˜BKšœB˜B˜Kšœ#™#—Kš�œ�œ�œ˜"Kš�œ�œ�œ˜#Kš�œ�œ�œÐci˜2˜Kšœ%™%—Kš�œ�œ�œ˜"Kš�œ�œ�œ˜#Kš�œ�œ�œ˜!Kš�œ�œ�œ£˜2Kš�œ�œ�œ£˜1˜K™—Kš�œ�œ�œ˜"Kš�œ�œ�œ˜%Kš�œ�œ�œ˜!Kš�œ�œ�œÏi£˜4Kš�œ�œ�œ£˜2Kš�œ�œ�œ¤£˜3K˜Kšœ �œ�œ(˜KKšœ˜—˜™ Kšœ™——š ž œ�œ�œ�œ �œ˜;KšœB˜B˜Kšœ$™$—Kš�œ�œ�œ˜"Kš�œ�œ�œ˜%Kš�œ�œ�œ˜!Kš�œ�œ�œ¤£˜4Kš�œ�œ�œ¤£˜3K˜Kšœ˜Kšœ˜—K˜šœ�œ�œ˜'KšœQ�œ˜XK˜—šžœ�œ�œ�œ˜Mš�œ˜Kšœ �œ �œ ˜1Kšœ�œ˜)Kšœ �œ �œ ˜3Kšœ �œ �œ ˜0Kšœ �œ �œ ˜5Kšœ �œ �œ ˜2Kšœ�œ˜&Kšœ�œ˜'Kšœ �œ �œ ˜4Kšœ �œ �œ ˜4Kšœ �œ �œ ˜0Kšœ �œ�œ ˜4Kšœ �œ ˜Kšœ�œ˜$Kšœ �œ�œ˜6—Kšœ˜K˜——K˜™ K™Kšœ2�œ-˜bKšœQ˜QKšœ2˜2Kšœ1˜1šœ,�œ,˜[Kšœ ˜ Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Jšœ˜Kš�œ˜J˜J˜Jšœ˜Jš�œ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ ——K™Kš�œ˜K˜—…—±¨÷‰