SunELFFiles.mesa
Copyright Ó 1992, 1993 by Xerox Corporation. All rights reserved.
Katsuyuki Komatsu January 25, 1993 4:07 pm PST
DIRECTORY
Basics USING [BITAND, BITLSHIFT, BITSHIFT, Card16FromH, Card32FromF, Comparison, FWORD, HWORD, Int32FromF],
BasicTime USING [GMT, Now],
CCTypes USING[CCError, CCErrorCase],
CirioTypes USING [zeroBA],
Commander USING [Register, CommandProc],
CommanderOps USING [ArgumentVector, Parse],
Convert USING [IntFromRope],
IO,
List USING [Sort],
ObjectFiles USING[BracketPairKind, CNameOfStab, CreateParsed, DescribeModule, FileSegmentPC, GlobalVarLoc, MakeUnknownVarLoc, ReadInstruction, RopeForStabType, SimpleSeg, Stab, StabBody, StabType, UnreadableObjectFile, unspecdBitSize, VarLoc, VarLocBody, VersionStampInfo],
ObjectFilesPrivate USING[AlterFunStabType, BracketConsumer, BracketPair, BracketPairBody, CheckStaticVar, FnConsumer, FunStabSetBody, GetSPOffsetType, GetTypeRefProcType, HeaderBody, InstallStaticVarsType, LineNumToPCMapBody, MemorySegmentInfo, ModuleBody, ModuleFromParsedAndPCProcType, ObjectFileFlavorBody, Parsed, ParsedBody, PCtoLineNumMapBody, ReadHeaderProcType, ReadInitialDataAsRope, ReadStab, RegisterObjectFileFlavor, SLineData, StabList, StabRange, StabSet, TranslationTable, TranslationTableBody, VarLocFromStabProcType],
PFS USING [PathFromRope, RopeFromPath, StreamFromOpenFile, OpenFileFromStream],
PFSNames USING [PATH],
Random USING[ChooseInt, Create, RandomStream],
RMTWBackdoor USING [GetDotO],
Rope,
SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, GetStreamForFile, ReleaseStreamForFile, ShowReport];
SunELFFiles: CEDAR MONITOR
IMPORTS Basics, BasicTime, CCTypes, Commander, CommanderOps, Convert, IO, List, ObjectFiles, ObjectFilesPrivate, PFS, Random, RMTWBackdoor, Rope, SystemInterface
EXPORTS ObjectFiles
= BEGIN
CCError: ERROR[case: CCTypes.CCErrorCase, msg: ROPENIL] ← CCTypes.CCError;
Useful types
ROPE: TYPE ~ Rope.ROPE;
PATH: TYPE ~ PFSNames.PATH;
Following types are defined in ObjectFiles
Stab: TYPE = ObjectFiles.Stab;
StabList: TYPE = ObjectFilesPrivate.StabList;
StabBody: TYPE = ObjectFiles.StabBody;
StabType: TYPE = ObjectFiles.StabType;
StabRange: TYPE = ObjectFilesPrivate.StabRange;
FileSegmentPC: TYPE = ObjectFiles.FileSegmentPC;
VersionStampInfo: TYPE = ObjectFiles.VersionStampInfo;
some Stab types
LBrac: BYTE = 0c0H;
RBrac: BYTE = 0e0H;
SLine: BYTE = 044H;
Fun: BYTE = 024H;
PSym: BYTE = 0a0H;
LSym: BYTE = 080H;
RSym: BYTE = 040H;
STSym: BYTE = 026H;
LCSym: BYTE = 028H;
GSym: BYTE = 020H;
Main: BYTE = 02aH;
SO: BYTE = 064H;
BIncl: BYTE = 082H;
EIncl: BYTE = 0a2H;
Excl: BYTE = 0c2H;
SOL: BYTE = 084H;
Following types are defined in ObjectFilesPrivate
Parsed: TYPE = REF ParsedBody;
ParsedBody: PUBLIC TYPE = ObjectFilesPrivate.ParsedBody;
Module: TYPE = REF ModuleBody;
ModuleBody: PUBLIC TYPE = ObjectFilesPrivate.ModuleBody;
Header: TYPE = REF HeaderBody;
HeaderBody: TYPE = ObjectFilesPrivate.HeaderBody;
MemorySegmentInfo: TYPE ~ ObjectFilesPrivate.MemorySegmentInfo;
StabSet: TYPE = ObjectFilesPrivate.StabSet;
BracketPair: TYPE ~ ObjectFilesPrivate.BracketPair;
BracketPairBody: TYPE ~ ObjectFilesPrivate.BracketPairBody;
Following values are of global interest
unspecdBitSize: CARD ~ ObjectFiles.unspecdBitSize;
The following computations are adapted from /usr/include/sys/elf.h of the SunOS Release 5.x.
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;
SHFWrite: CARD = 1;
SHFAlloc: CARD = 2;
SHFExecInstr: CARD = 4;
STBLocal: CARD = 0;
STBGlobal: CARD = 1;
STBWeak: CARD = 2;
STTNoType: CARD = 0;
STTObject: CARD = 1;
STTFunc: CARD = 2;
STTSection: CARD = 3;
STTFile: CARD = 4;
The following computations are adapted from /usr/include/sys/elf←SPARC.h of the SunOS Release 5.x.
RSparcNone: CARD = 0;
RSparc8: CARD = 1;
RSparc16: CARD = 2;
RSparc32: CARD = 3;
RSparcDisk8: CARD = 4;
RSparcDisk16: CARD = 5;
RSparcDisk32: CARD = 6;
RSparcWDisp30: CARD = 7;
RSparcWDisp22: CARD = 8;
RSparcHi22: CARD = 9;
RSparc22: CARD = 10;
RSparc13: CARD = 11;
RSparcLo10: CARD = 12;
RSparcGot10: CARD = 13;
RSparcGot13: CARD = 14;
RSparcGot22: CARD = 15;
RSparcPc10: CARD = 16;
RSparcPc22: CARD = 17;
RSparcWPlt30: CARD = 18;
RSparcCopy: CARD = 19;
RSparcGlobDat: CARD = 20;
RSparcJmpSlot: CARD = 21;
RSparcRelative: CARD = 22;
RSparcUa32: CARD = 23;
The following record type was constructed based on /usr/include/sys/elf.h of the SunOS Release 5.x.
WireHeader: TYPE = REF WireHeaderBody;
WireHeaderBody: 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];
WireSectionHeader: TYPE = REF WireSectionHeaderBody;
WireSectionHeaderBody: 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];
WireStabEntry: TYPE = REF WireStabEntryBody;
WireStabEntryBody: TYPE = MACHINE DEPENDENT RECORD[
stringX(0: 0..31): Basics.FWORD,
type(0: 32..39): BYTE,
other(0: 40..47): BYTE,
desc(0: 48..63): Basics.HWORD,
value(0: 64..95): Basics.FWORD];
WireSymtabEntry: TYPE = REF WireSymtabEntryBody;
WireSymtabEntryBody: TYPE = MACHINE DEPENDENT RECORD[
name(0: 0..31): Basics.FWORD,
value(0: 32..63): Basics.FWORD,
size(0: 64..95): Basics.FWORD,
bind(0: 96..99): [0..15],
type(0: 100..103): [0..15],
other(0: 104..111): BYTE,
sectionIndex(0: 112..127): Basics.HWORD];
SymtabRange: TYPE = RECORD[first, count: CARD];
SymtabBind: TYPE ~ {
Local,
Global,
Weak
};
SymtabType: TYPE ~ {
NoType,
Object,
Func,
Section,
File
};
WireRelocEntry: TYPE = REF WireRelocEntryBody;
WireRelocEntryBody: TYPE = MACHINE DEPENDENT RECORD[
offset(0: 0..31): Basics.FWORD,
sym(0: 32..55): [0..16777215],
type(0: 56..63): BYTE,
addend(0: 64..95): Basics.FWORD];
Header
BitsOn: PROC [flags: CARD, mask: CARD] RETURNS [on: BOOL] ~ INLINE {
RETURN [Basics.BITAND[flags, mask] # 0] };
IsDataSection: PROC [section: SectionHeader] RETURNS [BOOL] ~ INLINE {
RETURN [(section.type = SHTProgBits OR section.type = SHTNoBits) AND BitsOn[section.flags, SHFAlloc] AND NOT BitsOn[section.flags, SHFExecInstr]] };
ReadHeader: ObjectFilesPrivate.ReadHeaderProcType ~ TRUSTED {
PROC[stream: IO.STREAM] RETURNS[Header] = TRUSTED
wHeader: WireHeader ← NEW[WireHeaderBody];
nBytes: INTIO.UnsafeGetBlock[stream, [LOOPHOLE[@wHeader^], 0, BYTES[WireHeaderBody]]];
magic: CARD ← Basics.Card32FromF[wHeader.magic];
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 # EMSparc);
nPageSize: CARD ← 1000H;
textSeg: MemorySegmentInfo ← [0, 0];
iDataSeg: MemorySegmentInfo ← [0, 0];
bssSeg: MemorySegmentInfo ← [0, 0];
symtabSeg: MemorySegmentInfo ← [0, 0];
symtabStrSeg: MemorySegmentInfo ← [0, 0];
symsSeg: MemorySegmentInfo ← [0, 0];
symsStrSeg: MemorySegmentInfo ← [0, 0];
textRelocSeg: MemorySegmentInfo ← [0, 0];
dataRelocSeg: MemorySegmentInfo ← [0, 0];
symsRelocSeg: MemorySegmentInfo ← [0, 0];
textLoadOffset: 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];
maxSymsSize: CARD ← 0;
header: Header;
IO.SetIndex[stream, sectHdrOffset];
FOR i: CARD IN [0..sectHdrNum) DO
wSectionHeader: WireSectionHeader ← NEW[WireSectionHeaderBody];
nBytes: INTIO.UnsafeGetBlock[stream, [LOOPHOLE[@wSectionHeader^], 0, BYTES[WireSectionHeaderBody]]];
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;
FOR i: CARD IN [0..sectHdrNum) DO
IO.SetIndex[stream, sectionList[sectStrTblX].offset+sectionList[i].nameIndex];
sectionList[i].name ← ReadRope[stream];
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;
IF objType = ETRelocatable THEN
sectionList[i].addr ← sectionList[i].offset - textSeg.byteOffset;
}
ELSE {
IF dataIndex = LAST[CARD] THEN {
iDataSeg ← [sectionList[i].offset, sectionList[i].size];
dataIndex ← i;
}
ELSE
iDataSeg.byteLength ← iDataSeg.byteLength + sectionList[i].size;
IF objType = ETRelocatable THEN
sectionList[i].addr ← sectionList[i].offset - iDataSeg.byteOffset;
};
};
(sectionList[i].type = SHTNoBits) AND BitsOn[sectionList[i].flags, SHFWrite] => {
IF bssIndex = LAST[CARD] THEN {
bssSeg ← [sectionList[i].offset, sectionList[i].size];
bssIndex ← i;
}
ELSE
bssSeg.byteLength ← bssSeg.byteLength + sectionList[i].size;
IF objType = ETRelocatable THEN
sectionList[i].addr ← sectionList[i].offset - bssSeg.byteOffset;
};
(sectionList[i].type = SHTSymTab) => {
IF symtabIndex = LAST[CARD] THEN {
symtabSeg ← [sectionList[i].offset, sectionList[i].size];
symtabIndex ← i;
IF sectionList[i].entrySize # BYTES[WireSymtabEntryBody] THEN ERROR;
symtabStrSeg ← [sectionList[sectionList[i].link].offset, sectionList[sectionList[i].link].size];
};
};
(sectionList[i].type = SHTProgBits) AND sectionList[i].flags = 0 => {
ignore .comment section that is (sectionList[i].entrySize = 0)
IF sectionList[i].entrySize = BYTES[WireStabEntryBody] THEN {
IF maxSymsSize < sectionList[i].size THEN {
symsSeg ← [sectionList[i].offset, sectionList[i].size];
symsIndex ← i;
symsStrSeg ← [sectionList[sectionList[i].link].offset, sectionList[sectionList[i].link].size]; -- Unfotunately, the link field of stab section is not reliable.
maxSymsSize ← 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]
ELSE IF sectionList[i].info = symsIndex THEN
symsRelocSeg ← [sectionList[i].offset, sectionList[i].size];
};
ENDCASE;
ENDLOOP;
IF symsIndex # 0 THEN {
symsStrName: ROPE ← Rope.Concat[sectionList[symsIndex].name, "str"];
symsRelocName: ROPE ← Rope.Concat[".rela", sectionList[symsIndex].name];
FOR i: CARD IN [0..sectHdrNum) DO
IF Rope.Equal[symsStrName, sectionList[i].name] THEN
symsStrSeg ← [sectionList[i].offset, sectionList[i].size];
IF Rope.Equal[symsRelocName, sectionList[i].name] THEN
symsRelocSeg ← [sectionList[i].offset, sectionList[i].size];
ENDLOOP;
};
header ← NEW[HeaderBody ← [
dynamic: objType = ETDynamicLib,
toolversion: BYTE[0] -- wHeader.version --,
machtype: machine,
magic: 0 -- wHeader.magic --,
text: textSeg,
iData: iDataSeg,
textReloc: textRelocSeg,
dataReloc: dataRelocSeg,
symsReloc: symsRelocSeg,
syms: symsSeg,
extSyms: symtabSeg,
textLoadOffset: textLoadOffset,
bssSize: bssSeg.byteLength,
entryPoint: Basics.Card32FromF[wHeader.entry],
nPageSize: nPageSize,
nEntries: symsSeg.byteLength/BYTES[WireStabEntryBody],
nExtEntries: symtabSeg.byteLength/BYTES[WireSymtabEntryBody],
stringOffset: symsStrSeg.byteOffset,
stringIndexLimit: symsStrSeg.byteLength,
extStringOffset: symtabStrSeg.byteOffset,
extStringIndexLimit: symtabStrSeg.byteLength,
clientData: sectionList
]];
RETURN[header];
};
Module
We assume that there are dbx stabs located in the whole in the stab table entry range [firstX..limitX).
We assume that the first stab is a special stab whose type is the Undefined (0x00), whose size is the count of stabs and whose value is the size of string table.
We also assume that this stab containing the file name.
SunELFModuleFromParsedAndPC: ObjectFilesPrivate.ModuleFromParsedAndPCProcType ~ {
PROC [whole: Parsed, spc: FileSegmentPC, moduleRope: ROPENIL] RETURNS [Module]
IF whole = NIL THEN RETURN [NIL] ELSE {
symtabRange: SymtabRange;
minFuncX: CARD;
minPC: CARD;
dataReloc: CARD;
[symtabRange, minFuncX, minPC, dataReloc] ← AlternativeFindModuleSymtabRange[whole, spc.relPC];
IF symtabRange = [0, 0] THEN RETURN [NIL];
IF symtabRange = [1, whole.header.nExtEntries-1] THEN {
We are fortunate, single module !
RETURN [ModuleFromParsedInner[whole]];
};
{
moduleWhole: Parsed ← NIL;
sourceRope: Rope.ROPENIL;
funcRope: Rope.ROPENIL;
dotOPathRope, dotORope: Rope.ROPENIL;
dotOId: CARD ← 0;
lag: LIST OF Module ← NIL;
newModule: Module ← NIL;
cell: LIST OF Module ← NIL;
sourceRope ← ReadSymtabRope[whole, symtabRange.first];
first, see if we already have it
FOR modules: LIST OF Module ← whole.modules, modules.rest WHILE modules # NIL DO
IF minPC < modules.first.firstPC THEN EXIT; -- we should have found it by now
IF Rope.Equal[PFS.RopeFromPath[modules.first.fileName], sourceRope] THEN { -- we already have it
RETURN[modules.first]
};
lag ← modules;
ENDLOOP;
IF whole.targetData = NIL THEN RETURN [NIL];
funcRope ← ReadSymtabRope[whole, minFuncX];
[dotOPathRope, dotORope, dotOId] ← GetFileNameAndID[whole, sourceRope];
IF dotOId = 0 THEN RETURN [NIL];
moduleWhole ← RMTWBackdoor.GetDotO[whole.targetData, dotOPathRope, dotORope, dotOId, GetDotOId];
newModule ← ModuleFromParsedInner[moduleWhole, funcRope, minPC, dataReloc];
IF newModule = NIL THEN RETURN [NIL];
cell ← LIST[newModule];
IF lag # NIL THEN lag.rest ← cell ELSE whole.modules ← cell;
newModule.whole ← whole;
newModule.moduleWhole ← moduleWhole;
RETURN [newModule];
};
};
};
ModuleFromParsedInner: PROC[whole: Parsed, funcRope: Rope.ROPENIL, funcPC, dataReloc: CARD ← 0] RETURNS[Module] = {
IF whole = NIL THEN RETURN [NIL] ELSE {
stream: IO.STREAM ← SystemInterface.GetStreamForFile[whole.file];
nest so that we can catch unwinds and release the stream
IF whole = NIL THEN RETURN [NIL] ELSE {
ENABLE UNWIND => {
SystemInterface.ReleaseStreamForFile[whole.file, stream];
};
stabRange: StabRange ← [0, whole.header.nEntries];
firstPC: CARD ← 0;
lag: LIST OF Module ← NIL;
first, see if we already have it
FOR modules: LIST OF Module ← whole.modules, modules.rest WHILE modules # NIL DO
IF modules.first.firstPC = firstPC THEN { -- we already have it
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[modules.first]
};
IF firstPC < modules.first.firstPC THEN { -- we should have found it by now
newModule: Module ← CreateModule[whole, stream, stabRange];
cell: LIST OF Module ← LIST[newModule];
cell.rest ← modules;
IF lag # NIL THEN lag.rest ← cell ELSE whole.modules ← cell;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[newModule];
};
lag ← modules;
ENDLOOP;
{
newModule: Module ← CreateModule[whole, stream, stabRange, funcRope, funcPC, dataReloc];
cell: LIST OF Module ← LIST[newModule];
IF lag # NIL THEN lag.rest ← cell ELSE whole.modules ← cell;
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[newModule];
};
};
};
};
GetFileNameAndID: PROC [whole: Parsed, sourceRope: Rope.ROPE] RETURNS [dotOPathRope, dotORope: Rope.ROPENIL, dotOId: CARD ← 0] = {
stream: IO.STREAM ← SystemInterface.GetStreamForFile[whole.file];
nest so that we can catch unwinds and release the stream
{
ENABLE UNWIND => {
SystemInterface.ReleaseStreamForFile[whole.file, stream];
};
nStabs: CARD ← whole.header.nEntries;
stabX, nextStabX: CARD ← 0;
strIndex, nextStrIndex: CARD ← whole.header.stringOffset;
source: Rope.ROPENIL;
dotOPath, dotO: Rope.ROPENIL;
ropeStream: IO.STREAMPFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
WHILE stabX < nStabs DO
IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireStabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]};
SELECT wireStabBuffer.type FROM
00H => {
stabX ← stabX + 1;
nextStabX ← stabX + Basics.Card16FromH[wireStabBuffer.desc];
strIndex ← nextStrIndex;
nextStrIndex ← nextStrIndex + Basics.Card32FromF[wireStabBuffer.value];
IO.SetIndex[ropeStream, strIndex+Basics.Card32FromF[wireStabBuffer.stringX]];
source ← ReadRope[ropeStream];
dotOPath ← NIL;
};
38H => {
stabX ← stabX + 1;
IO.SetIndex[ropeStream, strIndex+Basics.Card32FromF[wireStabBuffer.stringX]];
dotO ← ReadRope[ropeStream];
dotOPath ← Rope.Concat[dotOPath, dotO];
};
3cH => {
stabX ← nextStabX;
IF Rope.Equal[source, sourceRope] THEN RETURN [dotOPathRope: dotOPath, dotORope: dotO, dotOId: Basics.Card32FromF[wireStabBuffer.value]];
};
ENDCASE => stabX ← stabX + 1;
ENDLOOP;
};
};
GetDotOId: PROC [whole: Parsed] RETURNS [dotOId: CARD ← 0] = {
stream: IO.STREAM ← SystemInterface.GetStreamForFile[whole.file];
nest so that we can catch unwinds and release the stream
{
ENABLE UNWIND => {
SystemInterface.ReleaseStreamForFile[whole.file, stream];
};
nStabs: CARD ← whole.header.nEntries;
stabX, nextStabX: CARD ← 0;
WHILE stabX < nStabs DO
IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireStabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]};
SELECT wireStabBuffer.type FROM
00H => {
stabX ← stabX + 1;
nextStabX ← stabX + Basics.Card16FromH[wireStabBuffer.desc];
};
3cH => {
stabX ← nextStabX;
RETURN [Basics.Card32FromF[wireStabBuffer.value]];
};
ENDCASE => stabX ← stabX + 1;
ENDLOOP;
};
};
LineNumList: TYPE = REF LineNumListBody;
LineNumListBody: TYPE = RECORD [nLines: CARD, lines: LIST OF REF ANYNIL];
CreateModule: PROC[whole: Parsed, stream: IO.STREAM, stabRange: StabRange ← [0, 0], funcRope: Rope.ROPENIL, funcPC, dataReloc: CARD ← 0] RETURNS[Module] =
BEGIN
module: Module ← NEW[ModuleBody];
lineNums: LineNumList ← NEW [LineNumListBody ← [0, NIL]];
lineNums2: LineNumList ← NEW [LineNumListBody ← [0, NIL]];
nStabs: CARD ← stabRange.count;
prepare the Module for a call on BuildBrackets
module.whole ← whole;
module.firstStabX ← stabRange.first;
module.limitStabX ← stabRange.first+stabRange.count;
module.firstPC ← 0;
module.limitPC ← whole.header.text.byteLength;
module.dataReloc ← dataReloc;
lets read the all stabs now (WITH their ropes)
module.stabs ← NEW[StabSet[nStabs]];
{I: CARD ← 0;
WHILE I<nStabs DO
stab: Stab;
numStabsRead: CARD;
[stab, numStabsRead] ← BasicReadStab[whole, stream, stabRange.first+I];
module.stabs[I] ← stab;
stab.module ← module;
FOR J: CARD IN (I .. I + numStabsRead) DO
unusedStab: Stab ← NEW [StabBody];
unusedStab.module ← NIL; -- Indicates unused entry
module.stabs[J] ← unusedStab;
ENDLOOP;
I ← I + numStabsRead;
ENDLOOP;
};
now lets finish up
RelocateStabAndLineNum[whole, stream, module, nStabs, funcRope, funcPC, dataReloc, lineNums, lineNums2];
InstallPCLineNumMaps[module, lineNums, lineNums2];
module.fileName ← PFS.PathFromRope[module.stabs[0].rope];
module.staticVarsInstalled ← FALSE;
module.versionStampInfo ← NIL;
module.outerBracket ← NEW[ObjectFilesPrivate.BracketPairBody←[
module: module,
kind: syntheticOuter,
firstX: 0,
limitX: module.whole.header.nEntries,
firstPC: module.firstPC,
pcLimit: module.limitPC,
funStab: NIL,
funIndex: 0,
symbols: NIL,
innerBrackets: NIL]];
RETURN[module];
END;
usage: RandomTestFindStabRange /dir/.../dir/[sun4/]foo[.c2c].o
RandomTestFindSymtabRange: Commander.CommandProc = {
args: CommanderOps.ArgumentVector ← CommanderOps.Parse[cmd];
path: PATHPFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
{ 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, "SunELF"];
IO.PutF[cmd.out, "beginning seed = %g at %g\N", IO.card[nextSeed], IO.time[start]];
FOR I: INT IN [0..100) DO
pc: CARD ← Random.ChooseInt[rs, 0, whole.header.text.byteLength];
range: SymtabRange ← AlternativeFindModuleSymtabRange[whole, pc].symtabRange;
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];
};
Finding Modules by Symtab
SymtabBody: TYPE ~ RECORD[symtabX: CARD, value: CARD, size: CARD, symtabBind: SymtabBind, symtabType: SymtabType, symtabSection: CARD];
nullSymtabBody: SymtabBody ~ [0, 0, 0, Local, NoType, 0];
AlternativeFindModuleSymtabRange: PROC[whole: Parsed, relativePC: CARD] RETURNS[symtabRange: SymtabRange ← [0, 0], minFuncX, minPC: CARD ← 0, dataReloc: CARD ← 0] = {
baseFile: SymtabBody ← nullSymtabBody;
maxPC: CARD ← 0;
highSymtabX: CARD ← 0;
foundDataReloc: BOOLEANFALSE;
FindModuleSymtabRange: PROC [nominalX: CARD] RETURNS [failed: BOOL] = {
IF nominalX >= whole.header.nExtEntries THEN RETURN[failed: TRUE];
baseFile ← nullSymtabBody;
maxPC ← 0;
highSymtabX ← 0;
foundDataReloc ← FALSE;
minPC ← LAST[CARD];
FOR x: CARD DECREASING IN [0..nominalX] DO
info: SymtabBody ← ReadSymtabBody[whole, x];
SELECT info.symtabType FROM
Func => IF info.symtabSection # 0 THEN {
maxPC ← MAX[maxPC, info.value + info.size];
IF info.symtabBind = Local AND info.value < minPC THEN {
minFuncX ← x; minPC ← info.value}};
File => {baseFile ← info; EXIT};
NoType => {dataReloc ← info.value; foundDataReloc ← TRUE};
ENDCASE;
highSymtabX ← MAX[highSymtabX, info.symtabX];
ENDLOOP;
IF baseFile.symtabType # File THEN {
RETURN[failed: TRUE]};
FOR x: CARD IN (nominalX..whole.header.nExtEntries) DO
info: SymtabBody ← ReadSymtabBody[whole, x];
SELECT info.symtabType FROM
Func => IF info.symtabSection # 0 THEN {
maxPC ← MAX[maxPC, info.value + info.size];
IF info.symtabBind = Local AND info.value < minPC THEN {
minFuncX ← x; minPC ← info.value}};
File => EXIT;
NoType => IF NOT foundDataReloc THEN {
dataReloc ← info.value; foundDataReloc ← TRUE};
ENDCASE;
highSymtabX ← MAX[highSymtabX, info.symtabX];
ENDLOOP;
RETURN[failed: FALSE];
};
IF whole = NIL THEN RETURN[[0, 0], 0, 0, 0] ELSE {
nominalX: CARD ← SearchForPCSymtab[whole, relativePC];
DO
IF FindModuleSymtabRange[nominalX].failed THEN RETURN[[0, 0], 0, 0, 0];
IF minPC <= relativePC AND relativePC < maxPC THEN {
RETURN[[baseFile.symtabX, highSymtabX-baseFile.symtabX+1], minFuncX, minPC, dataReloc]};
IF minPC > relativePC THEN EXIT;
retry because SearchForPCSymtab may return wrong range
nominalX ← highSymtabX + 1;
ENDLOOP;
RETURN[[0, 0], 0, 0, 0];
};
};
SearchForPCSymtab: PROC[whole: Parsed, pc: CARD] RETURNS[CARD] =
BEGIN
x: CARD ← 0;
y: CARD ← whole.header.nExtEntries;
WHILE x+1 < y DO
mid: CARD ← (x+y)/2;
midSymtab: SymtabBody ← SearchFwdForPCSymtab[whole, mid, y];
SELECT TRUE FROM
midSymtab.symtabX = y => y ← mid;
pc < midSymtab.value => y ← mid;
midSymtab.value = pc => RETURN[midSymtab.symtabX];
midSymtab.value < pc => x ← mid;
ENDCASE => ERROR;
ENDLOOP;
RETURN[x];
END;
SearchFwdForPCSymtab: PROC[whole: Parsed, start: CARD, limit: CARD] RETURNS[SymtabBody] =
BEGIN
FOR x: CARD ← start, x+1 WHILE x < limit DO
info: SymtabBody ← ReadSymtabBody[whole, x];
IF info.symtabType = Func AND info.symtabBind = Local THEN RETURN[info];
IF info.symtabBind = Global THEN EXIT;
ENDLOOP;
RETURN[[limit, 0, 0, Local, NoType, 0]];
END;
SymtabBindFromData: PROC [data: [0..15]] RETURNS [symtabType: SymtabBind] ~ {
val: CARD ← data;
symtabType ← SELECT val FROM
STBLocal => Local,
STBGlobal => Global,
STBWeak => Weak,
ENDCASE => ERROR;
};
SymtabTypeFromData: PROC [data: [0..15]] RETURNS [symtabType: SymtabType] ~ {
val: CARD ← data;
symtabType ← SELECT val FROM
STTNoType => NoType,
STTObject => Object,
STTFunc => Func,
STTSection => Section,
STTFile => File,
ENDCASE => ERROR;
};
ReadSymtabBody: ENTRY PROC[whole: Parsed, symtabX: CARD] RETURNS[SymtabBody] =
BEGIN
ENABLE UNWIND => NULL;
stream: IO.STREAM ← SystemInterface.GetStreamForFile[whole.file];
IO.SetIndex[stream, whole.header.extSyms.byteOffset+symtabX*BYTES[WireSymtabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireSymtabBuffer^], 0, BYTES[WireSymtabEntryBody]]]};
SystemInterface.ReleaseStreamForFile[whole.file, stream];
RETURN[[symtabX, Basics.Card32FromF[wireSymtabBuffer.value], Basics.Card32FromF[wireSymtabBuffer.size], SymtabBindFromData[wireSymtabBuffer.bind], SymtabTypeFromData[wireSymtabBuffer.type], Basics.Card16FromH[wireSymtabBuffer.sectionIndex]]];
END;
ReadSymtabRope: ENTRY PROC[whole: Parsed, symtabX: CARD] RETURNS[rope: Rope.ROPENIL] =
BEGIN
ENABLE UNWIND => NULL;
stream: IO.STREAM ← SystemInterface.GetStreamForFile[whole.file];
IO.SetIndex[stream, whole.header.extSyms.byteOffset+symtabX*BYTES[WireSymtabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireSymtabBuffer^], 0, BYTES[WireSymtabEntryBody]]]};
IO.SetIndex[stream, whole.header.extStringOffset+Basics.Card32FromF[wireSymtabBuffer.name]];
rope ← ReadRope[stream];
SystemInterface.ReleaseStreamForFile[whole.file, stream];
END;
Variables
SunELFVarLocFromStab: ObjectFilesPrivate.VarLocFromStabProcType ~ {
PROC [stab: Stab] RETURNS [ObjectFiles.VarLoc]
header: Header ~ stab.module.whole.header;
MkSegment: PROC [kind: ObjectFiles.SimpleSeg] RETURNS [ObjectFiles.VarLoc] ~ {
segRope: ROPE;
segBase: CARD ~ SELECT kind FROM
text => 0,
data => header.text.byteLength,
bss => header.text.byteLength + header.iData.byteLength,
ENDCASE => ERROR;
segSize: CARD ~ SELECT kind FROM
text => header.text.byteLength,
data => header.iData.byteLength,
bss => header.bssSize,
ENDCASE => ERROR;
IF stab.value >= segSize THEN ObjectFiles.UnreadableObjectFile[IO.PutFR["value (%xH) greater than segment size (%xH) for symbol %g in %g", [cardinal[stab.value]], [cardinal[segSize]], [rope[ObjectFiles.CNameOfStab[stab]]], [rope[ObjectFiles.DescribeModule[stab.module]]] ]];
SELECT kind FROM
text => segRope ← "text";
data => segRope ← "data";
bss => segRope ← "bss";
ENDCASE => ERROR;
RETURN [NEW [ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: fSegment[
[0, segRope],
stab.value*8,
stab.value + segBase + header.text.byteOffset - header.textLoadOffset] ]]]};
SELECT stab.stabType FROM
Fun => RETURN MkSegment[text];
STSym => RETURN MkSegment[data];
LCSym => RETURN MkSegment[bss];
LSym, PSym => {
byteOffset: INT ~ LOOPHOLE[stab.value];
vLB: ObjectFiles.VarLoc;
IF stab.stabType=PSym AND stab.size>4 AND stab.size # LAST[CARD] THEN
vLB ← NEW[ObjectFiles.VarLocBody ← [
bitSize: stab.size*8,
where: indirect[
base: NEW[ObjectFiles.VarLocBody ← [
bitSize: 32,
where: frame[bitOffset: 8*byteOffset]]],
offset: CirioTypes.zeroBA]]]
ELSE vLB ← NEW[ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: frame[bitOffset: 8*byteOffset]]];
RETURN[vLB]};
RSym => {
sz: CARD ~ IF stab.size#LAST[CARD] AND stab.size#0 THEN stab.size*8 ELSE unspecdBitSize;
vLB: ObjectFiles.VarLoc;
IF stab.size>4 AND stab.size # LAST[CARD] THEN
vLB ← NEW[ObjectFiles.VarLocBody ← [
bitSize: sz,
where: indirect[
base: NEW[ObjectFiles.VarLocBody ← [
bitSize: 32,
where: register[regNum: stab.value]]],
offset: CirioTypes.zeroBA]]]
ELSE vLB ← NEW[ObjectFiles.VarLocBody ← [
bitSize: sz,
where: register[regNum: stab.value]]];
RETURN[vLB]
};
GSym => RETURN [NEW [ObjectFiles.VarLocBody ← [
bitSize: IF stab.size#0 THEN stab.size*8 ELSE unspecdBitSize,
where: namedCommon[Rope.Concat["←", ObjectFiles.CNameOfStab[stab]], 0, 0, FALSE, FALSE] ]]];
ENDCASE => RETURN ObjectFiles.MakeUnknownVarLoc[IO.PutFR["unrecognized stabType (%02xH) for %g", [cardinal[ORD[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[stab]]] ]];
};
SunELFInstallStaticVars: ObjectFilesPrivate.InstallStaticVarsType ~
PROC[module: Module] =
this procedure examines all stabs up to the first Fun stab, looking for certain expected stabs. These are recorded in the whole.
{
IF NOT module.staticVarsInstalled THEN
FOR x: CARD IN [module.firstStabX..module.limitStabX)
DO
stab: Stab ← ObjectFilesPrivate.ReadStab[module, x];
IF stab = NIL THEN LOOP;
IF stab.stabType = Fun THEN EXIT;
IF stab.stabType = STSym OR stab.stabType = LCSym THEN
{
IF module.versionStampStab = NIL THEN
{
gvi: ObjectFiles.GlobalVarLoc ← NIL;
gvi ← NARROW[ObjectFilesPrivate.CheckStaticVar[stab, "versionStamp", TRUE]];
IF gvi # NIL THEN
{
dataRope: ROPE ← 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;
};
C Line-Number to Relative-PC maps
PCtoLineNumMap: TYPE = REF PCtoLineNumMapBody;
PCtoLineNumMapBody: TYPE = ObjectFilesPrivate.PCtoLineNumMapBody;
sorted by PC
LineNumToPCMap: TYPE = REF LineNumToPCMapBody;
LineNumToPCMapBody: TYPE = ObjectFilesPrivate.LineNumToPCMapBody;
sorted by Line Num
SLineData: TYPE = ObjectFilesPrivate.SLineData;
InstallPCLineNumMaps: PROC[module: Module, lineNums, lineNums2: LineNumList] =
{
CompareByCLineNum: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] =
{
info1: REF SLineData ← NARROW[ref1];
info2: REF SLineData ← NARROW[ref2];
IF info1.cLineNum < info2.cLineNum THEN RETURN[less];
IF info1.cLineNum > info2.cLineNum THEN RETURN[greater];
IF info1.parsedRelPC.relPC < info2.parsedRelPC.relPC THEN RETURN[less];
IF info1.parsedRelPC.relPC > info2.parsedRelPC.relPC THEN RETURN[greater];
RETURN[equal];
};
CompareByPC: PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Basics.Comparison] =
{
info1: REF SLineData ← NARROW[ref1];
info2: REF SLineData ← NARROW[ref2];
IF info1.parsedRelPC.relPC < info2.parsedRelPC.relPC THEN RETURN[less];
IF info1.parsedRelPC.relPC > info2.parsedRelPC.relPC THEN RETURN[greater];
IF info1.cLineNum < info2.cLineNum THEN RETURN[less];
IF info1.cLineNum > info2.cLineNum THEN RETURN[greater];
RETURN[equal];
};
sortedList: LIST OF REF ANYNIL;
IF module.pcToLineNum # NIL OR module.lineNumToPC # NIL THEN
{
IF module.pcToLineNum = NIL OR module.lineNumToPC = NIL THEN ERROR;
RETURN;
};
sortedList ← List.Sort[lineNums.lines, CompareByCLineNum];
module.lineNumToPC ← NEW[LineNumToPCMapBody[lineNums.nLines]];
FOR I: INTEGER IN [0..lineNums.nLines) DO
info: REF SLineData ← NARROW[sortedList.first];
module.lineNumToPC[I] ← info^;
sortedList ← sortedList.rest;
ENDLOOP;
sortedList ← List.Sort[lineNums2.lines, CompareByPC];
module.pcToLineNum ← NEW[PCtoLineNumMapBody[lineNums2.nLines]];
FOR I: INTEGER IN [0..lineNums2.nLines) DO
info: REF SLineData ← NARROW[sortedList.first];
module.pcToLineNum[I] ← info^;
sortedList ← sortedList.rest;
ENDLOOP;
};
Stabs
TypeFromData: PROC [data: BYTE] RETURNS [stabType: ObjectFiles.StabType] ~ {
val: CARD ← data;
stabType ← SELECT val FROM
LBrac => LBrac,
RBrac => RBrac,
SLine => SLine,
Fun => Fun,
PSym => PSym,
LSym => LSym,
RSym => RSym,
STSym => STSym,
LCSym => LCSym,
GSym => GSym,
Main => Main,
SO => SO,
BIncl => BIncl,
EIncl => EIncl,
Excl => Excl,
SOL => SOL,
ENDCASE => Unspecified
};
BasicReadStab: ENTRY PROC[whole: Parsed, stream: IO.STREAM, stabX: CARD] RETURNS[stab: Stab, numStabsRead: CARD] ~ {
warning: does NOT relocate stabs.
Also: the module field is set to NIL;
ENABLE UNWIND => NULL;
stab ← NEW [StabBody];
[stab^, numStabsRead] ← ReadStabBody[whole, stream, stabX];
RETURN
};
hack to avoid messing up the stream buffering
previousStream: IO.STREAMNIL;
cloneStream: IO.STREAMNIL;
ReadStabBody: PROC [whole: Parsed, stream: IO.STREAM, stabX: CARD] RETURNS [stab: StabBody, numStabsRead: CARD] ~ {
rope: ROPE ← "\\";
size, rLen, offset: CARD16 ← 0;
value: CARD32;
stabType: ObjectFiles.StabType;
IO.SetIndex[stream, whole.header.syms.byteOffset+stabX*BYTES[WireStabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]};
stabType ← TypeFromData[wireStabBuffer.type];
size ← Basics.Card16FromH[wireStabBuffer.desc];
value ← Basics.Card32FromF[wireStabBuffer.value];
IF stream#previousStream THEN {
cloneStream ← PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
previousStream ← stream;
};
rope ← ReadStringX[cloneStream, whole, Basics.Card32FromF[wireStabBuffer.stringX]];
rLen ← rope.Length[];
numStabsRead ← 1;
IF ~rope.IsEmpty[] THEN
WHILE rope.Fetch[rLen-1] = '\\ DO
offset ← offset + 1;
IO.SetIndex[stream, whole.header.syms.byteOffset+(stabX + offset)*BYTES[WireStabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireStabBuffer^], 0, BYTES[WireStabEntryBody]]]};
rope ← rope.Substr[len:rLen-1].Concat[ReadStringX[cloneStream, whole, Basics.Card32FromF[wireStabBuffer.stringX]]];
rLen ← rope.Length[];
numStabsRead ← numStabsRead + 1;
ENDLOOP;
stab ← [
module: NIL,
stabX: stabX,
stabType: stabType,
size: size,
value: value,
rope: rope
];
RETURN};
RelocateStabAndLineNum: PROC [whole: Parsed, stream: IO.STREAM, module: Module, nStabs: CARD, funcRope: Rope.ROPENIL, funcPC, dataReloc: CARD ← 0, lineNum, lineNum2: LineNumList] ~ {
sectionList: SectionList ← NARROW[whole.header.clientData];
nRelocEntries: INT ← whole.header.symsReloc.byteLength / BYTES[WireRelocEntryBody];
symtabStream: IO.STREAMPFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
previousSymtabX: CARDLAST[CARD];
symtabX: CARD;
sectionIndex: CARD;
baseValue: CARD;
value: CARD;
stabX: CARD;
stabRope: Rope.ROPE ← Rope.Concat[funcRope, ":f("]; -- local function
FOR I: CARD IN [0..nRelocEntries) DO
IO.SetIndex[stream, whole.header.symsReloc.byteOffset+I*BYTES[WireRelocEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[stream, [LOOPHOLE[@wireRelocBuffer^], 0, BYTES[WireRelocEntryBody]]]};
symtabX ← wireRelocBuffer.sym;
IF symtabX # previousSymtabX THEN {
IO.SetIndex[symtabStream, whole.header.extSyms.byteOffset+symtabX*BYTES[WireSymtabEntryBody]];
TRUSTED{[] ← IO.UnsafeGetBlock[symtabStream, [LOOPHOLE[@wireSymtabBuffer^], 0, BYTES[WireSymtabEntryBody]]]};
sectionIndex ← Basics.Card16FromH[wireSymtabBuffer.sectionIndex];
baseValue ← Basics.Card32FromF[wireSymtabBuffer.value] + sectionList[sectionIndex].addr;
IF IsDataSection[sectionList[sectionIndex]] THEN baseValue ← baseValue + dataReloc;
previousSymtabX ← symtabX;
};
value ← baseValue + Basics.Int32FromF[wireRelocBuffer.addend];
stabX ← Basics.Card32FromF[wireRelocBuffer.offset] / BYTES[WireStabEntryBody];
SELECT wireRelocBuffer.type FROM
RSparc32 => module.stabs[stabX].value ← value;
ENDCASE => ERROR;
IF module.stabs[stabX].stabType = Fun AND Rope.IsPrefix[stabRope, module.stabs[stabX].rope] THEN {
module.firstPC ← module.firstPC + (funcPC - module.stabs[stabX].value);
module.limitPC ← module.limitPC + (funcPC - module.stabs[stabX].value);
};
ENDLOOP;
FOR I: CARD IN [0..nStabs) DO
SELECT module.stabs[I].stabType FROM
Fun => IF Rope.Find[module.stabs[I].rope, ":P("] = -1 THEN
value ← module.stabs[I].value ← module.stabs[I].value + module.firstPC;
SLine => {
info: REF SLineData ← NEW[SLineData←[cLineNum: module.stabs[I].size, parsedRelPC: [[1, ".text"], module.stabs[I].value + value]]];
lineNum.lines ← CONS[info, lineNum.lines];
lineNum.nLines ← lineNum.nLines + 1;
lineNum2.lines ← CONS[info, lineNum2.lines];
lineNum2.nLines ← lineNum2.nLines + 1;
module.stabs[I].value ← module.stabs[I].value + value;
};
LBrac, RBrac => module.stabs[I].value ← module.stabs[I].value + value;
ENDCASE;
ENDLOOP;
RETURN};
wireStabBuffer: WireStabEntry ← NEW[WireStabEntryBody];
all users should be in the monitor
wireSymtabBuffer: WireSymtabEntry ← NEW[WireSymtabEntryBody];
all users should be in the monitor
wireRelocBuffer: WireRelocEntry ← NEW[WireRelocEntryBody];
all users should be in the monitor
ReadStringX: PROC[stream: IO.STREAM, whole: Parsed, stringX: CARD] RETURNS[rope: ROPE] ~ {
IO.SetIndex[stream, whole.header.stringOffset+stringX];
rope ← ReadRope[stream]};
WARNING: the rope reading code causes random repositioning of the stream. That is CRUDE and expensive. Simply for this experiment. I need to do something better. Read in the whole string table? read in the symbols, sort them, then read in string table and pick out the interesting strings? What?
Symbol ropes
RopeBufferSize: CARD = 100;
ropeBuffer: REF PACKED ARRAY [0..RopeBufferSize) OF CHARNEW[PACKED ARRAY [0..RopeBufferSize) OF CHAR];
we assume that the stream has been positioned at the beginning of a sequence of chars terminated by a '\000 char.
ReadRope: PROC[s: IO.STREAM] RETURNS[rope: ROPE] =
BEGIN
ENABLE UNWIND => NULL;
rope: ROPENIL;
WHILE TRUE DO
nChars: CARD ← RopeBufferSize; -- tentative
rt: Rope.Text;
TRUSTED{[] ← IO.UnsafeGetBlock[s, [LOOPHOLE[@ropeBuffer^], 0, RopeBufferSize]]};
FOR I: CARD IN [0..RopeBufferSize) DO
IF ropeBuffer[I] = '\000 THEN {nChars ← I; EXIT};
ENDLOOP;
rt ← Rope.NewText[nChars];
FOR I: CARD IN [0..nChars) DO rt[I] ← ropeBuffer[I] ENDLOOP;
rope ← IF rope = NIL THEN (IF nChars = 0 THEN "" ELSE rt)
ELSE (IF nChars = 0 THEN rope ELSE Rope.Concat[rope, rt]);
IF nChars < RopeBufferSize THEN EXIT;
ENDLOOP;
RETURN[rope];
END;
Stab Structure
IsExternalFun: PROC [stab: Stab] RETURNS [BOOL] ~ {
RETURN[Rope.Find[stab.rope, ":P", 0, TRUE] # -1]};
SunELFScanModuleStructure: 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 => IF IsExternalFun[stab] THEN I ← I + 1 ELSE {
funStab: Stab ~ stab;
firstLocal: Stab ← NIL;
WHILE I+1 < module.stabs.nStabs DO
I ← I + 1;
stab ← module.stabs[I];
IF stab.module = NIL THEN LOOP;
SELECT stab.stabType FROM
PSym, RSym => NULL;
LBrac => {
SELECT module.stabs[I+1].stabType FROM
STSym, LSym, RSym => firstLocal ← module.stabs[I+1];
ENDCASE;
EXIT};
Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab while scanning the arguments for function %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
REPEAT FINISHED => SystemInterface.ShowReport[IO.PutFR["Missed an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
I ← perFn[funStab, firstLocal, I+module.firstStabX] - module.firstStabX};
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => I ← I + 1;
ENDCASE => {
SystemInterface.ShowReport[IO.PutFR["Found %g stab while scanning in the global space of %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
I ← I + 1};
ENDLOOP;
RETURN};
SunELFScanFnStructure: 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 PassLocals[module, funStab, funStab.stabX+1, nextX, perParm];
limitX ← DoBrack[module, funStab, module.stabs[nextX-module.firstStabX], 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 => IF stab.value > funStab.value THEN 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 ← SunELFScanBktStructure[module, funStab, first, NIL, NIL].limitX;
RETURN};
SunELFScanBktStructure: 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 + 1;
stab: Stab;
IF first.stabType # LBrac THEN ERROR;
firstPc ← first.value;
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
RBrac => RETURN [I+1+module.firstStabX, firstPc, stab.value];
STSym, LSym, RSym => IF perLocal#NIL THEN perLocal[stab];
LBrac => I ← DoBrack[module, funStab, stab, perSubBracket] - 1 - module.firstStabX;
Fun => IF NOT IsExternalFun[stab] THEN {--shouldn't happen, but ...
SystemInterface.ShowReport[IO.PutFR["Found FUN stab before an LBRAC in function %g in %g", [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
RETURN [I+module.firstStabX, stab.value, stab.value]};
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab before an RBRAC 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[I+module.firstStabX, module.limitPC, module.limitPC]};
PassLocals: PROC [module: Module, funStab: Stab, firstX, limitX: CARD, to: PROC [Stab]] ~ {
FOR I: CARD IN [firstX - module.firstStabX .. limitX-module.firstStabX) DO
stab: Stab ← module.stabs[I];
IF stab.module#NIL THEN SELECT stab.stabType FROM
PSym, RSym, LSym, STSym => to[stab];
SLine, Invalid, Unspecified, Main, SO, BIncl, EIncl, Excl, SOL => NULL;
ENDCASE => SystemInterface.ShowReport[IO.PutFR["Found %g stab in parms/locals of %g in %g", [rope[ObjectFiles.RopeForStabType[stab.stabType]]], [rope[ObjectFiles.CNameOfStab[funStab]]], [rope[ObjectFiles.DescribeModule[module]]] ], $normal];
ENDLOOP;
RETURN};
SunELFGetTypeRef: ObjectFilesPrivate.GetTypeRefProcType ~ {
PROC [sourceStream:IO.STREAM] RETURNS [Rope.ROPE]
typeRef: Rope.ROPE;
lastChar: CHARIO.PeekChar[sourceStream];
IF IsDigit[lastChar] THEN {
typeRef ← IO.GetTokenRope[sourceStream, NumTok].token;
RETURN[typeRef]}
ELSE IF lastChar='( THEN DO
lastChar ← IO.GetChar[sourceStream];
typeRef ← Rope.Concat[typeRef, Rope.FromChar[lastChar]];
IF lastChar = ') THEN RETURN[typeRef]
ENDLOOP
ELSE CCError[cirioError, IO.PutFR1["malformed type rep (starts with %q)", [character[lastChar]] ]];
};
IsDigit: PROC [c:CHAR] RETURNS [BOOL]
= INLINE { RETURN [c IN ['0 .. '9]] };
NumTok: PROC [char: CHAR] RETURNS [IO.CharClass] ~ {
SELECT char FROM
IN ['0..'9] => RETURN [other];
ENDCASE => RETURN [break]};
SunELFAlterFunStab: ObjectFilesPrivate.AlterFunStabType ~ {RETURN [module.funStabs[funStabX].stab]; };
Instruction decoder
SunELFGetSPOffset: ObjectFilesPrivate.GetSPOffsetType ~ {
entryRelativePC: CARD ← spc.relPC;
inst0: CARD ← ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC]];
inst1: CARD ← ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC+4]];
inst2: CARD ← ObjectFiles.ReadInstruction[module, [spc.fSeg, spc.relPC+8]];
spOffset: INT ← SaveProtocol1[inst0, inst1, inst2];
IF spOffset = 0 THEN spOffset ← SaveProtocol2[inst0];
RETURN[spOffset];
};
Following procedures compute the SP offset from FP by examining the entry protocol to a procedure.
SPoffset = 0 means that the instructions do not form the expected protocol.
protocol 1 is
sethi %hi(Offset),%g1
add %g1,%lo(Offset),%g1
save %sp,%g1,%sp
SaveProtocol1: PROC[inst0, inst1, inst2: CARD] RETURNS[spOffset: INT] ~ {
decoded0: DecodedSparcInstruction ← DecodeSparcInstruction[inst0];
decoded1: DecodedSparcInstruction ← DecodeSparcInstruction[inst1];
decoded2: DecodedSparcInstruction ← DecodeSparcInstruction[inst2];
check for sethi %hi(spOffset),%g1
IF decoded0.op # 0 THEN RETURN[0];
IF decoded0.op2 # 4 THEN RETURN[0];
IF decoded0.rd # 1 THEN RETURN[0]; -- this is %g1
check for add %g1,%lo(spOffset),%g1
IF decoded1.op # 2 THEN RETURN[0];
IF decoded1.op3 # 0 THEN RETURN[0];
IF decoded1.i # 1 THEN RETURN[0];
IF decoded1.rs1 # 1 THEN RETURN[0]; -- this is %g1
IF decoded1.rd # 1 THEN RETURN[0]; -- this is %g1
check for save %sp,%g1,%sp
IF decoded2.op # 2 THEN RETURN[0];
IF decoded2.op3 # 74B THEN RETURN[0];
IF decoded2.i # 0 THEN RETURN[0];
IF decoded2.rs1 # 16B THEN RETURN[0]; -- this is %sp
IF decoded2.rs2 # 1 THEN RETURN[0]; -- this is %g1
IF decoded2.rd # 16B THEN RETURN[0]; -- this is %sp
spOffset ← LOOPHOLE[Basics.BITSHIFT[decoded0.imm22, 10] + decoded1.simm13];
};
protocol 2 is
save %sp, spOffset,%sp
SaveProtocol2: PROC[inst0: CARD] RETURNS[spOffset: INT] ~ {
decoded0: DecodedSparcInstruction ← DecodeSparcInstruction[inst0];
check for save %sp, spOffset, %sp
IF decoded0.op # 2 THEN RETURN[0];
IF decoded0.op3 # 74B THEN RETURN[0];
IF decoded0.i # 0 THEN RETURN[0];
IF decoded0.rs1 # 16B THEN RETURN[0]; -- this is %sp
IF decoded0.rd # 16B THEN RETURN[0]; -- this is %sp
spOffset ← decoded0.simm13;
};
DecodedSparcInstruction: TYPE = RECORD[
op, disp30, rd, a, cond, op2, imm22, disp22, op3, rs1, i, asi, rs2, simm13, opf: CARD];
DecodeSparcInstruction: PROC[inst: CARD] RETURNS[DecodedSparcInstruction] ~ {
RETURN[[
op: Basics.BITAND[3, Basics.BITSHIFT[inst, -30]],
disp30: Basics.BITAND[7777777777B, inst],
rd: Basics.BITAND[37B, Basics.BITSHIFT[inst, -25]],
a: Basics.BITAND[1, Basics.BITSHIFT[inst, -29]],
cond: Basics.BITAND[17B, Basics.BITSHIFT[inst, -25]],
op2: Basics.BITAND[7, Basics.BITSHIFT[inst, -22]],
imm22: Basics.BITAND[17777777B, inst],
disp22: Basics.BITAND[17777777B, inst],
op3: Basics.BITAND[77B, Basics.BITSHIFT[inst, -19]],
rs1: Basics.BITAND[37B, Basics.BITSHIFT[inst, -14]],
i: Basics.BITAND[1, Basics.BITSHIFT[inst, -13]],
asi: Basics.BITAND[377B, Basics.BITSHIFT[inst, -5]],
rs2: Basics.BITAND[37B, inst],
simm13: Basics.BITAND[17777B, inst],
opf: Basics.BITAND[777B, Basics.BITSHIFT[inst, -5]]]];
};
Main code
transTable: ObjectFilesPrivate.TranslationTable ← NEW[ObjectFilesPrivate.TranslationTableBody[2]];
Commander.Register["SunELFRandomTestFindSymtabRange", RandomTestFindSymtabRange];
transTable[0] ← [0, 4, ElfMagic, "SunELF", first];
transTable[1] ← [18, 2, EMSparc, "SunELF", last];
ObjectFilesPrivate.RegisterObjectFileFlavor[NEW[ObjectFilesPrivate.ObjectFileFlavorBody ← [
"SunELF",
SunADotOut,
ReadHeader,
SunELFModuleFromParsedAndPC,
SunELFVarLocFromStab,
SunELFGetTypeRef,
NIL,
SunELFScanModuleStructure,
SunELFScanFnStructure,
SunELFScanBktStructure,
TRUE,
SunELFInstallStaticVars,
SunELFAlterFunStab,
SunELFGetSPOffset
]],
transTable];
END.