<<>> <> <> <> <> <> <> <> <> DIRECTORY Basics USING [Card16FromH, Card32FromF, Comparison, FWORD, HWORD], BasicTime USING [GMT, Now], CCTypes USING[CCError, CCErrorCase], CirioTypes USING [zeroBA], Commander USING [Register, CommandProc], CommanderOps USING [ArgumentVector, Parse], Convert USING [IntFromRope], IO, List USING[LORA, CompareProc, 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], PBasics USING [BITAND, BITSHIFT], PFS USING [PathFromRope, StreamFromOpenFile, OpenFileFromStream], PFSNames USING [PATH], Random USING[ChooseInt, Create, RandomStream], Rope, SunADotOut, SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, ReleaseStreamForFile, ShowReport]; SunADotOutFiles: CEDAR MONITOR IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PBasics, PFS, Random, Rope, SystemInterface EXPORTS ObjectFiles, SunADotOut = BEGIN CCError: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE _ NIL] _ CCTypes.CCError; <> 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; <> <> <> <> MOldsun2: CARD = 0; M68010: CARD = 1; M68020: CARD = 2; MSparc: CARD = 3; OMagic: CARD16 = 0407B; NMagic: CARD16 = 0410B; ZMagic: CARD16 = 0413B; <> <> PageSize: CARD32 = 02000H; OldPageSize: CARD32 = 00800H; <> WireHeader: TYPE = REF WireHeaderBody; WireHeaderBody: TYPE = MACHINE DEPENDENT RECORD[ dynamic: BYTE[0..0], toolversion: BYTE[0..127], machtype: BYTE, magic: Basics.HWORD, textSize: Basics.FWORD, iDataSize: Basics.FWORD, bssSize: Basics.FWORD, symsSize: Basics.FWORD, entryPoint: Basics.FWORD, trSize: Basics.FWORD, drSize: Basics.FWORD]; WireSTEntry: TYPE = REF WireSTEntryBody; WireSTEntryBody: 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]; ReadHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED { <> wHeader: WireHeader _ NEW[WireHeaderBody]; nBytes: INT _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[WireHeaderBody]]]; magic: CARD _ Basics.Card16FromH[wHeader.magic]; nBadMagic: BOOLEAN _ (magic # OMagic) AND (magic # NMagic)AND (magic # ZMagic); <> <> nPageSize: CARD _ IF wHeader.machtype = MOldsun2 THEN OldPageSize ELSE PageSize; textOffset: CARD _ IF wHeader.machtype = MOldsun2 THEN (IF magic = ZMagic THEN nPageSize ELSE BYTES[WireHeaderBody]) ELSE (IF magic = ZMagic THEN 0 ELSE BYTES[WireHeaderBody]); textSize: CARD _ Basics.Card32FromF[wHeader.textSize]; iDataSeg: MemorySegmentInfo _ [textOffset + textSize, Basics.Card32FromF[wHeader.iDataSize]]; textRelocSeg: MemorySegmentInfo _ [iDataSeg.byteOffset+iDataSeg.byteLength, Basics.Card32FromF[wHeader.trSize]]; dataRelocSeg: MemorySegmentInfo _ [textRelocSeg.byteOffset+textRelocSeg.byteLength, Basics.Card32FromF[wHeader.drSize]]; symsSeg: MemorySegmentInfo _ [dataRelocSeg.byteOffset+dataRelocSeg.byteLength, Basics.Card32FromF[wHeader.symsSize]]; textLoadOffset: CARD32 _ IF magic = ZMagic THEN 02000H ELSE 0; <> <> header: Header _ NEW[HeaderBody _ [ dynamic: wHeader.dynamic # 0, toolversion: wHeader.toolversion, machtype: wHeader.machtype, magic: magic, text: [textOffset, textSize], iData: iDataSeg, textReloc: textRelocSeg, dataReloc: dataRelocSeg, syms: symsSeg, debug: [0, 0], linno: [0, 0], textLoadOffset: textLoadOffset, bssSize: Basics.Card32FromF[wHeader.bssSize], entryPoint: Basics.Card32FromF[wHeader.entryPoint], nPageSize: nPageSize, nEntries: symsSeg.byteLength/BYTES[WireSTEntryBody], stringOffset: symsSeg.byteOffset+symsSeg.byteLength ]]; RETURN[header]; }; <<>> <> <<>> <> <> <> <> <> <<>> SunADotOutModuleFromParsedAndPC: ObjectFilesPrivate.ModuleFromParsedAndPCProcType ~ { <> IF whole = NIL THEN RETURN[NIL] ELSE { stabRange: StabRange _ AlternativeFindModuleStabRange[whole, spc.relPC]; RETURN [ModuleFromParsedInner[whole, stabRange]]; }; }; 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]] RETURNS[Module] = BEGIN module: Module _ NEW[ModuleBody]; firstSO: Stab; nStabs: CARD; lineNums: LineNumList; lineNums2: LineNumList; [firstSO, ] _ BasicReadStab[whole, stream, stabRange.first]; nStabs _ stabRange.count; lineNums _ NEW [LineNumListBody _ [0, NIL]]; lineNums2 _ NEW [LineNumListBody _ [0, NIL]]; <<>> <> module.whole _ whole; module.firstStabX _ stabRange.first; module.limitStabX _ stabRange.first+stabRange.count; module.firstPC _ firstSO.value; module.limitPC _ whole.header.text.byteLength; -- (bogus, but it will suffice for reasons given earlier) <> <<(I did some timing tests on a Dorado for RopeImpl. It took about 6 seconds to perform this loop, including the allocates. On the other hand, it takes about 4 seconds to spin through the entries without allocating the stab records. So, since at some point I have to traverse all the entries to find the Fun stabs, I might as well allocate them.)>> <<(we also relocate the pc value of bracket stabs.)>> <<>> module.stabs _ NEW[StabSet[nStabs]]; {I: CARD _ 0; WHILE I> <<>> InstallPCLineNumMaps[module, lineNums, lineNums2]; module.fileName _ PFS.PathFromRope[IF module.stabs[1].stabType = SO THEN module.stabs[1].rope ELSE module.stabs[0].rope]; module.staticVarsInstalled _ FALSE; module.versionStampInfo _ NIL; module.outerBracket _ NEW[ObjectFilesPrivate.BracketPairBody_[ module: module, kind: syntheticOuter, firstX: 0, limitX: module.whole.header.nEntries, firstPC: module.firstPC, pcLimit: module.limitPC, funStab: NIL, funIndex: 0, symbols: NIL, innerBrackets: NIL]]; RETURN[module]; END; <<>> <> <<>> StabIndexTypeAndValue: TYPE = RECORD[stabX: CARD, stabType: StabType, value: CARD32]; NullStabIndexTypeAndValue: StabIndexTypeAndValue = [0, Invalid, 0]; <> <> AlternativeFindModuleStabRange: PROC[whole: Parsed, relativePC: CARD] RETURNS[StabRange _ [0, 0]] = BEGIN { < {>> <> <> <> IF whole = NIL THEN RETURN[[0, 0]] ELSE BEGIN nominalX: CARD _ SearchForPC[whole, relativePC]; baseSO: StabIndexTypeAndValue _ NullStabIndexTypeAndValue; -- tentative maxPC: CARD _ 0; highDbx: CARD _ 0; IF nominalX = whole.header.nEntries THEN RETURN[[0, 0]]; <> FOR x: CARD DECREASING IN [0..nominalX] DO info: StabIndexTypeAndValue _ CheckStab[whole, x]; <> IF info.stabType = Fun OR info.stabType = SLine OR info.stabType = SO THEN maxPC _ MAX[maxPC, info.value]; IF info.stabType = SO THEN {baseSO _ info}; IF info.stabType = Unspecified OR info.stabType = Invalid THEN EXIT; highDbx _ MAX[highDbx, info.stabX]; ENDLOOP; IF baseSO.stabType # SO THEN { <> <> <> RETURN[[0, 0]];}; <> FOR x: CARD IN (nominalX..whole.stabLimit) DO info: StabIndexTypeAndValue _ CheckStab[whole, x]; <> IF info.stabType = Fun OR info.stabType = SLine THEN maxPC _ MAX[maxPC, info.value]; IF info.stabType = Unspecified OR info.stabType = Invalid THEN EXIT; highDbx _ MAX[highDbx, info.stabX]; ENDLOOP; IF baseSO.value <= relativePC AND relativePC <= maxPC THEN { <> <> <> RETURN[[baseSO.stabX, highDbx-baseSO.stabX+1]];}; <> <> <> RETURN[[0, 0]]; END; }; END; <> <> <<>> SearchForPC: PROC[whole: Parsed, pc: CARD] RETURNS[CARD] = BEGIN x: CARD _ 0; y: CARD _ whole.stabLimit; <> <> < pc>> <<>> WHILE x+1 < y DO mid: CARD _ (x+y)/2; midStab: StabIndexTypeAndValue _ SearchFwdForPCStab[whole, mid, y]; SELECT TRUE FROM midStab.stabX = y => y _ mid; pc < midStab.value => y _ mid; midStab.value = pc => RETURN[midStab.stabX]; midStab.value < pc => x _ mid; ENDCASE => ERROR; ENDLOOP; RETURN[x]; END; <> <<>> SearchFwdForPCStab: PROC[whole: Parsed, start: CARD, limit: CARD] RETURNS[StabIndexTypeAndValue] = BEGIN dbxLimit: CARD _ 0; -- tentative FOR x: CARD _ start, x+1 WHILE x < limit DO info: StabIndexTypeAndValue _ CheckStab[whole, x]; IF info.stabType = SO OR info.stabType = Fun OR info.stabType = SLine THEN RETURN[info]; IF info.stabType # Unspecified AND info.stabType # Invalid THEN dbxLimit _ x+1; < 1fH THEN dbxLimit _ x+1;>> ENDLOOP; IF limit = whole.stabLimit AND dbxLimit > start THEN whole.stabLimit _ dbxLimit; RETURN[[limit, Invalid, 0]]; END; CheckStab: ENTRY PROC[whole: Parsed, stabX: CARD] RETURNS[StabIndexTypeAndValue] = BEGIN ENABLE UNWIND => NULL; stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireSTEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@WireStabBuffer^], 0, BYTES[WireSTEntryBody]]]}; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[[stabX, TypeFromData[WireStabBuffer.type], Basics.Card32FromF[WireStabBuffer.value]]]; END; SunADotOutVarLocFromStab: ObjectFilesPrivate.VarLocFromStabProcType ~ { <> header: Header ~ stab.module.whole.header; MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ { segRope:Rope.ROPE; segBase: CARD ~ SELECT kind FROM text => 0, data => header.text.byteLength, bss => header.text.byteLength + header.iData.byteLength, ENDCASE => ERROR; IF stab.value < segBase THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["value (%xH) less than segment base (%xH) for symbol %g in %g", [cardinal[stab.value]], [cardinal[segBase]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]] ]]; SELECT kind FROM text => segRope _ "text"; 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 - segBase)*8, stab.value + 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]]] ]]; }; <> 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; }; <<>> <> <<>> <> < NULL;>> <> <> <> <0 AND stab.rope.Fetch[rlen-1]='\\ THEN {>> <> <> <> <> <<}>> <> <> <> <> <<>> 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, lineNum, lineNum2: LineNumList _ NIL] RETURNS[stab: Stab, numStabsRead: CARD] ~ { <> <> <<>> ENABLE UNWIND => NULL; stab _ NEW [StabBody]; [stab^, numStabsRead] _ ReadStabBody[whole, stream, stabX, lineNum, lineNum2]; RETURN }; <> previousStream: IO.STREAM _ NIL; cloneStream: IO.STREAM _ NIL; ReadStabBody: PROC [whole: Parsed, stream: IO.STREAM, stabX: CARD, lineNum, lineNum2: LineNumList _ NIL] RETURNS [stab: StabBody, numStabsRead: CARD] ~ { rope: Rope.ROPE _ "\\"; size, rLen, offset: CARD16 _ 0; value: CARD32; stabType: ObjectFiles.StabType; IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireSTEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@WireStabBuffer^], 0, BYTES[WireSTEntryBody]]]}; 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[WireSTEntryBody]]; TRUSTED{[] _ IO.UnsafeGetBlock[stream, [LOOPHOLE[@WireStabBuffer^], 0, BYTES[WireSTEntryBody]]]}; 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 ]; IF stab.stabType = SLine AND lineNum # NIL THEN { info: REF SLineData _ NEW[SLineData_[cLineNum: Basics.Card16FromH[WireStabBuffer.desc], parsedRelPC: [[1, ".text"], stab.value]]]; lineNum.lines _ CONS[info, lineNum.lines]; lineNum.nLines _ lineNum.nLines + 1; lineNum2.lines _ CONS[info, lineNum2.lines]; lineNum2.nLines _ lineNum2.nLines + 1; }; RETURN}; WireStabBuffer: WireSTEntry _ NEW[WireSTEntryBody]; <> ReadStringX: PROC[stream: IO.STREAM, whole: Parsed, stringX: CARD] RETURNS[rope: 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.ROPE] = BEGIN ENABLE UNWIND => NULL; rope: 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; <<>> <> RandomTestFindStabRange: Commander.CommandProc = { args: CommanderOps.ArgumentVector _ CommanderOps.Parse[cmd]; path: PATH _ PFS.PathFromRope[args[1]]; fileSet: SystemInterface.FileSet _ SystemInterface.CreateFileSet[]; { ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet]; file: SystemInterface.CirioFile _ SystemInterface.GetCirioFile[fileSet, path]; nextSeed: INT _ IF args.argc < 3 THEN 4466 ELSE Convert.IntFromRope[args[2]]; start: BasicTime.GMT _ BasicTime.Now[]; WHILE TRUE DO rs: Random.RandomStream _ Random.Create[seed: nextSeed]; whole: Parsed _ ObjectFiles.CreateParsed[file, "SunADotOut"]; 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: StabRange _ AlternativeFindModuleStabRange[whole, pc]; IO.PutF[cmd.out, "\Tpc = %g gives firstX: %g count: %g\N", IO.card[pc], IO.card[range.first], IO.card[range.count]]; ENDLOOP; ENDLOOP; }; SystemInterface.CloseFileSet[fileSet]; }; <> SADOScanModuleStructure: 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, RSym => NULL; STSym, LSym => IF BracketFollows[module, I] THEN {firstLocal _ stab; EXIT} ELSE {firstLocal _ NIL; EXIT}; LBrac => {firstLocal _ stab; EXIT}; Fun, GSym, LCSym => {firstLocal _ NIL; EXIT}; SLine, 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]; 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}; BracketFollows: PROC [module: Module, J: CARD] RETURNS [BOOL] ~ { FOR J _ J+1, J+1 WHILE J < module.stabs.nStabs DO stab: Stab ¬ module.stabs[J]; IF stab.module = NIL THEN LOOP; SELECT stab.stabType FROM Fun, GSym, LCSym => RETURN [FALSE]; LBrac => RETURN [TRUE]; ENDCASE => NULL; ENDLOOP; RETURN [FALSE]}; SADOScanFnStructure: PROC [module: Module, funStab: Stab, firstLocal: Stab _ NIL, nextX: CARD, perParm: PROC [Stab] _ NIL, perBracket: ObjectFilesPrivate.BracketConsumer _ NIL] RETURNS [limitX, limitPc: CARD] ~ { K: CARD; more: BOOL _ TRUE; IF perParm#NIL THEN PassLocals[module, funStab, funStab.stabX+1, nextX, perParm]; IF firstLocal=NIL THEN limitX _ nextX ELSE limitX _ DoBrack[module, funStab, firstLocal, perBracket]; K _ limitX-module.firstStabX; WHILE K < module.stabs.nStabs DO --seek limitPC, and more bracket pairs. stab: Stab _ module.stabs[K]; IF stab.module = NIL THEN K _ K + 1 ELSE SELECT stab.stabType FROM Fun => RETURN [limitX, stab.value]; LBrac, RSym => IF more THEN {limitX _ DoBrack[module, funStab, stab, perBracket]; K _ limitX-module.firstStabX} ELSE K _ K + 1; STSym, LSym => IF more AND BracketFollows[module, K] THEN {limitX _ DoBrack[module, funStab, stab, perBracket]; K _ limitX-module.firstStabX} ELSE {K _ K + 1; more _ FALSE}; ENDCASE => K _ K + 1; 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 _ SADOScanBktStructure[module, funStab, first, NIL, NIL].limitX; RETURN}; SADOScanBktStructure: 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, RSym => IF perLocal#NIL THEN perLocal[stab]; LBrac => { J: CARD _ I+1; firstPc _ stab.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]; STSym, LSym, RSym, LBrac => J _ DoBrack[module, funStab, stab, perSubBracket] - module.firstStabX; SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => 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]; 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 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]}; 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}; SunADotOutGetTypeRef: 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]}; ModuleFromParsedAndStabRange: PUBLIC PROC[whole: Parsed, stabRange: StabRange] RETURNS[Module] = { RETURN [ModuleFromParsedInner[whole, stabRange]]; }; ModuleFromParsedInner: PROC[whole: Parsed, stabRange: StabRange] RETURNS[Module] = { firstX, limitX: CARD; stream: IO.STREAM; IF stabRange.count = 0 THEN RETURN[NIL]; firstX _ stabRange.first; limitX _ stabRange.first+stabRange.count; stream _ SystemInterface.GetStreamForFile[whole.file]; <> { ENABLE UNWIND => { SystemInterface.ReleaseStreamForFile[whole.file, stream]; }; firstSO: Stab; firstPC: CARD; lag: LIST OF Module _ NIL; [firstSO, ] _ BasicReadStab[whole, stream, firstX]; -- rope field not filled firstPC _ firstSO.value; <> 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]; cell: LIST OF Module _ LIST[newModule]; IF lag # NIL THEN lag.rest _ cell ELSE whole.modules _ cell; SystemInterface.ReleaseStreamForFile[whole.file, stream]; RETURN[newModule]; }; }; }; SADOInstallStaticVars: 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.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; }; SADOAlterFunStab: ObjectFilesPrivate.AlterFunStabType ~ {RETURN [module.funStabs[funStabX].stab]; }; SADOGetSPOffset: 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[PBasics.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: PBasics.BITAND[3, PBasics.BITSHIFT[inst, -30]], disp30: PBasics.BITAND[7777777777B, inst], rd: PBasics.BITAND[37B, PBasics.BITSHIFT[inst, -25]], a: PBasics.BITAND[1, PBasics.BITSHIFT[inst, -29]], cond: PBasics.BITAND[17B, PBasics.BITSHIFT[inst, -25]], op2: PBasics.BITAND[7, PBasics.BITSHIFT[inst, -22]], imm22: PBasics.BITAND[17777777B, inst], disp22: PBasics.BITAND[17777777B, inst], op3: PBasics.BITAND[77B, PBasics.BITSHIFT[inst, -19]], rs1: PBasics.BITAND[37B, PBasics.BITSHIFT[inst, -14]], i: PBasics.BITAND[1, PBasics.BITSHIFT[inst, -13]], asi: PBasics.BITAND[377B, PBasics.BITSHIFT[inst, -5]], rs2: PBasics.BITAND[37B, inst], simm13: PBasics.BITAND[17777B, inst], opf: PBasics.BITAND[777B, PBasics.BITSHIFT[inst, -5]]]]; }; <
> <<>> transTable: ObjectFilesPrivate.TranslationTable _ NEW[ObjectFilesPrivate.TranslationTableBody[3]]; Commander.Register["sunadoRandomTestFindStabRange", RandomTestFindStabRange]; transTable[0] _ [2, 2, 263, "SunADotOut"]; transTable[1] _ [2, 2, 264, "SunADotOut"]; transTable[2] _ [2, 2, 267, "SunADotOut"]; ObjectFilesPrivate.RegisterObjectFileFlavor[NEW[ObjectFilesPrivate.ObjectFileFlavorBody _ [ "SunADotOut", SunADotOut, ReadHeader, SunADotOutModuleFromParsedAndPC, SunADotOutVarLocFromStab, SunADotOutGetTypeRef, NIL, SADOScanModuleStructure, SADOScanFnStructure, SADOScanBktStructure, TRUE, SADOInstallStaticVars, SADOAlterFunStab, SADOGetSPOffset ]], transTable]; <<>> END..