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: ROPE ← NIL] ← 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: ROPE ← NIL,
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: INT ← IO.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: CARD ← LAST[CARD];
maxSymsSize: CARD ← 0;
header: Header;
IO.SetIndex[stream, sectHdrOffset];
FOR i:
CARD
IN [0..sectHdrNum)
DO
wSectionHeader: WireSectionHeader ← NEW[WireSectionHeaderBody];
nBytes: INT ← IO.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: ROPE ← NIL] 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.ROPE ← NIL;
funcRope: Rope.ROPE ← NIL;
dotOPathRope, dotORope: Rope.ROPE ← NIL;
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.
ROPE ←
NIL, 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.
ROPE ←
NIL, 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.ROPE ← NIL;
dotOPath, dotO: Rope.ROPE ← NIL;
ropeStream: IO.STREAM ← PFS.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 ANY ← NIL];
CreateModule:
PROC[whole: Parsed, stream:
IO.
STREAM, stabRange: StabRange ← [0, 0], funcRope: Rope.
ROPE ←
NIL, 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: PATH ← PFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
{
ENABLE
UNWIND => SystemInterface.CloseFileSet[fileSet];
file: SystemInterface.CirioFile ← SystemInterface.GetCirioFile[fileSet, path];
nextSeed: INT ← IF args.argc < 3 THEN 4466 ELSE Convert.IntFromRope[args[2]];
start: BasicTime.GMT ← BasicTime.Now[];
WHILE
TRUE
DO
rs: Random.RandomStream ← Random.Create[seed: nextSeed];
whole: Parsed ← ObjectFiles.CreateParsed[file, "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: BOOLEAN ← FALSE;
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.
ROPE ←
NIL] =
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 ANY ← NIL;
IF module.pcToLineNum #
NIL
OR module.lineNumToPC #
NIL
THEN
{
IF module.pcToLineNum = NIL OR module.lineNumToPC = NIL THEN ERROR;
RETURN;
};
sortedList ← List.Sort[lineNums.lines, CompareByCLineNum];
module.lineNumToPC ← NEW[LineNumToPCMapBody[lineNums.nLines]];
FOR
I:
INTEGER
IN [0..lineNums.nLines)
DO
info: REF SLineData ← NARROW[sortedList.first];
module.lineNumToPC[I] ← info^;
sortedList ← sortedList.rest;
ENDLOOP;
sortedList ← List.Sort[lineNums2.lines, CompareByPC];
module.pcToLineNum ← NEW[PCtoLineNumMapBody[lineNums2.nLines]];
FOR
I:
INTEGER
IN [0..lineNums2.nLines)
DO
info: REF SLineData ← NARROW[sortedList.first];
module.pcToLineNum[I] ← info^;
sortedList ← sortedList.rest;
ENDLOOP;
};
Stabs
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.STREAM ← NIL;
cloneStream: IO.STREAM ← NIL;
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.
ROPE ←
NIL, funcPC, dataReloc:
CARD ← 0, lineNum, lineNum2: LineNumList] ~ {
sectionList: SectionList ← NARROW[whole.header.clientData];
nRelocEntries: INT ← whole.header.symsReloc.byteLength / BYTES[WireRelocEntryBody];
symtabStream: IO.STREAM ← PFS.StreamFromOpenFile[openFile~PFS.OpenFileFromStream[stream]];
previousSymtabX: CARD ← LAST[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 CHAR ← NEW[PACKED ARRAY [0..RopeBufferSize) OF CHAR];
we assume that the stream has been positioned at the beginning of a sequence of chars terminated by a '\000 char.
ReadRope:
PROC[s:
IO.
STREAM]
RETURNS[rope:
ROPE] =
BEGIN
ENABLE UNWIND => NULL;
rope: ROPE ← NIL;
WHILE
TRUE
DO
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: CHAR ← IO.PeekChar[sourceStream];
IF IsDigit[lastChar]
THEN {
typeRef ← IO.GetTokenRope[sourceStream, NumTok].token;
RETURN[typeRef]}
ELSE
IF lastChar='(
THEN
DO
lastChar ← IO.GetChar[sourceStream];
typeRef ← Rope.Concat[typeRef, Rope.FromChar[lastChar]];
IF lastChar = ') THEN RETURN[typeRef]
ENDLOOP
ELSE CCError[cirioError, IO.PutFR1["malformed type rep (starts with %q)", [character[lastChar]] ]];
};
IsDigit:
PROC [c:
CHAR]
RETURNS [
BOOL]
= INLINE { RETURN [c IN ['0 .. '9]] };
NumTok:
PROC [char:
CHAR]
RETURNS [
IO.CharClass] ~ {
SELECT char
FROM
IN ['0..'9] => RETURN [other];
ENDCASE => RETURN [break]};
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.