DIRECTORY Basics USING [Card32FromF, FWORD], Commander USING[CommandProc, Register], CommanderOps USING[ArgumentVector, Parse], Convert USING[CardFromRope, IntFromRope, RopeFromCard], ObjectFiles USING[BracketNest, BracketPairKind, BracketProc, CGrammar, FunInfo, GlobalVarLoc, Module, ModuleInfo, NameAndNumber, NoFileSegmentPC, noFSeg, Parsed, PCRange, FileSegmentPC, Stab, StabType, SymbolProc, UnreadableObjectFile, VarLoc, VarLocBody, VersionStampInfo], ObjectFilesPrivate USING[BracketConsumer, BracketFinisher, BracketPair, BracketPairBody, FnConsumer, FnFinisher, FunHandleBody, FunStabInfo, FunStabSet, FunStabSetBody, GetTypeRefProcType, Header, HeaderBody, LineNumToPCMap, LineNumToPCMapBody, ModuleBody, ObjectFileFlavor, ParsedBody, PCtoLineNumMap, PCtoLineNumMapBody, SLineData, StabList, StabSet, TranslationTable, TranslationTableBody], IO USING[card, Close, GetChar, GetIndex, PutF, PutF1, PutFL, PutFLR, PutFR, PutFR1, PutRope, rope, SetIndex, STREAM, UnsafeGetBlock], PFS USING [PathFromRope, RopeFromPath, StreamOpen], PFSNames USING [PATH, ShortName, ComponentRope, EmptyPath, Equal], Rope USING[Cat, Concat, Equal, Fetch, Find, Index, IsEmpty, IsPrefix, Length, NewText, ROPE, Substr, Text], SGI USING [WireTables, UnPackLineNumbers], SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetNameOfFile, GetStreamForFile, ReleaseStreamForFile, ShowReport]; ObjectFilesImpl: CEDAR MONITOR IMPORTS Basics, Commander, CommanderOps, Convert, IO, ObjectFiles, PFS, PFSNames, Rope, SystemInterface, SGI EXPORTS ObjectFiles, ObjectFilesPrivate = { PATH: TYPE ~ PFSNames.PATH; ROPE: TYPE ~ Rope.ROPE; Parsed: TYPE ~ REF ParsedBody; ParsedBody: PUBLIC TYPE ~ ObjectFilesPrivate.ParsedBody; Module: TYPE ~ REF ModuleBody; ModuleBody: PUBLIC TYPE ~ ObjectFilesPrivate.ModuleBody; ModuleInfo: TYPE ~ ObjectFiles.ModuleInfo; Header: TYPE ~ REF HeaderBody; HeaderBody: TYPE ~ ObjectFilesPrivate.HeaderBody; FileSegmentPC: TYPE ~ ObjectFiles.FileSegmentPC; Stab: TYPE ~ ObjectFiles.Stab; StabType: TYPE ~ ObjectFiles.StabType; StabList: TYPE ~ ObjectFilesPrivate.StabList; StabSet: TYPE ~ ObjectFilesPrivate.StabSet; BracketConsumer: TYPE ~ ObjectFilesPrivate.BracketConsumer; BracketFinisher: TYPE ~ ObjectFilesPrivate.BracketFinisher; FnConsumer: TYPE ~ ObjectFilesPrivate.FnConsumer; FnFinisher: TYPE ~ ObjectFilesPrivate.FnFinisher; FlavorSeq: TYPE = RECORD[SEQUENCE length: CARD OF ObjectFilesPrivate.ObjectFileFlavor]; translationTable: ObjectFilesPrivate.TranslationTable ¬ NIL; registry: REF FlavorSeq _ NEW[FlavorSeq[0]]; OFFFromStream: PUBLIC PROC[stream: IO.STREAM] RETURNS [ROPE] ~ { index: INT; ValueFromStream: PROC [num: CARD] RETURNS [val: CARD] = { val ¬ 0; IO.SetIndex[stream, translationTable[num].byteOffset]; FOR j: CARD IN [0..translationTable[num].length) DO val ¬ (val * 256) + ORD[IO.GetChar[stream]]; ENDLOOP; }; IF stream = NIL THEN RETURN["stream was NIL, so no OFF rope was returned."]; IF translationTable = NIL THEN RETURN["table of OFF's was NIL."]; index ¬ IO.GetIndex[stream]; FOR i: CARD IN [0..translationTable.length) DO IF translationTable[i].type = middle OR translationTable[i].type = last THEN LOOP; IF ValueFromStream[i] = translationTable[i].compareValue THEN { IF translationTable[i].type = point THEN { IO.SetIndex[stream, index]; RETURN[translationTable[i].format]; }; FOR cont: CARD IN [i+1..translationTable.length) DO IF ValueFromStream[cont] # translationTable[cont].compareValue THEN EXIT; IF translationTable[cont].type = last THEN { IO.SetIndex[stream, index]; RETURN[translationTable[cont].format]; }; ENDLOOP; }; ENDLOOP; IO.SetIndex[stream, index]; RETURN["No OFF rope for object File."]; }; RegisterObjectFileFlavor: PUBLIC PROC[flavor: ObjectFilesPrivate.ObjectFileFlavor, table: ObjectFilesPrivate.TranslationTable ¬ NIL] ~ { i: CARD; IF (i ¬ RetrieveObjectFileFlavorInner[flavor.formatSpecificString]) # LAST[CARD] THEN registry[i] ¬ flavor ELSE { newR: REF FlavorSeq ¬ NEW[FlavorSeq[registry.length+1]]; FOR i IN [0..registry.length) DO newR[i] ¬ registry[i]; ENDLOOP; newR[registry.length] ¬ flavor; registry ¬ newR; }; IF table # NIL THEN { newTT: ObjectFilesPrivate.TranslationTable ¬ NIL; IF translationTable = NIL THEN translationTable ¬ NEW[ObjectFilesPrivate.TranslationTableBody[table.length]] ELSE { newLen: CARD ¬ translationTable.length + table.length; newTT ¬ translationTable; translationTable ¬ NEW[ObjectFilesPrivate.TranslationTableBody[newLen]]; FOR i: CARD IN [0..newTT.length) DO translationTable[i+table.length] ¬ newTT[i]; ENDLOOP; }; FOR i: CARD IN [0..table.length) DO translationTable[i] ¬ table[i]; ENDLOOP; }; }; RetrieveObjectFileFlavor: PUBLIC PROC[formatSpecificString: ROPE] RETURNS[flavor: ObjectFilesPrivate.ObjectFileFlavor] ~ { i:CARD ¬ RetrieveObjectFileFlavorInner[formatSpecificString]; IF i # LAST[CARD] THEN RETURN [registry[i]] ELSE ERROR; }; RetrieveObjectFileFlavorInner: PROC[formatSpecificString: ROPE] RETURNS[registryIndex: CARD] ~ { FOR i: CARD IN [0 .. registry.length) DO IF Rope.Equal[formatSpecificString, registry[i].formatSpecificString] THEN RETURN [i]; ENDLOOP; RETURN[LAST[CARD]]}; CreateParsed: PUBLIC ENTRY PROC[f: SystemInterface.CirioFile, fs: ROPE ¬ NIL, targetData: REF ANY _ NIL] RETURNS[Parsed] = { ENABLE UNWIND => NULL; parsed: Parsed ¬ NEW[ParsedBody]; stream: IO.STREAM ¬ SystemInterface.GetStreamForFile[f]; parsed.file ¬ f; parsed.targetData ¬ targetData; IF fs = NIL THEN fs ¬ OFFFromStream[stream]; parsed.formatSpecificString ¬ fs; parsed.cGrammar ¬ RetrieveObjectFileFlavor[parsed.formatSpecificString].cGrammar; parsed.header ¬ RetrieveObjectFileFlavor[parsed.formatSpecificString].readHeaderProc[stream]; parsed.stabLimit ¬ parsed.header.nEntries; SystemInterface.ReleaseStreamForFile[f, stream]; RETURN[parsed]; }; GetObjectFile: PUBLIC PROC[whole: Parsed] RETURNS[SystemInterface.CirioFile] = {IF whole = NIL THEN RETURN[NIL] ELSE RETURN[whole.file]}; GetFormatString: PUBLIC PROC[whole: Parsed] RETURNS[ROPE] ~ { {IF whole = NIL THEN RETURN[NIL] ELSE RETURN[whole.formatSpecificString]}; }; GetModule: PUBLIC PROC[info: ModuleInfo] RETURNS[Module] = { IF info.whole = NIL THEN RETURN[NIL] ELSE FOR mods: LIST OF Module ¬ info.whole.modules, mods.rest WHILE mods # NIL DO IF PFSNames.Equal[mods.first.fileName, info.fileName] AND mods.first.instance = info.instance THEN RETURN[mods.first]; ENDLOOP; RETURN[NIL]; }; GetModuleInfo: PUBLIC PROC[module: Module] RETURNS[REF ModuleInfo] = { ENABLE UnreadableObjectFile => GOTO fails; IF module = NIL THEN RETURN[NIL]; RETURN[NEW[ModuleInfo¬[ whole: IF module.moduleWhole = NIL THEN module.whole ELSE module.moduleWhole, fileName: module.fileName, instance: module.instance ]]]; EXITS fails => RETURN[NIL]; }; ModuleFromParsedAndPC: PUBLIC PROC [whole: Parsed, spc: FileSegmentPC, moduleRope: ROPE ¬ NIL] RETURNS [Module] ~ { IF whole = NIL THEN RETURN[NIL] ELSE RETURN[RetrieveObjectFileFlavor[whole.formatSpecificString].moduleFromParsedAndPCProc[whole: whole, spc: spc, moduleRope: moduleRope]]; }; FindVersionStamp: PUBLIC PROC[module: Module] RETURNS[REF ObjectFiles.VersionStampInfo] = { IF module = NIL THEN RETURN[NIL]; InstallStaticVars[module]; RETURN[module.versionStampInfo]; }; FindGlobalFrameVar: PUBLIC PROC[module: Module] RETURNS[ObjectFiles.GlobalVarLoc] = { IF module = NIL THEN RETURN[NIL]; InstallStaticVars[module]; RETURN[module.globalFrameGvl] }; InstallStaticVars: PROC[module: Module] ~ { RetrieveObjectFileFlavor[module.whole.formatSpecificString].installStaticVarsProc[module]; }; UnreadableDotO: PUBLIC ERROR[msg: ROPE] = CODE; VarLocFromStab: PUBLIC PROC [stab: Stab] RETURNS [ObjectFiles.VarLoc ¬ NIL] ~ { RETURN[RetrieveObjectFileFlavor[stab.module.whole.formatSpecificString].varLocFromStabProc[stab]]; }; GetTypeRef: PUBLIC PROC[module: Module, sourceStream: IO.STREAM] RETURNS [ROPE]~ { RETURN[RetrieveObjectFileFlavor[module.whole.formatSpecificString].getTypeRefProc[sourceStream]]; }; MakeUnknownVarLoc: PUBLIC PROC [why: ROPE] RETURNS [ObjectFiles.VarLoc] ~ { RETURN [NEW [ObjectFiles.VarLocBody ¬ [bitSize: 8 -- should this be unspecdBitSize?? , indirect: FALSE--, where: unknown[why] ]]]}; CheckStaticVar: PUBLIC PROC[stab: Stab, namePrefix: ROPE, allowSuffix: BOOL] RETURNS [ObjectFiles.VarLoc] = { foundName: ROPE; foundStab: Stab; [foundName, foundStab] ¬ CheckStaticStab[stab, namePrefix, allowSuffix]; IF foundStab = NIL THEN RETURN[NIL]; RETURN VarLocFromStab[stab]}; CheckStaticStab: PROC[stab: Stab, namePrefix: ROPE, allowSuffix: BOOL] RETURNS[foundName: ROPE, foundStab: Stab] = { namePrefixLen: CARD = namePrefix.Length[]; text: ROPE ¬ ReadStabRope[stab]; length: CARD ¬ Rope.Length[text]; IF Rope.IsPrefix[namePrefix, text] THEN -- possible hit { FOR J: CARD IN [namePrefixLen..length) DO char: CHAR ¬ Rope.Fetch[text, J]; IF char = ': THEN -- bingo RETURN [text.Substr[len: J], stab]; IF char < '0 OR char > '9 OR NOT allowSuffix THEN EXIT; -- non digit ENDLOOP; }; RETURN[NIL, NIL]; }; ReadInstruction: PUBLIC PROC[module: Module, spc: FileSegmentPC] RETURNS[inst: CARD] = { IF module = NIL THEN RETURN[0] ELSE { buffer: Basics.FWORD; stream: IO.STREAM ¬ SystemInterface.GetStreamForFile[module.whole.file]; IO.SetIndex[stream, module.whole.header.text.byteOffset+spc.relPC]; TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[LONG[@buffer]], 0, 4]]}; SystemInterface.ReleaseStreamForFile[module.whole.file, stream]; RETURN[Basics.Card32FromF[buffer]]; }; }; GetSPOffset: PUBLIC PROC[module: Module, spc: FileSegmentPC] RETURNS[INT] = { IF module = NIL THEN RETURN[0] ELSE RETURN[RetrieveObjectFileFlavor[module.whole.formatSpecificString].getSPOffsetProc[module, spc]]; }; ReadInitialDataAsRope: PUBLIC PROC[module: Module, fileByteOffset: CARD] RETURNS[ROPE] = { rope: ROPE; stream: IO.STREAM ¬ SystemInterface.GetStreamForFile[module.whole.file]; { ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[module.whole.file, stream]; IO.SetIndex[stream, fileByteOffset]; rope ¬ ReadRope[stream]; }; SystemInterface.ReleaseStreamForFile[module.whole.file, stream]; RETURN[rope]; }; FunHandle: TYPE = REF FunHandleBody; FunHandleBody: PUBLIC TYPE = ObjectFilesPrivate.FunHandleBody; FunInfo: TYPE = ObjectFiles.FunInfo; GenFuns: PUBLIC PROC[module: Module, for: PROC[FunHandle] RETURNS[--stop-- BOOLEAN]] = { IF module = NIL THEN RETURN; InstallFunStabs[module]; FOR I: CARD IN [0..module.funStabs.nFunStabs) DO IF for[module.funStabs[I].funHandle] THEN EXIT; ENDLOOP; }; GetFunInfo: PUBLIC PROC[fun: FunHandle] RETURNS[FunInfo] = { funIndex: CARD ¬ fun.index; module: Module ¬ fun.module; stab: Stab ¬ module.funStabs[funIndex].stab; cName: ROPE ¬ CNameOfStab[stab]; firstPC: CARD ¬ stab.value; nextIndex: CARD ¬ funIndex+1; limitPC: CARD ¬ IF nextIndex = module.funStabs.nFunStabs THEN module.limitPC ELSE module.funStabs[nextIndex].stab.value; RETURN[[stab, cName, [firstPC, limitPC]]]; }; GetFunBrackets: PUBLIC PROC[fun: FunHandle] RETURNS[BracketPair] = { funIndex: CARD ¬ fun.index; module: Module ¬ fun.module; IF NOT module.funStabs[funIndex].bracketsScanned THEN InstallBracketPairsForOneFunStab[module, funIndex]; RETURN[module.funStabs[funIndex].brackets]; }; BracketPair: TYPE = REF BracketPairBody; BracketPairBody: PUBLIC TYPE = ObjectFilesPrivate.BracketPairBody; BracketNest: TYPE = ObjectFiles.BracketNest; BracketPairKind: TYPE = ObjectFiles.BracketPairKind; FunStabSet: TYPE = ObjectFilesPrivate.FunStabSet; FunStabSetBody: TYPE = ObjectFilesPrivate.FunStabSetBody; FunStabInfo: TYPE = ObjectFilesPrivate.FunStabInfo; SymbolProc: TYPE = ObjectFiles.SymbolProc; BracketProc: TYPE = ObjectFiles.BracketProc; GenOtherSymbolStabs: PUBLIC PROC[module: Module, for: SymbolProc] = {GenSymbolStabs[GetOuterBracketPair[module], for]}; GenFunBracketPairs: PUBLIC PROC[module: Module, for: BracketProc] = { IF module = NIL THEN RETURN; InstallFunStabs[module]; FOR I: CARD IN [0..module.funStabs.nFunStabs) DO InstallBracketPairsForOneFunStab[module, I]; IF for[module.funStabs[I].brackets] THEN EXIT; ENDLOOP; }; GetOuterBracketPair: PUBLIC PROC[module: Module] RETURNS[BracketPair] = {IF module = NIL THEN RETURN[NIL] ELSE RETURN[module.outerBracket]}; GetFunStab: PUBLIC PROC[bp: BracketPair] RETURNS[Stab] = {IF bp = NIL OR bp.kind # syntheticFun THEN RETURN[NIL] ELSE RETURN[bp.funStab]}; GetFunHandle: PUBLIC PROC[bp: BracketPair] RETURNS[FunHandle] = { InstallFunStabs[bp.module]; IF bp = NIL OR bp.kind # syntheticFun THEN RETURN[NIL] ELSE RETURN[bp.module.funStabs[bp.funIndex].funHandle]; }; GetFunHandleFromNest: PUBLIC PROC[nest: BracketNest] RETURNS[FunHandle] = {RETURN[IF nest = NIL OR nest.rest = NIL THEN NIL ELSE GetFunHandle[nest.rest.first]]}; GetBracketPairKind: PUBLIC PROC[bp: BracketPair] RETURNS[BracketPairKind] = {IF bp = NIL THEN RETURN[nil] ELSE RETURN[bp.kind]}; GetPCRange: PUBLIC PROC[bp: BracketPair] RETURNS[ObjectFiles.PCRange] = {IF bp = NIL THEN RETURN[[0, 0]] ELSE RETURN[[bp.firstPC, bp.pcLimit]]}; GenSubBracketPairs: PUBLIC PROC[bp: BracketPair, for: BracketProc] = { IF bp = NIL THEN RETURN; IF (bp.kind = syntheticFun OR bp.kind = actual) AND NOT bp.module.funStabs[bp.funIndex].bracketsScanned THEN InstallBracketPairsForOneFunStab[bp.module, bp.funIndex]; FOR bps: LIST OF BracketPair ¬ bp.innerBrackets, bps.rest WHILE bps # NIL DO IF for[bps.first] THEN EXIT; ENDLOOP; }; GenSymbolStabs: PUBLIC PROC[bp: BracketPair, for: SymbolProc] = { IF bp = NIL THEN RETURN; {module: Module ~ bp.module; SELECT bp.kind FROM syntheticFun, actual => { IF NOT module.funStabs[bp.funIndex].bracketsScanned THEN <> UnreadableObjectFile[IO.PutFR1["unscanned actual or syntheticFun bp in %g", [rope[DescribeModule[module]]] ]]; FOR stabs: StabList ¬ bp.symbols, stabs.rest WHILE stabs # NIL DO IF for[stabs.first] THEN EXIT; ENDLOOP; RETURN}; syntheticOuter => { IF Rope.Equal[module.whole.formatSpecificString, "XCOFF"] THEN { stabX: CARD ¬ module.firstStabX; limitX: CARD ¬ module.funStabs.firstX; FOR i: CARDINAL IN [stabX-module.firstStabX .. limitX-module.firstStabX) DO stab: Stab ~ module.stabs[i]; IF stab.stabType#SLine AND for[stab] THEN RETURN; ENDLOOP; FOR fsi: CARD IN [0..module.funStabs.nFunStabs) DO funStab: Stab ¬ AlterFunStab[module, fsi]; IF for[funStab] THEN RETURN; ENDLOOP; RETURN} ELSE { stabX: CARD ¬ module.firstStabX; fsi: CARDINAL ¬ 0; WHILE stabX < module.limitStabX DO limitX, newX: CARD ¬ module.limitStabX; funStabX: CARD ¬ LAST[CARD]; funStab: Stab ¬ NIL; IF fsi ERROR--MJS August 22, 1990: there are no nil bps--; ENDCASE => ERROR; }}; AlterFunStab: PROC [module: Module, funStabX: CARD] RETURNS [Stab] ~ { IF module = NIL THEN RETURN[NIL] ELSE RETURN[RetrieveObjectFileFlavor[module.whole.formatSpecificString].alterFunStabProc[module, funStabX]]; }; GetBracketNestForPC: PUBLIC PROC[module: Module, spc: FileSegmentPC] RETURNS[BracketNest] = { IF module = NIL THEN RETURN[NIL]; InstallFunStabs[module]; FOR I: CARD IN [0..module.funStabs.nFunStabs) DO IF I+1 = module.funStabs.nFunStabs OR spc.relPC < module.funStabs[I+1].stab.value THEN -- we have the function {innerNest: BracketNest; InstallBracketPairsForOneFunStab[module, I]; {fsi: FunStabInfo ~ module.funStabs[I]; IF fsi.brackets=NIL THEN UnreadableObjectFile[IO.PutFLR[ "Lack (cached) of brackets for relPC %g(%xH) in %g, probably in procedure %g", LIST[[cardinal[spc.relPC]], [cardinal[spc.relPC]], [rope[PFS.RopeFromPath[module.fileName]]], [rope[IF fsi.stab#NIL THEN fsi.stab.rope ELSE "?NIL stab?"]]] ]]; innerNest ¬ FindBracketNestInBracketPair[fsi.brackets, spc]; RETURN[CONS[module.outerBracket, CONS[fsi.brackets, innerNest]]]; }}; ENDLOOP; RETURN[LIST[module.outerBracket]]; }; FindBracketNestInBracketPair: PROC[bp: BracketPair, spc: FileSegmentPC] RETURNS[BracketNest] = { FOR subBpis: LIST OF BracketPair ¬ bp.innerBrackets, subBpis.rest WHILE subBpis # NIL DO IF spc.relPC < subBpis.first.firstPC THEN RETURN[NIL]; IF spc.relPC < subBpis.first.pcLimit THEN RETURN[CONS[subBpis.first, FindBracketNestInBracketPair[subBpis.first, spc]]]; ENDLOOP; RETURN[NIL]; }; StabRecList: TYPE = LIST OF StabRec; StabRec: TYPE = RECORD[i, count, nextX: CARD, stab, firstLocal: Stab]; InsertFunStabSorted: PROCEDURE [list: StabRecList, stab: StabRec] RETURNS [StabRecList]~ { IF list = NIL THEN RETURN[LIST[stab]] ELSE IF stab.stab.value > list.first.stab.value THEN RETURN[CONS[stab, list]] ELSE RETURN[CONS[list.first, InsertFunStabSorted[list.rest, stab]]]; }; ScanModuleStructure: PUBLIC PROC [module: Module, perFn: FnConsumer] ~ { flavor: ObjectFilesPrivate.ObjectFileFlavor ~ RetrieveObjectFileFlavor[module.whole.formatSpecificString]; flavor.scanModuleStructure[module, perFn]; RETURN}; ScanFnStructure: PUBLIC PROC [ module: Module, funStab: Stab, firstLocal: Stab _ NIL, nextX: CARD, perParm: PROC [Stab] _ NIL, perBracket: BracketConsumer _ NIL ] RETURNS [limitX, limitPc: CARD] ~ { flavor: ObjectFilesPrivate.ObjectFileFlavor ~ RetrieveObjectFileFlavor[module.whole.formatSpecificString]; RETURN flavor.scanFnStructure[module, funStab, firstLocal, nextX, perParm, perBracket]}; ScanBracketStructure: PUBLIC PROC [ module: Module, funStab: Stab, first: Stab, perLocal: PROC [Stab] _ NIL, perSubBracket: BracketConsumer _ NIL ] RETURNS [limitX, firstPc, limitPc: CARD] ~ { flavor: ObjectFilesPrivate.ObjectFileFlavor ~ RetrieveObjectFileFlavor[module.whole.formatSpecificString]; RETURN flavor.scanBktStructure[module, funStab, first, perLocal, perSubBracket]}; InstallFunStabs: PROC[module: Module] = { flavor: ObjectFilesPrivate.ObjectFileFlavor ~ RetrieveObjectFileFlavor[module.whole.formatSpecificString]; fnsOrderedByStart: BOOL ~ flavor.fnsOrderedByStart; funStabs: StabRecList ¬ NIL; nFunStabs: CARD ¬ 0; index: CARD; nextX: CARD ¬ module.limitStabX; firstFunStabX: CARD ¬ LAST[CARD]; funStabSet: FunStabSet; IF module.funStabsInstalled THEN RETURN; IF flavor.scanModuleStructure=NIL THEN { privX: CARD ¬ LAST[CARD]; FOR I: CARD IN [0..module.stabs.nStabs) DO stab: Stab ¬ module.stabs[I]; IF stab.module = NIL THEN LOOP; IF stab.stabType = Fun THEN { IF firstFunStabX = LAST[CARD] THEN firstFunStabX ¬ stab.stabX; IF privX # LAST[CARD] THEN { funStabs ¬ InsertFunStabSorted[funStabs, [nFunStabs, I - privX, 0, module.stabs[privX], NIL]]; nFunStabs ¬ nFunStabs+1; }; privX ¬ I; }; ENDLOOP; IF privX # LAST[CARD] THEN { funStabs ¬ InsertFunStabSorted[funStabs, [nFunStabs, module.stabs.nStabs - privX, 0, module.stabs[privX], NIL]]; nFunStabs ¬ nFunStabs+1; }; } ELSE { NoteFn: PROC [funStab: Stab, firstLocal: Stab _ NIL, nextX: CARD] RETURNS [limitX: CARD] ~ { IF nFunStabs=0 THEN firstFunStabX _ funStab.stabX; limitX _ ScanFnStructure[module, funStab, firstLocal, nextX, NIL, NIL].limitX; funStabs _ InsertFunStabSorted[funStabs, [nFunStabs, limitX - funStab.stabX, nextX, funStab, firstLocal]]; nFunStabs ¬ nFunStabs+1; RETURN}; ScanModuleStructure[module, NoteFn]; }; funStabSet ¬ NEW[FunStabSetBody[nFunStabs]]; funStabSet.firstX ¬ firstFunStabX; index ¬ nFunStabs-1; FOR stabs: StabRecList ¬ funStabs, stabs.rest WHILE stabs # NIL DO firstX: CARD ¬ stabs.first.stab.stabX; handle: FunHandle ¬ NEW[FunHandleBody¬[module, index --stabs.first.i--]]; IF fnsOrderedByStart AND nextX <= firstX THEN UnreadableObjectFile[IO.PutFR["bug in InstallFunStabs at %g'th fun in %g", [cardinal[stabs.first.i]], [rope[DescribeModule[module]]] ]]; funStabSet[index --stabs.first.i--] ¬ [stabs.first.stab, firstX, stabs.first.count, stabs.first.firstLocal, stabs.first.nextX, handle, FALSE, NIL]; nextX ¬ firstX; index ¬ index - 1; ENDLOOP; module.funStabs ¬ funStabSet; module.funStabsInstalled ¬ TRUE; RETURN}; InstallBracketPairsForOneFunStab: PROC [module: Module, funStabIndex: CARD] ~ { flavor: ObjectFilesPrivate.ObjectFileFlavor ~ RetrieveObjectFileFlavor[module.whole.formatSpecificString]; fsi: FunStabInfo ~ module.funStabs[funStabIndex]; funStab: Stab ~ fsi.stab; fbp: BracketPair; parmsTail: StabList _ NIL; innerBracketsTail: LIST OF BracketPair _ NIL; NoteParm: PROC [stab: Stab] ~ {[fbp.symbols, parmsTail] _ AppendStabToList[stab, fbp.symbols, parmsTail]}; NoteTopBlock: PROC [first: Stab] RETURNS [limitX: CARD] ~ { bp: BracketPair; this: LIST OF BracketPair; [bp, limitX] _ MakeBracket[first]; this _ LIST[bp]; IF innerBracketsTail=NIL THEN fbp.innerBrackets _ this ELSE innerBracketsTail.rest _ this; innerBracketsTail _ this; RETURN}; MakeBracket: PROC [first: Stab] RETURNS [bp: BracketPair, limitX: CARD] ~ { localsTail: StabList _ NIL; innerTail: LIST OF BracketPair _ NIL; AddLocal: PROC [stab: Stab] ~ {[bp.symbols, localsTail] _ AppendStabToList[stab, bp.symbols, localsTail]}; AddChild: PROC [first: Stab] RETURNS [limitX: CARD] ~ { sub: BracketPair; this: LIST OF BracketPair; [sub, limitX] _ MakeBracket[first]; this _ LIST[sub]; IF innerTail#NIL THEN innerTail.rest _ this ELSE bp.innerBrackets _ this; innerTail _ this}; bp _ NEW [BracketPairBody _ [ module: module, kind: actual, firstX: first.stabX, limitX: 0, firstPC: 0, pcLimit: 0, funStab: funStab, funIndex: funStabIndex, symbols: NIL, innerBrackets: NIL]]; [bp.limitX, bp.firstPC, bp.pcLimit] _ ScanBracketStructure[module, funStab, first, AddLocal, AddChild]; RETURN [bp, bp.limitX]}; IF module.funStabs[funStabIndex].bracketsScanned THEN RETURN; module.funStabs[funStabIndex].bracketsScanned _ TRUE; -- if error occurs, then we won't do this again. IF flavor.installBracketPairsForOneFunStabProc#NIL THEN { flavor.installBracketPairsForOneFunStabProc[module, funStabIndex]; RETURN}; module.funStabs[funStabIndex].brackets _ fbp _ NEW[BracketPairBody_[ module: module, kind: syntheticFun, firstX: funStab.stabX, limitX: 0, firstPC: funStab.value, pcLimit: 0, funStab: funStab, funIndex: funStabIndex, symbols: NIL, innerBrackets: NIL]]; [fbp.limitX, fbp.pcLimit] _ ScanFnStructure[module, fsi.stab, fsi.firstLocal, fsi.nextX, NoteParm, NoteTopBlock]; IF fbp.innerBrackets#innerBracketsTail --more than one bracket-- THEN { tbp: BracketPair ~ NEW[BracketPairBody_[ module: module, kind: actual, firstX: fbp.innerBrackets.first.firstX, limitX: innerBracketsTail.first.limitX, firstPC: fbp.innerBrackets.first.firstPC, pcLimit: innerBracketsTail.first.pcLimit, funStab: funStab, funIndex: funStabIndex, symbols: NIL, innerBrackets: fbp.innerBrackets]]; fbp.innerBrackets _ LIST[tbp]}; RETURN}; AppendStabToList: PROC [elt: Stab, head, tail: StabList] RETURNS [StabList, StabList] ~ { this: StabList ~ LIST[elt]; IF tail#NIL THEN tail.rest _ this ELSE head _ this; RETURN [head, this]}; ScanSymbolStabs: PUBLIC PROC[module: Module, firstX: CARD, head, tail: StabList] RETURNS[--nextX-- CARD, --head, tail of collected symbols-- StabList, StabList] = {x: CARD ¬ firstX; WHILE x < module.limitStabX DO stab: Stab ¬ ReadStab[module, x]; IF stab = NIL THEN LOOP; SELECT stab.stabType FROM LBrac, RBrac, Fun, GSym, STSym, LCSym => RETURN[x, head, tail]; SLine => NULL; -- we ignore SLines ENDCASE => { -- we simply collect all others as potentially interesting to our clients symbol: StabList ¬ LIST[stab]; IF head#NIL AND stab=head.first THEN ERROR; IF head = NIL THEN head ¬ symbol ELSE tail.rest ¬ symbol; tail ¬ symbol}; x ¬ x+1; ENDLOOP; RETURN[x, head, tail]}; LineNumToPCMap: TYPE ~ ObjectFilesPrivate.LineNumToPCMap; LineNumToPCMapBody : TYPE ~ ObjectFilesPrivate.LineNumToPCMapBody; PCtoLineNumMap: TYPE ~ REF PCtoLineNumMapBody; PCtoLineNumMapBody: TYPE ~ ObjectFilesPrivate.PCtoLineNumMapBody; SLineData: TYPE = ObjectFilesPrivate.SLineData; GetPCForLineNum: PUBLIC PROC[module: Module, cLineNum: CARD] RETURNS[FileSegmentPC] = TRUSTED BEGIN map: LineNumToPCMap; IF module = NIL THEN RETURN[ObjectFiles.NoFileSegmentPC]; IF module.lineNumToPC = NIL THEN { IF Rope.Equal[module.whole.formatSpecificString, "SGI"] THEN { stream: IO.STREAM ¬ SystemInterface.GetStreamForFile [module.whole.file]; parsed: Parsed ¬ LOOPHOLE[module.whole, Parsed]; wireTables: SGI.WireTables ¬ NARROW[parsed.privateInfo, SGI.WireTables]; SGI.UnPackLineNumbers[stream, module, wireTables]; } ELSE ERROR; }; map ¬ module.lineNumToPC; FOR I: CARDINAL IN [0..map.nSlines) DO IF map[I].cLineNum >= cLineNum THEN RETURN[map[I].parsedRelPC]; ENDLOOP; IF map.nSlines # 0 THEN RETURN[[ObjectFiles.noFSeg, module.limitPC]]; RETURN[ObjectFiles.NoFileSegmentPC]; -- probably no dbx stabs END; GetLineNumForPC: PUBLIC PROC[module: Module, spc: FileSegmentPC] RETURNS[CARD] = TRUSTED BEGIN map: PCtoLineNumMap; IF module = NIL THEN RETURN[0]; IF module.pcToLineNum = NIL THEN { IF Rope.Equal[module.whole.formatSpecificString, "SGI"] THEN { stream: IO.STREAM ¬ SystemInterface.GetStreamForFile [module.whole.file]; parsed: Parsed ¬ LOOPHOLE[module.whole, Parsed]; wireTables: SGI.WireTables ¬ NARROW[parsed.privateInfo, SGI.WireTables]; SGI.UnPackLineNumbers[stream, module, wireTables]; } ELSE ERROR; }; map ¬ module.pcToLineNum; FOR I: CARDINAL DECREASING IN [0..map.nSlines) DO IF map[I].parsedRelPC.relPC <= spc.relPC THEN RETURN[map[I].cLineNum]; ENDLOOP; IF map.nSlines # 0 THEN RETURN[map[0].cLineNum]; RETURN[0]; -- probably no dbx stabs END; ReadStab: PUBLIC PROC[module: Module, stabX: CARD] RETURNS[Stab] = { IF module=NIL THEN RETURN[NIL]; IF stabX >= module.limitStabX THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["Attempt to fetch stab (%g) beyond limit (%g) from %g", [cardinal[stabX]], [cardinal[module.limitStabX]], [rope[PFS.RopeFromPath[module.fileName]]] ]]; RETURN[module.stabs[stabX- module.firstStabX]]; }; ReadStabRope: PUBLIC ENTRY PROC [stab: Stab] RETURNS [rope: ROPE] ~ { ENABLE UNWIND => NULL; IF stab=NIL THEN RETURN[NIL] ELSE RETURN[stab.rope]}; CNameOfStab: PUBLIC PROC[stab: Stab] RETURNS[rope: ROPE] = { ENABLE UNWIND => NULL; rope: ROPE ¬ ReadStabRope[stab]; SELECT stab.stabType FROM Fun, PSym, LSym, RSym, GSym, LCSym, STSym => { colPos: INT ¬ Rope.Find[rope, ":"]; IF colPos < 0 THEN RETURN[rope] ELSE RETURN[Rope.Substr[rope, 0, colPos]]; }; ENDCASE => RETURN[rope]; }; CGrammarOfStab: PUBLIC PROC[stab: Stab] RETURNS[ObjectFiles.CGrammar] ~ { IF stab # NIL AND stab.module # NIL AND stab.module.whole # NIL THEN RETURN[stab.module.whole.cGrammar] ELSE RETURN [UNKNOWN] }; 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 start: CARD ¬ 0; end: CARD ¬ RopeBufferSize; -- tentative nChars: CARD; rt: Rope.Text; TRUSTED{[] ¬ IO.UnsafeGetBlock[s, [LOOPHOLE[@RopeBuffer­], 0, RopeBufferSize]]}; IF NOT rope.IsEmpty AND RopeBuffer[0] = '\000 THEN EXIT; FOR I: CARD IN [0..RopeBufferSize) DO IF RopeBuffer[I] = '\000 THEN LOOP ELSE {start ¬ I; EXIT}; ENDLOOP; FOR I: CARD IN [start..RopeBufferSize) DO IF RopeBuffer[I] = '\000 THEN {end ¬ I; EXIT}; ENDLOOP; nChars ¬ end - start; rt ¬ Rope.NewText[nChars]; FOR I: CARD IN [0..nChars) DO rt[I] ¬ RopeBuffer[start + 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 end < RopeBufferSize THEN EXIT; ENDLOOP; RETURN[rope]; END; ParseNameRope: PUBLIC PROC[stab: Stab] RETURNS[ObjectFiles.NameAndNumber] = { BadParse: ERROR = CODE; { ENABLE BadParse => GO TO failure; text: ROPE ¬ ReadStabRope[stab]; pos: INT ¬ 0; length: INT ¬ Rope.Length[text]; findFailure: INT ~ -1; ReadInitialName: PROC RETURNS[ROPE] = { sep1: ROPE ~ "_"; -- an underscore in modern Ascii. sep1Index: INT ¬ text.Find[s2: sep1]; IF sep1Index = findFailure THEN BadParse[]; pos ¬ sep1Index+1; RETURN[text.Substr[len: sep1Index]]; }; ReadChar: PROC RETURNS[CHAR] = { tentativeChar: CHAR ¬ Rope.Fetch[text, pos]; IF tentativeChar < '0 OR '9 < tentativeChar THEN {pos ¬ pos+1; RETURN[tentativeChar]} ELSE RETURN[' ]; }; ReadNumber: PROC RETURNS[INT] = { firstNonDigit: INT ¬ pos; number: INT; WHILE firstNonDigit < length DO c: CHAR ¬ Rope.Fetch[text, firstNonDigit]; IF c < '0 OR '9 < c THEN EXIT; firstNonDigit ¬ firstNonDigit + 1; ENDLOOP; IF firstNonDigit = pos THEN BadParse[]; number ¬ Convert.IntFromRope[text.Substr[start: pos, len: firstNonDigit-pos]]; IF text.Fetch[pos] = '0 THEN number ¬ -number; pos ¬ firstNonDigit; RETURN[number]; }; ReadTrailer: PROC RETURNS[ROPE] = { trailerStart: INT ¬ pos; colonLoc: INT ¬ Rope.Index[text, pos, ":"]; pos ¬ colonLoc; RETURN[text.Substr[start: trailerStart, len: colonLoc-trailerStart]]; }; name: ROPE ¬ ReadInitialName[]; char: CHAR ¬ ReadChar[]; number: INT ¬ ReadNumber[!BadParse => GOTO failure]; trailer: ROPE ¬ ReadTrailer[]; RETURN[[name, char, number, trailer, TRUE]]; EXITS failure => RETURN[[NIL, ' , 0, "", FALSE]]; }; }; RopeForBracketPair: PUBLIC PROC[bp: BracketPair] RETURNS[ROPE] = {IF bp = NIL THEN RETURN[NIL] ELSE RETURN[Rope.Cat["<", Convert.RopeFromCard[bp.firstX], ", ", Convert.RopeFromCard[bp.limitX], ">"]]}; PrintModule: Commander.CommandProc = { args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; name: ROPE ¬ args[1]; type: ROPE ¬ IF args.argc < 4 THEN NIL ELSE args[3]; path: PATH ¬ PFS.PathFromRope[name]; outPath: PATH ¬ PrintFileName[path]; outFile: IO.STREAM ¬ PFS.StreamOpen[outPath, create]; fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[]; { ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet]; file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path]; whole: Parsed ¬ CreateParsed[file, type]; relativePC: CARD ¬ IF args.argc < 3 THEN 0 ELSE Convert.CardFromRope[args[2]]; module: Module ¬ ModuleFromParsedAndPC[whole, [[0, ""], relativePC]]; IO.PutF[outFile, "Module details for %g embedding at relative pc: %g\N\N", IO.rope[name], IO.card[relativePC]]; IO.PutF[outFile, "textSize: %g, nEntries: %g\N", IO.card[whole.header.text.byteLength], IO.card[whole.header.nEntries]]; IO.PutF1[cmd.out, "\Ndetails being written to %g\N\N", IO.rope[PFS.RopeFromPath[outPath]]]; FOR x: CARD IN [0..module.stabs.nStabs) DO stab: Stab; rope: ROPE; fields: ROPE; stab ¬ ReadStab[module, module.firstStabX+x]; IF stab = NIL THEN LOOP; rope ¬ ReadStabRope[stab]; fields ¬ RopeForStabFields[stab]; IO.PutF1[outFile, "%g\N", IO.rope[fields]]; IF Rope.Length[rope] # 0 THEN IO.PutF1[outFile, " %g\N", IO.rope[rope]]; IO.PutRope[outFile, "\N"]; ENDLOOP; }; SystemInterface.CloseFileSet[fileSet]; IO.Close[outFile]; IO.PutF1[cmd.out, "\Ndetails written to %g\N\N", IO.rope[PFS.RopeFromPath[outPath]]]; }; RopeForStabFields: PROC[stab: Stab] RETURNS[ROPE] = { fields: ROPE ¬ NIL; fields ¬ Rope.Concat[fields, IO.PutFR1["stabX: %g, ", IO.card[stab.stabX]]]; fields ¬ Rope.Concat[fields, IO.PutFR1["stabType: %g, ", IO.rope[RopeForStabType[stab.stabType]]]]; fields ¬ Rope.Concat[fields, IO.PutFR1["size: %g, ", IO.card[stab.size]]]; fields ¬ Rope.Concat[fields, IO.PutFR1["value: %g, ", IO.card[stab.value]]]; RETURN[fields]; }; RopeForStabType: PUBLIC PROC[stabType: StabType] RETURNS[ROPE] = { RETURN[SELECT stabType FROM BIncl => "BIncl", EIncl => "EIncl", Excl => "Excl", Fun => "Fun", GSym => "GSym", Invalid => "Invalid", LBrac => "LBrac", LCSym => "LCSym", LSym => "LSym", Main => "Main", PSym => "PSym", RBrac => "RBrac", RSym => "RSym", SLine => "SLine", SO => "SO", SOL => "SOL", STSym => "STSym", Unspecified => "Unspecified", ENDCASE => ""]; }; PrintFileName: PROC[filePath: PATH] RETURNS[PATH] = { stemRope: ROPE ¬ filePath.ShortName.ComponentRope; length: INT ¬ Rope.Length[stemRope]; firstDot: INT ¬ Rope.Find[stemRope, ".", 1]; RETURN[PFS.PathFromRope[Rope.Concat[Rope.Substr[stemRope, 0, firstDot], ".ObjectFileDetails"]]]; }; ShowModuleFunctions: Commander.CommandProc = { args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; path: PATH ¬ PFS.PathFromRope[args[1]]; type: ROPE ¬ IF args.argc < 4 THEN NIL ELSE args[3]; fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[]; { ENABLE { UNWIND => SystemInterface.CloseFileSet[fileSet]; SystemInterface.ShowReport => { cmd.out.PutF["%g: %g\n", [atom[priority]], [rope[msgText]] ]; RESUME}; }; file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path]; whole: Parsed ¬ CreateParsed[file, type]; relativePC: CARD ¬ IF args.argc < 3 THEN 0 ELSE Convert.CardFromRope[args[2]]; module: Module ¬ ModuleFromParsedAndPC[whole, [[0, NIL], relativePC]]; ShowOne: PROC[fun: FunHandle] RETURNS[--stop-- BOOLEAN] = { info: FunInfo ¬ GetFunInfo[fun]; bp: BracketPair ¬ GetFunBrackets[fun]; IO.PutFL[cmd.out, "%g\N\Tx: [%g..%g), pc: [%g..%g)\N", LIST[IO.rope[info.cName], IO.card[bp.firstX], IO.card[bp.limitX], IO.card[bp.firstPC], IO.card[bp.pcLimit]] ]; RETURN[FALSE]; }; IO.PutF[cmd.out, "Module functions for %g embedding at relative pc = %g\N\N", IO.rope[PFS.RopeFromPath[path]], IO.card[relativePC]]; GenFuns[module, ShowOne]; }; }; ShowOneModuleFunction: Commander.CommandProc = { args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; path: PATH ¬ PFS.PathFromRope[args[1]]; type: ROPE ¬ IF args.argc < 4 THEN NIL ELSE args[3]; fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[]; BEGIN ENABLE { UNWIND => SystemInterface.CloseFileSet[fileSet]; SystemInterface.ShowReport => { cmd.out.PutF["%g: %g\n", [atom[priority]], [rope[msgText]] ]; RESUME}; }; file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path]; whole: Parsed ¬ CreateParsed[file, type]; relativePC: CARD ¬ IF args.argc < 3 THEN 0 ELSE Convert.CardFromRope[args[2]]; module: Module ¬ ModuleFromParsedAndPC[whole, [[0, ""], relativePC]]; bn: BracketNest ¬ GetBracketNestForPC[module, [[0, ""], relativePC]]; funbp: BracketPair ¬ bn.rest.first; IO.PutF[cmd.out, "\NOne Module function for %g embedding at relative pc = %g\N\N", IO.rope[PFS.RopeFromPath[path]], IO.card[relativePC]]; IO.PutF1[cmd.out, "%g\N", IO.rope[CNameOfStab[funbp.funStab]]]; Showbps[cmd.out, 5, funbp]; END; }; Showbps: PROC[on: IO.STREAM, depth: INT, bp: BracketPair] = { tab: PROC[plus: CARD] = {FOR I: CARD IN [0..depth+plus) DO IO.PutRope[on, " "] ENDLOOP}; tab[0]; IO.PutFL[on, "{ x: [%g..%g), pc: [%g..%g)\N", LIST[IO.card[bp.firstX], IO.card[bp.limitX], IO.card[bp.firstPC], IO.card[bp.pcLimit]] ]; FOR symbols: StabList ¬ bp.symbols, symbols.rest WHILE symbols # NIL DO ShowStab[on, depth, symbols.first]; ENDLOOP; FOR innerbps: LIST OF BracketPair ¬ bp.innerBrackets, innerbps.rest WHILE innerbps # NIL DO Showbps[on, depth+5, innerbps.first]; ENDLOOP; tab[0]; IO.PutRope[on, "}\N\N"]; }; ShowStab: PROC[on: IO.STREAM, depth: CARD, stab: Stab] = { fields: ROPE ¬ RopeForStabFields[stab]; text: ROPE ¬ ReadStabRope[stab]; FOR I: CARD IN [0..depth) DO IO.PutRope[on, " "] ENDLOOP; IO.PutF1[on, "%g\N", IO.rope[fields]]; IF Rope.Length[text] # 0 THEN { FOR I: CARD IN [0..depth+2) DO IO.PutRope[on, " "] ENDLOOP; IO.PutF1[on, "%g\N", IO.rope[text]]; }; IO.PutRope[on, "\N"]; }; ShowModuleGlobalStabs: Commander.CommandProc = { args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; path: PATH ¬ PFS.PathFromRope[args[1]]; type: ROPE ¬ IF args.argc < 4 THEN NIL ELSE args[3]; fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[]; { ENABLE { UNWIND => SystemInterface.CloseFileSet[fileSet]; SystemInterface.ShowReport => { cmd.out.PutF["%g: %g\n", [atom[priority]], [rope[msgText]] ]; RESUME}; }; file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path]; whole: Parsed ¬ CreateParsed[file, type]; relativePC: CARD ¬ IF args.argc < 3 THEN 0 ELSE Convert.CardFromRope[args[2]]; module: Module ¬ ModuleFromParsedAndPC[whole, [[0, ""], relativePC]]; ReportStab: PROC [stab: Stab] RETURNS [--stop-- BOOLEAN] ~ { IF stab.module#NIL THEN ShowStab[cmd.out, 5, stab]; RETURN [FALSE]}; IO.PutF[cmd.out, "\NModule global stabs for %g embedding at relative pc = %g\N\N", IO.rope[PFS.RopeFromPath[path]], IO.card[relativePC]]; InstallFunStabs[module]; GenOtherSymbolStabs[module, ReportStab]; }; }; CheckModuleBrackets: Commander.CommandProc = { args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; path: PATH ¬ PFS.PathFromRope[args[1]]; type: ROPE ¬ IF args.argc < 4 THEN NIL ELSE args[3]; fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[]; { ENABLE { UNWIND => SystemInterface.CloseFileSet[fileSet]; SystemInterface.ShowReport => { cmd.out.PutF["%g: %g\n", [atom[priority]], [rope[msgText]] ]; RESUME}; }; file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path]; whole: Parsed ¬ CreateParsed[file, type]; relativePC: CARD ¬ IF args.argc < 3 THEN 0 ELSE Convert.CardFromRope[args[2]]; module: Module ¬ ModuleFromParsedAndPC[whole, [[0, ""], relativePC]]; CheckOne: PROC[fun: FunHandle] RETURNS[--stop-- BOOLEAN] = { info: FunInfo ¬ GetFunInfo[fun]; funBPI: BracketPair ¬ GetFunBrackets[fun]; RETURN[FALSE]; }; IO.PutF[cmd.out, "\Nchecking Module brackets for %g embedding at relative pc = %g\N\N", IO.rope[PFS.RopeFromPath[path]], IO.card[relativePC]]; GenFuns[module, CheckOne]; }; }; <> UnreadableObjectFile: PUBLIC ERROR[msg: ROPE] = CODE; RaiseUnreadableObjectFileForFun: PUBLIC PROC[msg: ROPE, module: Module, fun: Stab] = { funName: ROPE ¬ IF fun = NIL THEN NIL ELSE CNameOfStab[fun]; UnreadableObjectFile[IO.PutFR["%g in function: %g of %g", [rope[msg]], [rope[funName]], [rope[DescribeModule[module]]] ]]; }; RaiseUnreadableObjectFileForModule: PROC[msg: ROPE, stabX: CARD, module: Module] = { UnreadableObjectFile[IO.PutFR["%g at stabX: %g in %g", [rope[msg]], [cardinal[stabX]], [rope[DescribeModule[module]]] ]]; }; DescribeModule: PUBLIC PROC [module: Module] RETURNS [ROPE] ~ { moduleName: PATH ~ IF module = NIL THEN PFSNames.EmptyPath ELSE module.fileName; wholeName: PATH ~ IF module = NIL OR module.whole = NIL OR module.whole.file = NIL THEN PFSNames.EmptyPath ELSE SystemInterface.GetNameOfFile[module.whole.file]; RETURN IO.PutFR["module: %g of objectFile: %g", [rope[PFS.RopeFromPath[moduleName]]], [rope[PFS.RopeFromPath[wholeName]]] ]}; Commander.Register["PrintModule", PrintModule, "usage:\N\TPrintModule name relPC [format]\N\Twhere\N\T\Tname is file name of the containing whole object file\N\T\TrelPC is a containingWhole-relative PC within the module\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["ShowModuleFunctions", ShowModuleFunctions, "usage:\N\TShowModuleFunctions name relPC [format]\N\Twhere\N\T\Tname is file name of the containing whole object file\N\T\TrelPC is a containingWhole-relative PC within the module\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["ShowOneModuleFunction", ShowOneModuleFunction, "usage:\N\TShowOneModuleFunction name relPC [format]\N\Twhere\N\T\Tname is file name of the containing whole object file\N\T\TrelPC is a containingWhole-relative PC within the module\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["ShowModuleGlobalStabs", ShowModuleGlobalStabs, "usage:\N\TShowModuleGlobalStabs name relPC [format]\N\Twhere\N\T\Tname is file name of containing whole object file\N\T\TrelPC is a containingWhole-relative PC within the module\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["CheckModuleBrackets", CheckModuleBrackets, "usage:\N\TCheckModuleBrackets name relPC [format]\N\Twhere\N\T\Tname is file name of containing whole object file\N\T\TrelPC is a containingWhole-relative PC within the module\N\T\Tformat is XCOFF or SunADotOut"]; }.. H ObjectFilesImpl.mesa Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Modified from DotOAccessImpl.mesa Laurie Horton, June 24, 1992 6:08 pm PDT Philip James, February 22, 1992 11:05 am PST Katsuyuki Komatsu January 23, 1993 4:35 pm PST Last tweaked by Mike Spreitzer January 21, 1993 5:53 pm PST Willie-s, June 30, 1992 2:42 pm PDT Jas, January 5, 1993 2:27 pm PST Ychou, June 29, 1993 12:06 pm PDT Useful types Following types are defined in ObjectFiles and ObjectFilesPrivate Registration Whole Object Files Are we supposed to create the modules list too? Maybe we should push this down into a file specific implementation... Modules This should search info.whole.modules looking for info.fileName & info.instance. Finding Modules Globalish variables a returned NIL stab means that the check failed we expect to find 0 or more digits followed by a colon Instructions Initialized Storage Functions pcs are relative to the whole Bracket Pairs For Function (synthetic) bracket pairs: leftX is the index of the FUN stab, and rightX is one less than the index of the next function stab, except for the last such bracketPair, in which case rightX is the highest existing stab index. For this pair, the pc on the LBrac is the pc on the Fun stab, and the pc on the RBrac is the pc of the following Fun stab (or, if not embedded or embedded and the last embedded, then header.textSize, or if embedded and not the last embedded, then the first PC occurring in the next embedded file). this is a crock, but until I can build a bracket pair for a function without building the nested bracket pairs, I don't have a bp to hand to for. GetStabRange: PUBLIC PROC[bp: BracketPair] RETURNS[StabRange] = {IF bp = NIL THEN RETURN[[0, 0]] ELSE RETURN[[bp.firstX, bp.limitX-bp.firstX]]}; foo: IO.STREAM; funStab _ module.funStabs[fsi].stab; IF funStab#NIL AND for[funStab] THEN RETURN; we assume that the fun stabs appear in increasing pc order terminated by a LBrac, RBrac, Fun, global symbol, or attempting to go past the end of the symbol table. if we reach here, then we have attempted to go past the end of the symbol table. C Line-Number to Relative-PC maps sorted by Line Num sorted by FileSectionId pc will be relative to containing objectFile. One should think as follows. For the map from PC to CLine number: sort the SLines, first by increasing PC, and second by increasing CLine Then, search backwards among the SLines until we find the first SLine with a PC less or equal to the target pc. Report the CLine in that SLine. For the map from CLine number to PC sort the SLines, first by increasing CLine, then by increasing PC Then, search forwards among the SLines until we find the first SLine with CLine greater or equal to the target CLine. Report the PC in that SLine. It is intended to support the following model: given a pc, find the line for which that pc was actually generated given a line, find the first pc generated after the start of that line. we tacitly assume that whenever the C compiler generates an SLine containing , that the compiler is processing CLine, and that its "nextPC" variable is PC. It may be that no instructions are actually generated until we get to another CLine. Must be a SGI file, need to unpack the line numbers pc is expected to be relative to containing objectFile. We attempt to find the highest line number such that the pc applies to an instruction generated after the imaginary point at the start of the line. Must be a SGI file, need to unpack the line numbers Stabs This routine treats stabX as relative to the entire Module. symbol ropes we assume that the stream has been positioned at the beginning of a sequence of chars terminated by a '\000 char. Our assumption about the initial stream position does not strictly hold. We have observed strings like &24 _ RopeBuffer ^(100)['\000, '\000, '\000, '\000, '@, '(, '#, '), 'm, 'o, 'b, '_, 'v, 'e, 'r, 's, 'i, 'o, 'n, ' , '[, '1, '8, '7, '3, '3, '5, '2, '2, '5, '1, ...] Take care of case where this buffer ends in non-zero character and next starts with zero. Find first non-zero character. Find last non-zero character after the first non-zero character. ReadRope: PROC[s: IO.STREAM] RETURNS[rope: ROPE] = { 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]; }; Name Ropes note: each of the following procedures read a field starting with the char at pos, then update pos to point to the first character following the field that they just read. this works even if there is no colon Printing Print Module use: PrintModule /dir/.../dir/[sun4/]foo[.c2c].o relativePC writes foo.ModuleDetails stream: IO.STREAM _ SystemInterface.GetStreamForFile[whole.file]; nest so that we can catch unwinds and release the stream fields _ Rope.Concat[fields, IO.PutFR1["rope: %g, ", IO.rope[stab.rope]]]; ShowModuleFunctions foo.o pc (note: stab indices are only approx plus or minus 1) ShowOneModuleFunction foo.o pc (note: stab indices are only approx plus or minus 1, depending on whether one is dealing with a synthetic fun bracket or a real bracket. Recall that the symbols stabs are not even between the brackets anyway, so no one should be looking at these values.) ShowModuleGlobalStabs foo.o pc Random test FindStabRange This procedure can be used to compare the mechanism embedded in the load state with our Alternative find routine in this module. Errors Main code Ê4–"cedarcode" style•NewlineDelimiter ™codešœ™Kšœ ÏeœC™NK™!K™(K™,K™.K™;K™#K™ K™!—K˜šÏk ˜ Kšœžœžœ˜"Kšœ žœ˜'Kšœ žœ˜*Kšœžœ*˜7Kšœ žœ˜’Kšœžœñ˜‰Kšžœžœežœ˜…Kšžœžœ*˜3Kšœ žœžœ.˜BKšœžœMžœ˜kKšœžœ!˜*Kšœžœƒ˜˜—K˜K˜K˜šÏnœžœž˜Kšžœ+žœžœ&˜lKšžœ ˜'—Kšœ˜K˜™ Kšžœžœ žœ˜Kšžœžœžœ˜—K˜K˜™AK™Kšœžœžœ ˜Kšœ žœžœ!˜8K˜Kšœžœžœ ˜Kšœ žœžœ!˜8Kšœ žœ˜*K™Kšœžœžœ ˜Kšœ žœ!˜1K˜Kšœžœ˜0K˜Kšœžœ˜Kšœ žœ˜&Kšœ žœ˜-Kšœ žœ˜+K˜Kšœžœ&˜;Kšœžœ&˜;Kšœ žœ!˜1Kšœ žœ!˜1—K™K™ K™Kš œ žœžœžœ žœžœ&˜WK˜Kšœ8žœ˜K˜šœ žœ˜$K™—K˜šŸœžœžœžœ žœ œžœ˜XKšžœ žœžœžœ˜K˜š žœŸœžœžœ ž˜0Kšžœ#žœžœ˜/Kšžœ˜—Kšœ˜—K˜šŸ œžœžœžœ ˜:Kšœ˜Kšœ žœ ˜K˜K˜,Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜Kš œ žœžœ'žœžœ'˜xKšžœ$˜*Kšœ˜—K˜šŸœžœžœžœ˜BKšœ˜Kšœ žœ ˜K˜Kšžœžœ+žœ4˜iKšžœ%˜+Kšœ˜—K™—šœ ™ K˜Kšœ žœžœ˜(Kšœžœžœ&˜BK˜K˜Kšœ žœ˜,Kšœžœ˜4K˜Kšœ žœ!˜1Kšœžœ%˜9Kšœ žœ"˜3K˜Kšœ žœ˜*Kšœ žœ˜,K˜K˜KšœBžœÑ™–K˜šŸœžœžœ!˜AKšœ5˜5—K˜šŸœžœžœ$˜CKšœ˜Kšžœ žœžœžœ˜Kšœ˜š žœŸœžœžœ ž˜0šœ,˜,K™‘—Kšžœ"žœžœ˜.Kšžœ˜—Kšœ˜—K˜šŸœžœžœžœ˜GKšœžœ žœžœžœžœžœžœ˜D—K˜šŸ œžœžœžœ˜8Kšœžœžœžœžœžœžœžœžœ˜Q—K˜šŸ œžœžœžœ ˜?Kšœ˜K˜Kš žœžœžœžœžœžœ˜7šœž˜Kšžœ,˜2—Kšœ˜—K˜šŸœžœžœžœ ˜IKšœžœžœžœžœ žœžœžœžœ!˜W—K˜šŸœžœžœžœ˜LKš œžœžœžœžœžœžœ ˜4—K˜šŸ œžœžœžœ˜GKš œžœžœžœžœ žœžœ˜H—K˜šŸ œžœžœžœ ™?Kš œžœžœžœžœ žœžœ$™P—K˜šŸœžœžœ%˜DKšœ˜Kšžœžœžœžœ˜Kš žœžœžœžœ1žœ:˜¦š žœžœžœ*žœžœž˜LKšžœžœžœ˜Kšžœ˜—Kšœ˜—K˜Kšœžœžœ™šŸœžœžœ&˜AKšžœžœžœžœ˜K˜šžœ ž˜šœ˜šžœžœ.ž˜8šœÐ˜ÐKšœ8˜8—KšœžœW˜n—šžœ*žœ žœž˜AKšžœžœžœ˜Kšžœ˜—Kšžœ˜—šœ˜šžœ8žœ˜@Kšœžœ˜ Kšœžœ˜&šžœžœžœ7ž˜KKšœ˜Kšžœžœ žœžœ˜1Kšžœ˜—šžœžœžœ ž˜2Kšœ*˜*šžœž˜Kšžœ˜—Kšžœ˜—Kšžœ˜—šžœ˜Kšœžœ˜ Kšœžœ˜šžœž˜"Kšœžœ˜'Kšœ žœžœžœ˜Kšœžœ˜šžœžœ˜'K˜K™$K˜%K˜+Kšœ žœ˜Kšžœžœ$žœžœI˜­Kšœ˜—š žœžœžœžœžœž˜_Kšœ˜Kšžœžœ žœžœ˜1Kšžœ˜—šžœ žœžœžœ˜K˜)šžœž˜Kšžœ˜—K˜—Kš žœ žœžœžœžœ™,K˜ Kšžœ˜—Kšžœ˜ ——Kšœž -œ˜:Kšžœžœ˜—Kšœ˜—K˜šŸ œžœžœžœ ˜Fšžœ žœžœ˜Kšžœžœ˜ —šž˜Kšžœa˜g—K˜K˜—šŸœžœžœ%žœ˜[Kšœ˜Kš žœ žœžœžœžœ˜!Kšœ˜š žœŸœžœžœ ž˜0K™:šžœ!žœ-žœ ˜nKšœ˜Kšœ,˜,Kšœ'˜'šžœžœžœžœ˜8KšœN˜NKšžœ.˜2Kšœžœ!˜*Kš œžœ žœžœžœ˜A—K˜šžœ žœžœžœ˜KšœXžœ˜^K˜K˜—K˜ Kšœ˜—Kšžœ˜—šžœ žœžœžœ˜Kšœjžœ˜pK˜K˜—K˜—šžœ˜š Ÿœžœ$žœ žœžœ žœ˜\Kšžœ žœ˜2Kšœ=žœžœ ˜NKšœj˜jK˜Kšžœ˜—Kšœ$˜$K˜—Kšœ žœ˜,K˜"K˜šžœ+žœ žœž˜BKšœžœ˜&Kšœžœ œ˜IKšžœžœžœžœq˜¶Kšœ œežœžœ˜“K˜K˜Kšžœ˜—K˜Kšœžœ˜ Kšžœ˜K˜—šŸ œžœ žœ˜OKšœj˜jKšœ1˜1Kšœ˜Kšœ˜Kšœžœ˜Kšœžœžœžœ˜-šŸœžœ ˜KšœN˜N—šŸ œžœžœ žœ˜;Kšœ˜Kšœžœžœ ˜Kšœ"˜"Kšœžœ˜šžœž˜Kšžœ˜Kšžœ˜#—Kšœ˜Kšžœ˜—šŸ œžœžœžœ˜KKšœžœ˜Kšœ žœžœžœ˜%šŸœžœ ˜KšœN˜N—šŸœžœžœ žœ˜7Kšœ˜Kšœžœžœ ˜Kšœ#˜#Kšœžœ˜šžœ ž˜Kšžœ˜Kšžœ˜—Kšœ˜—šœžœ˜K˜Kšœ ˜ K˜Kšœ˜Kšœ˜Kšœ˜Kšœ žœ˜ Kšœžœ˜—Kšœg˜gKšžœ˜—Kšžœ/žœžœ˜=Kšœ0žœ 0˜fšžœ-žœžœ˜9KšœB˜BKšžœ˜—šœ/žœ˜DKšœ˜Kšœ˜Kšœ˜K˜ Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ žœ˜ Kšœžœ˜—Kšœq˜qšžœ% œžœ˜Gšœžœ˜(Kšœ˜Kšœ ˜ Kšœ'˜'Kšœ'˜'Kšœ)˜)Kšœ)˜)Kšœ˜Kšœ˜Kšœ žœ˜ Kšœ#˜#—Kšœžœ˜—Kšžœ˜K˜—šŸœžœ#žœ˜YKšœžœ˜Kšžœžœžœžœ ˜3Kšžœ˜K˜—K™gšŸœžœžœžœžœ  œžœ #œ˜¢Kšœžœ ˜šžœž˜K˜!Kšžœžœžœžœ˜šžœž˜Kšœ)žœ˜?Kšœ žœ ˜"šžœ I˜VKšœžœ˜Kš žœžœžœžœžœ˜+Kšžœžœžœžœ˜9K˜——K˜Kšžœ˜—K™PKšžœ˜—K˜—K™™!K˜Kšœžœ%˜9šœžœ)˜BK™K™—Kšœžœžœ˜.šœžœ)˜AK™—K˜Kšœ žœ ˜/K˜˜K™-™™$K™GK™—™#™AK™“———K™™.K™BK™G—K™Kšœü™ü—š Ÿœžœžœžœžœž˜]Kšž˜K˜Kšžœ žœžœžœ˜9šžœžœžœ˜!Jšœ˜šžœ6žœ˜>Jšœ3™3Jšœžœžœ8˜IKšœžœ˜0Jšœžœ%˜HJšœ2˜2Jšœžœžœ˜ —Jšœ˜—K˜J˜š žœŸœžœžœž˜&Kšžœžœžœ˜?Kšžœ˜—Kšžœžœžœ'˜EKšžœ ˜=Kšžœ˜—˜K™7K™“—š Ÿœžœžœ%žœžœž˜XKšž˜K˜Kšžœ žœžœžœ˜šžœžœžœ˜!Jšœ˜šžœ6žœ˜>J™3Jšœžœžœ8˜IKšœžœ˜0Jšœžœ%˜HJšœ2˜2Jšœžœžœ˜ —J˜—J˜š žœŸœžœž œžœž˜1šžœ'ž˜-Kšžœ˜—Kšžœ˜—Kšžœžœžœ˜0Kšžœ ˜#Kšžœ˜—K˜—K™™K™K™;š Ÿœžœžœžœžœ˜BKšœ˜Kš žœžœžœžœžœ˜Kšžœžœ"žœwžœ$˜äKšžœ)˜/Kšœ˜K™—š Ÿ œžœžœžœžœžœ˜EKšžœžœžœ˜Kšžœžœžœžœžœžœžœ ˜5K˜—š Ÿ œžœžœ žœžœ˜:Kšœ˜Kšžœžœžœ˜Kšœžœ˜ šžœž˜šœ,˜,Kšœ˜Kšœžœ˜#Kš žœ žœžœžœžœ˜JKšœ˜—Kšžœžœ˜K˜—Kšœ˜K˜—šŸœžœžœ žœ˜Iš žœžœžœžœžœžœž˜DKšžœ˜"—šž˜Kšžœžœ˜—Kšœ˜——K˜™ K™K˜KšŸœžœ˜KšŸ œžœžœžœžœžœžœžœžœžœžœ˜iK˜˜Kšœq™q—š Ÿœžœžœžœžœžœ˜2Kšž˜Kšžœžœžœ˜Kšœžœžœ˜šžœžœž˜ Kšœžœ˜Kšœžœ  ˜(Kšœžœ˜ K˜K˜Kšžœžœžœ%˜PK˜K™•K™K™YKš žœžœžœžœžœ˜8K˜K™š žœŸœžœžœž˜%Kšžœžœž˜"Kšžœ žœ˜Kšžœ˜—K˜K™@š žœŸœžœžœž˜)Kšžœžœ žœ˜.Kšžœ˜K˜—K˜K˜Kš žœŸœžœžœ žœžœ˜Dš œžœžœžœžœ žœžœ˜9Kšžœžœ žœžœ˜:—Kšžœžœžœ˜"Kšžœ˜—Kšžœ˜ Kšžœ˜K™—š Ÿœžœžœžœžœžœ™2Kšœ™Kšžœžœžœ™Kšœžœžœ™šžœžœž™ Kšœžœ  ™+K™K™Kšžœžœžœ%™PK™š žœŸœžœžœž™%Kšžœžœžœ™1Kšžœ™K™—K™Kš žœŸœžœžœ žœžœ™<š œžœžœžœžœ žœžœ™9Kšžœžœ žœžœ™:—Kšžœžœžœ™%Kšžœ™—Kšžœ™ Kšœ™—K˜—K™K™ ™šŸ œžœžœ žœ˜KKšœ˜KšŸœžœžœ˜Kšœ˜Kšžœ žœžœ ˜!Kšœžœ˜ Kšœžœ˜ Kšœžœ˜ Kšœ žœ˜K˜K™«K™šŸœžœžœžœ˜%Kšœ˜K• CharPropsPostfixXeroxCharCodes$šœžœ !˜3Kšœ žœ˜%Kšžœžœ ˜+K˜Kšžœ˜$Kšœ˜—K˜šŸœžœžœžœ˜Kšœ˜Kšœžœ˜,šžœžœž˜0Kšœžœ˜$—Kšœžœžœ˜Kšœ˜—K˜šŸ œžœžœžœ˜Kšœ˜Kšœžœ˜Kšœžœ˜ šžœž˜Kšœžœ#˜*Kšžœžœžœžœ˜K˜"Kšžœ˜—Kšžœžœ ˜'K˜OKšžœžœ˜.K˜Kšžœ ˜Kšœ˜—˜K™$—šŸ œžœžœžœ˜!Kšœ˜Kšœžœ˜Kšœ žœ˜+K˜Kšžœ?˜EKšœ˜K˜—Kšœžœ˜Kšœžœ˜Kšœžœžœ ˜4Kšœ žœ˜Kšžœžœ˜,šž˜Kšœ žœžœ žœ˜+—Kšœ˜Kšœ˜—K™—™K™š Ÿœžœžœžœžœ˜@Kšœžœžœžœžœžœžœžœ^˜‡——K™™ ˜Kšœ;™;K™—šŸ œ˜$Kšœ˜K˜