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
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
= {
Useful types
PATH: TYPE ~ PFSNames.PATH;
ROPE: TYPE ~ Rope.ROPE;
Following types are defined in ObjectFiles and ObjectFilesPrivate
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;
Registration
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]]};
Whole Object Files
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];
Are we supposed to create the modules list too?
Maybe we should push this down into a file specific implementation...
};
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]};
};
Modules
GetModule:
PUBLIC
PROC[info: ModuleInfo]
RETURNS[Module] = {
IF info.whole =
NIL
THEN
RETURN[NIL]
ELSE
This should search info.whole.modules looking for info.fileName & info.instance.
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];
};
Finding Modules
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]];
Globalish variables
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]};
a returned NIL stab means that the check failed
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
{
we expect to find 0 or more digits followed by a colon
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];
};
Instructions
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]];
};
Initialized Storage
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];
};
Functions
FunHandle: TYPE = REF FunHandleBody;
FunHandleBody: PUBLIC TYPE = ObjectFilesPrivate.FunHandleBody;
FunInfo:
TYPE = ObjectFiles.FunInfo;
pcs are relative to the whole
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];
};
Bracket Pairs
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;
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).
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];
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.
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]]};
GetStabRange: PUBLIC PROC[bp: BracketPair] RETURNS[StabRange] =
{IF bp = NIL THEN RETURN[[0, 0]] ELSE RETURN[[bp.firstX, bp.limitX-bp.firstX]]};
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;
};
foo: IO.STREAM;
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
<<MJS August 22, 1990: Every BracketPair is created with its symbols filled in, except for syntheticOuter bps, so I comment out the following (which wouldn't work anyway, 'cause it doesn't side-effect my bp):
InstallBracketPairsForOneFunStab[module, bp.funIndex];>>
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<module.funStabs.nFunStabs
THEN {
funStabX ¬ fsi;
funStab ← module.funStabs[fsi].stab;
limitX ¬ module.funStabs[fsi].firstX;
newX ¬ limitX + module.funStabs[fsi].count;
fsi ¬ fsi.SUCC;
IF fsi<module.funStabs.nFunStabs AND module.funStabs[fsi].firstX < newX THEN UnreadableObjectFile[IO.PutFR1["funStabs out of order in %g", [rope[DescribeModule[module]]] ]];
};
FOR i:
CARDINAL
IN [
CARDINAL[stabX-module.firstStabX] ..
CARDINAL[limitX-module.firstStabX])
DO
stab: Stab ~ module.stabs[i];
IF stab.stabType#SLine AND for[stab] THEN RETURN;
ENDLOOP;
IF funStabX#
LAST[
CARD]
THEN {
funStab ¬ AlterFunStab[module, funStabX];
IF for[funStab]
THEN
RETURN;
};
IF funStab#NIL AND for[funStab] THEN RETURN;
stabX ¬ newX;
ENDLOOP;
RETURN};};
nil => 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
we assume that the fun stabs appear in increasing pc order
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]};
terminated by a LBrac, RBrac, Fun, global symbol, or attempting to go past the end of the symbol table.
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;
if we reach here, then we have attempted to go past the end of the symbol table.
RETURN[x, head, tail]};
C Line-Number to Relative-PC maps
LineNumToPCMap: TYPE ~ ObjectFilesPrivate.LineNumToPCMap;
LineNumToPCMapBody :
TYPE ~ ObjectFilesPrivate.LineNumToPCMapBody;
sorted by Line Num
PCtoLineNumMap: TYPE ~ REF PCtoLineNumMapBody;
PCtoLineNumMapBody:
TYPE ~ ObjectFilesPrivate.PCtoLineNumMapBody;
sorted by FileSectionId
SLineData: TYPE = ObjectFilesPrivate.SLineData;
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 <CLine, PC>, 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.
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 {
Must be a SGI file, need to unpack the line numbers
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;
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.
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 {
Must be a SGI file, need to unpack the line numbers
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;
Stabs
This routine treats stabX as relative to the entire Module.
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]
};
symbol ropes
RopeBufferSize: CARD = 100;
RopeBuffer: REF PACKED ARRAY [0..RopeBufferSize) OF CHAR ¬ NEW[PACKED ARRAY [0..RopeBufferSize) OF CHAR];
we assume that the stream has been positioned at the beginning of a sequence of chars terminated by a '\000 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]]};
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.
IF NOT rope.IsEmpty AND RopeBuffer[0] = '\000 THEN EXIT;
Find first non-zero character.
FOR
I:
CARD
IN [0..RopeBufferSize)
DO
IF RopeBuffer[I] = '\000 THEN LOOP
ELSE {start ¬ I; EXIT};
ENDLOOP;
Find last non-zero character after the first non-zero character.
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;
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
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;
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.
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];
};
this works even if there is no colon
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]];
};
};
Printing
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], ">"]]};
Print Module
use: PrintModule /dir/.../dir/[sun4/]foo[.c2c].o relativePC
writes foo.ModuleDetails
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]];
stream: IO.STREAM ← SystemInterface.GetStreamForFile[whole.file];
nest so that we can catch unwinds and release the stream
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]]];
fields ← Rope.Concat[fields, IO.PutFR1["rope: %g, ", IO.rope[stab.rope]]];
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 foo.o pc
(note: stab indices are only approx plus or minus 1)
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 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.)
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 foo.o pc
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];
};
};
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.
<<RandomCompareFindStabRange: PUBLIC PROC[firstSeed: CARD, whole: Parsed, otherFind: PROC[relativePC: CARD] RETURNS[StabRange], out: IO.STREAM, totalToTest: CARD] =
{
nextSeed: INT ¬ firstSeed;
tested: CARD ¬ 0;
errors: CARD ¬ 0;
start: BasicTime.
GMT ¬ BasicTime.Now[];
WHILE tested < totalToTest DO
rs: Random.RandomStream ¬ Random.Create[seed: nextSeed];
IO.PutF[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];
range1: StabRange ¬ AlternativeFindStabRange[whole, pc];
range2: StabRange ¬ otherFind[pc];
IO.PutF[out, "\Tpc = %g gives firstX: %g count: %g\N", IO.card[pc], IO.card[range1.firstX], IO.card[range1.count]];
IF range1.firstX # range2.firstX
OR range1.count # range2.count
THEN
{IO.PutF[out, "ERROR: otherFind gives firstX: %g count: %g\N", IO.card[range2.firstX], IO.card[range2.count]]; errors ¬ errors+1};
tested ¬ tested+1;
ENDLOOP;
IO.PutF[out, "after %g cumulative tests, we have %g errors\N", IO.card[tested], IO.card[errors]];
ENDLOOP;
};>>
Errors
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]]] ]};
Main code
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"];
}..