XCOFFFiles.mesa
Copyright Ó 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Modified from DotOAccessImpl.mesa
Laurie Horton, June 24, 1992 6:07 pm PDT
Philip James, February 24, 1992 11:40 am PST
Last tweaked by Mike Spreitzer October 2, 1992 1:27 pm PDT
Chauser, March 24, 1992 5:25 pm PST
Katsuyuki Komatsu June 21, 1992 1:55 pm PDT
DIRECTORY
Basics USING [BITAND, BITOR, 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, RopeFromChar],
IO USING[card, EndOf, GetChar, GetFWord, GetHWord, PeekChar, PutF, PutFR, SetIndex, STREAM, time, UnsafeGetBlock],
List USING[LORA, CompareProc, Sort],
ObjectFiles USING [BracketNest, BracketPairKind, CNameOfStab, CreateParsed, FileSegmentPC, GlobalVarLoc, MakeUnknownVarLoc, RopeForStabType, SimpleSeg, Stab, StabBody, StabType, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo],
ObjectFilesPrivate USING [AlterFunStabType, BracketPair, BracketPairBody, CheckStaticVar, FunStabInfo, FunStabSet, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, Module, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, RaiseUnreadableObjectFileForFun, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, ReadStabRope, RegisterObjectFileFlavor, ScanSymbolStabs, SLineData, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType],
PFS USING [PathFromRope, RopeFromPath, StreamFromOpenFile, OpenFileFromStream],
PFSNames USING [PATH],
Random USING [ChooseInt, Create, RandomStream],
RCTW USING [GetTokenRope, RCTWData, RCTWDataBody],
Rope USING[Concat, Equal, Fetch, FromChar, Index, IsEmpty, Length, Match, ROPE],
SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, ReleaseStreamForFile];
XCOFFFiles:
CEDAR
MONITOR
IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, RCTW, Rope, SystemInterface
EXPORTS ObjectFiles
= BEGIN
CCError: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE ← NIL] ← CCTypes.CCError;
Useful types
ROPE: TYPE ~ Rope.ROPE;
PATH: TYPE ~ PFSNames.PATH;
Following types are defined in ObjectFiles
Stab: TYPE = ObjectFiles.Stab;
StabBody: TYPE = ObjectFiles.StabBody;
StabType: TYPE = ObjectFiles.StabType;
FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC;
VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo;
some Stab types
Block: BYTE = 64H;
Brac: BYTE = 65H;
LBrac: BYTE = 00H;
RBrac: BYTE = 00H;
Fun: BYTE = 8eH;
SLine: BYTE = 00H;
STSym: BYTE = 85H;
LCSym: BYTE = 00H;
Decl: BYTE = 8cH;
GSym: BYTE = 80H;
PSym: BYTE = 82H;
LSym: BYTE = 81H;
RSym: BYTE = 83H;
SO: BYTE = 67H;
HidEnt:
BYTE = 6bH;
interesting symbol type
XTYSD: BYTE = 1; -- CSECT Section Definition --
interesting storage mapping class
XMCRW: BYTE = 5; -- Read Write Data --
Following types are defined in ObjectFilesPrivate
Parsed: TYPE = REF ParsedBody;
ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody;
Header: TYPE = REF HeaderBody;
HeaderBody: PUBLIC TYPE = ObjectFilesPrivate.HeaderBody;
Module: TYPE = REF ModuleBody;
ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody;
StabList: TYPE = ObjectFilesPrivate.StabList;
StabSet: TYPE = ObjectFilesPrivate.StabSet;
StabRange: TYPE = ObjectFilesPrivate.StabRange;
MemorySegmentInfo: TYPE ~ ObjectFilesPrivate.MemorySegmentInfo;
Following values are of global interest
unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize;
pj theContStab: Stab ~ [edo: 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 edo.stabs[i] wherever continuation stabs would appear.
DotOCookies
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 symbols are adapted from /usr/include/filehdr.h
FRelFlg: CARD16 = 0001H;
FExec: CARD16 = 0002H;
FLnNo: CARD16 = 0004H;
FLSyms: CARD16 = 0008H;
FAr16WR: CARD16 = 0080H;
FAr32WR: CARD16 = 0100H;
FAr32W: CARD16 = 0200H;
FDynLoad: CARD16 = 1000H;
FShrObj: CARD16 = 2000H;
FLdMinusR:
CARD16 = 8000H;
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[
magic: Basics.HWORD,
numSections: Basics.HWORD,
timeDate: Basics.FWORD,
symPtr: Basics.FWORD,
numSyms: Basics.FWORD,
sizeOptHdr: Basics.HWORD,
flags: Basics.HWORD];
SectionList: TYPE = REF SectionListBody;
SectionListBody:
TYPE =
RECORD[
list: SEQUENCE length: CARD OF SectionHeader];
SectionHeader: TYPE = REF SectionHeaderBody;
SectionHeaderBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
name: Rope.ROPE ← NIL,
pAddr: CARD32,
vAddr: CARD32,
size: CARD32,
dataPtr: CARD32,
relocPtr: CARD32,
lnnoPtr: CARD32,
numRelocEntries: CARD16,
numLnnoEntries: CARD16,
flags: CARD32];
WireSectionHeader: TYPE = REF WireSectionHeaderBody;
WireSectionHeaderBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
name: PACKED ARRAY [0..7] OF BYTE,
pAddr: Basics.FWORD,
vAddr: Basics.FWORD,
size: Basics.FWORD,
dataPtr: Basics.FWORD,
relocPtr: Basics.FWORD,
lnnoPtr: Basics.FWORD,
numRelocEntries: Basics.HWORD,
numLnnoEntries: Basics.HWORD,
flags: Basics.FWORD];
WireAuxHeader: TYPE = REF WireAuxHeaderBody;
WireAuxHeaderBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
magic: Basics.HWORD,
vStamp: Basics.HWORD,
textSize: Basics.FWORD,
dataSize: Basics.FWORD,
bssSize: Basics.FWORD,
entryPtr: Basics.FWORD,
textBase: Basics.FWORD,
dataBase: Basics.FWORD,
tocAddress: Basics.FWORD,
entryPtSectionNum: Basics.HWORD,
textSectionNum: Basics.HWORD,
dataSectionNum: Basics.HWORD,
tocSectionNum: Basics.HWORD,
loaderSectionNum: Basics.HWORD,
bssSectionNum: Basics.HWORD,
maxAlignmentForText: Basics.HWORD,
maxAlignmentForData: Basics.HWORD,
moduleTypeField: ARRAY [0..1] OF BYTE,
reservedField: ARRAY [0..1] OF BYTE,
maxStackSize: Basics.FWORD,
reservedFields: ARRAY [0..3] OF Basics.FWORD
];
ByteEntry: TYPE = REF ByteEntryBody;
ByteEntryBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
val(0:0..7): BYTE];
TwoByteEntry: TYPE = REF TwoByteEntryBody;
TwoByteEntryBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
val(0:0..15): Basics.HWORD];
StabSize: CARD ← 18;
WireSTEntry: TYPE = REF WireSTEntryBody;
WireSTEntryBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
name(0: 0..63): PACKED ARRAY [0..7] OF BYTE,
value(0: 64..95): Basics.FWORD,
sectionNumber(0: 96..111): Basics.HWORD,
derivedType(0: 112..119): BYTE,
type(0: 120..127): BYTE,
storageClass(0: 128..135): BYTE,
numAuxEntries(0: 136..143): BYTE,
pad(0: 144..159): Basics.HWORD
];
AuxType: TYPE = {symbol, file, csect};
WireSTAuxEntry: TYPE = REF WireSTAuxEntryBody;
WireSTAuxEntryBody:
TYPE =
MACHINE
DEPENDENT
RECORD[
aux(0: 0..159):
SELECT
OVERLAID AuxType
FROM
symbol => [
name(0: 0..63): PACKED ARRAY [0..7] OF BYTE,
pad(0: 64..159): Basics.HWORD],
file => [
fileName(0: 0..111): PACKED ARRAY [0..13] OF BYTE,
pad(0: 112..159): Basics.HWORD],
csect => [
csectLength(0: 0..31): Basics.FWORD,
parameterType(0: 32..63): Basics.FWORD,
snParameterType(0: 64..79): Basics.HWORD,
alignment(0: 80..84): [0..31],
symbolType(0: 85..87): [0..7],
storageMappingClass(0: 88..95): BYTE,
stab(0: 96..127): Basics.FWORD,
snStab(0: 128..143): Basics.HWORD,
pad(0: 144..159): Basics.HWORD]
ENDCASE];
ReadHeader: ObjectFilesPrivate.ReadHeaderProcType ~
TRUSTED {
PROC[stream: IO.STREAM] RETURNS[Header] = TRUSTED {
wHeader: WireHeader ← NEW[WireHeaderBody];
wAuxHeader: WireAuxHeader ← NEW[WireAuxHeaderBody];
nBytes: INT ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[WireHeaderBody]]];
nBytes2: INT ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wAuxHeader^], 0, Basics.Card16FromH[wHeader.sizeOptHdr]]];
magic: CARD ← Basics.Card16FromH[wHeader.magic];
nBadMagic: BOOLEAN ← (magic # OMagic) AND (magic # NMagic)AND (magic # ZMagic);
flags: CARD ← Basics.Card16FromH[wHeader.flags];
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 ← 01000H;
IF wHeader.machtype = MOldsun2 THEN OldPageSize ELSE PageSize;
SymbolSize: CARD ← 18;
RelocEntrySize: CARD ← 10;
LnnoEntrySize: CARD ← 6;
textOffset:
CARD ← Basics.Card32FromF[wAuxHeader.textBase];
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[wAuxHeader.textSize];
iDataSeg: MemorySegmentInfo ← [Basics.Card32FromF[wAuxHeader.dataBase], Basics.Card32FromF[wAuxHeader.dataSize]];
iDataSeg: SegmentInfo ← [textOffset + textSize, Basics.Card32FromF[wHeader.iDataSize]];
symsSeg: MemorySegmentInfo ← [Basics.Card32FromF[wHeader.symPtr], Basics.Card32FromF[wHeader.numSyms] *
SymbolSize];
dataRelocSeg.byteOffset+dataRelocSeg.byteLength, Basics.Card32FromF[wHeader.symsSize]];
debugSeg: MemorySegmentInfo ← [Basics.Card32FromF[wHeader.symPtr], Basics.Card32FromF[wHeader.numSyms] * SymbolSize];
textLoadOffset:
CARD32 ← 0;
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.
linnoSeg, debugSeg, textRelocSeg, dataRelocSeg: MemorySegmentInfo ← [0, 0];
iDataSeg.byteOffset+iDataSeg.byteLength, Basics.Card32FromF[wHeader.trSize]];
textRelocSeg.byteOffset+textRelocSeg.byteLength, Basics.Card32FromF[wHeader.drSize]]
numSects: CARD ← Basics.Card16FromH[wHeader.numSections];
sectionList: SectionList ← NEW[SectionListBody[numSects]];
debugIndex, textIndex, dataIndex: CARD ← LAST[CARD];
header: Header;
FOR i:
CARD
IN [0..numSects)
DO
wSectionHeader: WireSectionHeader ← NEW[WireSectionHeaderBody];
nBytes: INT ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[WireSectionHeaderBody]]];
sectionList[i] ← NEW[SectionHeaderBody];
FOR j:
CARD
IN [0..8)
DO
c: CARD ← wSectionHeader.name[j];
ch: CHAR ← VAL[c];
IF c = 0 THEN EXIT;
sectionList[i].name ← sectionList[i].name.Concat[Convert.RopeFromChar[from: ch, quote: FALSE]];
ENDLOOP;
sectionList[i].pAddr ← Basics.Card32FromF[wSectionHeader.pAddr];
sectionList[i].vAddr ← Basics.Card32FromF[wSectionHeader.vAddr];
sectionList[i].size ← Basics.Card32FromF[wSectionHeader.size];
sectionList[i].dataPtr ← Basics.Card32FromF[wSectionHeader.dataPtr];
sectionList[i].relocPtr ← Basics.Card32FromF[wSectionHeader.relocPtr];
sectionList[i].lnnoPtr ← Basics.Card32FromF[wSectionHeader.lnnoPtr];
sectionList[i].numRelocEntries ← Basics.Card16FromH[wSectionHeader.numRelocEntries];
sectionList[i].numLnnoEntries ← Basics.Card16FromH[wSectionHeader.numLnnoEntries];
sectionList[i].flags ← Basics.Card32FromF[wSectionHeader.flags];
ENDLOOP;
FOR i:
CARD
IN [0..numSects)
DO
IF Rope.Equal[sectionList[i].name, ".debug", TRUE] THEN debugIndex ← i;
IF Rope.Equal[sectionList[i].name, ".text", TRUE] THEN textIndex ← i;
IF Rope.Equal[sectionList[i].name, ".data", TRUE] THEN dataIndex ← i;
IF Rope.Equal[sectionList[i].name, ".loader", TRUE] THEN flags ← Basics.BITOR[flags, FLdMinusR];
ENDLOOP;
IF debugIndex #
LAST[
CARD]
THEN {
debugSeg ← [sectionList[debugIndex].dataPtr, sectionList[debugIndex].size];
};
IF textIndex #
LAST[
CARD]
THEN {
linnoSeg ← [sectionList[textIndex].lnnoPtr, sectionList[textIndex].numLnnoEntries * LnnoEntrySize];
textOffset ← sectionList[textIndex].dataPtr;
textRelocSeg ← [sectionList[textIndex].relocPtr, sectionList[textIndex].numRelocEntries * RelocEntrySize];
};
IF dataIndex #
LAST[
CARD]
THEN {
iDataSeg.byteOffset ← sectionList[dataIndex].dataPtr;
dataRelocSeg ← [sectionList[dataIndex].relocPtr, sectionList[dataIndex].numRelocEntries * RelocEntrySize];
};
header ←
NEW[HeaderBody ← [
dynamic: FALSE,
toolversion: BYTE[0],
machtype: BYTE[0],
magic: magic,
flags: flags,
text: [textOffset, textSize],
iData: iDataSeg,
textReloc: textRelocSeg,
dataReloc: dataRelocSeg,
syms: symsSeg,
debug: debugSeg,
linno: linnoSeg,
textLoadOffset: textLoadOffset,
bssSize: Basics.Card32FromF[wAuxHeader.bssSize],
entryPoint: Basics.Card32FromF[wAuxHeader.entryPtr],
nPageSize: nPageSize,
nEntries: Basics.Card32FromF[wHeader.numSyms],
stringOffset: symsSeg.byteOffset+symsSeg.byteLength
]];
RETURN[header];
};
EmbeddedDotOs
We assume that there are dbx stabs located in the dotO in the symbol table entry range [firstX..limitX).
We assume that the first stab is a SO stab whose value is the next module symbol table entry of the embedded dotO. We assume that this 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 EmbeddedDotO. Thus, we can use header.textSize as a (bogus) limitPC.
XCOFFModuleFromParsedAndPC: ObjectFilesPrivate.ModuleFromParsedAndPCProcType ~ {
PROC[whole: Parsed, spc: FileSegmentPC, moduleRope: ROPE ← NIL] RETURNS[Module] = {
IF whole =
NIL
THEN
RETURN[
NIL]
ELSE
{
stabRange, pcRange: StabRange;
firstX, limitX: CARD;
stream: IO.STREAM;
[stabRange, pcRange] ← AlternativeFindModuleStabRange[whole, spc.relPC, moduleRope];
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: CARD32 ← pcRange.first;
lag: LIST OF Module ← NIL;
[firstSO, ] ← BasicReadStab[whole, stream, firstX];
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, pcRange];
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, pcRange];
cell: LIST OF Module ← LIST[newModule];
IF lag # NIL THEN lag.rest ← cell ELSE whole.modules ← cell;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[newModule];
};
};
};
};
CreateModule:
PROC[parsed: Parsed, stream:
IO.
STREAM, stabRange, pcRange: StabRange ← [0, 0]]
RETURNS[Module] = {
module: Module ← NEW[ModuleBody];
rctw: RCTW.RCTWData ← NEW[RCTW.RCTWDataBody];
sizes: REF KnownSizeList ← NEW[KnownSizeList ← CopyList[KnownSizes]];
firstSO: Stab;
nStabs: CARD;
[firstSO, ] ← BasicReadStab[parsed, stream, stabRange.first, sizes];
nStabs ← stabRange.count;
prepare the embeddedDotO for a call on BuildBrackets
module.whole ← parsed;
module.firstStabX ← 0;
module.limitStabX ← stabRange.count;
module.firstPC ← pcRange.first; -- firstSO.value;
module.limitPC ← parsed.header.text.byteLength; -- (bogus, but it will suffice for reasons given earlier)
lets read the all stabs now (without 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]];
rctw.module ← module;
{I: CARD ← 0;
current: CARD ← 0;
tmp: REF StabSet ← NIL;
auxCount: CARD ← 0;
funFlag: BOOLEAN ← FALSE;
WHILE I<nStabs
DO
stab: Stab;
nAux: CARD;
[module.stabs[current], nAux] ← BasicReadStab[parsed, stream, stabRange.first+I, sizes];
stab ← module.stabs[current];
stab.module ← module;
IF funFlag
THEN {
module.stabs[current - 1].rope ← stab.rope;
funFlag ← FALSE;
};
IF stab.stabType = Fun
THEN
funFlag ← TRUE;
IF stab.stabType = LBrac
OR stab.stabType = RBrac
THEN
stab.value ← stab.value + module.firstPC;
stab.stabX ← stab.stabX - auxCount - stabRange.first + GlobalPreDefinedTypes.length;
current ← current+1;
I ← I+1+nAux;
auxCount ← auxCount + nAux;
ENDLOOP;
tmp ← module.stabs;
module.stabs ← NEW[StabSet[current + 30]];
FOR I
IN [0..current)
DO
module.stabs[I+GlobalPreDefinedTypes.length] ← tmp[I];
ENDLOOP;
FOR I
IN [0..GlobalPreDefinedTypes.length)
DO
module.stabs[I] ←
NEW[StabBody ← [
module: module,
stabX: I,
stabType: LSym,
size: 0,
value: 0,
rope: GlobalPreDefinedTypes[I]
]];
ENDLOOP;
module.limitStabX ← module.stabs[current-1].stabX + GlobalPreDefinedTypes.length + 1;
nStabs ← current;
};
now lets finish up
module.firstSO ← module.stabs[0];
module.secondSO ← IF module.stabs[module.stabs[0].dx].stabType = SO THEN module.stabs[module.stabs[0].dx] ELSE NIL;
module.fileName ← PFS.PathFromRope[IF module.secondSO = NIL THEN ReadStabRope[module.firstSO] ELSE ReadStabRope[module.secondSO]];
module.fileName ← PFS.PathFromRope[ObjectFilesPrivate.ReadStabRope[module.stabs[0]]];
module.staticVarsInstalled ← FALSE;
module.versionStampInfo ← NIL;
module.outerBracket ←
NEW[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]];
InstallPCLineNumMaps[module, stabRange];
RETURN[module];
};
Finding Embedded dotOs
StabIndexTypeAndValue: TYPE = RECORD[stabX, stabXTo: CARD, stabType: StabType, value: CARD32];
NullStabIndexTypeAndValue: StabIndexTypeAndValue = [0, 0, Invalid, 0];
This procedure should only be used when examining a dotO 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 to obtain the stab range for an embedded dot O. Those procedures use a table available from the nub to find the stab range, then produce the embedded dotO through a call on CreateEmbeddedDotO.
AlternativeFindModuleStabRange:
PROC[whole: ObjectFilesPrivate.Parsed, relativePC:
CARD, moduleRope: Rope.
ROPE ←
NIL]
RETURNS[sr: StabRange, pcRange: StabRange ← [0, 0]] = {
stream: IO.STREAM ← NIL;
IF whole =
NIL
THEN
RETURN[[0, 0]]
ELSE {
ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[whole.file, stream];
stream ← SystemInterface.GetStreamForFile[whole.file];
[sr, pcRange] ← AlternativeFindModuleStabRangeInner[whole, relativePC, moduleRope, stream];
SystemInterface.ReleaseStreamForFile[whole.file, stream];
};
};
LastStabX: CARD = 0ffffffffH;
AlternativeFindModuleStabRangeInner:
PROC[whole: ObjectFilesPrivate.Parsed, relativePC:
CARD, moduleRope: Rope.
ROPE, stream:
IO.
STREAM]
RETURNS[sr: StabRange, pcRange: StabRange ← [0, 0]] = {
firstStabX: CARD ← 0;
checkWholeFile: BOOL ← moduleRope.IsEmpty;
pattern: Rope.ROPE ← Rope.Concat[moduleRope, ".*"];
baseSO: Stab ← BasicReadStab[whole, stream, firstStabX].stab;
baseSO.value points the next baseSO on AIX.
nextStabX: CARD ← IF baseSO.value = 0 OR baseSO.value = LastStabX THEN whole.stabLimit ELSE baseSO.value;
name: Rope.ROPE ← baseSO.rope;
IF baseSO.stabType # SO THEN RETURN[[0, 0]];
WHILE firstStabX < whole.stabLimit
DO
maxPC: CARD ← 0;
minPC: CARD ← LAST[CARD];
highDbx: CARD ← baseSO.stabX;
IF checkWholeFile
OR (~name.IsEmpty
AND Rope.Match[pattern, name])
THEN {
FOR x:
CARD ← baseSO.stabX, highDbx
WHILE x < nextStabX
DO
info: StabIndexTypeAndValue ← CheckStab[whole, stream, x];
IF info.stabType = Fun
OR info.stabType = SLine
OR info.stabType = LBrac
OR info.stabType = RBrac
-- OR info.stabType = SO --
THEN {
maxPC ← MAX[maxPC, info.value];
minPC ← MIN[minPC, info.value];
};
highDbx ← info.stabXTo + 1;
ENDLOOP;
IF minPC <= relativePC
AND relativePC <= maxPC
THEN
RETURN[[baseSO.stabX, nextStabX-baseSO.stabX], [minPC, maxPC]];
};
firstStabX ← nextStabX;
baseSO ← BasicReadStab[whole, stream, firstStabX].stab;
baseSO.value points the next baseSO on AIX.
nextStabX ← IF baseSO.value = 0 OR baseSO.value = LastStabX THEN whole.stabLimit ELSE baseSO.value;
name ← baseSO.rope;
ENDLOOP;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[[0, 0]];
};
CheckStab:
ENTRY
PROC[whole: Parsed, stream:
IO.
STREAM, stabX:
CARD]
RETURNS[StabIndexTypeAndValue] = {
ENABLE UNWIND => NULL;
rope: Rope.ROPE ← NIL;
GetRope:
PROC []
RETURNS [rope: Rope.
ROPE] ~ {
IF stream#previousStream
THEN {
cloneStream←PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
previousStream ← stream;
};
rope ← RopeFromData[whole, stream, wireStabBuffer.name, wireStabBuffer.sectionNumber, wireStabBuffer.storageClass, IF wireStabBuffer.numAuxEntries = 0 THEN wireStabBuffer.name ELSE wsAux.name];
};
GetSymTypeAndClass:
PROC []
RETURNS [symType, class:
CARD] ~ {
RETURN[wsAux.symbolType, wsAux.storageMappingClass]
};
IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*StabSize];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, StabSize]]};
IF wireStabBuffer.numAuxEntries # 0
THEN {
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wsAux^], 0, StabSize]]};
};
RETURN[[stabX, stabX + wireStabBuffer.numAuxEntries, TypeFromData[wireStabBuffer.storageClass, GetRope, GetSymTypeAndClass, wireStabBuffer.type], Basics.Card32FromF[wireStabBuffer.value]]];
};
XCOFFVarLocFromStab: ObjectFilesPrivate.VarLocFromStabProcType ~ {
PROC [stab: Stab] RETURNS [DotOAccess.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.iData.byteOffset, --header.text.byteLength,--
bss => header.textReloc.byteOffset, --header.text.byteLength + header.iData.byteLength,--
ENDCASE => ERROR;
PJames 1/31/92: Doesn't look appropriate for XCoff...stab.value has a different type of value...
IF stab.value < segBase THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["value (%xH) less than segment base (%xH) for symbol %g in %g", [cardinal[stab.value]], [cardinal[segBase]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]] ]];
SELECT kind
FROM
text => segRope ← "text";
data => segRope ← "data";
bss => segRope ← "bss";
ENDCASE => ERROR;
RETURN [
NEW [ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: fSegment[
[0, segRope],
(stab.value-- - segBase--)*8,
stab.value + segBase] ]]]};
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#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: frame[bitOffset: 8*byteOffset]]];
RETURN[vLB]};
RSym => {
vLB: ObjectFiles.VarLoc;
IF 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: register[regNum: stab.value]]],
offset: CirioTypes.zeroBA]]]
ELSE vLB ←
NEW[ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: register[regNum: stab.value]]];
RETURN[vLB]
};
GSym =>
RETURN [
NEW [ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#LAST[CARD] AND 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[stab.size]], [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;
FMap: TYPE ~ LIST OF FMapData;
FMapBody:
TYPE ~
RECORD [
seq: SEQUENCE len: CARD OF FMapData];
FMapData: TYPE ~ REF FMapDataBody;
FMapDataBody:
TYPE ~
RECORD[
fName: Rope.ROPE,
stabOffset: CARD];
InstallPCLineNumMaps:
PROC[module: Module, stabRange: StabRange] = {
fMap, fMapTmp: FMap ← NIL;
firstStabX: CARD ← stabRange.first;
limitStabX: CARD ← stabRange.first + stabRange.count;
CompareByCLineNum:
PROC[ref1:
REF
ANY, ref2:
REF
ANY]
RETURNS [Basics.Comparison] =
BEGIN
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];
END;
CompareByPC:
PROC[ref1:
REF
ANY, ref2:
REF
ANY]
RETURNS [Basics.Comparison] =
BEGIN
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];
END;
CompareBySI: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] =
BEGIN
info1: FMapData ← NARROW[ref1];
info2: FMapData ← NARROW[ref2];
IF info1.stabOffset < info2.stabOffset THEN RETURN[less];
IF info1.stabOffset > info2.stabOffset THEN RETURN[greater];
RETURN[equal];
END;
IF module.pcToLineNum #
NIL
OR module.lineNumToPC #
NIL
THEN {
IF module.pcToLineNum = NIL OR module.lineNumToPC = NIL THEN ERROR;
RETURN;
};
we have to create them
{
nItems: INTEGER ← 0;
list1: LIST OF REF ANY ← NIL; -- LIST OF REF SLineData
list2: LIST OF REF ANY ← NIL; -- LIST OF REF SLineData
sortedList: LIST OF REF ANY ← NIL;
linno, relPC, pOffset: CARD ← 0;
inCurrentModule: BOOLEAN ← FALSE;
stream: IO.STREAM ← SystemInterface.GetStreamForFile[module.whole.file];
IO.SetIndex[stream, module.whole.header.linno.byteOffset];
FOR
I:
CARD
IN [0..module.whole.header.linno.byteLength / 6)
DO
IO.SetIndex[stream, module.whole.header.linno.byteOffset + I*6];
relPC ← Basics.Card32FromF[IO.GetFWord[stream]];
linno ← Basics.Card16FromH[IO.GetHWord[stream]];
IF linno = 0
THEN
IF relPC <= limitStabX
AND relPC >= firstStabX
THEN {
inCurrentModule ← TRUE;
IO.SetIndex[stream, module.whole.header.syms.byteOffset + 18 * relPC + 18 * 5 + 4];
pOffset ← Basics.Card16FromH[IO.GetHWord[stream]];
}
ELSE
inCurrentModule ← FALSE
ELSE
IF inCurrentModule
THEN {
info: REF SLineData ← NEW[SLineData ← [cLineNum: linno + pOffset - 1, parsedRelPC: [[0 --??--, PFS.RopeFromPath[module.fileName]], relPC]]];
list1 ← CONS[info, list1];
list2 ← CONS[info, list2];
nItems←nItems + 1;
};
ENDLOOP;
SystemInterface.ReleaseStreamForFile[module.whole.file, stream];
FOR I: CARD IN [module.firstStabX..module.limitStabX) DO
stab: Stab ← ReadStab[module, I];
IF stab.stabType = SLine THEN {
info: REF SLineData ← NEW[SLineData←[cLineNum: --pj fill this in! stab.desc-- 0, parsedRelPC: [[2, ".text"], stab.value]]];
list1 ← CONS[info, list1];
list2 ← CONS[info, list2];
nItems ← nItems+1};
sortedList ← List.Sort[list1, CompareByCLineNum];
module.lineNumToPC ← NEW[LineNumToPCMapBody[nItems]];
FOR
I:
INTEGER
IN [0..nItems)
DO
info: REF SLineData ← NARROW[sortedList.first];
module.lineNumToPC[I] ← info^;
sortedList ← sortedList.rest;
ENDLOOP;
sortedList ← List.Sort[list2, CompareByPC];
module.pcToLineNum ← NEW[PCtoLineNumMapBody[nItems]];
FOR
I:
INTEGER
IN [0..nItems)
DO
info: REF SLineData ← NARROW[sortedList.first];
module.pcToLineNum[I] ← info^;
sortedList ← sortedList.rest;
ENDLOOP;
};
};
Stabs
This routine treats stabX as relative to the entire containing dotO file.
warning: does NOT relocate LBrac or RBrac stabs.
warning: does NOT read the associated rope
Also: the edo field is set to NIL;
BasicReadStab:
ENTRY
PROC[parsed: Parsed, stream:
IO.
STREAM, stabX:
CARD, sizes:
REF KnownSizeList ←
NIL]
RETURNS[stab: Stab, nAux:
CARD ← 0] ~ {
ENABLE UNWIND => NULL;
stab ← NEW[StabBody];
[stab^, nAux] ← ReadStabBody[parsed, stream, stabX, sizes];
RETURN
};
TypeFromData:
PROC [data:
BYTE, getName:
PROC
RETURNS [Rope.
ROPE], getSymTypeAndClass:
PROC
RETURNS [symType, class:
CARD], typ:
BYTE ← 0]
RETURNS [stabType: StabType] ~ {
dataVal: CARD ← data;
typeVal: CARD ← typ;
IF typeVal = 20H
THEN
stabType ← Fun
ELSE
SELECT dataVal
FROM
Block =>
{
name: Rope.ROPE ← getName[];
SELECT
TRUE
FROM
Rope.Equal[".bb", name] => stabType ← LBrac;
Rope.Equal[".eb", name] => stabType ← RBrac;
ENDCASE => ERROR;
};
Brac =>
{
name: Rope.ROPE ← getName[];
SELECT
TRUE
FROM
Rope.Equal[".bf", name] => stabType ← LBrac;
Rope.Equal[".ef", name] => stabType ← RBrac;
ENDCASE => ERROR;
};
00000H => SLine; -- no SLine s in XCOFF
Fun => stabType ← Fun; -- gets in the way.
PSym => stabType ← PSym;
LSym => stabType ← LSym;
RSym => stabType ← RSym;
STSym => stabType ← STSym;
00000H => LCSym; -- ?
GSym => stabType ← GSym;
HidEnt =>
{
symType, class: CARD;
[symType, class] ← getSymTypeAndClass[];
IF symType = XTYSD AND class = XMCRW THEN stabType ← Invalid ELSE stabType ← Unspecified;
};
00000H => Main; -- not used?
SO => stabType ← SO;
00000H => BIncl;
00000H => EIncl;
00000H => SOL;
ENDCASE => stabType ← Unspecified
};
DebugStab: CARD = 0fffeH;
previousStream: IO.STREAM ← NIL;
cloneStream: IO.STREAM ← NIL;
ReadStabBody:
PROC [parsed: Parsed, stream:
IO.
STREAM, stabX:
CARD, sizes:
REF KnownSizeList]
RETURNS [stab: StabBody, nAux:
CARD ← 0] ~ {
size: CARD;
rope: Rope.ROPE ← NIL;
GetRope:
PROC []
RETURNS [Rope.
ROPE] ~ {
RETURN[rope]
};
GetSymTypeAndClass:
PROC []
RETURNS [symType, class:
CARD] ~ {
RETURN[wsAux.symbolType, wsAux.storageMappingClass]
};
IO.SetIndex[stream, parsed.header.syms.byteOffset+stabX*StabSize];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, StabSize]]};
IF wireStabBuffer.numAuxEntries # 0
THEN {
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wsAux^], 0, StabSize]]};
};
nAux ← wireStabBuffer.numAuxEntries;
IF stream#previousStream
THEN {
cloneStream←PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
previousStream ← stream;
};
rope ← RopeFromData[parsed, cloneStream, wireStabBuffer.name, wireStabBuffer.sectionNumber, wireStabBuffer.storageClass, IF wireStabBuffer.numAuxEntries = 0 THEN wireStabBuffer.name ELSE wsAux.name];
IF sizes #
NIL
THEN
[size, sizes^] ← SizeFromName[rope, sizes^]
stab ← [
module: NIL,
stabX: stabX,
stabType: TypeFromData[wireStabBuffer.storageClass, GetRope, GetSymTypeAndClass, wireStabBuffer.type], --wireStabBuffer.type,
value: Basics.Card32FromF[wireStabBuffer.value],
size: size,
rope: rope
];
RETURN};
dataChar: ByteEntry ← NEW[ByteEntryBody];
RopeFromData:
PROC [parsed: Parsed, stream:
IO.
STREAM, data:
PACKED
ARRAY [0..7]
OF
BYTE, sn: Basics.
HWORD, storeClass:
BYTE, auxData:
PACKED
ARRAY [0..7]
OF
BYTE]
RETURNS [name: Rope.
ROPE ←
NIL] ~
TRUSTED {
len: TwoByteEntry ← NEW[TwoByteEntryBody];
dbg: BOOL ← IF Basics.Card16FromH[sn] = DebugStab THEN TRUE ELSE FALSE;
sum, offset: CARD ← 0;
IF dbg
AND storeClass = 67H
THEN {
data ← auxData;
dbg ← FALSE;
};
offset ← IF dbg THEN parsed.header.debug.byteOffset ELSE parsed.header.stringOffset;
FOR i:
CARD
IN [0..4)
DO
n: CARD ← data[i];
sum ← sum + n;
ENDLOOP;
IF sum = 0
THEN {
FOR i:
CARD
IN [4..8)
DO
n: CARD ← data[i];
sum ← sum * 256 + n;
ENDLOOP;
IO.SetIndex[stream, offset + sum];
IF IO.EndOf[stream] THEN RETURN[""];
DO
c: CHAR ← ' ;
c ← IO.GetChar[stream];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@dataChar^], 0, 1]]};
c ← dataChar.val;
IF c = VAL[0] THEN EXIT;
name ← name.Concat[Convert.RopeFromChar[from: c, quote: FALSE]];
ENDLOOP;
}
ELSE
FOR i:
CARD
IN [0..8)
DO
num: CARD ← data[i];
IF num = 0 THEN EXIT;
name ← name.Concat[Convert.RopeFromChar[from: VAL[num], quote: FALSE]];
ENDLOOP;
RETURN
};
wireStabBuffer: WireSTEntry ← NEW[WireSTEntryBody];
wsAux: WireSTAuxEntry ←
NEW[WireSTAuxEntryBody];
all users should be in the monitor
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, "XCOFF"];
IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed], IO.time[start]];
FOR
I:
INT
IN [0..100)
DO
range: StabRange;
pc: CARD ← Random.ChooseInt[rs, 0, whole.header.text.byteLength];
[range, ] ← 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];
};
SizeFromName:
PROC[name:
ROPE, sizes: KnownSizeList ←
NIL]
RETURNS [size:
CARD ← 0, newSizes: KnownSizeList] ~ {
c: CHAR;
newID: CARD;
where: CARD ← 0;
IF sizes = NIL THEN RETURN;
newSizes ← sizes;
where ← Rope.Index[name, 0, ":"] + 1;
IF where = ABS[name.Length[]]+ 1 THEN RETURN;
IF (c ← name.Fetch[where]) # 't
AND c # 'T
THEN {
typeID: INT;
IF IsDigit[c]
OR c = '-
THEN
[typeID, ] ← GetNum[name, where]
ELSE
[typeID, ] ← GetNum[name, where+1];
typeID: INT ← -1;
IF IsDigit[c] THEN
typeID ← Convert.IntFromRope[name.Substr[where]]
ELSE
typeID ← Convert.IntFromRope[name.Substr[where + 1]];
RETURN[FindInList[typeID, sizes], newSizes];
};
[newID, where] ← GetNum[name, where+ 1];
IF name.Fetch[where] # '= THEN ERROR;
where ← where + 1;
SELECT name.Fetch[where]
FROM
'f => {
type: INT;
[type, where] ← GetNum[name, where+ 1];
size ← FindInList[type, sizes];
};
'*, 'e => size ← 4;
'u, 's => {
[size, where] ← GetNum[name, where +1]};
'a => {
garb, start, end, type: INT;
baseSize: CARD;
c: CHAR ← name.Fetch[where + 1];
IF c# 'r THEN ERROR;
[garb, where] ← GetNum[name, where+2];
IF name.Fetch[where] # '; THEN ERROR;
[start, where] ← GetNum[name, where+1];
IF name.Fetch[where] # '; THEN ERROR;
[end, where] ← GetNum[name, where+1];
IF name.Fetch[where] # '; THEN ERROR;
[type, where] ← GetNum[name, where+1];
baseSize ← FindInList[type, sizes];
size ← (end - start + 1) * baseSize;
};
ENDCASE => size ← 0;
newSizes ← CONS[[newID, size], newSizes];
size ← 0;
};
GetNum:
PROC [rope:
ROPE, index:
CARD]
RETURNS [num:
INT ← 0, newIndex:
CARD ← 0] ~ {
len: CARD ← rope.Length[];
i: CARD;
negFlag: BOOL ← FALSE;
FOR i ← index, i + 1
UNTIL i = len
DO
c: CHAR ← rope.Fetch[i];
IF ~IsDigit[c]
AND c # '-
THEN {
newIndex ← i;
EXIT;
};
IF c = '-
THEN
negFlag ← TRUE
ELSE
num ← num * 10 + (c - '0);
ENDLOOP;
IF i = len
THEN
newIndex ← i;
IF negFlag
THEN
num ← -num;
};
KnownSize: TYPE ~ RECORD[typeID: INT, size: CARD];
KnownSizeList: TYPE ~ LIST OF KnownSize;
These sizes were determined from /usr/include/dbxstclass.h (no guarantees though)
KnownSizes: KnownSizeList ← LIST[[-1, 4], [-2, 1], [-3, 2], [-4, 4], [-5, 1], [-6, 1], [-7, 2], [-8, 4], [-9, 4], [-10, 4], [-11, 0], [-12, 4], [-13, 8], [-14, 10], [-15, 4], [-16, 1], [-17, 4], [-18, 8], [-19, 1], [-20, 1], [-21, 1], [-22, 2], [-23, 1], [-24, 1], [-25, 8], [-26, 16], [-27, 1], [-28, 2], [-29, 4], [-30, 2]];
CopyList:
PROC [l: KnownSizeList]
RETURNS [n: KnownSizeList ←
NIL] ~ {
n ← NIL;
FOR i: KnownSizeList ← l, i.rest
WHILE i #
NIL
DO
n ← CONS[i.first, n];
ENDLOOP;
};
FindInList:
PROC [i:
INT, l: KnownSizeList]
RETURNS [s:
CARD ←
LAST[
CARD]] ~ {
FOR loop: KnownSizeList ← l, loop.rest
WHILE loop #
NIL
DO
IF loop.first.typeID = i THEN RETURN[loop.first.size];
ENDLOOP;
ERROR;
};
IsDigit:
PROC [c:
CHAR]
RETURNS [
BOOL]
= INLINE { RETURN [c IN ['0 .. '9]] };
XCOFFGetTypeRef: ObjectFilesPrivate.GetTypeRefProcType ~ {
PROC [sourceStream:IO.STREAM] RETURNS [Rope.ROPE]
typeRef: Rope.ROPE;
lastChar: CHAR;
IF IsDigit[lastChar ←
IO.PeekChar[sourceStream]]
OR lastChar = '-
THEN {
typeRef ← RCTW.GetTokenRope[sourceStream];
RETURN[typeRef]}
ELSE
DO
lastChar ← IO.GetChar[sourceStream];
typeRef ← Rope.Concat[typeRef, Rope.FromChar[lastChar]];
IF lastChar = ') THEN RETURN[typeRef]
ENDLOOP
};
The function stab is module.funStabs[funStabIndex].stab
XCOFFInstallBracketPairsForOneFunStab:
PROC[module: Module, funStabIndex:
CARD] =
{
funStab: Stab ← module.funStabs[funStabIndex].stab;
paramNames, lastParamName: LIST OF Rope.ROPE ← NIL;
paramStabs, lastParamStab: LIST OF Stab ← NIL; -- includes param mod stabs
x: CARD ← funStab.stabX+1;
good: BOOL ← TRUE;
module.funStabs[funStabIndex].brackets ←
NEW[BracketPairBody←[
module: module,
kind: syntheticFun,
firstX: funStab.stabX,
limitX: 0,
firstPC: funStab.value,
pcLimit: 0,
funStab: funStab,
funIndex: funStabIndex,
symbols: NIL,
innerBrackets: NIL]];
The following loop finds the limitX and pcLimit. These might be at different X values if there are global symbols between procedures (which can happen with Sun's cc). good goes false once we've found the limitX and are just looking for the pcLimit. The loop also accumulates innerBrackets, if any. We make a feeble attempt to distinguish parameters from local variables; this attempt will fail for Gnu cc; it it's important to get this right, look at the `symbol descriptor' in a variable's stab.
We assume the following structure:
some param stabs
some stabs that modify the param stabs
symbol stabs for the first inner block (if any)
Note that both C compilers feels free to omit the LBrac and RBrac of a procedure with no local variables. Gnu cc further feels free to omit the L&RBrac of procedures with no non-trivial nested scopes.
WHILE x < module.limitStabX
DO
stab: Stab ← ObjectFilesPrivate.ReadStab[module, x];
TakeBP:
PROC ~ {
finalRBracX: CARD;
[finalRBracX, module.funStabs[funStabIndex].brackets.innerBrackets, paramStabs] ← ScanOneBracketPairSequence[module, funStab, funStabIndex, x, paramStabs, lastParamStab];
IF good THEN module.funStabs[funStabIndex].brackets.limitX ← finalRBracX+1;
module.funStabs[funStabIndex].brackets.pcLimit ←
IF finalRBracX<module.limitStabX
THEN ObjectFilesPrivate.ReadStab[module, finalRBracX].value
ELSE module.limitPC;
RETURN};
IF stab = NIL THEN LOOP;
SELECT stab.stabType
FROM
PSym => {
stabCell: LIST OF Stab ← LIST[stab];
name: Rope.ROPE ← ObjectFiles.CNameOfStab[stab];
nameCell: LIST OF Rope.ROPE ← LIST[name];
IF paramStabs#NIL AND stab=paramStabs.first THEN ERROR;
IF paramNames = NIL THEN paramNames ← nameCell ELSE lastParamName.rest ← nameCell;
lastParamName ← nameCell;
IF paramStabs = NIL THEN paramStabs ← stabCell ELSE lastParamStab.rest ← stabCell;
lastParamStab ← stabCell};
RSym, LSym => {
stabCell: LIST OF Stab ← LIST[stab];
name: Rope.ROPE ← ObjectFiles.CNameOfStab[stab];
isAParam: BOOLEAN ← FALSE; -- initial value
FOR pNames:
LIST
OF Rope.
ROPE ← paramNames, pNames.rest
WHILE pNames #
NIL
DO
IF Rope.Equal[name, pNames.first]
THEN
{isAParam ← TRUE; EXIT};
ENDLOOP;
IF isAParam
THEN {
IF paramStabs = NIL THEN paramStabs ← stabCell ELSE lastParamStab.rest ← stabCell;
lastParamStab ← stabCell}
ELSE
-- we are facing the first symbol of a nested block
{TakeBP[]; EXIT};
};
GSym, LCSym, STSym =>
IF good
THEN {
module.funStabs[funStabIndex].brackets.limitX ← stab.stabX;
good ← FALSE};
SLine, Unspecified => NULL;
LBrac => {TakeBP[]; EXIT};
Fun => {
IF good THEN module.funStabs[funStabIndex].brackets.limitX ← stab.stabX;
module.funStabs[funStabIndex].brackets.pcLimit ← stab.value;
EXIT};
ENDCASE => ObjectFilesPrivate.RaiseUnreadableObjectFileForFun[
IO.PutFR["Unexpected stab (of stabType %02xH) in intro to %g",
[rope[ObjectFiles.RopeForStabType[stab.stabType]]],
[rope[ObjectFiles.CNameOfStab[funStab]]] ],
module, funStab];
x ← x + 1;
REPEAT
FINISHED => {
IF good THEN module.funStabs[funStabIndex].brackets.limitX ← module.limitStabX;
module.funStabs[funStabIndex].brackets.pcLimit ← module.limitPC;
};
ENDLOOP;
module.funStabs[funStabIndex].brackets.symbols ← paramStabs;
this is coded to expect the symbols before the LBrac.
We have discovered that the Sun C compiler places local variables symbols in the symbol table before their enclosing left bracket.!! This is confirmed by the example in "Dbx and Dbxtool Interfaces, Second Edition, Revised, 7 January 1988. See lines 46 and 47 on page 28. It is also confirmed by some comments in /import/gdb/dbxread.c. See source position 90236. This is in the vicinity of "case N←RBRAC". On the positive side, the code in /import/gdb/dbxread.c confirms that the local variables symbols are expected to be properly sorted in some way with respect to the RBrac/LBrac stabs.
The comment in /import/gdb/dbxread.c also suggests that there are some C compilers that place the symbols inside the LBrac/RBrac pair. It shouldn't be difficult to recode this to handle the second case. One will have to collect the symbols during the scan. For full generality, one might expect to receive the symbols anytime one is outside an inner pair.
We assume that firstX is pointing at the first symbol of the first bracket pair. (If the enclosing bracket pair is an innermost pair, then firstX is pointing at either an RBrac, a Fun, or is an attempt to go past the end of the symbol table.)
Upon return, nextX will point to an unmatched RBrac, a Fun, or will be an attempt to go past the end of the symbol table.
BracketPair: TYPE ~ ObjectFilesPrivate.BracketPair;
BracketPairBody: TYPE ~ ObjectFilesPrivate.BracketPairBody;
ScanOneBracketPairSequence:
PROC[module: Module, fun: Stab, funIndex:
CARD, firstX:
CARD, symHead, symTail: StabList]
RETURNS[
--finalRBracX--
CARD,
--innerBrackets--
LIST
OF BracketPair,
--symbols-- StabList] =
{
innerBrackets: LIST OF BracketPair ← NIL;
lastInnerBracket: LIST OF BracketPair ← NIL;
x: CARD ← firstX;
DO
xAfterSymbs: CARD;
stabAfterSymbs: Stab;
[xAfterSymbs, symHead, symTail] ← ObjectFilesPrivate.ScanSymbolStabs[module, x, symHead, symTail];
IF xAfterSymbs >= module.limitStabX
THEN
RETURN[xAfterSymbs, innerBrackets, symHead];
stabAfterSymbs ← ObjectFilesPrivate.ReadStab[module, xAfterSymbs];
SELECT stabAfterSymbs.stabType
FROM
LBrac =>
{
finalRBracX: CARD;
nestedInnerBrackets: LIST OF BracketPair;
bracket: BracketPair;
bracketCell: LIST OF BracketPair;
[finalRBracX, nestedInnerBrackets, symHead] ← ScanOneBracketPairSequence[module, fun, funIndex, xAfterSymbs+1, symHead, symTail];
bracket ←
NEW[BracketPairBody←[
module: module,
kind: actual,
firstX: stabAfterSymbs.stabX,
limitX: finalRBracX+1,
firstPC: stabAfterSymbs.value,
pcLimit: IF finalRBracX<module.limitStabX THEN ObjectFilesPrivate.ReadStab[module, finalRBracX].value ELSE module.limitPC,
funIndex: funIndex,
symbols: symHead,
innerBrackets: nestedInnerBrackets]];
bracketCell ← LIST[bracket];
IF innerBrackets = NIL THEN innerBrackets ← bracketCell ELSE lastInnerBracket.rest ← bracketCell;
lastInnerBracket ← bracketCell;
symHead ← symTail ← NIL;
x ← finalRBracX+1;
};
RBrac, Fun, GSym, STSym, LCSym => RETURN[xAfterSymbs, innerBrackets, symHead];
ENDCASE => ERROR; -- can't happen
ENDLOOP};
GlobalPreDefinedTypes: REF PDTType ← NIL;
GPTDs:
LIST
OF Rope.
ROPE ←
LIST [
"int:t-1=r-1;-2147483648;2147483647",
"char:t-2=@s8;r-2;0;255",
"short:t-3=@s16;r-3;-32768;32767",
"long:t-4=-1",
"unsigned char:t-5=@s8;r-5;0;255",
"signed char:t-6=@s8;r-6;-128;127",
"unsigned short:t-7=@s16;r-7;0;65535",
"unsigned int:t-8=r-8;0;4294967295",
"unsigned:t-9=-8",
"unsigned long:t-10=-8",
"void:t-11=r-11;0;0",
"float:t-12=g-12;4",
"double:t-13=g-12;8",
"long double:t-14=g-12;10",
"integer:t-15=-1",
"boolean:t-16=efalse:0,true:1,",
"shortreal:t-17=g-12;4",
"real:t-18=g-12;8",
"stringptr:t-19=N-19",
"character:t-20=@s8;r-20;0;255",
"logical*1:t-21=@s8;r-21;0;255",
"logical*2:t-22=@s16;r-22;0;65535",
"logical*4:t-23=r-23;0;4294967295",
"logical:t-24=-23",
"complex:t-25=c-25;8",
"double complex:t-26=c-25;16",
"integer*1:t-27=-6",
"integer*2:t-28=-3",
"integer*4:t-29=-1",
"wchar:t-30=@s16;r-30;0;65535"];
PDTType: TYPE ~ RECORD [body: SEQUENCE length: CARD OF Rope.ROPE];
IntallPreDefinedTypes:
PROC ~ {
count: CARD ← 0;
l: LIST OF Rope.ROPE ← NIL;
FOR l ← GPTDs, l.rest
UNTIL l =
NIL
DO
count ← count + 1;
ENDLOOP;
GlobalPreDefinedTypes ← NEW[PDTType[count]];
l ← GPTDs;
FOR index:
CARD
IN [0..count)
DO
GlobalPreDefinedTypes[index] ← l.first;
l ← l.rest;
ENDLOOP;
};
It seems AIX ld doesn't relocate static symbol (STSym) offset. So, we get data section's base offset and add the offset to local symbol offset.
GetDataSectionOffset:
PROC[module: Module]
RETURNS[
CARD] ~ {
IsDotO:
PROC
RETURNS[
BOOL] ~ {
RETURN[Basics.BITAND[module.whole.header.flags, (FLdMinusR+FShrObj+FDynLoad+FExec)] = 0];
};
Section's base offset doesn't correct if file is .o.
IF IsDotO[] THEN RETURN [0];
FOR x:
CARD
DECREASING
IN [module.firstStabX..module.limitStabX)
DO
stab: Stab ← ObjectFilesPrivate.ReadStab[module, x];
IF stab.stabType = Invalid THEN RETURN [stab.value];
ENDLOOP;
RETURN [0];
};
XCOFFInstallStaticVars: 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.
{
numFuns: INT ← 1;
dataStabOffset: CARD ← 0; -- globalFrame stab seems to be offset from versionStringStab, which has to be searched for at times...
IF
NOT module.staticVarsInstalled
THEN
FOR y:
CARD
IN [module.firstStabX..module.limitStabX)
DO
x: CARD ← module.firstStabX + module.limitStabX - 1 - y;
stab: Stab ← ObjectFilesPrivate.ReadStab[module, x];
IF stab = NIL THEN LOOP;
IF stab.stabType = Fun
THEN {
IF numFuns = 0 THEN EXIT;
numFuns ← numFuns - 1;
};
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
{
stream: IO.STREAM ← NIL;
dataRope: Rope.ROPE;
module.versionStampStab ← stab;
dataStabOffset ← GetDataSectionOffset[module];
dataRope ← ObjectFilesPrivate.ReadInitialDataAsRope[module, gvi.fileByteOffset + dataStabOffset];
IF dataRope.IsEmpty[]
THEN {
ENABLE UNWIND => SystemInterface.ReleaseStreamForFile [module.whole.file, stream];
Force find the version stamp mob
Before ld, the version stamp mob is further into the
.data section than usual, and the stab entry shows
no indication of this, so if no rope was found at
the correct location, walk through until @(#) is found.
searchFor: Rope.ROPE ← "@(#)";
c: CHAR;
searchForIndex: INT ← 0;
found: BOOL ← FALSE;
stream ← SystemInterface.GetStreamForFile[module.whole.file];
IO.SetIndex[stream, gvi.fileByteOffset + dataStabOffset];
dataRope ← "";
WHILE ~found
DO
tmpOffset: CARD ← 0;
WHILE ((c ←
IO.GetChar[stream]) # searchFor.Fetch[searchForIndex])
DO
dataStabOffset ← dataStabOffset + 1;
ENDLOOP;
tmpOffset ← tmpOffset + 1;
searchForIndex ← searchForIndex + 1;
WHILE (searchForIndex < searchFor.Length[]
AND (c ←
IO.GetChar[stream]) = searchFor.Fetch[searchForIndex])
DO
tmpOffset ← tmpOffset + 1;
searchForIndex ← searchForIndex + 1;
ENDLOOP;
tmpOffset ← tmpOffset + 1;
IF searchForIndex = searchFor.Length[]
THEN
found ← TRUE
ELSE
dataStabOffset ← dataStabOffset + tmpOffset;
ENDLOOP;
dataRope ← searchFor;
WHILE ((c ←
IO.GetChar[stream]) # '\000)
DO
dataRope ← dataRope.Concat[Rope.FromChar[c]];
ENDLOOP;
SystemInterface.ReleaseStreamForFile [module.whole.file, stream];
};
stab.value ← stab.value+dataStabOffset;
IF module.globalFrameStab #
NIL
THEN
module.globalFrameStab.value ← module.globalFrameStab.value + dataStabOffset;
IF module.globalFrameStab #
NIL
THEN {
module.globalFrameGvl.bitOffset ← module.globalFrameGvl.bitOffset + dataStabOffset * 8;
module.globalFrameGvl.fileByteOffset ← module.globalFrameGvl.fileByteOffset + dataStabOffset;
};
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;
};
XCOFFAlterFunStab: ObjectFilesPrivate.AlterFunStabType ~ {
rope assignement has been done in CreateModule.
module.funStabs[funStabX].stab.rope ← module.stabs[module.funStabs[funStabX].firstX+1].rope;
RETURN [module.funStabs[funStabX].stab]; };
XCOFFGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ {
On AIX, SP offset from FP is always 0 (SP = FP).
RETURN [0];
};
Main code
transTable: ObjectFilesPrivate.TranslationTable;
IntallPreDefinedTypes[];
transTable ←NEW[ObjectFilesPrivate.TranslationTableBody[1]];
Commander.Register["xcoffRandomTestFindStabRange", RandomTestFindStabRange];
transTable[0] ← [0, 2, 479, "XCOFF"];
ObjectFilesPrivate.RegisterObjectFileFlavor[
NEW [ObjectFilesPrivate.ObjectFileFlavorBody ← [
"XCOFF",
XCOFF,
ReadHeader,
XCOFFModuleFromParsedAndPC,
XCOFFVarLocFromStab,
XCOFFGetTypeRef,
XCOFFInstallBracketPairsForOneFunStab,
NIL, NIL, NIL,
FALSE,
XCOFFInstallStaticVars,
XCOFFAlterFunStab,
XCOFFGetSPOffset
]],
transTable];
END.