SunADotOutFiles.mesa
Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved.
Modified from DotOAccessImpl.mesa
Laurie Horton, June 24, 1992 6:10 pm PDT
Philip James, February 10, 1992 1:42 pm PST
Last tweaked by Mike Spreitzer January 21, 1993 5:33 pm PST
Chauser, March 24, 1992 10:36 am PST
Katsuyuki Komatsu April 1, 1992 3:32 pm PST
Willie-s, January 22, 1993 2:18 pm PST
DIRECTORY
Basics USING [BITAND, BITSHIFT, Card16FromH, Card32FromF, Comparison, FWORD, HWORD],
BasicTime USING [GMT, Now],
CCTypes USING[CCError, CCErrorCase],
CirioTypes USING [zeroBA],
Commander USING [Register, CommandProc],
CommanderOps USING [ArgumentVector, Parse],
Convert USING [IntFromRope],
IO,
List USING[LORA, CompareProc, Sort],
ObjectFiles USING[BracketPairKind, CNameOfStab, CreateParsed, DescribeModule, FileSegmentPC, GlobalVarLoc, MakeUnknownVarLoc, ReadInstruction, RopeForStabType, SimpleSeg, Stab, StabBody, StabType, UnreadableObjectFile, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo],
ObjectFilesPrivate USING[AlterFunStabType, BracketConsumer, BracketPair, BracketPairBody, CheckStaticVar, FnConsumer, FunStabSetBody, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, RegisterObjectFileFlavor, SLineData, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType],
PFS USING [PathFromRope, StreamFromOpenFile, OpenFileFromStream],
PFSNames USING [PATH],
Random USING[ChooseInt, Create, RandomStream],
Rope,
SunADotOut,
SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, ReleaseStreamForFile, ShowReport];
SunADotOutFiles: CEDAR MONITOR
IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, Rope, SystemInterface
EXPORTS ObjectFiles, SunADotOut
= BEGIN
CCError: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE ¬ NIL] ¬ CCTypes.CCError;
Useful types
PATH: TYPE ~ PFSNames.PATH;
Following types are defined in ObjectFiles
Stab: TYPE = ObjectFiles.Stab;
StabList: TYPE = ObjectFilesPrivate.StabList;
StabBody: TYPE = ObjectFiles.StabBody;
StabType: TYPE = ObjectFiles.StabType;
StabRange: TYPE = ObjectFilesPrivate.StabRange;
FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC;
VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo;
some Stab types
LBrac: BYTE = 0c0H;
RBrac: BYTE = 0e0H;
SLine: BYTE = 044H;
Fun: BYTE = 024H;
PSym: BYTE = 0a0H;
LSym: BYTE = 080H;
RSym: BYTE = 040H;
STSym: BYTE = 026H;
LCSym: BYTE = 028H;
GSym: BYTE = 020H;
Main: BYTE = 02aH;
SO: BYTE = 064H;
BIncl: BYTE = 082H;
EIncl: BYTE = 0a2H;
Excl: BYTE = 0c2H;
SOL: BYTE = 084H;
Following types are defined in ObjectFilesPrivate
Parsed: TYPE = REF ParsedBody;
ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody;
Module: TYPE = REF ModuleBody;
ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody;
Header: TYPE = REF HeaderBody;
HeaderBody: TYPE = ObjectFilesPrivate.HeaderBody;
MemorySegmentInfo: TYPE ~ ObjectFilesPrivate.MemorySegmentInfo;
StabSet: TYPE = ObjectFilesPrivate.StabSet;
BracketPair: TYPE ~ ObjectFilesPrivate.BracketPair;
BracketPairBody: TYPE ~ ObjectFilesPrivate.BracketPairBody;
Following values are of global interest
unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize;
theContStab: Stab ~ NEW [StabBody ← [module: NIL, stabX: CARD.LAST, stringX: CARD32.LAST, type: BYTE.LAST, other: BYTE.LAST, desc: CARD16.LAST, value: CARD32.LAST, rope: "don't look at me, I'm a continuation of an earlier stab", dx: CARD.LAST]];
This stab is put in module.stabs[i] wherever continuation stabs would appear.
The following computations are adapted from /usr/include/sys/exec.h,
obtained by: REdit cartiff -f /usr/include/sys/exec.h
MOldsun2: CARD = 0;
M68010: CARD = 1;
M68020: CARD = 2;
MSparc: CARD = 3;
OMagic: CARD16 = 0407B;
NMagic: CARD16 = 0410B;
ZMagic: CARD16 = 0413B;
The following computations are adapted from /usr/include/sun4/a.out.h,
obtained by: REdit cartiff -f /usr/include/sun4/a.out.h
PageSize: CARD32 = 02000H;
OldPageSize: CARD32 = 00800H;
The following record type was constructed based on page 1339 of the Sun Release 4.0 documentation (A.OUT documentation)
WireHeader: TYPE = REF WireHeaderBody;
WireHeaderBody: TYPE = MACHINE DEPENDENT RECORD[
dynamic: BYTE[0..0],
toolversion: BYTE[0..127],
machtype: BYTE,
magic: Basics.HWORD,
textSize: Basics.FWORD,
iDataSize: Basics.FWORD,
bssSize: Basics.FWORD,
symsSize: Basics.FWORD,
entryPoint: Basics.FWORD,
trSize: Basics.FWORD,
drSize: Basics.FWORD];
WireSTEntry: TYPE = REF WireSTEntryBody;
WireSTEntryBody: TYPE = MACHINE DEPENDENT RECORD[
stringX(0: 0..31): Basics.FWORD,
type(0: 32..39): BYTE,
other(0: 40..47): BYTE,
desc(0: 48..63): Basics.HWORD,
value(0: 64..95): Basics.FWORD];
ReadHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED {
PROC[stream: IO.STREAM] RETURNS[Header] = TRUSTED
wHeader: WireHeader ¬ NEW[WireHeaderBody];
nBytes: INT ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader­], 0, BYTES[WireHeaderBody]]];
magic: CARD ¬ Basics.Card16FromH[wHeader.magic];
nBadMagic: BOOLEAN ¬ (magic # OMagic) AND (magic # NMagic)AND (magic # ZMagic);
The following computations are adapted from /usr/include/sun4/a.out.h,
obtained by: REdit cartiff -f /usr/include/sun4/a.out.h
nPageSize: CARD ¬ IF wHeader.machtype = MOldsun2 THEN OldPageSize ELSE PageSize;
textOffset: CARD ¬ IF wHeader.machtype = MOldsun2 THEN
(IF magic = ZMagic THEN nPageSize ELSE BYTES[WireHeaderBody])
ELSE
(IF magic = ZMagic THEN 0 ELSE BYTES[WireHeaderBody]);
textSize: CARD ¬ Basics.Card32FromF[wHeader.textSize];
iDataSeg: MemorySegmentInfo ¬ [textOffset + textSize, Basics.Card32FromF[wHeader.iDataSize]];
textRelocSeg: MemorySegmentInfo ¬ [iDataSeg.byteOffset+iDataSeg.byteLength, Basics.Card32FromF[wHeader.trSize]];
dataRelocSeg: MemorySegmentInfo ¬ [textRelocSeg.byteOffset+textRelocSeg.byteLength, Basics.Card32FromF[wHeader.drSize]];
symsSeg: MemorySegmentInfo ¬ [dataRelocSeg.byteOffset+dataRelocSeg.byteLength, Basics.Card32FromF[wHeader.symsSize]];
textLoadOffset: CARD32 ¬ IF magic = ZMagic THEN 02000H ELSE 0;
text segment is loaded into memory at nominal 0 + textLoadOffset
the 02000H is the largest page size on certain machines, and allows the first page of memory to remain unmapped.
header: Header ¬ NEW[HeaderBody ¬ [
dynamic: wHeader.dynamic # 0,
toolversion: wHeader.toolversion,
machtype: wHeader.machtype,
magic: magic,
text: [textOffset, textSize],
iData: iDataSeg,
textReloc: textRelocSeg,
dataReloc: dataRelocSeg,
syms: symsSeg,
debug: [0, 0],
linno: [0, 0],
textLoadOffset: textLoadOffset,
bssSize: Basics.Card32FromF[wHeader.bssSize],
entryPoint: Basics.Card32FromF[wHeader.entryPoint],
nPageSize: nPageSize,
nEntries: symsSeg.byteLength/BYTES[WireSTEntryBody],
stringOffset: symsSeg.byteOffset+symsSeg.byteLength
]];
RETURN[header];
};
Module
We assume that there are dbx stabs located in the whole in the symbol table entry range [firstX..limitX).
We assume that the first stab is a SO stab whose value is the first pc of the module.
We assume that this or the next stab is a SO stab containing the file name.
The first and limitX have presumably been obtained by other means. For example, at this writing the CirioNub will provide access to a table of pc ranges located in the target world. (In addition, we provide a rather crude mechanism below to use when the CirioNub approach is not available. (e.g., when examining a file that is not part of a PCedar load state.)
We are unable to define a legitimate limitPC. We assume that when, later, an attempt is made to look up a pc in the bracket structure, we have already determined that that pc definitely belongs to this Module. Thus, we can use header.textSize as a (bogus) limitPC.
SunADotOutModuleFromParsedAndPC: ObjectFilesPrivate.ModuleFromParsedAndPCProcType ~ {
PROC [whole: Parsed, spc: FileSegmentPC, moduleRope: ROPENIL] RETURNS [Module] ~ {
IF whole = NIL THEN RETURN[NIL] ELSE
{
stabRange: StabRange ¬ AlternativeFindModuleStabRange[whole, spc.relPC];
RETURN [ModuleFromParsedInner[whole, stabRange]];
};
};
LineNumList: TYPE = REF LineNumListBody;
LineNumListBody: TYPE = RECORD [nLines: CARD, lines: LIST OF REF ANY ¬ NIL];
CreateModule: PROC[whole: Parsed, stream: IO.STREAM, stabRange: StabRange ¬ [0, 0]] RETURNS[Module] =
BEGIN
module: Module ¬ NEW[ModuleBody];
firstSO: Stab;
nStabs: CARD;
lineNums: LineNumList;
lineNums2: LineNumList;
[firstSO, ] ¬ BasicReadStab[whole, stream, stabRange.first];
nStabs ¬ stabRange.count;
lineNums ¬ NEW [LineNumListBody ¬ [0, NIL]];
lineNums2 ¬ NEW [LineNumListBody ¬ [0, NIL]];
prepare the Module for a call on BuildBrackets
module.whole ¬ whole;
module.firstStabX ¬ stabRange.first;
module.limitStabX ¬ stabRange.first+stabRange.count;
module.firstPC ¬ firstSO.value;
module.limitPC ¬ whole.header.text.byteLength; -- (bogus, but it will suffice for reasons given earlier)
lets read the all stabs now (WITH their ropes)
(I did some timing tests on a Dorado for RopeImpl. It took about 6 seconds to perform this loop, including the allocates. On the other hand, it takes about 4 seconds to spin through the entries without allocating the stab records. So, since at some point I have to traverse all the entries to find the Fun stabs, I might as well allocate them.)
(we also relocate the pc value of bracket stabs.)
module.stabs ¬ NEW[StabSet[nStabs]];
{I: CARD ¬ 0;
WHILE I<nStabs DO
stab: Stab;
numStabsRead:CARD;
[stab, numStabsRead] ¬ BasicReadStab[whole, stream, stabRange.first+I, lineNums, lineNums2];
module.stabs[I] ¬ stab;
stab.module ¬ module;
IF stab.stabType = LBrac OR stab.stabType = RBrac THEN
stab.value ¬ stab.value + module.firstPC;
FOR J: CARD IN (I .. I + numStabsRead) DO
unusedStab: Stab ¬ NEW [StabBody];
unusedStab.module ¬ NIL; -- Indicates unused entry
module.stabs[J] ¬ unusedStab;
ENDLOOP;
I ¬ I + numStabsRead;
ENDLOOP;
};
now lets finish up
InstallPCLineNumMaps[module, lineNums, lineNums2];
module.fileName ¬ PFS.PathFromRope[IF module.stabs[1].stabType = SO THEN module.stabs[1].rope ELSE module.stabs[0].rope];
module.staticVarsInstalled ¬ FALSE;
module.versionStampInfo ¬ NIL;
module.outerBracket ¬ NEW[ObjectFilesPrivate.BracketPairBody¬[
module: module,
kind: syntheticOuter,
firstX: 0,
limitX: module.whole.header.nEntries,
firstPC: module.firstPC,
pcLimit: module.limitPC,
funStab: NIL,
funIndex: 0,
symbols: NIL,
innerBrackets: NIL]];
RETURN[module];
END;
Finding Modules
StabIndexTypeAndValue: TYPE = RECORD[stabX: CARD, stabType: StabType, value: CARD32];
NullStabIndexTypeAndValue: StabIndexTypeAndValue = [0, Invalid, 0];
This procedure should only be used when examining a whole which is not in the load state. If we are given a pc in a running PCR, it is far faster to use procedures in LoadStateAccess (if supported!) to obtain the stab range for a Module. Those procedures use a table available from the nub to find the stab range, then produce the Module through a call on CreateModule.
foo: IO.STREAMNIL;
AlternativeFindModuleStabRange: PROC[whole: Parsed, relativePC: CARD] RETURNS[StabRange ¬ [0, 0]] =
BEGIN
{
ENABLE PFS.Error => {
foo ← PFS.StreamOpen[PFS.PathFromRope["/tmp/PJ.out"], create];
CONTINUE};
foo ← PFS.StreamOpen[PFS.PathFromRope["/tmp/PJ.out"], append];
IF whole = NIL THEN RETURN[[0, 0]] ELSE
BEGIN
nominalX: CARD ¬ SearchForPC[whole, relativePC];
baseSO: StabIndexTypeAndValue ¬ NullStabIndexTypeAndValue; -- tentative
maxPC: CARD ¬ 0;
highDbx: CARD ¬ 0;
IF nominalX = whole.header.nEntries THEN RETURN[[0, 0]];
IO.PutF[foo, "downLooping [%g .. 0]\n", IO.card[nominalX]];
FOR x: CARD DECREASING IN [0..nominalX] DO
info: StabIndexTypeAndValue ¬ CheckStab[whole, x];
IO.PutF[foo, "(%g)\tstabType:\t%g\n", IO.card[x], IO.rope[ObjectFiles.RopeForStabType[info.stabType]]];
IF info.stabType = Fun OR info.stabType = SLine OR info.stabType = SO THEN
maxPC ¬ MAX[maxPC, info.value];
IF info.stabType = SO THEN {baseSO ¬ info};
IF info.stabType = Unspecified OR info.stabType = Invalid THEN EXIT;
highDbx ¬ MAX[highDbx, info.stabX];
ENDLOOP;
IF baseSO.stabType # SO THEN {
IO.PutF[foo, "Bailing out because baseSO.stabType # SO\n"];
IO.Close[foo];
foo ← NIL;
RETURN[[0, 0]];};
IO.PutF[foo, "upLooping [%g .. %g]\n", IO.card[nominalX], IO.card[whole.stabLimit]];
FOR x: CARD IN (nominalX..whole.stabLimit) DO
info: StabIndexTypeAndValue ¬ CheckStab[whole, x];
IO.PutF[foo, "(%g)\tstabType:\t%g\n", IO.card[x], IO.rope[ObjectFiles.RopeForStabType[info.stabType]]];
IF info.stabType = Fun OR info.stabType = SLine THEN
maxPC ¬ MAX[maxPC, info.value];
IF info.stabType = Unspecified OR info.stabType = Invalid THEN EXIT;
highDbx ¬ MAX[highDbx, info.stabX];
ENDLOOP;
IF baseSO.value <= relativePC AND relativePC <= maxPC THEN {
IO.PutF[foo, "good answer: [%g, %g]\n", IO.card[baseSO.stabX], IO.card[highDbx-baseSO.stabX+1]];
IO.Close[foo];
foo ← NIL;
RETURN[[baseSO.stabX, highDbx-baseSO.stabX+1]];};
IO.PutF[foo, "bad answer [0, 0] because\n\tbaseSO.value\t%g\n\trelativePC\t%g\n\tmaxPC\t%g\nThese values aren't in descending order.", IO.card[baseSO.value], IO.card[relativePC], IO.card[maxPC]];
IO.Close[foo];
foo ← NIL;
RETURN[[0, 0]];
END;
};
END;
if successful, the value returned is somewhere within the range of stabXs for the desired Module. If unsuccessful, the value returned is whole.header.nEntries.
We depend upon the fact that all pc containing dbx stabs for a given whole file occur before or after any other dbx stab. We do not require that the pc values be sorted within the block of stabs for a given whole. However, we require that all our pc values are greater than or less than a pc value from some other block of dbx stabs.
SearchForPC: PROC[whole: Parsed, pc: CARD] RETURNS[CARD] =
BEGIN
x: CARD ¬ 0;
y: CARD ¬ whole.stabLimit;
now, we assert an invariant
all SO dbx stabs to the left of or at x have a pc value < pc
all SO dbx stabs to the right of or at y have a pc value > pc
WHILE x+1 < y DO
mid: CARD ¬ (x+y)/2;
midStab: StabIndexTypeAndValue ¬ SearchFwdForPCStab[whole, mid, y];
SELECT TRUE FROM
midStab.stabX = y => y ¬ mid;
pc < midStab.value => y ¬ mid;
midStab.value = pc => RETURN[midStab.stabX];
midStab.value < pc => x ¬ mid;
ENDCASE => ERROR;
ENDLOOP;
RETURN[x];
END;
We start looking at start, and stop just before limit. Hence, if we fail to find a pc stab, then we return [limit, 0, 0]
SearchFwdForPCStab: PROC[whole: Parsed, start: CARD, limit: CARD] RETURNS[StabIndexTypeAndValue] =
BEGIN
dbxLimit: CARD ¬ 0; -- tentative
FOR x: CARD ¬ start, x+1 WHILE x < limit DO
info: StabIndexTypeAndValue ¬ CheckStab[whole, x];
IF info.stabType = SO OR info.stabType = Fun OR info.stabType = SLine THEN RETURN[info];
IF info.stabType # Unspecified AND info.stabType # Invalid THEN dbxLimit ¬ x+1;
IF info.stabType > 1fH THEN dbxLimit ← x+1;
ENDLOOP;
IF limit = whole.stabLimit AND dbxLimit > start THEN whole.stabLimit ¬ dbxLimit;
RETURN[[limit, Invalid, 0]];
END;
CheckStab: ENTRY PROC[whole: Parsed, stabX: CARD] RETURNS[StabIndexTypeAndValue] =
BEGIN
ENABLE UNWIND => NULL;
stream: IO.STREAM ¬ SystemInterface.GetStreamForFile[whole.file];
IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireSTEntryBody]];
TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@WireStabBuffer­], 0, BYTES[WireSTEntryBody]]]};
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[[stabX, TypeFromData[WireStabBuffer.type], Basics.Card32FromF[WireStabBuffer.value]]];
END;
SunADotOutVarLocFromStab: ObjectFilesPrivate.VarLocFromStabProcType ~ {
PROC [stab: Stab] RETURNS [ObjectFiles.VarLoc] ~ {
header: Header ~ stab.module.whole.header;
MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ {
segRope:Rope.ROPE;
segBase: CARD ~ SELECT kind FROM
text => 0,
data => header.text.byteLength,
bss => header.text.byteLength + header.iData.byteLength,
ENDCASE => ERROR;
IF stab.value < segBase THEN ObjectFiles.UnreadableObjectFile[IO.PutFLR["value (%xH) less than segment base (%xH) for symbol %g in %g", LIST[[cardinal[stab.value]], [cardinal[segBase]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]]] ]];
SELECT kind FROM
text => segRope ¬ "text";
data => segRope ¬ "data";
bss => segRope ¬ "bss";
ENDCASE => ERROR;
RETURN [NEW [ObjectFiles.VarLocBody ¬ [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: fSegment[
[0, segRope],
(stab.value - segBase)*8,
stab.value + header.text.byteOffset - header.textLoadOffset] ]]]};
SELECT stab.stabType FROM
Fun => RETURN MkSegment[text];
STSym => RETURN MkSegment[data];
LCSym => RETURN MkSegment[bss];
LSym, PSym => {
byteOffset: INT ~ LOOPHOLE[stab.value];
vLB: ObjectFiles.VarLoc;
IF stab.stabType=PSym AND stab.size>4 AND stab.size # LAST[CARD] THEN
vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [
bitSize: stab.size*8,
where: indirect[
base: NEW[ObjectFiles.VarLocBody ¬ [
bitSize: 32,
where: frame[bitOffset: 8*byteOffset]]],
offset: CirioTypes.zeroBA]]]
ELSE vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: frame[bitOffset: 8*byteOffset]]];
RETURN[vLB]};
RSym => {
sz: CARD ~ IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize;
vLB: ObjectFiles.VarLoc;
IF stab.size>4 AND stab.size # LAST[CARD] THEN
vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [
bitSize: sz,
where: indirect[
base: NEW[ObjectFiles.VarLocBody ¬ [
bitSize: 32,
where: register[regNum: stab.value]]],
offset: CirioTypes.zeroBA]]]
ELSE vLB ¬ NEW[ObjectFiles.VarLocBody ¬ [
bitSize: sz,
where: register[regNum: stab.value]]];
RETURN[vLB]
};
GSym => RETURN [NEW [ObjectFiles.VarLocBody ¬ [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: namedCommon[Rope.Concat["←", ObjectFiles.CNameOfStab[stab]], 0, 0, FALSE, FALSE] ]]];
ENDCASE => RETURN ObjectFiles.MakeUnknownVarLoc[IO.PutFR["unrecognized stabType (%02xH) for %g", [cardinal[ORD[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[stab]]] ]];
};
C Line-Number to Relative-PC maps
PCtoLineNumMap: TYPE = REF PCtoLineNumMapBody;
PCtoLineNumMapBody: TYPE = ObjectFilesPrivate.PCtoLineNumMapBody;
sorted by PC
LineNumToPCMap: TYPE = REF LineNumToPCMapBody;
LineNumToPCMapBody: TYPE = ObjectFilesPrivate.LineNumToPCMapBody;
sorted by Line Num
SLineData: TYPE = ObjectFilesPrivate.SLineData;
InstallPCLineNumMaps: PROC[module: Module, lineNums, lineNums2: LineNumList] =
{
CompareByCLineNum: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] =
{
info1: REF SLineData ¬ NARROW[ref1];
info2: REF SLineData ¬ NARROW[ref2];
IF info1.cLineNum < info2.cLineNum THEN RETURN[less];
IF info1.cLineNum > info2.cLineNum THEN RETURN[greater];
IF info1.parsedRelPC.relPC < info2.parsedRelPC.relPC THEN RETURN[less];
IF info1.parsedRelPC.relPC > info2.parsedRelPC.relPC THEN RETURN[greater];
RETURN[equal];
};
CompareByPC: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] =
{
info1: REF SLineData ¬ NARROW[ref1];
info2: REF SLineData ¬ NARROW[ref2];
IF info1.parsedRelPC.relPC < info2.parsedRelPC.relPC THEN RETURN[less];
IF info1.parsedRelPC.relPC > info2.parsedRelPC.relPC THEN RETURN[greater];
IF info1.cLineNum < info2.cLineNum THEN RETURN[less];
IF info1.cLineNum > info2.cLineNum THEN RETURN[greater];
RETURN[equal];
};
sortedList: LIST OF REF ANY ¬ NIL;
IF module.pcToLineNum # NIL OR module.lineNumToPC # NIL THEN
{
IF module.pcToLineNum = NIL OR module.lineNumToPC = NIL THEN ERROR;
RETURN;
};
sortedList ¬ List.Sort[lineNums.lines, CompareByCLineNum];
module.lineNumToPC ¬ NEW[LineNumToPCMapBody[lineNums.nLines]];
FOR I: INTEGER IN [0..lineNums.nLines) DO
info: REF SLineData ¬ NARROW[sortedList.first];
module.lineNumToPC[I] ¬ info­;
sortedList ¬ sortedList.rest;
ENDLOOP;
sortedList ¬ List.Sort[lineNums2.lines, CompareByPC];
module.pcToLineNum ¬ NEW[PCtoLineNumMapBody[lineNums2.nLines]];
FOR I: INTEGER IN [0..lineNums2.nLines) DO
info: REF SLineData ¬ NARROW[sortedList.first];
module.pcToLineNum[I] ¬ info­;
sortedList ¬ sortedList.rest;
ENDLOOP;
};
Stabs
MergeContinuationStabs: ENTRY PROC[module: Module, stabX: CARD] ~ {
ENABLE UNWIND => NULL;
stab: Stab ← module.stabs[stabX];
DO
rlen: INT ~ stab.rope.Length[];
IF rlen>0 AND stab.rope.Fetch[rlen-1]='\\ THEN {
s2: Stab ~ module.stabs[stabX+stab.dx];
IF s2.stabType=stab.stabType AND s2.value=stab.value AND s2.other=stab.other AND s2.desc=stab.desc THEN {
stab.dx ← stab.dx.SUCC;
stab.rope ← stab.rope.Substr[len: rlen-1].Concat[s2.rope];
}
ELSE EXIT}
ELSE EXIT;
ENDLOOP;
RETURN};
TypeFromData: PROC [data: BYTE] RETURNS [stabType: ObjectFiles.StabType] ~ {
val: CARD ¬ data;
stabType ¬ SELECT val FROM
LBrac => LBrac,
RBrac => RBrac,
SLine => SLine,
Fun => Fun,
PSym => PSym,
LSym => LSym,
RSym => RSym,
STSym => STSym,
LCSym => LCSym,
GSym => GSym,
Main => Main,
SO => SO,
BIncl => BIncl,
EIncl => EIncl,
Excl => Excl,
SOL => SOL,
ENDCASE => Unspecified
};
BasicReadStab: ENTRY PROC[whole: Parsed, stream: IO.STREAM, stabX: CARD, lineNum, lineNum2: LineNumList ¬ NIL] RETURNS[stab: Stab, numStabsRead: CARD] ~ {
warning: does NOT relocate LBrac or RBrac stabs.
Also: the module field is set to NIL;
ENABLE UNWIND => NULL;
stab ¬ NEW [StabBody];
[stab­, numStabsRead] ¬ ReadStabBody[whole, stream, stabX, lineNum, lineNum2];
RETURN
};
hack to avoid messing up the stream buffering
previousStream: IO.STREAM ¬ NIL;
cloneStream: IO.STREAM ¬ NIL;
ReadStabBody: PROC [whole: Parsed, stream: IO.STREAM, stabX: CARD, lineNum, lineNum2: LineNumList ¬ NIL] RETURNS [stab: StabBody, numStabsRead: CARD] ~ {
rope: Rope.ROPE ¬ "\\";
size, rLen, offset: CARD16 ¬ 0;
value: CARD32;
stabType: ObjectFiles.StabType;
IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireSTEntryBody]];
TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@WireStabBuffer­], 0, BYTES[WireSTEntryBody]]]};
stabType ¬ TypeFromData[WireStabBuffer.type];
size ¬ Basics.Card16FromH[WireStabBuffer.desc];
value ¬ Basics.Card32FromF[WireStabBuffer.value];
IF stream#previousStream THEN {
cloneStream¬PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
previousStream ¬ stream;
};
rope ¬ ReadStringX[cloneStream, whole, Basics.Card32FromF[WireStabBuffer.stringX]];
rLen ¬ rope.Length[];
numStabsRead ¬ 1;
IF ~rope.IsEmpty[] THEN
WHILE rope.Fetch[rLen-1] = '\\ DO
offset ¬ offset + 1;
IO.SetIndex[stream, whole.header.syms.byteOffset+(stabX + offset)*BYTES[WireSTEntryBody]];
TRUSTED{[] ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[@WireStabBuffer­], 0, BYTES[WireSTEntryBody]]]};
rope ¬ rope.Substr[len:rLen-1].Concat[ReadStringX[cloneStream, whole, Basics.Card32FromF[WireStabBuffer.stringX]]];
rLen ¬ rope.Length[];
numStabsRead ¬ numStabsRead + 1;
ENDLOOP;
stab ¬ [
module: NIL,
stabX: stabX,
stabType: stabType,
size: size,
value: value,
rope: rope
];
IF stab.stabType = SLine AND lineNum # NIL THEN {
info: REF SLineData ¬ NEW[SLineData¬[cLineNum: Basics.Card16FromH[WireStabBuffer.desc], parsedRelPC: [[1, ".text"], stab.value]]];
lineNum.lines ¬ CONS[info, lineNum.lines];
lineNum.nLines ¬ lineNum.nLines + 1;
lineNum2.lines ¬ CONS[info, lineNum2.lines];
lineNum2.nLines ¬ lineNum2.nLines + 1;
};
RETURN};
WireStabBuffer: WireSTEntry ¬ NEW[WireSTEntryBody];
all users should be in the monitor
ReadStringX: PROC[stream: IO.STREAM, whole: Parsed, stringX: CARD] RETURNS[rope: Rope.ROPE] ~ {
IO.SetIndex[stream, whole.header.stringOffset+stringX];
rope ¬ ReadRope[stream]};
WARNING: the rope reading code causes random repositioning of the stream. That is CRUDE and expensive. Simply for this experiment. I need to do something better. Read in the whole string table? read in the symbols, sort them, then read in string table and pick out the interesting strings? What?
symbol ropes
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.ROPE] =
BEGIN
ENABLE UNWIND => NULL;
rope: Rope.ROPE ¬ NIL;
WHILE TRUE DO
nChars: CARD ¬ RopeBufferSize; -- tentative
rt: Rope.Text;
TRUSTED{[] ¬ IO.UnsafeGetBlock[s, [LOOPHOLE[@RopeBuffer­], 0, RopeBufferSize]]};
FOR I: CARD IN [0..RopeBufferSize) DO
IF RopeBuffer[I] = '\000 THEN {nChars ¬ I; EXIT};
ENDLOOP;
rt ¬ Rope.NewText[nChars];
FOR I: CARD IN [0..nChars) DO rt[I] ¬ RopeBuffer[I] ENDLOOP;
rope ¬ IF rope = NIL THEN (IF nChars = 0 THEN "" ELSE rt)
ELSE (IF nChars = 0 THEN rope ELSE Rope.Concat[rope, rt]);
IF nChars < RopeBufferSize THEN EXIT;
ENDLOOP;
RETURN[rope];
END;
usage: RandomTestFindStabRange /dir/.../dir/[sun4/]foo[.c2c].o
RandomTestFindStabRange: Commander.CommandProc =
{
args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
path: PATH ¬ PFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[];
{ ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
file: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, path];
nextSeed: INT ¬ IF args.argc < 3 THEN 4466 ELSE Convert.IntFromRope[args[2]];
start: BasicTime.GMT ¬ BasicTime.Now[];
WHILE TRUE DO
rs: Random.RandomStream ¬ Random.Create[seed: nextSeed];
whole: Parsed ¬ ObjectFiles.CreateParsed[file, "SunADotOut"];
IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed], IO.time[start]];
FOR I: INT IN [0..100) DO
pc: CARD ¬ Random.ChooseInt[rs, 0, whole.header.text.byteLength];
range: StabRange ¬ AlternativeFindModuleStabRange[whole, pc];
IO.PutF[cmd.out, "\Tpc = %g gives firstX: %g count: %g\N", IO.card[pc], IO.card[range.first], IO.card[range.count]];
ENDLOOP;
ENDLOOP;
};
SystemInterface.CloseFileSet[fileSet];
};
Stab Structure
SADOScanModuleStructure: PROC [module: Module, perFn: ObjectFilesPrivate.FnConsumer] ~ {
I: CARD ¬ 0;
WHILE I < module.stabs.nStabs DO
stab: Stab ¬ module.stabs[I];
IF stab.module = NIL THEN I ¬ I+1
ELSE SELECT stab.stabType FROM
GSym, LCSym, STSym, LSym => I ¬ I + 1;
Fun => {funStab: Stab ~ stab;
firstLocal: Stab ¬ NIL;
WHILE I+1 < module.stabs.nStabs DO
I ¬ I + 1;
stab ¬ module.stabs[I];
IF stab.module = NIL THEN LOOP;
SELECT stab.stabType FROM
PSym, RSym => NULL;
STSym, LSym => IF BracketFollows[module, I]
THEN {firstLocal ¬ stab; EXIT}
ELSE {firstLocal ¬ NIL; EXIT};
LBrac => {firstLocal ¬ stab; EXIT};
Fun, GSym, LCSym => {firstLocal ¬ NIL; EXIT};
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab while scanning the arguments for function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
I ¬ perFn[funStab, firstLocal, I+module.firstStabX] - module.firstStabX};
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => I ¬ I + 1;
ENDCASE => {
SystemInterface.ShowReport[IO.PutFR["Found %g stab while scanning in the global space of %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
I ¬ I + 1};
ENDLOOP;
RETURN};
BracketFollows: PROC [module: Module, J: CARD] RETURNS [BOOL] ~ {
FOR J ¬ J+1, J+1 WHILE J < module.stabs.nStabs DO
stab: Stab ¬ module.stabs[J];
IF stab.module = NIL THEN LOOP;
SELECT stab.stabType FROM
Fun, GSym, LCSym => RETURN [FALSE];
LBrac => RETURN [TRUE];
ENDCASE => NULL;
ENDLOOP;
RETURN [FALSE]};
SADOScanFnStructure: PROC [module: Module, funStab: Stab, firstLocal: Stab ¬ NIL, nextX: CARD, perParm: PROC [Stab] ¬ NIL, perBracket: ObjectFilesPrivate.BracketConsumer ¬ NIL] RETURNS [limitX, limitPc: CARD] ~ {
K: CARD;
more: BOOL ¬ TRUE;
IF perParm#NIL THEN PassLocals[module, funStab, funStab.stabX+1, nextX, perParm];
IF firstLocal=NIL THEN limitX ¬ nextX
ELSE limitX ¬ DoBrack[module, funStab, firstLocal, perBracket];
K ¬ limitX-module.firstStabX;
WHILE K < module.stabs.nStabs DO --seek limitPC, and more bracket pairs.
stab: Stab ¬ module.stabs[K];
IF stab.module = NIL THEN K ¬ K + 1
ELSE SELECT stab.stabType FROM
Fun => RETURN [limitX, stab.value];
LBrac, RSym => IF more
THEN {limitX ¬ DoBrack[module, funStab, stab, perBracket];
K ¬ limitX-module.firstStabX}
ELSE K ¬ K + 1;
STSym, LSym => IF more AND BracketFollows[module, K]
THEN {limitX ¬ DoBrack[module, funStab, stab, perBracket];
K ¬ limitX-module.firstStabX}
ELSE {K ¬ K + 1; more ¬ FALSE};
ENDCASE => K ¬ K + 1;
ENDLOOP;
RETURN [limitX, module.limitPC]};
DoBrack: PROC [module: Module, funStab, first: Stab, perSubBracket: ObjectFilesPrivate.BracketConsumer] RETURNS [limitX: CARD] ~ {
IF perSubBracket#NIL THEN limitX ¬ perSubBracket[first]
ELSE limitX ¬ SADOScanBktStructure[module, funStab, first, NIL, NIL].limitX;
RETURN};
SADOScanBktStructure: PROC [module: Module, funStab, first: Stab, perLocal: PROC [Stab] ¬ NIL, perSubBracket: ObjectFilesPrivate.BracketConsumer ¬ NIL] RETURNS [limitX, firstPc, limitPc: CARD] ~ {
I: CARD ¬ first.stabX - module.firstStabX;
stab: Stab;
FOR I ¬ I, I+1 WHILE I < module.stabs.nStabs DO
stab ¬ module.stabs[I];
IF stab.module = NIL THEN LOOP;
SELECT stab.stabType FROM
STSym, LSym, RSym => IF perLocal#NIL THEN perLocal[stab];
LBrac => {
J: CARD ¬ I+1;
firstPc ¬ stab.value;
WHILE J < module.stabs.nStabs DO
stab ¬ module.stabs[J];
IF stab.module = NIL THEN J ¬ J+1
ELSE SELECT stab.stabType FROM
RBrac => RETURN [J+1+module.firstStabX, firstPc, stab.value];
STSym, LSym, RSym, LBrac => J ¬ DoBrack[module, funStab, stab, perSubBracket] - module.firstStabX;
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => J ¬ J +1;
Fun => {--Since we're debugging C, which has no nested functions, this shouldn't happen; if it does, we assume the bracket parsing has failed and re-synch with top level enumeration of functions
SystemInterface.ShowReport[IO.PutFR["Found FUN stab after an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
RETURN [J+module.firstStabX, firstPc, stab.value]};
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab after an LBRAC in function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
SystemInterface.ShowReport[IO.PutFR["Missed an RBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
RETURN[J+module.firstStabX, firstPc, module.limitPC]};
Fun => {--shouldn't happen, but ...
SystemInterface.ShowReport[IO.PutFR["Found FUN stab before an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
RETURN [I+module.firstStabX, stab.value, stab.value]};
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab before an LBRAC in function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
SystemInterface.ShowReport[IO.PutFR["Missed an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
RETURN[I+module.firstStabX, module.limitPC, module.limitPC]};
PassLocals: PROC [module: Module, funStab: Stab, firstX, limitX: CARD, to: PROC [Stab]] ~ {
FOR I: CARD IN [firstX - module.firstStabX .. limitX-module.firstStabX) DO
stab: Stab ¬ module.stabs[I];
IF stab.module#NIL THEN SELECT stab.stabType FROM
PSym, RSym, LSym, STSym => to[stab];
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab in parms/locals of %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
RETURN};
SunADotOutGetTypeRef: ObjectFilesPrivate.GetTypeRefProcType ~ {
PROC [sourceStream:IO.STREAM] RETURNS [Rope.ROPE]
typeRef: Rope.ROPE;
lastChar: CHAR ¬ IO.PeekChar[sourceStream];
IF IsDigit[lastChar] THEN {
typeRef ¬ IO.GetTokenRope[sourceStream, NumTok].token;
RETURN[typeRef]}
ELSE IF lastChar='( THEN DO
lastChar ¬ IO.GetChar[sourceStream];
typeRef ¬ Rope.Concat[typeRef, Rope.FromChar[lastChar]];
IF lastChar = ') THEN RETURN[typeRef]
ENDLOOP
ELSE CCError[cirioError, IO.PutFR1["malformed type rep (starts with %q)", [character[lastChar]] ]];
};
IsDigit: PROC [c:CHAR] RETURNS [BOOL]
= INLINE { RETURN [c IN ['0 .. '9]] };
NumTok: PROC [char: CHAR] RETURNS [IO.CharClass] ~ {
SELECT char FROM
IN ['0..'9] => RETURN [other];
ENDCASE => RETURN [break]};
ModuleFromParsedAndStabRange: PUBLIC PROC[whole: Parsed, stabRange: StabRange] RETURNS[Module] =
{
RETURN [ModuleFromParsedInner[whole, stabRange]];
};
ModuleFromParsedInner: PROC[whole: Parsed, stabRange: StabRange] RETURNS[Module] =
{
firstX, limitX: CARD;
stream: IO.STREAM;
IF stabRange.count = 0 THEN RETURN[NIL];
firstX ¬ stabRange.first;
limitX ¬ stabRange.first+stabRange.count;
stream ¬ SystemInterface.GetStreamForFile[whole.file];
nest so that we can catch unwinds and release the stream
{
ENABLE UNWIND => {
SystemInterface.ReleaseStreamForFile[whole.file, stream];
};
firstSO: Stab;
firstPC: CARD;
lag: LIST OF Module ¬ NIL;
[firstSO, ] ¬ BasicReadStab[whole, stream, firstX]; -- rope field not filled
firstPC ¬ firstSO.value;
first, see if we already have it
FOR modules: LIST OF Module ¬ whole.modules, modules.rest WHILE modules # NIL DO
IF modules.first.firstPC = firstPC THEN -- we already have it
{
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[modules.first]
};
IF firstPC < modules.first.firstPC THEN -- we should have found it by now
{
newModule: Module ¬ CreateModule[whole, stream, stabRange];
cell: LIST OF Module ¬ LIST[newModule];
cell.rest ¬ modules;
IF lag # NIL THEN lag.rest ¬ cell ELSE whole.modules ¬ cell;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[newModule];
};
lag ¬ modules;
ENDLOOP;
{
newModule: Module ¬ CreateModule[whole, stream, stabRange];
cell: LIST OF Module ¬ LIST[newModule];
IF lag # NIL THEN lag.rest ¬ cell ELSE whole.modules ¬ cell;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[newModule];
};
};
};
SADOInstallStaticVars: ObjectFilesPrivate.InstallStaticVarsType ~
PROC[module: Module] =
this procedure examines all stabs up to the first Fun stab, looking for certain expected stabs. These are recorded in the whole.
{
IF NOT module.staticVarsInstalled THEN
FOR x: CARD IN [module.firstStabX..module.limitStabX)
DO
stab: Stab ¬ ObjectFilesPrivate.ReadStab[module, x];
IF stab = NIL THEN LOOP;
IF stab.stabType = Fun THEN EXIT;
IF stab.stabType = STSym OR stab.stabType = LCSym THEN
{
IF module.versionStampStab = NIL THEN
{
gvi: ObjectFiles.GlobalVarLoc ¬ NIL;
gvi ¬ NARROW[ObjectFilesPrivate.CheckStaticVar[stab, "versionStamp", TRUE]];
IF gvi # NIL THEN
{
dataRope: Rope.ROPE ¬ ObjectFilesPrivate.ReadInitialDataAsRope[module, gvi.fileByteOffset];
module.versionStampStab ¬ stab;
module.versionStampInfo ¬ NEW[ObjectFiles.VersionStampInfo¬[gvi, dataRope]];
LOOP;
};
};
IF module.globalFrameStab = NIL THEN
{
gvi: ObjectFiles.GlobalVarLoc ¬ NIL;
gvi ¬ NARROW[ObjectFilesPrivate.CheckStaticVar[stab, "globalframe", TRUE]];
IF gvi # NIL THEN
{
module.globalFrameStab ¬ stab;
module.globalFrameGvl ¬ gvi;
LOOP;
};
};
};
ENDLOOP;
module.staticVarsInstalled ¬ TRUE;
};
SADOAlterFunStab: ObjectFilesPrivate.AlterFunStabType ~ {RETURN [module.funStabs[funStabX].stab]; };
SADOGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ {
entryRelativePC: CARD ¬ spc.relPC;
inst0: CARD ¬ ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC]];
inst1: CARD ¬ ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC+4]];
inst2: CARD ¬ ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC+8]];
spOffset: INT ¬ SaveProtocol1[inst0, inst1, inst2];
IF spOffset = 0 THEN spOffset ¬ SaveProtocol2[inst0];
RETURN[spOffset];
};
Following procedures compute the SP offset from FP by examining the entry protocol to a procedure.
SPoffset = 0 means that the instructions do not form the expected protocol.
protocol 1 is
sethi %hi(Offset),%g1
add %g1,%lo(Offset),%g1
save %sp,%g1,%sp
SaveProtocol1: PROC[inst0, inst1, inst2: CARD] RETURNS[spOffset: INT] ~ {
decoded0: DecodedSparcInstruction ¬ DecodeSparcInstruction[inst0];
decoded1: DecodedSparcInstruction ¬ DecodeSparcInstruction[inst1];
decoded2: DecodedSparcInstruction ¬ DecodeSparcInstruction[inst2];
check for sethi %hi(spOffset),%g1
IF decoded0.op # 0 THEN RETURN[0];
IF decoded0.op2 # 4 THEN RETURN[0];
IF decoded0.rd # 1 THEN RETURN[0]; -- this is %g1
check for add %g1,%lo(spOffset),%g1
IF decoded1.op # 2 THEN RETURN[0];
IF decoded1.op3 # 0 THEN RETURN[0];
IF decoded1.i # 1 THEN RETURN[0];
IF decoded1.rs1 # 1 THEN RETURN[0]; -- this is %g1
IF decoded1.rd # 1 THEN RETURN[0]; -- this is %g1
check for save %sp,%g1,%sp
IF decoded2.op # 2 THEN RETURN[0];
IF decoded2.op3 # 74B THEN RETURN[0];
IF decoded2.i # 0 THEN RETURN[0];
IF decoded2.rs1 # 16B THEN RETURN[0]; -- this is %sp
IF decoded2.rs2 # 1 THEN RETURN[0]; -- this is %g1
IF decoded2.rd # 16B THEN RETURN[0]; -- this is %sp
spOffset ¬ LOOPHOLE[Basics.BITSHIFT[decoded0.imm22, 10] + decoded1.simm13];
};
protocol 2 is
save %sp, spOffset,%sp
SaveProtocol2: PROC[inst0: CARD] RETURNS[spOffset: INT] ~ {
decoded0: DecodedSparcInstruction ¬ DecodeSparcInstruction[inst0];
check for save %sp, spOffset, %sp
IF decoded0.op # 2 THEN RETURN[0];
IF decoded0.op3 # 74B THEN RETURN[0];
IF decoded0.i # 0 THEN RETURN[0];
IF decoded0.rs1 # 16B THEN RETURN[0]; -- this is %sp
IF decoded0.rd # 16B THEN RETURN[0]; -- this is %sp
spOffset ¬ decoded0.simm13;
};
DecodedSparcInstruction: TYPE = RECORD[
op, disp30, rd, a, cond, op2, imm22, disp22, op3, rs1, i, asi, rs2, simm13, opf: CARD];
DecodeSparcInstruction: PROC[inst: CARD] RETURNS[DecodedSparcInstruction] ~ {
RETURN[[
op: Basics.BITAND[3, Basics.BITSHIFT[inst, -30]],
disp30: Basics.BITAND[7777777777B, inst],
rd: Basics.BITAND[37B, Basics.BITSHIFT[inst, -25]],
a: Basics.BITAND[1, Basics.BITSHIFT[inst, -29]],
cond: Basics.BITAND[17B, Basics.BITSHIFT[inst, -25]],
op2: Basics.BITAND[7, Basics.BITSHIFT[inst, -22]],
imm22: Basics.BITAND[17777777B, inst],
disp22: Basics.BITAND[17777777B, inst],
op3: Basics.BITAND[77B, Basics.BITSHIFT[inst, -19]],
rs1: Basics.BITAND[37B, Basics.BITSHIFT[inst, -14]],
i: Basics.BITAND[1, Basics.BITSHIFT[inst, -13]],
asi: Basics.BITAND[377B, Basics.BITSHIFT[inst, -5]],
rs2: Basics.BITAND[37B, inst],
simm13: Basics.BITAND[17777B, inst],
opf: Basics.BITAND[777B, Basics.BITSHIFT[inst, -5]]]];
};
Main code
transTable: ObjectFilesPrivate.TranslationTable ¬ NEW[ObjectFilesPrivate.TranslationTableBody[3]];
Commander.Register["sunadoRandomTestFindStabRange", RandomTestFindStabRange];
transTable[0] ¬ [2, 2, 263, "SunADotOut"];
transTable[1] ¬ [2, 2, 264, "SunADotOut"];
transTable[2] ¬ [2, 2, 267, "SunADotOut"];
ObjectFilesPrivate.RegisterObjectFileFlavor[NEW[ObjectFilesPrivate.ObjectFileFlavorBody ¬ [
"SunADotOut",
SunADotOut,
ReadHeader,
SunADotOutModuleFromParsedAndPC,
SunADotOutVarLocFromStab,
SunADotOutGetTypeRef,
NIL,
SADOScanModuleStructure,
SADOScanFnStructure,
SADOScanBktStructure,
TRUE,
SADOInstallStaticVars,
SADOAlterFunStab,
SADOGetSPOffset
]],
transTable];
END..