ObjectFiles.mesa
Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved.
Adapted from DotOAccess
Laurie Horton, June 19, 1992 10:56 am PDT
Spreitzer, December 13, 1991 8:08 am PST
Philip James, September 12, 1991 7:53 pm PDT
Katsuyuki Komatsu December 23, 1992 5:05 pm PST
Jas, January 5, 1993 10:46 am PST
DIRECTORY
CirioTypes USING [BitAddr],
IO USING [STREAM],
PFSNames USING [PATH],
Rope USING[ROPE],
SystemInterface USING[CirioFile];
ObjectFiles: CEDAR DEFINITIONS =
BEGIN
Useful shorthands
ROPE: TYPE ~ Rope.ROPE;
PATH: TYPE ~ PFSNames.PATH;
BitAddr: TYPE ~ CirioTypes.BitAddr;
Errors
UnreadableObjectFile: ERROR[msg: ROPE];
generally means that some sort of assumed invariant has failed
Whole Object Files
Parsed: TYPE = REF ParsedBody;
ParsedBody: TYPE;
CreateParsed: PROC[f: SystemInterface.CirioFile, fs: ROPE ¬ NIL, targetData: REF ANY ¬ NIL] RETURNS[Parsed];
fs identifies the object file format.
We leave it up to someone else to avoid creating more than one cookie for the same file.
GetObjectFile: PROC[whole: Parsed] RETURNS[SystemInterface.CirioFile];
returns the file used for the objectFile
GetFormatString: PROC[whole: Parsed] RETURNS[Rope.ROPE];
returns the format specific string for the objectFile
Modules
Module: TYPE = REF ModuleBody;
ModuleBody: TYPE;
A Module represents an element of a composite object file; the results of a single compilation.
ModuleInfo: TYPE = RECORD[
whole: Parsed,
fileName: PATH,
instance: INT];
The fileName is as reported in the symbols. Thus, the directory part may no longer be relevent, because we copy files around. The extension, if any, what the source file actually had; if the symbols provide no reliable indication of extension, it doesn't show up here.
When multiple Modules in a Parsed share the same base of fileName, instance distinguishes them.
GetModule: PROC[info: ModuleInfo] RETURNS[Module];
GetModuleInfo: PROC[Module] RETURNS[REF ModuleInfo];
Returns NIL if can't find the info.
ModuleFromParsedAndPC: PROC [whole: Parsed, spc: FileSegmentPC, moduleRope: ROPE ¬ NIL] RETURNS [Module];
Returns the module responsible for the given pc.
DescribeModule: PROC [Module] RETURNS [ROPE];
Globalish variables
A VarLoc represents where a variable is to be found.
MemorySegmentId: TYPE ~ RECORD [segName: ROPE, segNum: INT];
Relative to a FileEntry from the incremental loader.
FileSegmentId: TYPE ~ RECORD [fSegNum: INT, fSegName: ROPE];
Relative to a Parsed.
noMSeg: MemorySegmentId = [NIL, 0];
noFSeg: FileSegmentId = [0, NIL];
SimpleSeg: TYPE ~ {text, data, bss};
simpleMSeg: READONLY ARRAY SimpleSeg OF MemorySegmentId;
simpleFSeg: READONLY ARRAY SimpleSeg OF FileSegmentId;
VarLoc: TYPE = REF VarLocBody;
GlobalVarLoc: TYPE ~ REF fSegment VarLocBody;
IndirectVarLoc: TYPE ~ REF indirect VarLocBody;
VarLocCase: TYPE ~ {register, frame, frameExtension, fSegment, mSegment, namedCommon, indirect, unknown};
VarLocBody: TYPE = RECORD[
bitSize: CARD,
If the symbols don't specify a size, this field is unspecdBitSize.
where: SELECT case: VarLocCase FROM
register => [regNum: CARD],
frame => [bitOffset: INT],
frameExtension => [bitOffset: INT],
Maybe not all compilers produce these...
fSegment => [fSeg: FileSegmentId, bitOffset, fileByteOffset: CARD],
Relative to a file segment in a Parsed; something in LoadStateAccess should be able to resolve this to a segment VarLoc.
mSegment => [mSeg: MemorySegmentId, bitOffset, fileByteOffset: CARD],
Relative to a memory segment in a FileEntry from the incremental loader.
namedCommon => [name: ROPE, bitOffset, absBase: CARD, absFound, absValid: BOOL],
indirect => [base: VarLoc, offset: BitAddr],
unknown => [why: ROPE],
ENDCASE];
unspecdBitSize: CARD ~ CARD.LAST;
LoadedVarLoc: TYPE ~ RECORD [VarLoc];
Represents a VarLoc that's in memory terms, not file terms. The fSegment variant is forbidden, and absValid must be TRUE.
CGrammar: TYPE ~ {UNKNOWN, SunADotOut, XCOFF, SGIOBJ};
UnreadableDotO: ERROR[msg: Rope.ROPE];
RopeForStabType: PROC [type: StabType] RETURNS[Rope.ROPE];
CNameOfStab: PROC[stab: Stab] RETURNS[rope: Rope.ROPE];
CGrammarOfStab: PROC[stab: Stab] RETURNS[CGrammar];
VarLocFromStab: PUBLIC PROC [stab: Stab] RETURNS [VarLoc ¬ NIL];
MakeUnknownVarLoc: PROC [why: ROPE] RETURNS [VarLoc];
VersionStampInfo: TYPE = RECORD[
varLoc: GlobalVarLoc,
contents: ROPE];
FindVersionStamp: PROC[whole: Module] RETURNS[REF VersionStampInfo];
returns NIL if no version stamp found
FindGlobalFrameVar: PROC[whole: Module] RETURNS[GlobalVarLoc];
returns NIL if no global frame var
the global frame var contains the global frame variables as embedded fields
(At the time of this writing it is not recorded in a recognizable way in the mob, but rather is found by its name in the whole file.)
Instructions
ReadInstruction: PROC[module: Module, spc: FileSegmentPC] RETURNS[inst: CARD];
Given PC is relative to the given file segment of the given Parsed.
GetSPOffset: PROC[module: Module, spc: FileSegmentPC] RETURNS[INT];
Given PC is relative to the given file segment of the given Parsed.
Functions
FunHandle: TYPE = REF FunHandleBody;
FunHandleBody: TYPE;
FunInfo: TYPE = RECORD[stab: Stab, cName: ROPE, pcs: PCRange];
pcs are relative to the containing whole
GenFuns: PROC[module: Module, for: PROC[FunHandle] RETURNS[--stop-- BOOLEAN]];
GetFunInfo: PROC[fun: FunHandle] RETURNS[FunInfo];
GetFunBrackets: PROC[fun: FunHandle] RETURNS[BracketPair];
the returned bp will be a syntheticFun.
Bracket Pairs
BracketPair: TYPE = REF BracketPairBody;
BracketPairBody: TYPE;
A BracketPair represents a C-level scope. We create one synthetic bracket pair covering the entire module. Notice that a BracketPair contains the entire tree of brackets included in the pair.
A BracketPair encloses a PC if the PC is greaterOrEqual to the PC of the LBrac, and less than the PC of the RBrac.
BracketNest: TYPE = LIST OF BracketPair;
A BracketNest defines a scope. It need not include an innermost pair of brackets. The first bracketPair in the nest is the one that covers the entire module, the last bracket pair is the innermost bracket pair of the list.
BracketPairKind: TYPE = {syntheticOuter, syntheticFun, actual, nil};
SymbolProc: TYPE = PROC[Stab] RETURNS[--stop-- BOOLEAN];
BracketProc: TYPE = PROC[BracketPair] RETURNS[--stop-- BOOLEAN];
PCRange: TYPE = RECORD[first, limit: CARD];
Represents the pcs >= first and < limit.
GenOtherSymbolStabs: PROC[module: Module, for: SymbolProc];
Generates all non-SLine stabs that occur outside the range of a Function definition.
GenFunBracketPairs: PROC[module: Module, for: BracketProc];
Enumerates the functions occurring in the whole.
GetOuterBracketPair: PROC[module: Module] RETURNS[BracketPair];
GetFunStab: PROC[bp: BracketPair] RETURNS[Stab];
To be used by clients of GenFunBracketPairs to find the Fun stab for the functions.
Returns NIL unless bp is the outer (synthetic) bracket pair for a function, in which case it returns the appropriate Fun stab.
GetFunHandle: PROC[bp: BracketPair] RETURNS[FunHandle];
Returns NIL unless bp is the outer (synthetic) bracket pair for a function, in which case it returns the appropriate Fun stab.
GetFunHandleFromNest: PROC[nest: BracketNest] RETURNS[FunHandle];
GetBracketPairKind: PROC[bp: BracketPair] RETURNS[BracketPairKind];
GetPCRange: PROC[bp: BracketPair] RETURNS[PCRange];
GenSubBracketPairs: PROC[bp: BracketPair, for: BracketProc];
Generates the immediate descendents of bp.
GenSymbolStabs: PROC[bp: BracketPair, for: SymbolProc];
Generates the symbol stabs corresponding to bp. (For current Sun compilers, these symbol stabs occur BEFORE the LBrac of the pair.) These are the symbols belonging to the static name scope corresponding to bp. Thus, in order to see all symbol stabs (internal to a function) visible to a given bracket nest, call GenStabsForBracketPair on each BracketPair in the nest.
GetBracketNestForPC: PROC[module: Module, spc: FileSegmentPC] RETURNS[BracketNest];
Produces a BracketNest whose innermost bracket pair is the tightest bracket pair enclosing the given relative PC. The outermost bracket pair is the synthetic bracket pair covering the entire Module file. The relativePC is relative to the given file segment of the Parsed.
The FunHandle for the enclosing function may be obtained by:
nest: BracketNest ← GetBracketNestForPC[module, spc];
fun: FunHandle ← GetFunHandleFromNest[nest];
GetTypeRef: PROC[module: Module, sourceStream: IO.STREAM] RETURNS [Rope.ROPE];
C Line-Number to Relative-PC maps
FileSegmentPC: TYPE ~ RECORD [fSeg: FileSegmentId, relPC: CARD];
The FileSegmentId is included because we have no guarantee of only one code segment per module. The relPC is relative to the Parsed.
NoFileSegmentPC: FileSegmentPC = [fSeg: noFSeg, relPC: 0];
The FileSegmentId is included because we have no guarantee of only one code segment per module. The relPC is relative to the Parsed.
GetPCForLineNum: PROC[module: Module, cLineNum: CARD] RETURNS[FileSegmentPC];
Returned pc is relative to containing Parsed. Returns [noFseg, 0] if can't map.
GetLineNumForPC: PROC[module: Module, spc: FileSegmentPC] RETURNS[CARD];
Returns 0 if can't map.
Stabs
Stab: TYPE = REF StabBody;
StabBody: TYPE = RECORD[
module: Module,
stabX: CARD,
stabType: StabType ¬ Invalid,
stabStorClass: StorageClass ¬ SCInvalid,
size: CARD ¬ 0, --LAST[CARD],
value: CARD32,
rope: ROPE,
index: CARD ¬ 0,
extRef: BOOLEAN ¬ FALSE,
fdIndex: INT32 ¬ 0
];
Note: Each of our Stabs covers the set of DBX stabs that should be put together because they cover one string continued across several stabs; rope is the whole string.
Note: if the stab.type = LBrac or RBrac, then stab.value will be corrected by adding an appropriate relocation to the raw value read from the file. Thus, the client need not worry about the fact that component whole files have not had their symbol table LBrac and RBrac entries properly relocated.
StabType: TYPE ~ {
Invalid,
Unspecified,
LBrac,
RBrac,
SLine,
Fun,
PSym,
LSym,
RSym,
STSym,
LCSym,
GSym,
Main,
SO,
BIncl,
EIncl,
Excl,
SOL
};
StorageClass: TYPE ~ {
SCInvalid,
SCNil,
SCText,
SCData,
SCBss,
SCRegister,
SCAbs,
SCUnspecified,
SCBits,
SCInfo,
SCRegImage,
SCUserStruct,
SCSData,
SCSBss,
SCRData,
SCCommon,
SCSCommon,
SCVerRegister,
SCVariant,
SCSUndefined
};
Name ropes
NameAndNumber: TYPE = RECORD[name: ROPE, char: CHAR, number: INT, trailer: ROPE, valid: BOOLEAN];
Variable names in the C file are described in [PCedar2.0]<C2C>C2CNamingDoc.tioga. The format is <rope, underscore, optionalChar, number, optionalTrailer>. In addition, within a whole file this name is followed by a <colon, char, other info>. The parsing routines return a NameAndNumber to represent all this information.
name is the initial rope
char is the optionalChar (blank if not present)
number is number
trailer is optionalTrailer (empty if not present)
valid = TRUE only if the name was structured as described
ParseNameRope: PROC[stab: Stab] RETURNS[NameAndNumber];
case is always blank.
Printing
RopeForBracketPair: PROC[bp: BracketPair] RETURNS[ROPE];
An errorless way to describe a BracketPair.
END..