SGIFiles.mesa
Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved.
Modified from DotOAccessImpl.mesa
Edwards, June 16, 1992 12:05 pm PDT
Jas, January 8, 1993 1:30 pm PST
Katsuyuki Komatsu January 25, 1993 4:15 pm PST
DIRECTORY
Basics USING [Card16FromH, Card32FromF, Comparison, BITLSHIFT, BITRSHIFT, BITAND, BITOR, FWORD, HWORD],
BasicTime USING [GMT, Now],
CCTypes USING [CCError, CCErrorCase],
CirioTypes USING [zeroBA],
Commander USING [Register, Handle],
CommandTool USING [ArgumentVector, Parse],
Convert USING [IntFromRope, RopeFromChar],
IO USING [card, EndOf, GetChar, GetIndex, PutF, PutFR, SetIndex, STREAM, time, UnsafeGetBlock],
List USING [CompareProc, Sort],
ObjectFiles USING [BracketNest, BracketPairKind, BracketProc, CNameOfStab, CreateParsed, DescribeModule, FileSegmentPC, FunInfo, GlobalVarLoc, MakeUnknownVarLoc, ModuleInfo, Parsed, RopeForStabType, SimpleSeg, Stab, StabBody, StorageClass, StabType, SymbolProc, UnreadableObjectFile, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo],
ObjectFilesPrivate USING [AlterFunStabType, BracketConsumer, BracketPair, BracketPairBody, CheckStaticVar, FnConsumer, FunStabSet, FunStabInfo, FunHandleBody, FunStabSetBody, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, Module, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, RegisterObjectFileFlavor, RaiseUnreadableObjectFileForFun, SLineData, ScanSymbolStabs, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType],
PFS USING [PathFromRope, RopeFromPath],
PFSNames USING [PATH],
Random USING [ChooseInt, Create, RandomStream],
Rope USING [Concat, Equal, FromChar, ROPE],
SGI,
SystemInterface USING [CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, GetNameOfFile, ReleaseStreamForFile, ShowReport],
UXStrings USING [UnixString, Create];
SGIFiles: CEDAR MONITOR
IMPORTS Basics, BasicTime, CCTypes, Commander, CommandTool, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, Rope, SystemInterface, UXStrings
EXPORTS ObjectFiles, SGI =
BEGIN
CCError: ERROR[case: CCTypes.CCErrorCase, msg: ROPENIL] ← CCTypes.CCError;
Useful type definitions
ROPE: TYPE = Rope.ROPE;
PATH: TYPE = PFSNames.PATH;
Comparison: TYPE = Basics.Comparison;
FWORD: TYPE = Basics.FWORD;
HWORD: TYPE = Basics.HWORD;
Following types are defined in ObjectFiles
Stab: TYPE = ObjectFiles.Stab;
StabBody: TYPE = ObjectFiles.StabBody;
StabType: TYPE = ObjectFiles.StabType;
StorageClass: TYPE = ObjectFiles.StorageClass;
FunInfo: TYPE = ObjectFiles.FunInfo;
SymbolProc: TYPE = ObjectFiles.SymbolProc;
BracketProc: TYPE = ObjectFiles.BracketProc;
BracketNest: TYPE = ObjectFiles.BracketNest;
BracketPairKind: TYPE = ObjectFiles.BracketPairKind;
VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo;
Following types are defined in ObjectFilesPrivate
Parsed: TYPE = REF ParsedBody;
ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody;
Module: TYPE = REF ModuleBody;
ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody;
ModuleInfo: TYPE = ObjectFiles.ModuleInfo;
StabSet: TYPE = ObjectFilesPrivate.StabSet;
StabRange: TYPE = ObjectFilesPrivate.StabRange;
MemorySegmentInfo: TYPE = ObjectFilesPrivate.MemorySegmentInfo;
FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC;
BracketPair: TYPE = REF BracketPairBody;
BracketPairBody: TYPE = ObjectFilesPrivate.BracketPairBody;
FunStabSet: TYPE = ObjectFilesPrivate.FunStabSet;
FunStabSetBody: TYPE = ObjectFilesPrivate.FunStabSetBody;
FunStabInfo: TYPE = ObjectFilesPrivate.FunStabInfo;
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;
Header: TYPE = REF HeaderBody;
HeaderBody: PUBLIC TYPE = ObjectFilesPrivate.HeaderBody;
FunHandle: TYPE = REF FunHandleBody;
FunHandleBody: TYPE = ObjectFilesPrivate.FunHandleBody;
Type defs for this module
WireHeader: TYPE = REF SGI.WireHeaderBody;
WireAuxHeader: TYPE = REF SGI.WireAuxHeaderBody;
WireSectionHeader: TYPE = REF SGI.WireSectionHeaderBody;
WireSymHeader: TYPE = REF SGI.WireSymHeaderBody;
WirePackedLineNum: TYPE = REF SGI.WirePackedLineNumBody;
WireProcDescriptor: TYPE = REF SGI.WireProcDescriptorBody;
WireRelFileTable: TYPE = REF SGI.WireRelFileTableBody;
WireFileDescriptor: TYPE = REF SGI.WireFileDescriptorBody;
WireSTEntry: TYPE = REF SGI.WireSTEntryBody;
WireExtSTEntry: TYPE = REF SGI.WireExtSTEntryBody;
WireTypeInfo: TYPE = REF SGI.WireTypeInfoBody;
WireRelIndex: TYPE = REF SGI.WireRelIndexBody;
WireAuxSTEntry: TYPE = REF SGI.WireAuxSTEntryBody;
SectionTable: TYPE = REF SGI.SectionTableBody;
FileDescrTable: TYPE = REF SGI.FileDescrTableBody;
RelFileTable: TYPE = REF SGI.RelFileTableBody;
ProcDescrTable: TYPE = REF SGI.ProcDescrTableBody;
LocalSymTable: TYPE = REF SGI.LocalSymTableBody;
IndexedLocalSymTable: TYPE = REF SGI.IndexedLocalSymTableBody;
ExtSymTable: TYPE = REF SGI.ExtSymTableBody;
AuxSymTable: TYPE = REF SGI.AuxSymTableBody;
IndexedAuxSymTable: TYPE = REF SGI.IndexedAuxSymTableBody;
StringTable: TYPE = REF SGI.StringTableBody;
WireTables: TYPE = REF SGI.WireTablesBody;
StabIndexTypeAndValue: TYPE = RECORD
[
stabX: CARD,
type: StabType,
value: CARD
];
StabList: TYPE = ObjectFilesPrivate.StabList;
ScannedBracketPair: TYPE = RECORD[bpi: BracketPair, nextX: CARD];
FMap: TYPE = LIST OF FMapData;
FMapBody: TYPE = RECORD
[SEQUENCE maxIndex: CARD OF FMapData];
FMapData: TYPE = REF FMapDataBody;
FMapDataBody: TYPE = RECORD
[
fName: Rope.ROPE,
stabOffset: CARD
];
DotOType: TYPE = Rope.ROPE;
PDTType: TYPE = RECORD [SEQUENCE maxIndex: CARD OF Rope.ROPE];
ByteSequence: TYPE = REF ByteSequenceBody;
ByteSequenceBody: TYPE = RECORD
[SEQUENCE maxIndex: CARD OF BYTE];
========================================================================
========================================================================
Constants
========================================================================
========================================================================
IndexNil: CARD = 0FFFFFH; -- max valid index for aux entries
Magic nums
ECOFFMagic: CARD16 = 352;
Sizes based on Chapter 10
nPageSize: CARD = 01000H; -- this is according to getpagesize()
SymbolSize: CARD = 12;  -- this is the size of a local sym
ExtSymbolSize: CARD = 16; -- this is ext sym size
AuxSymbolSize: CARD = 4; -- this is aux sym size
RelocEntrySize: CARD = 8;
LnnoEntrySize: CARD = 4;
FileDescrSize: CARD = 72; -- Need to check this...may be some
padding problems
ProcDescrSize: CARD = 56;
BasicSizes: ARRAY [0..64) OF BYTE = [0,32,8,8,16,16,32,32,32,32,32,64,0,0,32,0,32,32,64,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
WordByteSize: CARD = 4;
WordBitSize: CARD = 32;
Elf stuff
ElfMagic: CARD = (Basics.BITLSHIFT[177B, 24] + Basics.BITLSHIFT['E.ORD, 16] + Basics.BITLSHIFT['L.ORD, 8] + 'F.ORD);
ElfClassNone: CARD = 0;
ElfClass32: CARD = 1;
ElfClass64: CARD = 2;
ElfDataNone: CARD = 0;
ElfData2LSB: CARD = 1;
ElfData2MSB: CARD = 2;
ETNone: CARD = 0;
ETRelocatable: CARD = 1;
ETExecutable: CARD = 2;
ETDynamicLib: CARD = 3;
ETCore: CARD = 4;
EMNone: CARD = 0;
EMM32: CARD = 1;
EMSparc: CARD = 2;
EM386: CARD = 3;
EM68K: CARD = 4;
EM88K: CARD = 5;
EM486: CARD = 6;
EM860: CARD = 7;
EMMips: CARD = 8;
EMS370: CARD = 9;
SHTNull: CARD = 0;
SHTProgBits: CARD = 1;
SHTSymTab: CARD = 2;
SHTStrTab: CARD = 3;
SHTRela: CARD = 4;
SHTHash: CARD = 5;
SHTDynamic: CARD = 6;
SHTNote: CARD = 7;
SHTNoBits: CARD = 8;
SHTRel: CARD = 9;
SHTShLib: CARD = 10;
SHTDynSym: CARD = 11;
SHTLoProc: CARD = 70000000H;
SHTMipsDebug: CARD = SHTLoProc+5;
SHFWrite: CARD = 1;
SHFAlloc: CARD = 2;
SHFExecInStr: CARD = 4;
ElfWireHeader: TYPE = REF ElfWireHeaderBody;
ElfWireHeaderBody: TYPE = MACHINE DEPENDENT RECORD[
magic: Basics.FWORD,
elfClass: BYTE,
elfData: BYTE,
elfVersion: BYTE,
elfPad1: BYTE,
elfPad2: PACKED ARRAY [8..15] OF BYTE,
type: Basics.HWORD,
machine: Basics.HWORD,
version: Basics.FWORD,
entry: Basics.FWORD,
progHdrOffset: Basics.FWORD,
sectHdrOffset: Basics.FWORD,
flags: Basics.FWORD,
elfHdrSize: Basics.HWORD,
progHdrSize: Basics.HWORD,
progHdrNum: Basics.HWORD,
sectHdrSize: Basics.HWORD,
sectHdrNum: Basics.HWORD,
sectStrTblX: Basics.HWORD];
SectionList: TYPE = REF SectionListBody;
SectionListBody: TYPE = RECORD[
list: SEQUENCE length: CARD OF SectionHeader];
SectionHeader: TYPE = REF SectionHeaderBody;
SectionHeaderBody: TYPE = RECORD[
name: ROPENIL,
nameIndex: CARD32,
type: CARD32,
flags: CARD32,
addr: CARD32,
offset: CARD32,
size: CARD32,
link: CARD32,
info: CARD32,
alignment: CARD32,
entrySize: CARD32];
ElfWireSectionHeader: TYPE = REF ElfWireSectionHeaderBody;
ElfWireSectionHeaderBody: TYPE = MACHINE DEPENDENT RECORD[
nameIndex: Basics.FWORD,
type: Basics.FWORD,
flags: Basics.FWORD,
addr: Basics.FWORD,
offset: Basics.FWORD,
size: Basics.FWORD,
link: Basics.FWORD,
info: Basics.FWORD,
alignment: Basics.FWORD,
entrySize: Basics.FWORD];
========================================================================
========================================================================
Global Variables
========================================================================
========================================================================
unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize;
NullStabIndexTypeAndValue: StabIndexTypeAndValue = [0, Invalid, 0];
========================================================================
========================================================================
Basic Low Level Support Routines
========================================================================
========================================================================
RawBytes: TYPE = RECORD [PACKED SEQUENCE COMPUTED CARD OF BYTE];
Printf: PROC [fmt: POINTER TO RawBytes, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10: UNSPECIFIED ← 0] RETURNS [INTEGER] = TRUSTED MACHINE CODE
{ "xr←printf" };
Print: PROC [s: STRING, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10: UNSPECIFIED ← 0] = TRUSTED
{
[] ← Printf[LOOPHOLE[@s.text], arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10];
};
DebugProc: PROC = TRUSTED MACHINE CODE
{
"XR�llDebugger";
};
========================================================================
========================================================================
Low Level Support Functions for Reading and Finding Symbol Table Entries
========================================================================
========================================================================
FindMatchingProcDescr: PUBLIC PROC [relPC: CARD, parsed: ObjectFiles.Parsed]
RETURNS [SGI.WireProcDescriptorBody, BOOLEAN] = TRUSTED {
privateParsed: ObjectFilesPrivate.Parsed ← LOOPHOLE[parsed, ObjectFilesPrivate.Parsed];
wireTables: WireTables ← NARROW[privateParsed.privateInfo, WireTables];
found: BOOLEANFALSE;
high, low, mid: INT32;
procDescrStartingAddr: CARD32 ← wireTables.procDescr[0].startAddress;
numOfProcs: INT32 ← wireTables.wSymHeader.procDescrIndexLimit;
dummy: SGI.WireProcDescriptorBody ← [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
IF relPC = 0 THEN RETURN [dummy, found];
A simple binary search through the procedure descriptor records to find the matching procedure information.
low ← 0; high ← numOfProcs;
WHILE low < high DO
mid ← (low+high+1)/2;
IF mid = numOfProcs THEN RETURN [dummy, found];
IF relPC < wireTables.procDescr[mid].startAddress THEN
high ← mid - 1
ELSE
low ← mid;
ENDLOOP;
RETURN [wireTables.procDescr[high], TRUE];
};
FixUpProcedureDescrAddrs: PROC [header: Header, numFileDescr: CARD32, fileDescr: FileDescrTable, procDescr: ProcDescrTable] =
{
numProcDescr: INT32;
j, jStart, jStop: CARD32;
i: CARD32;
FOR i IN [0..numFileDescr) DO
numProcDescr ← fileDescr[i].cpd;
jStart ← fileDescr[i].ipdFirst;
jStop ← jStart + numProcDescr;
FOR j IN [jStart..jStop) DO
procDescr[j].startAddress ← fileDescr[i].startAddress + procDescr[j].startAddress - header.textLoadOffset;
ENDLOOP;
ENDLOOP;
};
IsSameEndianSGI: PUBLIC PROC [stream: IO.STREAM]
RETURNS [BOOLEAN] = TRUSTED {
magicNum: Basics.HWORD;
nBytes, oldFileIndex: INT;
fileHeader: WireHeader ¬ NEW[SGI.WireHeaderBody];
oldFileIndex ¬ IO.GetIndex[stream];
IO.SetIndex[stream, 0]; -- SGI magic number is 2 bytes at start of file
nBytes ¬ IO.UnsafeGetBlock[stream,
[LOOPHOLE[@fileHeader^], 0, BYTES[SGI.WireHeaderBody]]];
IO.SetIndex[stream, oldFileIndex];
magicNum ¬ LOOPHOLE[fileHeader.magic];
IF (nBytes = 0) THEN
ERROR; -- something is very wrong
Check either majic numbers MIPSEL and MIPSEB
IF (magicNum.hi = 01H) AND (magicNum.lo = 062H OR magicNum.lo = 060H) THEN
RETURN [TRUE]
ELSE IF (magicNum.hi = 062H OR magicNum.hi = 060H) AND (magicNum.lo = 01H) THEN
RETURN [FALSE]
ELSE
ERROR; -- this is not a MIPS SGI file
};
ProcessQualifierSizes: PROC [typeInfo: SGI.WireTypeInfoBody, qualifiedSize: CARD, auxIndex: INT32, wireTables: WireTables] RETURNS [continued: BOOLEAN, size: CARD, nextAuxIndex: INT32] ~ TRUSTED {
qualifier: ARRAY [0..5) OF BYTE;
numQualifiers: CARD ¬ 0;
continued ¬ LOOPHOLE[typeInfo.continued, INT] = 1;
size ¬ qualifiedSize;
nextAuxIndex ¬ auxIndex;
collect the qualifiers if there are any
DO
IF (typeInfo.typeQual0 = SGI.TQNil) THEN
EXIT;
qualifier[numQualifiers] ¬ typeInfo.typeQual0;
numQualifiers ¬ numQualifiers + 1;
IF (typeInfo.typeQual1 = SGI.TQNil) THEN
EXIT;
qualifier[numQualifiers] ¬ typeInfo.typeQual1;
numQualifiers ¬ numQualifiers + 1;
IF (typeInfo.typeQual2 = SGI.TQNil) THEN
EXIT;
qualifier[numQualifiers] ¬ typeInfo.typeQual2;
numQualifiers ¬ numQualifiers + 1;
IF (typeInfo.typeQual3 = SGI.TQNil) THEN
EXIT;
qualifier[numQualifiers] ¬ typeInfo.typeQual3;
numQualifiers ¬ numQualifiers + 1;
IF (typeInfo.typeQual4 = SGI.TQNil) THEN
EXIT;
qualifier[numQualifiers] ¬ typeInfo.typeQual4;
numQualifiers ¬ numQualifiers + 1;
IF (typeInfo.typeQual5 = SGI.TQNil) THEN
EXIT;
qualifier[numQualifiers] ¬ typeInfo.typeQual5;
numQualifiers ¬ numQualifiers + 1;
IF numQualifiers > 5 THEN
EXIT;
ENDLOOP;
return the size
FOR i: INT IN (numQualifiers..0] DO
{
low, high, bitWidth: INT32;
SELECT qualifier[i] FROM
SGI.TQNil => NULL;
SGI.TQPtr =>
{
size ¬ WordBitSize;
RETURN;
};
SGI.TQProc => NULL; -- size info is redundant with pointer
SGI.TQVol => NULL;  -- volatile doesnt have any size info
SGI.TQArray =>
{
low ¬ LOOPHOLE[wireTables.auxSyms[nextAuxIndex].lowIndex];
nextAuxIndex ¬ nextAuxIndex + 1;
high ¬ LOOPHOLE[wireTables.auxSyms[nextAuxIndex].highIndex];
nextAuxIndex ¬ nextAuxIndex + 1;
bitWidth ¬ LOOPHOLE[wireTables.auxSyms[nextAuxIndex].bitWidth];
nextAuxIndex ¬ nextAuxIndex + 1;
size ¬ (high+1)*bitWidth;
RETURN;
}
ENDCASE => NULL;
};
ENDLOOP;
RETURN;
};
C Line-Number to Relative-PC maps
SLineData: TYPE = ObjectFilesPrivate.SLineData;
LineNum: TYPE = REF LineNumSeqBody;
LineNumSeqBody: TYPE = RECORD
[SEQUENCE maxIndex: CARD OF LineNumRecBody];
LineNumRecBody: TYPE = RECORD
[
lineNumber: INT32,
relativePC: CARD
];
UnPackLineNumbers: PUBLIC PROC [stream: IO.STREAM, module: Module, wireTables: WireTables] = TRUSTED
{
CompareByCLineNum: PROC [ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] = TRUSTED {
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] = TRUSTED {
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];
};
header: Header ¬ module.whole.header;
fileDescr: FileDescrTable ¬ wireTables.fileDescr;
procDescr: ProcDescrTable ¬ wireTables.procDescr;
numBytes: CARD ¬ wireTables.wSymHeader.numBytesPackedLineNums;
packedLineNum: WirePackedLineNum ¬ NEW[SGI.WirePackedLineNumBody[numBytes]];
l, count: BYTE;
signedShort, absOfSignedShort: INT16;
delta, lowByte: INT32;
packedIndex, stopIndex, lineTableIndex: INT32 ¬ 0;
k, numProcDescr: INT32;
j, jStart, jStop: CARD32;
numBytesRead: INT32;
currentSrcLine: CARD;
info: REF SLineData;
startAddress: CARD32;
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;
unpackedNums: LineNum ¬ NEW[LineNumSeqBody[wireTables.wSymHeader.lineNumIndexLimit]];
instrCount: CARD32;
fdIndex: INT32;
first we read in all of packed line numbers into an array - -
IO.SetIndex[stream, wireTables.wSymHeader.packedLineNumPtr];
numBytesRead ¬ IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[packedLineNum, CARD]+BYTES[CARD]], 0, numBytes]];
Even though we allocated for all of the line numbers we're only interested in the current files line numbers.
fdIndex ¬ module.fdIndex;
numProcDescr ¬ fileDescr[fdIndex].cpd;
jStart ¬ fileDescr[fdIndex].ipdFirst;
jStop ¬ jStart + numProcDescr;
unpack line numbers for each procedure in this file - -
FOR j IN [jStart..jStop) DO
IF (procDescr[j].iline # -1) AND (procDescr[j].lnLow # -1) AND (procDescr[j].lnHigh # -1) THEN
{
stopIndex ¬ fileDescr[fdIndex].ilineBase +
fileDescr[fdIndex].cline;
find out how many instructions there are in this procedure - -
find the next procedure that contains instructions - -
FOR k IN [j+1..numProcDescr) DO
IF procDescr[k].iline # -1 THEN
{
stopIndex ¬ fileDescr[fdIndex].ilineBase +
procDescr[k].iline;
EXIT;
};
ENDLOOP;
IF (stopIndex - procDescr[j].iline) > 0 THEN
{
startAddress ¬ procDescr[j].startAddress;
instrCount ¬ 0;
lineTableIndex ¬ fileDescr[fdIndex].ilineBase + procDescr[j].iline;
currentSrcLine ¬ procDescr[j].lnLow;
packedIndex ¬ fileDescr[fdIndex].cbLineOffset + procDescr[j].cbLineOffset;
unpack the line numbers for this procedure - -
WHILE lineTableIndex < stopIndex DO
watch out for sign problems here
delta ¬ packedLineNum[packedIndex];
IF delta > 127 THEN
delta ¬ LOOPHOLE[Basics.BITOR[delta, 0FFFF00H]];
delta ¬ LOOPHOLE[Basics.BITRSHIFT[delta, 4]];
count ¬ Basics.BITAND[packedLineNum[packedIndex], 0FH] + 1;
packedIndex ¬ packedIndex + 1;
signedShort ¬ LOOPHOLE[delta, INT16];
absOfSignedShort ¬ ABS[signedShort];
IF absOfSignedShort > 7 THEN
{
delta ¬ Basics.BITLSHIFT[packedLineNum[packedIndex], 8];
packedIndex ¬ packedIndex + 1;
lowByte ¬ Basics.BITAND[packedLineNum[packedIndex], 0FFH];
delta ¬ Basics.BITOR[delta, lowByte];
packedIndex ¬ packedIndex + 1;
signedShort ¬ LOOPHOLE[delta, INT16];
};
currentSrcLine ¬ currentSrcLine + signedShort;
FOR l IN [0..count) DO
unpackedNums[lineTableIndex].lineNumber ¬ currentSrcLine;
unpackedNums[ lineTableIndex].relativePC ¬ instrCount*4+startAddress;
instrCount ¬ instrCount + 1;
lineTableIndex ¬ lineTableIndex + 1;
ENDLOOP;
ENDLOOP;
};
};
ENDLOOP;
FOR I: CARD IN [0..wireTables.wSymHeader.lineNumIndexLimit) DO
info ¬ NEW[SLineData ¬ [
cLineNum: unpackedNums[I].lineNumber,
parsedRelPC:
[
[0 --??--, PFS.RopeFromPath[module.fileName]],
unpackedNums[I].relativePC
]
]];
list1 ¬ CONS[info, list1];
list2 ¬ CONS[info, list2];
ENDLOOP;
sortedList ¬ List.Sort[list1, CompareByCLineNum];
module.lineNumToPC ¬ NEW[LineNumToPCMapBody[wireTables.wSymHeader.lineNumIndexLimit]];
FOR I: INTEGER IN [0..wireTables.wSymHeader.lineNumIndexLimit) DO
info: REF SLineData ¬ NARROW[sortedList.first];
module.lineNumToPC[I] ¬ info^;
sortedList ¬ sortedList.rest;
ENDLOOP;
sortedList ¬ List.Sort[list2, CompareByPC];
module.pcToLineNum ¬ NEW[PCtoLineNumMapBody[wireTables.wSymHeader.lineNumIndexLimit]];
FOR I: INTEGER IN [0..wireTables.wSymHeader.lineNumIndexLimit) DO
info: REF SLineData ¬ NARROW[sortedList.first];
module.pcToLineNum[I] ¬ info^;
sortedList ¬ sortedList.rest;
ENDLOOP;
wireTables.pcToLineNum ¬ module.pcToLineNum;
wireTables.lineNumToPC ¬ module.lineNumToPC;
FREE[@packedLineNum];
FREE[@unpackedNums];
RETURN;
};
CalcSymbolSize: PUBLIC PROC [symTabIndex: CARD, fdIndex: INT32, wireTables: WireTables, isExternal: BOOLEAN] RETURNS [size : CARD ¬ 0] = TRUSTED {
SIze is returned in bits
thisSym: WireSTEntry;
auxIndex: CARD;
symIndex, basicType, qualifiedSize: CARD ¬ 0;
typeInfo: SGI.WireTypeInfoBody;
nonStandardWidth: BOOLEAN;
continued: BOOLEAN ¬ TRUE;
symBaseIndex: CARD;
symType: CARD;
IF isExternal THEN
{
thisSym ¬ LOOPHOLE[@wireTables.extSyms[symTabIndex].sym];
fdIndex ¬ wireTables.extSyms[symTabIndex].fileDescrIndex;
}
ELSE
{
thisSym ¬ LOOPHOLE[@wireTables.localSyms[symTabIndex]];
};
symType ¬ thisSym.symbolType;
SELECT symType FROM
SGI.STStruct,
SGI.STUnion =>
{
size ¬ thisSym.value*8;
RETURN;
};
SGI.STFile,
SGI.STProc,
SGI.STStaticProc,
SGI.STBlock,
SGI.STEnd =>
RETURN;
SGI.STConstant,
SGI.STLabel,
SGI.STRegReloc,
SGI.STForward,
SGI.STStaParam =>
{
size ¬ WordBitSize;
RETURN;
};
ENDCASE => NULL;
the first aux symbol is the TI
auxIndex ¬ wireTables.fileDescr[fdIndex].iauxBase + thisSym.index;
IF auxIndex >= IndexNil THEN
{
size ¬ WordBitSize;
RETURN;
};
typeInfo ¬ wireTables.auxSyms[auxIndex].typeInfo;
nonStandardWidth ¬ LOOPHOLE[typeInfo.fBitField];
basicType ¬ typeInfo.basicType;
IF (basicType = SGI.BTNil) THEN
RETURN;
calculate the size of the basic type
IF ((basicType = SGI.BTStruct) OR (basicType = SGI.BTUnion)) THEN
{
currentIndex: CARD;
relFileIndex: INT32;
relFileOffset: INT32;
relIndex: SGI.WireRelIndexBody ¬ wireTables.auxSyms[auxIndex+1].relIndex;
IF relIndex.relFileDescrIndex = 0FFFH THEN
{
relFileIndex ¬ wireTables.auxSyms[auxIndex+2].relFileIndex;
}
ELSE
{
relFileIndex ¬ relIndex.relFileDescrIndex;
};
relFileOffset ¬ wireTables.fileDescr[fdIndex].rfdBase + relFileIndex;
IF relFileOffset # 0 THEN
fdIndex ¬ wireTables.relFiles[relFileOffset];
symIndex ¬ relIndex.index;
symBaseIndex ¬ wireTables.fileDescr[fdIndex].isymBase;
currentIndex ¬ symIndex + symBaseIndex;
size ¬ wireTables.localSyms[currentIndex].value*8;
auxIndex ¬ auxIndex + 2;
}
ELSE IF ((basicType = SGI.BTTypedef) OR (basicType = SGI.BTIndirect)) THEN
{
I've never seen a basic type typedef in SGI, but just in case
size ¬ WordBitSize;
}
ELSE IF (nonStandardWidth = FALSE) THEN
size ¬ BasicSizes[basicType]
ELSE
IF wireTables.auxSyms[auxIndex+1].bitWidth # 0 THEN
size ¬ wireTables.auxSyms[auxIndex+1].bitWidth
ELSE
size ¬ 0;
process the qualifiers if there are any
WHILE continued DO
{
[continued, qualifiedSize, auxIndex] ¬ ProcessQualifierSizes[typeInfo, qualifiedSize, auxIndex, wireTables];
IF continued THEN
typeInfo ¬ wireTables.auxSyms[auxIndex].typeInfo;
};
ENDLOOP;
IF (qualifiedSize # 0) THEN
{
size ¬ qualifiedSize;
};
};
ReadElfWireSymHeader: PROC [stream: IO.STREAM] RETURNS [WireSymHeader] = TRUSTED
{
wHeader: ElfWireHeader ← NEW[ElfWireHeaderBody];
nBytes: INTIO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[ElfWireHeaderBody]]];
wSymHeader: WireSymHeader ← NIL;
sectHdrOffset: CARD ← Basics.Card32FromF[wHeader.sectHdrOffset];
sectHdrNum: CARD ← Basics.Card16FromH[wHeader.sectHdrNum];
type: CARD;
IO.SetIndex[stream, sectHdrOffset];
FOR i: CARD IN [0..sectHdrNum) DO
wSectionHeader: ElfWireSectionHeader ← NEW[ElfWireSectionHeaderBody];
nBytes: INTIO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[ElfWireSectionHeaderBody]]];
type ← Basics.Card32FromF[wSectionHeader.type];
IF type = SHTMipsDebug THEN
{
offset: CARD ← Basics.Card32FromF[wSectionHeader.offset];
wSymHeader ← NEW[SGI.WireSymHeaderBody];
[] ← ReadWireSymHeader[stream, offset, wSymHeader];
RETURN[wSymHeader];
};
ENDLOOP;
RETURN[wSymHeader];
};
InitParsedWireTables: PROC [stream: IO.STREAM, parsed: Parsed] = TRUSTED
{
filename: UXStrings.UnixString;
wireTables: WireTables ← NEW[SGI.WireTablesBody];
nBytes: CARD;
magic: CARD;
header: Header ← parsed.header;
symHeader: WireSymHeader;
symLimit, extSymLimit, auxSymLimit: CARD;
procDescLimit, fileDescLimit, relFileLimit: CARD;
filename ← UXStrings.Create[PFS.RopeFromPath[SystemInterface.GetNameOfFile[parsed.file]]];
Print["InitParsedWireTables %s\n", filename];
IO.SetIndex[stream, 0];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@magic], 0, 4]];
IF magic = ElfMagic THEN
{
Print["Found an ELF object\n"];
IO.SetIndex[stream, 0];
wireTables.wSymHeader ← ReadElfWireSymHeader[stream];
}
ELSE
{
magic ← Basics.BITRSHIFT[LOOPHOLE[magic, WORD], 16];
IF magic = ECOFFMagic THEN
{
read the file, optional and symbol headers
wireTables.wHeader ← ReadWireHeader[stream, 0, NIL];
wireTables.wAuxHeader ← ReadWireAuxHeader[stream, NIL];
wireTables.wSymHeader ← ReadWireSymHeader[stream, wireTables.wHeader.symPtr, NIL];
}
ELSE
{
Print["Found unknown magic number %d\n", magic]; ERROR;
};
};
symHeader ← wireTables.wSymHeader;
read the file descriptor table
IO.SetIndex[stream, symHeader.fileDescrPtr];
fileDescLimit ← symHeader.fileDescrIndexLimit;
wireTables.fileDescr ← NEW[SGI.FileDescrTableBody[fileDescLimit]];
FOR i: CARD IN [0..fileDescLimit) DO
[] ← ReadWireFileDescriptor[stream, LOOPHOLE[@wireTables.fileDescr[i]]];
ENDLOOP;
read the relative file table
IO.SetIndex[stream, symHeader.relFileDescrPtr];
relFileLimit ← symHeader.numRelFileDescr;
wireTables.relFiles ← NEW[SGI.RelFileTableBody[relFileLimit]];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.relFiles, CARD]+BYTES[CARD]], 0, relFileLimit*BYTES[SGI.RelFileTableBody]]];
read the procedure descriptor table
IO.SetIndex[stream, wireTables.wSymHeader.procDescrPtr];
procDescLimit ← symHeader.procDescrIndexLimit;
wireTables.procDescr ← NEW[SGI.ProcDescrTableBody[procDescLimit]];
FOR i: CARD IN [0..procDescLimit) DO
[] ← ReadWireProcDescriptor[stream, LOOPHOLE[@wireTables.procDescr[i]]];
ENDLOOP;
Add the file start address to each of the procedure descriptor addrs so that the procedure descriptor addrs are dotO relative.
FixUpProcedureDescrAddrs[header, fileDescLimit, wireTables.fileDescr, wireTables.procDescr];
read the local symbols
IO.SetIndex[stream, symHeader.symPtr];
symLimit ← symHeader.symIndexLimit;
wireTables.localSyms ← NEW[SGI.LocalSymTableBody[symLimit]];
FOR i: CARD IN [0..symLimit) DO
[] ← ReadWireSTEntry[stream, LOOPHOLE[@wireTables.localSyms[i]]];
ENDLOOP;
read the external symbols
IO.SetIndex[stream, symHeader.extSymPtr];
extSymLimit ← symHeader.extSymIndexLimit;
wireTables.extSyms ← NEW[SGI.ExtSymTableBody[extSymLimit]];
FOR i: CARD IN [0..extSymLimit) DO
[] ← ReadWireExtSTEntry[stream, LOOPHOLE[@wireTables.extSyms[i]]];
ENDLOOP;
Aux's are problematic as far as byte/bit reversing is concerned
because they are a union of bitfields and integers, so we read in
as un twiddled here and play with the bits as needed
IO.SetIndex[stream, symHeader.auxSymPtr];
auxSymLimit ← symHeader.auxSymIndexLimit;
wireTables.auxSyms ← NEW[SGI.AuxSymTableBody[auxSymLimit]];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.auxSyms, CARD]+BYTES[CARD]], 0, auxSymLimit*AuxSymbolSize]];
read the local strings
IO.SetIndex[stream, symHeader.symStringPtr];
wireTables.localStrings ← NEW[SGI.StringTableBody[symHeader.symStringIndexLimit]];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.localStrings, CARD]+BYTES[CARD]], 0, symHeader.symStringIndexLimit]];
read the external strings
IO.SetIndex[stream, symHeader.extSymStringPtr];
wireTables.extStrings ← NEW[SGI.StringTableBody[symHeader.extSymStringIndexLimit]];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[LOOPHOLE[wireTables.extStrings, CARD]+BYTES[CARD]], 0, symHeader.extSymStringIndexLimit]];
parsed.privateInfo ← wireTables;
};
RopeFromStream: PROC [stream: IO.STREAM, offset: CARD]
RETURNS [name: Rope.ROPENIL] =
TRUSTED
{
c: CHAR;
IO.SetIndex[stream, offset];
IF IO.EndOf[stream] THEN
RETURN[""];
DO
c ← ' ;
c ← IO.GetChar[stream];
IF (c = VAL[0]) THEN
EXIT;
name ← name.Concat[Convert.RopeFromChar[from: c, quote: FALSE]];
ENDLOOP;
Add a colon to the end of the name to be compatible with Sun,
this is so the CheckStaticStab routine will match, jas
name ← name.Concat[Convert.RopeFromChar[from: ':, quote: FALSE]];
RETURN
};
TypeAndClassFromData: PROC [sc: BYTE, st: BYTE ← 0] RETURNS [type: StabType, class: StorageClass] =
{
classVal: CARD ← sc;
typeVal: CARD ← st;
SELECT typeVal FROM
SGI.STNil => type ← Unspecified;
SGI.STGlobal => type ← GSym;
SGI.STStatic =>
{
IF classVal = SGI.SCBSS OR classVal = SGI.SCSBSS THEN
type ← LCSym
ELSE
type ← STSym;
};
SGI.STParam => type ← PSym;
SGI.STLocal => type ← LSym;
SGI.STLabel => type ← Unspecified;
SGI.STStaticProc, SGI.STProc => type ← Fun;
SGI.STBlock => type ← LBrac;
SGI.STEnd => type ← RBrac;
SGI.STMember => type ← LSym;
SGI.STTypeDef => type ← LSym;
SGI.STFile => type ← SO;
SGI.STConstant => type ← Unspecified;
ENDCASE => type ← Unspecified;
SELECT classVal FROM
SGI.SCNIL => class ← SCNil;
SGI.SCTEXT => class ← SCText;
SGI.SCDATA => class ← SCData;
SGI.SCBSS => class ← SCBss;
SGI.SCREGISTER => class ← SCRegister;
SGI.SCABS => class ← SCAbs;
SGI.SCUNDEFINED => class ← SCUnspecified;
SGI.SCBITS => class ← SCBits;
SGI.SCDBX => class ← SCInvalid;
SGI.SCREGIMAGE => class ← SCRegImage;
SGI.SCINFO => class ← SCUserStruct;
SGI.SCUSERSTRUCT => class ← SCUserStruct;
SGI.SCSDATA => class ← SCSData;
SGI.SCSBSS => class ← SCSBss;
SGI.SCRDATA => class ← SCRData;
SGI.SCVAR => class ← SCCommon;
SGI.SCCOMMON => class ← SCCommon;
SGI.SCSCOMMON => class ← SCSCommon;
SGI.SCVARREGISTER => class ← SCVerRegister;
SGI.SCVARIANT => class ← SCVariant;
SGI.SCUNDEFINE => class ← SCSUndefined;
ENDCASE => class ← SCInvalid
};
ReadStabBody: PROC [symTabIndex: CARD, fdIndex: INT32, isExternal: BOOLEAN, wireTables: WireTables,
header: Header, stream: IO.STREAM]
RETURNS [stab: StabBody] =
TRUSTED
{
size: CARD;
rope: Rope.ROPENIL;
wireSymTabEntry: WireSTEntry;
stringBase: INT32 ← wireTables.fileDescr[fdIndex].issBase;
type: StabType;
class: StorageClass;
IF (isExternal) THEN
{
wireSymTabEntry ← LOOPHOLE[@wireTables.extSyms[symTabIndex].sym];
rope ← RopeFromStream[stream, header.extStringOffset+wireSymTabEntry.symStringIndex];
}
ELSE
{
wireSymTabEntry ← LOOPHOLE[@wireTables.localSyms[symTabIndex]];
rope ← RopeFromStream[stream, header.stringOffset+stringBase+wireSymTabEntry.symStringIndex];
};
size is in bits, stab size needs to be in bytes
size ← CalcSymbolSize[symTabIndex, fdIndex, wireTables, isExternal]/8;
[type, class] ← TypeAndClassFromData[LOOPHOLE[wireSymTabEntry.storageClass],
LOOPHOLE[wireSymTabEntry.symbolType]];
stab ← [
module: NIL,
stabX: symTabIndex,
stabType: type,
stabStorClass: class,
size: size,
value: wireSymTabEntry.value,
rope: rope,
index: wireSymTabEntry.index,
extRef: isExternal,
fdIndex: fdIndex
];
RETURN
};
BasicReadStab: ENTRY PROC [stabX: CARD, fdIndex: INT32, isExternal: BOOLEAN, wireTables: WireTables,
header: Header, stream: IO.STREAM]
RETURNS[stab: Stab] =
{
ENABLE UNWIND => NULL;
stab ← NEW[StabBody];
stab^ ← ReadStabBody[stabX, fdIndex, isExternal, wireTables, header, stream];
RETURN
};
ReadWireHeader: PROC [stream: IO.STREAM, pos: CARD ← 0, wHeader: WireHeader ← NIL]
RETURNS [WireHeader] = TRUSTED
{
nBytes: INT;
IF (wHeader = NIL) THEN
wHeader ← NEW[SGI.WireHeaderBody];
IO.SetIndex[stream, pos];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[SGI.WireHeaderBody]]];
RETURN [wHeader];
};
ReadWireAuxHeader: PROC [stream: IO.STREAM, wAuxHeader: WireAuxHeader ← NIL]
RETURNS [WireAuxHeader] = TRUSTED
{
nBytes: INT;
IF (wAuxHeader = NIL) THEN
wAuxHeader ← NEW[SGI.WireAuxHeaderBody];
This routine must follow a call to the ReadWireHeader function to ensure that the proper offset is set for the read.
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wAuxHeader^], 0, BYTES[SGI.WireAuxHeaderBody]]];
RETURN [wAuxHeader];
};
ReadWireSectionHeader: PROC [stream: IO.STREAM, wSectHeader: WireSectionHeader ← NIL]
RETURNS [WireSectionHeader] = TRUSTED
{
nBytes: INT;
IF (wSectHeader = NIL) THEN
wSectHeader ← NEW[SGI.WireSectionHeaderBody];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectHeader^], 0,
BYTES[SGI.WireSectionHeaderBody]]];
RETURN [wSectHeader];
};
ReadWireSymHeader: PROC [stream: IO.STREAM, pos: CARD, wSymHeader: WireSymHeader ← NIL]
RETURNS [WireSymHeader] = TRUSTED
{
nBytes: INT;
IF (wSymHeader = NIL) THEN
wSymHeader ← NEW[SGI.WireSymHeaderBody];
IO.SetIndex[stream, pos];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSymHeader^], 0,
BYTES[SGI.WireSymHeaderBody]]];
RETURN [wSymHeader];
};
ReadWireProcDescriptor: PROC [stream: IO.STREAM, wProcDescriptor: WireProcDescriptor ← NIL]
RETURNS [WireProcDescriptor] =
TRUSTED
{
nBytes: INT;
IF (wProcDescriptor = NIL) THEN
wProcDescriptor ← NEW[SGI.WireProcDescriptorBody];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wProcDescriptor^], 0,
BYTES[SGI.WireProcDescriptorBody]]];
RETURN [wProcDescriptor];
};
ReadWireFileDescriptor: PROC [stream: IO.STREAM, wFileDescriptor: WireFileDescriptor ← NIL]
RETURNS [WireFileDescriptor] =
TRUSTED
{
nBytes: INT;
IF (wFileDescriptor = NIL) THEN
wFileDescriptor ← NEW[SGI.WireFileDescriptorBody];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wFileDescriptor^], 0,
BYTES[SGI.WireFileDescriptorBody]]];
RETURN [wFileDescriptor];
};
ReadWireSTEntry: PROC [stream: IO.STREAM, wSTEntry: WireSTEntry ← NIL]
RETURNS [WireSTEntry] =
TRUSTED
{
nBytes: INT;
IF (wSTEntry = NIL) THEN
wSTEntry ← NEW[SGI.WireSTEntryBody];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wSTEntry^], 0,
BYTES[SGI.WireSTEntryBody]]];
RETURN [wSTEntry];
};
ReadWireExtSTEntry: PROC [stream: IO.STREAM, wExtSTEntry: WireExtSTEntry ← NIL]
RETURNS [WireExtSTEntry] =
TRUSTED
{
nBytes: INT;
IF (wExtSTEntry = NIL) THEN
wExtSTEntry ← NEW[SGI.WireExtSTEntryBody];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wExtSTEntry^], 0,
BYTES[SGI.WireExtSTEntryBody]]];
RETURN [wExtSTEntry];
};
BitsOn: PROC [flags: CARD, mask: CARD] RETURNS [on: BOOL] ~ INLINE {
RETURN [Basics.BITAND[flags, mask] # 0] };
ReadELFHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED {
PROC [stream: IO.STREAM] RETURNS [Header] = TRUSTED
wHeader: ElfWireHeader ← NEW[ElfWireHeaderBody];
nBytes: INTIO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[ElfWireHeaderBody]]];
magic: CARD ← Basics.Card32FromF[wHeader.magic];
shortMagic: CARD ← Basics.BITRSHIFT[LOOPHOLE[magic, WORD], 16];
objType: CARD ← Basics.Card16FromH[wHeader.type];
machine: CARD ← Basics.Card16FromH[wHeader.machine];
nBadMagic: BOOLEAN ← (magic # ElfMagic) OR (wHeader.elfClass # ElfClass32) OR (wHeader.elfData # ElfData2MSB) OR ((objType # ETRelocatable) AND (objType # ETExecutable)) OR (machine # EMMips);
nPageSize: CARD ← 1000H;
textSeg: MemorySegmentInfo ← [0, 0];
iDataSeg: MemorySegmentInfo ← [0, 0];
symHdrSeg: MemorySegmentInfo ← [0, 0];
textRelocSeg: MemorySegmentInfo ← [0, 0];
dataRelocSeg: MemorySegmentInfo ← [0, 0];
bssSeg: MemorySegmentInfo ← [0, 0];
bssSize: CARD32 ← 0;
sectHdrOffset: CARD ← Basics.Card32FromF[wHeader.sectHdrOffset];
sectHdrNum: CARD ← Basics.Card16FromH[wHeader.sectHdrNum];
sectionList: SectionList ← NEW[SectionListBody[sectHdrNum]];
sectStrTblX: CARD ← Basics.Card16FromH[wHeader.sectStrTblX];
textIndex, dataIndex, bssIndex, symtabIndex, symsIndex: CARDLAST[CARD];
header: Header;
wSymHeader: WireSymHeader ← NEW[SGI.WireSymHeaderBody];
textLoadOffset: CARD32 ← Basics.Card32FromF[wHeader.entry];
IF nBadMagic THEN ERROR;
IO.SetIndex[stream, sectHdrOffset];
FOR i: CARD IN [0..sectHdrNum) DO
wSectionHeader: ElfWireSectionHeader ← NEW[ElfWireSectionHeaderBody];
nBytes: INTIO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[ElfWireSectionHeaderBody]]];
sectionList[i] ← NEW[SectionHeaderBody];
sectionList[i].nameIndex ← Basics.Card32FromF[wSectionHeader.nameIndex];
sectionList[i].type ← Basics.Card32FromF[wSectionHeader.type];
sectionList[i].flags ← Basics.Card32FromF[wSectionHeader.flags];
sectionList[i].addr ← Basics.Card32FromF[wSectionHeader.addr];
sectionList[i].offset ← Basics.Card32FromF[wSectionHeader.offset];
sectionList[i].size ← Basics.Card32FromF[wSectionHeader.size];
sectionList[i].link ← Basics.Card32FromF[wSectionHeader.link];
sectionList[i].info ← Basics.Card32FromF[wSectionHeader.info];
sectionList[i].alignment ← Basics.Card32FromF[wSectionHeader.alignment];
sectionList[i].entrySize ← Basics.Card32FromF[wSectionHeader.entrySize];
ENDLOOP;
IO.SetIndex[stream, sectionList[sectStrTblX].offset];
FOR i: CARD IN [0..sectHdrNum) DO
SELECT TRUE FROM
(sectionList[i].type = SHTProgBits) AND BitsOn[sectionList[i].flags, SHFAlloc] => {
IF NOT BitsOn[sectionList[i].flags, SHFWrite] THEN {
IF textIndex = LAST[CARD] THEN {
textSeg ← [sectionList[i].offset, sectionList[i].size];
textIndex ← i;
}
ELSE
textSeg.byteLength ← textSeg.byteLength + sectionList[i].size;
}
ELSE {
IF dataIndex = LAST[CARD] THEN {
iDataSeg ← [sectionList[i].offset, sectionList[i].size];
dataIndex ← i;
}
ELSE
iDataSeg.byteLength ← iDataSeg.byteLength + sectionList[i].size;
};
};
(sectionList[i].type = SHTNoBits) AND BitsOn[sectionList[i].flags, SHFWrite] => {
IF bssIndex = LAST[CARD] THEN {
bssSize ← bssSize + sectionList[i].size;
bssIndex ← i;
bssSeg ← [sectionList[i].offset, sectionList[i].size];
};
};
(sectionList[i].type = SHTRela) OR (sectionList[i].type = SHTRel) => {
IF sectionList[i].info = textIndex THEN
textRelocSeg ← [sectionList[i].offset, sectionList[i].size]
ELSE IF sectionList[i].info = dataIndex THEN
dataRelocSeg ← [sectionList[i].offset, sectionList[i].size];
};
(sectionList[i].type = SHTMipsDebug) => {
Print["Found the Debug section"];
[] ← ReadWireSymHeader[stream, sectionList[i].offset, wSymHeader];
symHdrSeg ← [sectionList[i].offset, sectionList[i].size];
};
ENDCASE;
ENDLOOP;
header ← NEW[HeaderBody ← [
dynamic: objType = ETDynamicLib,
toolversion: BYTE[0] -- wHeader.version --,
machtype: machine,
magic: shortMagic,
text: textSeg,
iData: iDataSeg,
textReloc: textRelocSeg,
dataReloc: dataRelocSeg,
syms: symHdrSeg,
debug: [0, 0],
linno: [0, 0],
textLoadOffset: textLoadOffset,
bssSize: bssSize,
entryPoint: Basics.Card32FromF[wHeader.entry],
nPageSize: nPageSize,
nEntries: wSymHeader.symIndexLimit,
stringOffset: wSymHeader.symStringPtr,
extStringOffset: wSymHeader.extSymStringPtr
]];
RETURN[header];
};
ReadHeader: PROC [stream: IO.STREAM]
RETURNS [Header] =
TRUSTED
{
wHeader: WireHeader;
wAuxHeader: WireAuxHeader;
wSymHeader: WireSymHeader;
magic: CARD;
nBytes: CARD;
dataRelocSeg: MemorySegmentInfo ← [0, 0];
bssRelocSeg: MemorySegmentInfo ← [0, 0];
textRawData, dataRawData, bssRawData, textRelocSeg: MemorySegmentInfo ← [0, 0];
header: Header;
numSects: CARD;
sectionTable: SectionTable;
sectionName: ROPENIL;
ch: CHAR;
Print["Reading Header ...\n"];
IO.SetIndex[stream, 0];
nBytes ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@magic], 0, 4]];
IF magic = ElfMagic THEN {
IO.SetIndex[stream, 0];
RETURN[ReadELFHeader[stream]]};
magic ← Basics.BITRSHIFT[LOOPHOLE[magic, WORD], 16];
IF magic # ECOFFMagic THEN
ERROR;
wHeader ← ReadWireHeader[stream, 0, NIL];
wAuxHeader ← ReadWireAuxHeader[stream, NIL];
wSymHeader ← NEW[SGI.WireSymHeaderBody];
magic ← wHeader.magic;
numSects ← wHeader.numSections;
sectionTable ← NEW[SGI.SectionTableBody[numSects]];
Fill in array of section headers
FOR i: CARD IN [0..numSects) DO
Read in raw section header data
[] ← ReadWireSectionHeader[stream, LOOPHOLE[@sectionTable[i]]];
ENDLOOP;
Find index of section headers for .text, .data segments
FOR i: CARD IN [0..numSects) DO
FOR j: CARD IN [0..8) DO
IF (sectionTable[i].name[j] = 0) THEN
EXIT;
ch ← VAL[sectionTable[i].name[j]];
sectionName ← sectionName.Concat[Rope.FromChar[ch]];
ENDLOOP;
IF Rope.Equal[sectionName, ".text", TRUE] THEN
{
textRawData ← [sectionTable[i].dataPtr, sectionTable[i].size];
textRelocSeg ← [sectionTable[i].relocPtr, sectionTable[i].numRelocEntries * RelocEntrySize]
}
ELSE IF Rope.Equal[sectionName, ".data", TRUE] THEN
{
dataRawData ← [sectionTable[i].dataPtr, sectionTable[i].size];
dataRelocSeg ← [sectionTable[i].vAddr, sectionTable[i].numRelocEntries * RelocEntrySize];
}
ELSE IF Rope.Equal[sectionName, ".bss", TRUE] THEN
{
bssRawData ← [sectionTable[i].dataPtr, sectionTable[i].size];
};
FREE[@sectionName];
sectionName ← NIL;
ENDLOOP;
[] ← ReadWireSymHeader[stream, wHeader.symPtr, wSymHeader];
Fill in the header for this file - -
header ← NEW[HeaderBody ←
[
dynamic: FALSE,
toolversion: BYTE[0],
machtype: BYTE[0],
magic: magic,
text: textRawData,
iData: dataRawData,
textReloc: textRelocSeg,
dataReloc: dataRelocSeg,
syms: [0, 0],
debug: [0, 0],
linno: [0, 0],
textLoadOffset: wAuxHeader.textBase,
bssSize: wAuxHeader.bssSize,
entryPoint: wAuxHeader.entryPtr,
nPageSize: nPageSize,
nEntries: wSymHeader.symIndexLimit,
stringOffset: wSymHeader.symStringPtr,
extStringOffset: wSymHeader.extSymStringPtr
]];
RETURN[header];
};
========================================================================
Used by SGIModuleFromParsedAndPC and RandomTestFindStabRange
search through file descriptors until you find one that contains the pc...
this will give us max and min symtab entry range
then once we know the file we can use proc descriptors to find max and min
pc symtab entries range
========================================================================
AlternativeFindModuleStabRange: PROC [header: Header, fileDescr: FileDescrTable,
procDescr: ProcDescrTable, symHeader: WireSymHeader,
relativePC: CARD]
RETURNS [sr: StabRange,
pcRange: StabRange ← [0, 0],
fdIndex: INT32 ← 0] =
{
IF header = NIL THEN
RETURN[[0, 0], [0, 0], 0]
ELSE
{
pcCount: CARD ← 0;
minPC: CARDLAST[CARD];
indexFirstSym, numSyms, numInstructions: INT32;
i, indexFirstProc: INT16;
startAddress, textOffset: CARD32;
absolutePC: CARD ← 0;
numFileDescr: INT32 ← symHeader.fileDescrIndexLimit;
textOffset ← header.textLoadOffset;
absolutePC ← textOffset + relativePC;
FOR i IN [0..numFileDescr) DO
startAddress ← fileDescr[i].startAddress;
IF absolutePC < startAddress THEN
{
IF i = 0 THEN RETURN[[0, 0], [0, 0], 0];
fdIndex ← i - 1;
startAddress ← fileDescr[fdIndex].startAddress;
WHILE fdIndex > 1 AND startAddress = fileDescr[fdIndex-1].startAddress AND fileDescr[fdIndex].fMerge # 0 DO
fdIndex ← fdIndex - 1;
ENDLOOP;
EXIT;
}
ENDLOOP;
IF (fdIndex > numFileDescr) THEN
RETURN[[0, 0], [0, 0], 0];
startAddress ← fileDescr[fdIndex].startAddress;
indexFirstProc ← fileDescr[fdIndex].ipdFirst;
minPC ← procDescr[indexFirstProc].startAddress + textOffset;
numInstructions ← fileDescr[fdIndex].cline;
pcCount ← 4 * numInstructions;
indexFirstSym ← fileDescr[fdIndex].isymBase;
numSyms ← fileDescr[fdIndex].csym;
IF (absolutePC < (minPC + pcCount)) THEN
RETURN[[ indexFirstSym, numSyms], [minPC-textOffset, pcCount], fdIndex];
RETURN[[0, 0], [0, 0], 0];
};
};
========================================================================
Used only by CreateModule
search though the external stabs and make a list of those that are associated
with a particular file
========================================================================
GetExtStabList: PROC [fdIndex: INT32, wireTables: WireTables, header: Header,
stream: IO.STREAM]
RETURNS [extStabList: LIST OF Stab, numExtSyms: CARD] =
TRUSTED
{
i: CARD;
totNumExtSyms: CARD ← wireTables.wSymHeader.extSymIndexLimit;
lastElem: LIST OF Stab ← NIL;
newStab: Stab;
numExtSyms ← 0;
extStabList ← NIL;
FOR i IN [0..totNumExtSyms) DO
strangely enough, in ext syms the fdindex is a half word but in the
symbolic header the max fdindex is a full word
IF (wireTables.extSyms[i].fileDescrIndex =
CARD16[fdIndex]) THEN
{
newStab ← BasicReadStab[i, fdIndex, TRUE, wireTables, header, stream];
IF (extStabList = NIL) THEN
{
extStabList ← LIST[newStab]; -- make one element list holding new Stab
lastElem ← extStabList;
}
ELSE
{
lastElem.rest ← LIST[newStab];
lastElem ← lastElem.rest;
};
lastElem.rest ← NIL;
numExtSyms ← numExtSyms + 1;
};
ENDLOOP;
};
========================================================================
Used only by SGIModuleFromParsedAndPC
========================================================================
CreateModule: PROC [parsed: Parsed, fdIndex: INT32, wireTables: WireTables,
stream: IO.STREAM, stabRange, pcRange: StabRange ← [0, 0]]
RETURNS [Module] = TRUSTED
{
module: Module ← NEW[ModuleBody];
nStabs: CARD ← stabRange.count;
currentIndex: CARD;
I: CARD ← 0;
nExtStabs: CARD;
extStabList, thisExtStab: LIST OF Stab ← NIL;
stab: Stab;
lineNumbers: LineNum ← NIL;
stringBase: INT32 ← wireTables.fileDescr[fdIndex].issBase;
fileNameOffset: INT32 ← wireTables.fileDescr[fdIndex].rss;
filename: UXStrings.UnixString;
[extStabList, nExtStabs] ←
GetExtStabList[fdIndex, wireTables, parsed.header, stream];
prepare the embeddedDotO for a call on BuildBrackets
module.whole ← parsed;
I'm puzzled as to why stabX info is kept...we read all our stabs into
the stabs array...so we shouldnt ever have to go back to the file...
and in any case .limitStabX includes the ext syms making it
useless for file access
module.firstStabX ← stabRange.first;
module.limitStabX ← stabRange.first + nStabs + nExtStabs;
module.firstPC ← pcRange.first;
module.limitPC ← pcRange.first + pcRange.count;
module.stabs ← NEW[StabSet[nStabs + nExtStabs]];
module.fdIndex ← fdIndex;
lets read all the local stabs now
(we also relocate the pc value of bracket stabs.)
currentIndex ← 0;
I ← 0;
WHILE (I < nStabs) DO
read in a sym table entry
module.stabs[currentIndex] ← BasicReadStab[stabRange.first+I, fdIndex, FALSE,
wireTables, parsed.header, stream];
stab ← module.stabs[currentIndex];
stab.module ← module;
IF (stab.stabType = LBrac) OR (stab.stabType = RBrac) THEN -- relocate bracket pcs
stab.value ← stab.value + module.firstPC;
IF (stab.stabType = Fun) THEN
stab.value ← stab.value - parsed.header.textLoadOffset;
currentIndex ← currentIndex + 1;
I ← I + 1;
ENDLOOP;
tack on the external symbols that belong to this module ... I think
external symbols really should be in the parsed structure but
that probably would require wholesale changes
FOR thisExtStab ← extStabList, thisExtStab.rest WHILE (thisExtStab # NIL) DO
module.stabs[currentIndex] ← thisExtStab.first;
currentIndex ← currentIndex + 1
ENDLOOP;
module.fileName ←
PFS.PathFromRope[RopeFromStream[stream, parsed.header.stringOffset+stringBase+fileNameOffset]];
filename ← UXStrings.Create[PFS.RopeFromPath[module.fileName]];
Print["CreateModule for file %s\n", filename];
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,
funIndex: 0,
symbols: NIL,
innerBrackets: NIL
]];
only unpack line numbers that haven't already been unpacked
I've changed the unpacking line numbers to be on demand, and the call is in ObjectFilesImpl.GetLineNumForPC and ObjectFilesImpl.GetPCForLineNum
IF wireTables.pcToLineNum = NIL THEN
UnPackLineNumbers[module.whole.header, wireTables.fileDescr, wireTables.procDescr, stream, module, wireTables];
RETURN[module];
};
========================================================================
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 first
pc of the embedded dotO. 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
EmbeddedDotO. Thus, we can use header.textSize as a (bogus) limitPC
========================================================================
SGIModuleFromParsedAndPC: PROC [whole: Parsed, spc: FileSegmentPC,
moduleRope: Rope.ROPENIL] RETURNS [newModule: Module ← NIL] = TRUSTED {
stabRange, pcRange: StabRange;
stream: IO.STREAM;
nBytes, fdIndex: INT32 ← 0;
firstPC: CARD32;
newElem, prevElem, modules: LIST OF Module;
wireTables: WireTables ← NIL;
IF whole = NIL THEN
RETURN
ELSE
{
stream ← SystemInterface.GetStreamForFile [whole.file];
IF (whole.privateInfo = NIL) THEN
InitParsedWireTables [stream, whole];
wireTables ← NARROW [whole.privateInfo, WireTables];
[stabRange, pcRange, fdIndex] ←
AlternativeFindModuleStabRange [whole.header,
wireTables.fileDescr,
wireTables.procDescr,
wireTables.wSymHeader,
spc.relPC];
IF stabRange.count = 0 THEN
RETURN;
stream ← SystemInterface.GetStreamForFile[whole.file];
nest so that we can catch unwinds and release the stream
{
if some outer block leaves us dangling clean up
ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[whole.file, stream];
firstPC ← pcRange.first;
prevElem ← NIL;
IF whole.modules = NIL THEN
{
newModule ← CreateModule[whole, fdIndex, wireTables,
stream, stabRange, pcRange];
newElem ← LIST[newModule]; -- make one element list holding new module
newElem.rest ← modules;
insert new element containing module in the list
IF (prevElem = NIL) THEN
whole.modules ← newElem
ELSE
prevElem.rest ← newElem;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN;
};
FOR modules ← whole.modules, modules.rest WHILE (modules # NIL) DO
first, see if we already have it
IF (modules.first.firstPC = firstPC) THEN -- we already have it
{
SystemInterface.ReleaseStreamForFile[whole.file, stream];
newModule ← modules.first;
RETURN
};
IF (firstPC < modules.first.firstPC) THEN
{ -- we should have found it by now
newModule ← CreateModule[whole, fdIndex, wireTables,
stream, stabRange, pcRange];
newElem ← LIST[newModule]; -- make one element list holding new module
newElem.rest ← modules;
insert new element containing module in the list
IF (prevElem = NIL) THEN
whole.modules ← newElem
ELSE
prevElem.rest ← newElem;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN;
};
prevElem ← modules;
ENDLOOP;
};
{
newModule: Module ← CreateModule[whole, fdIndex, wireTables,
stream, stabRange, pcRange];
cell: LIST OF Module ← LIST[newModule];
IF prevElem # NIL THEN prevElem.rest ← cell ELSE whole.modules ← cell;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[newModule];
};
};
};
========================================================================
Given a symbol table entry return a VarLoc record which contains
a storage class string, address, the size of the variable
in bits, and any bit offset
========================================================================
SGIVarLocFromStab: PROC [stab: Stab]
RETURNS [ObjectFiles.VarLoc] = {
header: Header ~ stab.module.whole.header;
wireTables: WireTables ← NARROW[stab.module.whole.privateInfo, WireTables];
MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ {
segRope: Rope.ROPE;
fileByteOffset: CARD;
bitOffset: CARD;
segBase: CARD ~ SELECT kind FROM
text => 0,
the dataReloc in the header is always the start of the data section where the wireTables.wAuxHeader.dataBase is the start of rdata if there was one.
data => header.dataReloc.byteOffset,
bss => wireTables.wAuxHeader.bssBase,
ENDCASE => ERROR;
IF stab.value < segBase THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["value (%xH) less than segment base (%xH) for symbol %g in %g", [cardinal[stab.value]], [cardinal[segBase]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]] ]];
SELECT kind FROM
text =>
{
segRope ← "text";
bitOffset ← (stab.value-segBase)*8;
fileByteOffset ← stab.value-segBase+header.text.byteOffset;
};
data =>
{
segRope ← "data";
bitOffset ← (stab.value-segBase)*8;
fileByteOffset ← stab.value-segBase+header.iData.byteOffset;
};
bss =>
{
segRope ← "bss";
bitOffset ← (stab.value-segBase)*8;
fileByteOffset ← stab.value-segBase+header.iData.byteOffset;
};
ENDCASE => ERROR;
RETURN [NEW [ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: fSegment[
[0, segRope],
bitOffset,
fileByteOffset] ]]]};
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[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]]] ]];
};
========================================================================
Used only by SGIInstallBracketPairsForOneFunStab
This is coded so that symbols both before and after LBracs are
saved with the appropriate bracket pair
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.
========================================================================
ScanOneBracketPairSequence: PROC [module: Module, fun: Stab, funIndex: CARD, firstX: CARD, unclaimedHead, unclaimedTail: StabList] RETURNS [--finalRBracX-- CARD, --innerBrackets-- LIST OF BracketPair, --head of unclaimed symbols-- StabList] =
{
innerBrackets: LIST OF BracketPair ← NIL;
lastInnerBracket: LIST OF BracketPair ← NIL;
x: CARD ← firstX;
symHead, symTail: StabList ← NIL;
DO
xAfterSymbs: CARD;
stabAfterSymbs: Stab;
[xAfterSymbs, symHead, symTail] ← ObjectFilesPrivate.ScanSymbolStabs[module, x, symHead, symTail];
IF xAfterSymbs >= module.limitStabX THEN {
IF unclaimedTail#NIL THEN unclaimedTail.rest ← symHead ELSE unclaimedHead ← symHead;
RETURN[xAfterSymbs, innerBrackets, unclaimedHead]};
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 => {
IF unclaimedTail#NIL THEN unclaimedTail.rest ← symHead ELSE unclaimedHead ← symHead;
RETURN[xAfterSymbs, innerBrackets, unclaimedHead]};
ENDCASE => ERROR; -- can't happen
ENDLOOP
};
SGIInstallBracketPairsForOneFunStab: PROC [module: Module,
funStabIndex: CARD] =
{
wasScanned: BOOLEAN ← module.funStabs[funStabIndex].bracketsScanned;
module.funStabs[funStabIndex].bracketsScanned ← TRUE; -- if error occurs, then we won't do this again.
IF NOT wasScanned THEN
{
funStab: Stab ← module.funStabs[funStabIndex].stab;
paramNames, lastParamName: LIST OF Rope.ROPENIL;
paramStabs, lastParamStab: LIST OF Stab ← NIL; -- includes param mod stabs
x: CARD ← funStab.stabX+1;
good: BOOLTRUE;
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.ROPELIST[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: BOOLEANFALSE; -- 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;
};
RETURN;
};
SGIScanModuleStructure: 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 => NULL;
LBrac => {firstLocal ← module.stabs[I]; EXIT};
Invalid, Unspecified , SO => 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};
Invalid, Unspecified, SO => I ← I + 1;
RBrac, LBrac => {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};
SGIScanFnStructure: PROC [module: Module, funStab: Stab, firstLocal: Stab ← NIL, nextX: CARD, perParm: PROC [Stab] ← NIL, perBracket: ObjectFilesPrivate.BracketConsumer ← NIL] RETURNS [limitX, limitPc: CARD] ~ {
IF perParm#NIL THEN PassParams[module, funStab, funStab.stabX+1, nextX, perParm];
IF firstLocal=NIL THEN limitX ← nextX
ELSE limitX ← DoBrack[module, funStab, firstLocal, perBracket];
FOR K: CARD ← limitX-module.firstStabX, K+1 WHILE K < module.stabs.nStabs DO
stab: Stab ← module.stabs[K];
IF stab.module = NIL THEN LOOP;
SELECT stab.stabType FROM
Fun => RETURN [limitX, stab.value];
ENDCASE => NULL;
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 ← SGIScanBktStructure[module, funStab, first, NIL, NIL].limitX;
RETURN};
SGIScanBktStructure: 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 => IF perLocal#NIL THEN perLocal[stab];
LBrac => {
J: CARD ← I+1;
firstPc ← stab.value+funStab.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+funStab.value];
STSym, LSym, LBrac => J ← DoBrack[module, funStab, stab, perSubBracket] - module.firstStabX;
Invalid, Unspecified, SO => 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]; };
Invalid, Unspecified, SO => NULL;
RBrac => {
firstPc ← first.value+funStab.value;
RETURN[I+module.firstStabX, firstPc, stab.value+funStab.value]; };
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]};
PassParams: 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];
Invalid, Unspecified, SO => NULL;
RBrac => RETURN;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab in parms of %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
RETURN};
========================================================================
this procedure examines all stabs up to the first Fun stab, looking
for certain expected stabs. These are recorded in the whole.
it fills in the global frame sym table entry pointer, the global frame
varloc pointer and a pointer to the version stamp in the module
========================================================================
SGIInstallStaticVars: PROC [module: Module] =
{
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;
};
========================================================================
No need to alter function sym tab entries with MIPS e-coff.
========================================================================
SGIAlterFunStab: PROC [module: Module, funStabX: CARD] RETURNS [Stab] = {
RETURN [module.funStabs[funStabX].stab];
};
SGIGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ TRUSTED {
privateModule: ObjectFilesPrivate.Module ← LOOPHOLE[module];
parsed: ObjectFiles.Parsed ← LOOPHOLE[privateModule.whole, ObjectFiles.Parsed];
absPC: CARD ← spc.relPC + parsed.header.textLoadOffset;
currentPDR: SGI.WireProcDescriptorBody;
found: BOOLEAN;
spOffset: INT;
[currentPDR, found] ← FindMatchingProcDescr [absPC, parsed];
IF found = FALSE THEN
spOffset ← 0
ELSE
spOffset ← LOOPHOLE[currentPDR.frameoffset];
RETURN[spOffset];
};
Functions for testing
========================================================================
testing ... see if we can parse a symtab entry for a random PC?
========================================================================
RandomTestFindStabRange: PROC [cmd: Commander.Handle]
RETURNS [result: REFNIL, msg: ROPENIL] =
{
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
path: PATHPFS.PathFromRope[args[1]];
range: StabRange;
pc: CARD;
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
wireTables: WireTables ← NIL;
{
ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
file: SystemInterface.CirioFile ← SystemInterface.GetCirioFile[fileSet,
path];
nextSeed: INTIF 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, "SGI"];
wireTables ← NARROW[whole.privateInfo, WireTables];
IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed],
IO.time[start]];
FOR I: INT IN [0..100) DO
pc ← Random.ChooseInt[rs, 0, whole.header.text.byteLength];
[range, [, ], ] ← AlternativeFindModuleStabRange[whole.header,
wireTables.fileDescr, wireTables.procDescr, wireTables.wSymHeader, 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];
};
Main Code
transTable: ObjectFilesPrivate.TranslationTable ← NEW[ ObjectFilesPrivate.TranslationTableBody[3]];
The magic number for MIPSEL is 354 (0x162)
transTable[0] ← [0, 2, 354, "SGI"]; -- byteOffset,length,compareValue,format
The magic number for the MIPSEB is 352 (0x160)
transTable[0] ← [0, 2, ECOFFMagic, "SGI"]; -- byteOffset,length,compareValue,format
transTable[1] ← [0, 4, ElfMagic, "SGI", first]; -- the SGI elf magic sequence
transTable[2] ← [18, 2, EMMips, "SGI", last];
Commander.Register["sgiRandomTestFindStabRange", RandomTestFindStabRange];
ObjectFilesPrivate.RegisterObjectFileFlavor[
NEW [ ObjectFilesPrivate.ObjectFileFlavorBody ←
[
"SGI",
SGIOBJ,
ReadHeader,
SGIModuleFromParsedAndPC,
SGIVarLocFromStab,
NIL,
NIL,
SGIScanModuleStructure,
SGIScanFnStructure,
SGIScanBktStructure,
TRUE,
SGIInstallStaticVars,
SGIAlterFunStab,
SGIGetSPOffset
]],
transTable];
END..