MobObjectFilesImpl.mesa
Copyright Ó 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Sturgis, March 29, 1990 2:31 pm PST
Last tweaked by Mike Spreitzer on December 23, 1991 9:54 am PST
Coolidge, July 17, 1990 5:16 pm PDT
Laurie Horton, September 3, 1991 5:21 pm PDT
Philip James, December 26, 1991 10:13 am PST
Baran, October 21, 1991 2:14 pm PDT
Katsuyuki Komatsu April 1, 1992 3:40 pm PST
Willie-s, June 11, 1992 1:48 pm PDT
DIRECTORY
Basics USING[bitsPerByte, BITXOR, LongNumber],
CCTypes USING[CCError, CCErrorCase],
CirioTypes USING[bitsPerPtr, zeroBA],
Commander USING[CommandProc, Register],
CommanderOps USING[ArgumentVector, Parse],
Convert USING[CardFromRope],
IO,
MobAccess USING[BlockDesc, BodySE, BTH, BTR, BTRExtension, ConstVal, CreateMobCookie, CTXH, CTXR, FetchBTR, FetchCTXR, FetchSER, FieldDesc, GenCallableBodies, GetCodedBTIFromBTH, GetCodedSeiFromSEH, GetParentOfBTH, GetRootBTH, IsLost, MakeSEHFromCodedSei, MobCookie, SEH, SER, TypeDesc, TypeInfoConsSE],
MobObjectAccessPrivate,
MobObjectFiles USING[VarLoc, VarLocBody],
ObjectFiles USING[BracketNest, BracketPair, CreateParsed, FindGlobalFrameVar, FunHandle, FunInfo, GenFunBracketPairs, GenFuns, GenSubBracketPairs, GenSymbolStabs, GetBracketNestForPC, GetFunBrackets, GetFunHandleFromNest, GetFunInfo, GetPCRange, GetSPOffset, IndirectVarLoc, Module, ModuleFromParsedAndPC, NameAndNumber, Parsed, ParseNameRope, PCRange, Stab, StabType, VarLoc, VarLocBody, VarLocCase, VarLocFromStab],
PFS USING [PathFromRope],
PFSNames USING [PATH],
RefTab USING[Create, Fetch, Insert, Key, Ref],
Rope USING[Concat, Equal, Length, ROPE],
SystemInterface USING[CirioFile, CloseFileSet, CreateFileSet, FileSet, GetCirioFile, ShowReport];
Public Procs for procedure Frame analysis
Assumes that seh is an id entry for a field in a local frame. Assumes that the seh is in the context associated with bth.
GetVarLoc:
PUBLIC
PROC[seh:
SEH, bth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
MOF.VarLoc] =
BEGIN
IF seh = NIL THEN RETURN[NullVarLoc["GetVarLoc[NIL]"]]
ELSE
BEGIN
varKey: RefTab.Key ¬ CreateVarKeyFromSEH[seh];
vi: VarInfo ¬ NARROW[RefTab.Fetch[jmpi.vars.table, varKey].val];
IF vi =
NIL
THEN
-- perhaps the appropriate analysis has not been done
BEGIN
ancestors: LIST OF BTH ¬ GetNearInclusiveAncestorBTHList[bth, jmpi];
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, ancestors.first];
IF cbi # NIL THEN AnalyzeOneCallableBody[cbi];
vi ¬ NARROW[RefTab.Fetch[jmpi.vars.table, varKey].val];
END;
IF vi # NIL THEN RETURN[GetVarLocFromVarInfo[vi]] ELSE RETURN[NullVarLoc["GetVarLoc: no vi"]];
END;
END;
FindNearBTHAncestorsForPC:
PUBLIC
PROC[pc:
CARD, jmpi: JointMobParsedInfo]
RETURNS[
LIST
OF
BTH] =
BEGIN
nest: ObjF.BracketNest ¬ ObjF.GetBracketNestForPC[jmpi.module, [[0, ""], pc]];
fun: ObjF.FunHandle ¬ ObjF.GetFunHandleFromNest[nest];
GetAnalyzedCBIForFun:
PROC
RETURNS[CallableBodyInfo] =
BEGIN
result: CallableBodyInfo ¬ GetCBIForFun[jmpi, fun];
IF result # NIL AND result.bi = NIL THEN AnalyzeOneCallableBody[result];
RETURN[result];
END;
cbi: CallableBodyInfo ¬ IF fun = NIL THEN NIL ELSE GetAnalyzedCBIForFun[];
FindTightestRecognizedBP:
PROC[subNest: ObjF.BracketNest]
RETURNS[BPInfo] =
BEGIN
tentative: BPInfo ¬ IF subNest.rest = NIL THEN NIL ELSE FindTightestRecognizedBP[subNest.rest];
IF tentative # NIL THEN RETURN[tentative];
tentative ¬ NARROW[RefTab.Fetch[jmpi.bracketPairs.table, subNest.first].val];
IF tentative # NIL AND tentative.associatedBody # NIL THEN RETURN[tentative] ELSE RETURN[NIL];
END;
tightestRecognizedBP: BPInfo ¬ FindTightestRecognizedBP[nest];
(maybe I should do FindTightestRecognizedBP[nest.rest.rest??)
tightestRecognizedBth: MA.BTH ¬ IF tightestRecognizedBP # NIL THEN tightestRecognizedBP.associatedBody.bth ELSE IF cbi#NIL THEN cbi.bth ELSE NIL;
IF tightestRecognizedBth=NIL THEN RETURN [NIL];
RETURN[GetNearInclusiveAncestorBTHList[tightestRecognizedBth, jmpi]];
END;
FindNearBTHAncestorsForBlock:
PUBLIC
PROC[block:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
LIST
OF
BTH] =
BEGIN
parent: BTH ¬ MA.GetParentOfBTH[block];
RETURN[GetNearInclusiveAncestorBTHList[parent, jmpi]];
END;
GetRootBTH:
PUBLIC
PROC[jmpi: JointMobParsedInfo]
RETURNS[
BTH] =
{RETURN[MA.GetRootBTH[jmpi.mob]]};
GetEntryPCofCallableBTH:
PUBLIC
PROC[callableBTH:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
CARD] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, callableBTH];
fun: ObjF.FunHandle ¬ IF cbi = NIL THEN NIL ELSE cbi.fun;
funInfo: ObjF.FunInfo ¬ IF fun = NIL THEN CCE[cirioError] ELSE ObjF.GetFunInfo[fun];
IF funInfo.stab.stabType # Fun THEN CCE[cirioError];
RETURN[funInfo.stab.value];
END;
GetNearInclusiveAncestorBTHList:
PROC[tightestBth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
LIST
OF
BTH] =
BEGIN
rootBTH: BTH ¬ MA.GetRootBTH[jmpi.mob];
list: LIST OF BTH ¬ LIST[tightestBth];
DO
IF list.first = rootBTH THEN RETURN[list];
IF RefTab.Fetch[jmpi.callableBodies.table, CreateBTKeyFromBTH[list.first]].val # NIL THEN RETURN[list];
list ¬ CONS[MA.GetParentOfBTH[list.first], list];
ENDLOOP;
END;
GetLocalFrameExtensionVar:
PUBLIC
PROC[bth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
SEH] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, bth];
IF cbi = NIL THEN RETURN[NIL];
AnalyzeOneCallableBody[cbi];
IF cbi.frameExtension = NIL THEN RETURN[NIL];
RETURN[cbi.frameExtension.seh];
GetGlobalLinkVar:
PUBLIC
PROC[bth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
SEH] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, bth];
IF cbi = NIL THEN RETURN[NIL];
AnalyzeOneCallableBody[cbi];
IF cbi.globalLink = NIL THEN RETURN[NIL];
RETURN[cbi.globalLink.seh];
END;
GetStaticLinkVar:
PUBLIC
PROC[bth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
SEH] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, bth];
IF cbi = NIL THEN RETURN[NIL];
AnalyzeOneCallableBody[cbi];
IF cbi.staticLink = NIL THEN RETURN[NIL];
RETURN[cbi.staticLink.seh];
END;
GetStrandedStaticLinkLoc:
PUBLIC
PROC[bth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
MOF.VarLoc] ~ {
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, bth];
IF cbi = NIL THEN RETURN[NIL];
AnalyzeOneCallableBody[cbi];
IF cbi.staticLink=
NIL
AND cbi.topStabs#
NIL
AND cbi.topStabs.rest=
NIL
AND cbi.bi.btr.class=Scope
THEN
RETURN ObjF.VarLocFromStab[cbi.topStabs.first];
ENABLE scopes are translated into C procedures of one argument, whose codedSei is negative (ie, not from Mimosa), so there's no corresponding SEH.
RETURN[NIL]};
GetCatchPhraseStrandedStaticLinkLoc:
PUBLIC
PROC[bth:
BTH, jmpi: JointMobParsedInfo]
RETURNS[
MOF.VarLoc] ~ {
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, bth];
IF cbi = NIL THEN RETURN[NIL];
AnalyzeOneCallableBody[cbi];
IF cbi.staticLink=
NIL
AND cbi.topStabs#
NIL
AND cbi.bi.btr.class=Catch
THEN
BEGIN
count:
CARD ¬ 0;
last: ObjF.Stab ¬
NIL;
prev: ObjF.Stab;
FOR x:
LIST
OF ObjF.Stab ¬ cbi.topStabs, x.rest
WHILE x#
NIL
DO
count ¬ count + 1;
prev ¬ last;
last ¬ x.first;
ENDLOOP;
IF count=5
THEN
RETURN ObjF.VarLocFromStab[prev];
END;
Catch phrases are translated into C procedures of five arguments, the second of which
is a stand-in for the Static Link (a pointer to the frame extension). There is no
corresponding Mesa SEH.
RETURN[NIL]};
GetGlobalFrameVarLoc:
PUBLIC
PROC[jmpi: JointMobParsedInfo]
RETURNS[
MOF.VarLoc]
= {RETURN [ObjF.FindGlobalFrameVar[jmpi.module]]};
NullVarLoc:
PROC [why: Rope.
ROPE ¬]
RETURNS[
MOF.VarLoc] =
{RETURN[NEW[ObjF.VarLocBody ¬ [0, unknown[why]]]]};
Individual CFunction analysis
jmpi.bodies is a hash table that maps from coded bti to BodyInfo
jmpi.vars is a hash table that maps from coded sei to VarInfo
jmpi.bracketPairs is a hash table that maps from ObjF.BracketPair to BPInfo
These are filled in for one entire C function at a time
Note: for a callableBody, the args and results will be installed in the CallableBodyInfo, while the local vars of the outermost block will be installed in a cbi.bi (a BodyInfo).
That is, there are two records for the same body table entry: a CallableBodyInfo and a BodyInfo.
To get from a pc to an innermost block containing the pc:
call AnalyzeCallableBodySet, if it hasn't been done (should have been done when creating the jmpi)
using ObjF.GetBracketNestForPC, get a bracket nest
using ObjF.GetFunHandleFromNest, get a FunHandle
using GetCBIForFun, obtain a cbi
if cbi.bi = NIL, then call AnalyzeOneCallableBody[cbi]
starting with the tightest bracket pair in the nest, look in jmpi.bracketPairs for an entry
having found an entry, BPInfo.associatedBody.bth is the tightest recognized block containing the PC
BodyInfo: TYPE = REF BodyInfoBody;
BodyInfoBody:
TYPE =
RECORD[
bth: BTH,
codedBti: CARD,
btr: BTR,
callable: BOOLEAN,
jmpi: JointMobParsedInfo,
parent: REF ANY, -- either BodyInfo or CallableBodyInfo. (It will be CallableBodyInfo exactly when this bti is callable, in which case it will be the CallableBodyInfo for this bti.)
callableAncestor: CallableBodyInfo, -- will be for this bti when this bti is callable.
associatedBps: LIST OF BPInfo, -- will be used for printing, bad situation if none or if more than one
vars: LIST OF VarInfo,
subBodies: LIST OF BodyInfo,
invalid: BOOLEAN ¬ FALSE,
bodyOccurredTwice: BOOLEAN ¬ FALSE];
VarInfo: TYPE = REF VarInfoBody;
VarInfoBody:
TYPE =
RECORD[
seh: SEH,
codedSei: CARD,
idBody: REF id MA.BodySE,
name: Rope.ROPE,
containingBody: REF ANY, -- either BodyInfo or CallableBodyInfo. (It will be CallableBodyInfo exactly when this is an arg or result.)
associatedStabs: LIST OF StabInfo,
correctedByteOffset: INT, -- this field can be removed when we go to a future Sun C compiler that does not make the offset error following multi word parameters. This field is only used for argument vars.
varLoc: MOF.VarLoc,
invalid: BOOLEAN ¬ FALSE,
varOccuredTwice: BOOLEAN ¬ FALSE];
StabInfo: TYPE = RECORD[stab: ObjF.Stab, owningBp: ObjF.BracketPair];
BPInfo: TYPE = REF BPInfoBody;
BPInfoBody:
TYPE =
RECORD[
bp: ObjF.BracketPair,
associatedBody: BodyInfo,
thereAreOtherAssociatedBodies: BOOLEAN -- TRUE if this bp associates with more than one BodyInfo. (A BAD situation.)
];
AnalyzeOneCallableBody:
PROC[cbi: CallableBodyInfo] = {
jmpi: JointMobParsedInfo ¬ cbi.jmpi;
containingBody is either BodyInfo or CallableBodyInfo
Create a VarInfo for the codedSei.
show them to be embedded in containingBody
VisitOneVarSeh:
PROC[containingBody:
REF
ANY, seh:
SEH, ser:
SER, idBody:
REF id
MA.BodySE]
RETURNS[VarInfo] = {
codedSei: CARD ¬ MA.GetCodedSeiFromSEH[seh];
varKey: REF CARD ¬ NEW[CARD¬codedSei];
vi: VarInfo ¬
NEW[VarInfoBody¬[
seh: seh,
codedSei: codedSei,
idBody: idBody,
name: idBody.hash,
containingBody: containingBody,
associatedStabs: NIL,
correctedByteOffset: 0,
varLoc: NIL]];
IF
NOT RefTab.Insert[jmpi.vars.table, varKey, vi]
THEN
BEGIN
oldVi: VarInfo ¬ NARROW[RefTab.Fetch[jmpi.vars.table, varKey].val];
oldVi.varOccuredTwice ¬ oldVi.invalid ¬ TRUE;
SystemInterface.ShowReport[IO.PutFR1["seh with coded sei = %g occurred more than once", IO.card[codedSei]], $debug];
END;
(other cases probably should be added)
(should I test for multiple instances?)
SELECT idBody.special
FROM
globalLink => cbi.globalLink ¬ vi;
staticLink => cbi.staticLink ¬ vi;
frameExtension => cbi.frameExtension ¬ vi;
ENDCASE => NULL;
RETURN[vi]};
containingBody is either BodyInfo or CallableBodyInfo
Create VarInfos for each.
show them to be embedded in containingBody
VisitAllVarSehsInAContext:
PROC[containingBody:
REF
ANY, ctxh:
CTXH]
RETURNS[
LIST
OF VarInfo] = {
ctxr: CTXR ¬ MA.FetchCTXR[ctxh];
seh: SEH ¬ IF ctxr = NIL THEN NIL ELSE ctxr.seList;
results: LIST OF VarInfo ¬ NIL;
lastResult: LIST OF VarInfo ¬ NIL;
WHILE seh #
NIL
DO
ser: SER ¬ MA.FetchSER[seh];
WITH ser.body
SELECT
FROM
idBody:
REF id
MA.BodySE =>
BEGIN
vi: VarInfo ¬ VisitOneVarSeh[containingBody, seh, ser, idBody];
viCell: LIST OF VarInfo ¬ LIST[vi];
IF results = NIL THEN results ¬ viCell ELSE lastResult.rest ¬ viCell;
lastResult ¬ viCell;
seh ¬ idBody.ctxLink;
END
ENDCASE => ERROR;
ENDLOOP;
RETURN[results]};
VisitAllVarSehsInArgsOrResults:
PROC[containingBody:
REF
ANY, seh:
SEH]
RETURNS[
LIST
OF VarInfo] = {
IF seh = NIL THEN RETURN[NIL]
ELSE
{
underSeh: SEH ¬ UnderTypeSeh[seh];
underSer: SER ¬ MA.FetchSER[underSeh];
WITH underSer.body
SELECT
FROM
cons:
REF cons
MA.BodySE =>
WITH cons.typeInfo
SELECT
FROM
ti:
REF record
MA.TypeInfoConsSE =>
RETURN[VisitAllVarSehsInAContext[containingBody, ti.fieldCtx]];
ENDCASE => CCE[cirioError];
ENDCASE => CCE[cirioError];
};
};
(0) we exit if the analysis has already been done
IF cbi.bi # NIL THEN RETURN;
(1) we begin by creating VarInfos for the args and results
BEGIN
btr: BTR ¬ MA.FetchBTR[cbi.bth];
WITH btr.extension
SELECT
FROM
ext:
REF Callable
MA.BTRExtension => {
ioTypeSer: SER ¬ MA.FetchSER[ext.ioType];
WITH ioTypeSer.body
SELECT
FROM
cons:
REF cons
MA.BodySE =>
WITH cons.typeInfo
SELECT
FROM
transfer:
REF transfer
MA.TypeInfoConsSE => {
cbi.args ¬ VisitAllVarSehsInArgsOrResults[cbi, transfer.typeIn];
cbi.results ¬ VisitAllVarSehsInArgsOrResults[cbi, transfer.typeOut]};
basic:
REF basic
MA.TypeInfoConsSE => {
I assume that this is an attempt to indicate that there are no arguments or results. This seems to occur for manufactured procedures that contain a block covered by an enable clause.
cbi.args ¬ NIL;
cbi.results ¬ NIL};
ENDCASE => CCE[cirioError];
ENDCASE => CCE[cirioError]};
ENDCASE => CCE[cirioError];
END;
(2) we walk the body tree, creating appropriate BodyInfo and VarInfo entries
{
alwaysRecord will be true for the root callable body, false for all visited sub bodies.
VisitOneBody:
PROC[parent: BodyInfo, bth:
BTH, alwaysRecord:
BOOLEAN]
RETURNS[BodyInfo] = {
bodyKey: RefTab.Key ¬ CreateBTKeyFromBTH[bth];
codedBti: CARD ¬ NARROW[bodyKey, REF CARD];
btr: MA.BTR ¬ MA.FetchBTR[bth];
biIsCallable:
BOOLEAN ¬
WITH btr.extension
SELECT
FROM
callable: REF Callable MA.BTRExtension => TRUE,
other: REF Other MA.BTRExtension => FALSE,
ENDCASE => ERROR;
bi: BodyInfo ¬
NEW[BodyInfoBody¬[
bth: bth,
btr: btr,
callable: biIsCallable,
codedBti: codedBti,
jmpi: jmpi,
parent: parent,
callableAncestor: cbi,
associatedBps: NIL,
vars: NIL,
subBodies: NIL]];
IF alwaysRecord
OR
NOT bi.callable
THEN
-- examine its details
{
we record this new block
IF
NOT RefTab.Insert[jmpi.bodies.table, bodyKey, bi]
THEN
{
oldBi: BodyInfo ¬ NARROW[RefTab.Fetch[jmpi.bodies.table, bodyKey].val];
oldBi.bodyOccurredTwice ¬ oldBi.invalid ¬ TRUE;
SystemInterface.ShowReport[IO.PutFR1["body with coded bti = %g occured more than once", IO.card[codedBti]], $debug];
};
now we visit the variables of the block
bi.vars ¬ VisitAllVarSehsInAContext[bi, btr.localCtx];
next, we visit the sub bodies, if any.
{
subBth: BTH ¬ btr.firstSon;
lastSubBody: LIST OF BodyInfo ¬ NIL;
WHILE subBth #
NIL
DO
subBtr: BTR ¬ MA.FetchBTR[subBth];
sub: BodyInfo ¬ VisitOneBody[bi, subBth, FALSE];
subCell: LIST OF BodyInfo ¬ LIST[sub];
IF bi.subBodies = NIL THEN bi.subBodies ¬ subCell ELSE lastSubBody.rest ¬ subCell;
lastSubBody ¬ subCell;
subBth ¬ IF subBtr.link.which = parent THEN NIL ELSE subBtr.link.index;
ENDLOOP;
};
};
RETURN[bi];
};
cbi.bi ¬ VisitOneBody[NIL, cbi.bth, TRUE];
};
(3) we walk the Fun, creating BPInfo entries and constructing associations between BPIs and BodyInfos; because Mimosa erroneously puts all static links in the null Context, this is also where we find the static links for the callable body.
{
the following two vars are used to compute corrected byte offsets for function parameters. The current Sun C compiler miscomputes the offsets for params following multi word arguments. These corrected byte offsets will be recorded in the appropriate VarInfo.
The code that constructs this correction appears at several places in ViewOneStab.
That code assumes that
the PSym stabs will be generated in first to last order among the parameters
the PSym stabs will occur before any modifying stabs (do we really assume this?)
cumByteOffset: CARD ¬ 0;
somePSymsSeen: BOOLEAN ¬ FALSE;
ViewSubBracketPair:
PROC[bp: ObjF.BracketPair]
RETURNS[
--stop--
BOOLEAN] = {
ViewOneBracketPair[bp, FALSE];
RETURN[FALSE]};
ViewOneBracketPair:
PROC[bp: ObjF.BracketPair, top:
BOOL] = {
containingBody is either BodyInfo or CallableBodyInfo. (It will be CallableBodyInfo exactly when the var triggering the assocition is an arg or result.) (Because DotOAccessImpl builds different BracketPairs for the a CFunction and for its outermost block, we should never find ourselves attempting to associate a CallableBodyInfo and its corresponding BodyInfo with the same BracketPair.)
Also, we avoid calling this procedure for certain troublesome vars whose locations in the mob and DotO do not correspond; e.g., staticLinks
NoteBpBtiAssociation:
PROC[containingBody:
REF
ANY] = {
WITH containingBody
SELECT
FROM
bi: BodyInfo => {
info: BPInfo ¬ NARROW[RefTab.Fetch[bi.jmpi.bracketPairs.table, bp].val];
alreadyRecordedInBi: BOOLEAN ¬ FALSE; -- tentative
IF info =
NIL
THEN {
info ¬ NEW[BPInfoBody¬[bp, bi, FALSE]];
IF NOT RefTab.Insert[bi.jmpi.bracketPairs.table, bp, info] THEN CCE[cirioError];
};
IF info.associatedBody # bi
THEN {
pcRange: ObjF.PCRange ¬ ObjF.GetPCRange[bp];
SystemInterface.ShowReport[IO.PutFR["warning: multiple Mesa block associations for the CBlock containing (ContainingDotO) relative PCs: [%g..%g)", IO.card[pcRange.first], IO.card[pcRange.limit]], $debug];
info.thereAreOtherAssociatedBodies ¬ TRUE;
};
FOR knownBPIs:
LIST
OF BPInfo ¬ bi.associatedBps, knownBPIs.rest
WHILE knownBPIs #
NIL
DO
IF knownBPIs.first = info THEN {alreadyRecordedInBi ¬ TRUE; EXIT};
ENDLOOP;
IF
NOT alreadyRecordedInBi
THEN {
IF bi.associatedBps #
NIL
THEN
SystemInterface.ShowReport[IO.PutFR1["warning: Mesa block with codedBti = %g has multiple associated CBlocks", IO.card[bi.codedBti]], $debug];
bi.associatedBps ¬ CONS[info, bi.associatedBps];
};
};
cbi: CallableBodyInfo => NULL; -- we needn't record this association (We shall handle PCs outside the outermost C block of a function by going to the Fun, then the CallableBodyInfo, then the associated cbi.)
ENDCASE => ERROR;
};
ViewOneStab:
PROC[stab: ObjF.Stab]
RETURNS[
--stop--
BOOLEAN] = {
IF stab.stabType = LSym
OR stab.stabType = PSym
OR stab.stabType = RSym
THEN {
varKey: RefTab.Key ¬ CreateVarKeyFromVarStab[stab];
codedSei: CARD ¬ IF varKey = NIL THEN 0 ELSE NARROW[varKey, REF CARD];
vi: VarInfo ¬ IF varKey = NIL THEN NIL ELSE NARROW[RefTab.Fetch[jmpi.vars.table, varKey].val];
IF stab.stabType = PSym
AND
NOT somePSymsSeen
THEN
{ -- for correcting param byte offsets due to errors in C compiler
somePSymsSeen ¬ TRUE;
cumByteOffset ¬ StabValueAsInt[stab];
};
IF varKey#
NIL
AND vi=
NIL
AND (cbi.staticLink=
NIL
OR cbi.globalLink=
NIL
OR cbi.frameExtension=
NIL)
THEN {
seh: SEH ¬ MA.MakeSEHFromCodedSei[jmpi.mob, codedSei, NIL];
IF seh#
NIL
AND
MA.IsLost[seh]
THEN {
ser: SER ¬ MA.FetchSER[seh];
WITH
MA.FetchSER[seh].body
SELECT
FROM
idser:
REF id
MA.BodySE =>
IF (
SELECT idser.special
FROM staticLink => cbi.staticLink=
NIL, globalLink => cbi.globalLink=
NIL, frameExtension => cbi.frameExtension=
NIL,
ENDCASE =>
FALSE)
THEN {
[] ¬ VisitOneVarSeh[cbi, seh, ser, idser];
vi ¬ NARROW[RefTab.Fetch[jmpi.vars.table, varKey].val]};
ENDCASE => NULL;
};
};
IF vi #
NIL
THEN {
vi.associatedStabs ¬ CONS[[stab, bp], vi.associatedStabs];
IF vi.containingBody= NIL THEN ERROR;
IF vi.idBody.special # staticLink
THEN
NoteBpBtiAssociation[vi.containingBody];
We do not record the staticLinks because
in the mob they appear in the outer block of a procedure
in the DotO they appear among the params
Thus, they would confuse the mapping.
IF stab.stabType = PSym
THEN vi.correctedByteOffset ¬ cumByteOffset;
for correcting param byte offsets due to errors in C compiler
}
ELSE cbi.unMatchedStabs ¬ CONS[stab, cbi.unMatchedStabs];
IF top THEN cbi.topStabs ¬ CONS[stab, cbi.topStabs];
IF stab.stabType = PSym
THEN cumByteOffset ¬ cumByteOffset + 4;
For correcting param byte offsets due to errors in C compiler.
We assume that each fun param occupies 4 bytes or 1 word.
};
RETURN[FALSE]};
ObjF.GenSymbolStabs[bp, ViewOneStab];
ObjF.GenSubBracketPairs[bp, ViewSubBracketPair];
RETURN};
fun: ObjF.FunHandle ¬ cbi.fun;
brackets: ObjF.BracketPair ¬ ObjF.GetFunBrackets[fun];
[] ¬ ViewOneBracketPair[brackets, TRUE];
};
};
this is adapted from RMTWAtomics.UnderTypeSEH. I hope this version works here.
UnderTypeSeh:
PROC[seh:
SEH]
RETURNS[
SEH] =
BEGIN
ser: MA.SER ¬ MA.FetchSER[seh];
WITH ser.body
SELECT
FROM
id:
REF id
MA.BodySE =>
BEGIN
we simply spin deeper into the Mob type structure
WITH id.idInfoAndValue
SELECT
FROM
idInfo:
REF
MA.TypeDesc =>
RETURN[UnderTypeSeh[idInfo.seh]];
ENDCASE => ERROR;
END;
cons: REF cons MA.BodySE => RETURN[seh];
ENDCASE => ERROR;
END;
Not useful until after completion of the appropriate call on AnalyzeOneCallableBody. (Specifically, not until after all calls on ViewOneStab for stabs related to this VarInfo.)
(Are there other cases of embedded fields? e.g., return values? why don't I handle them?)
We construct the varLoc if we have not already done so.
Note: Temporarily, we compute during pass (3) of AnalyzeOneCallableBody a correction to the byte offsets of C function parameters. This is to compensate for a bug in the current C compiler. This correction is used below.
GetVarLocFromVarInfo:
PROC[vi: VarInfo]
RETURNS[
MOF.VarLoc] = {
IF vi.varLoc =
NIL
THEN {
-- we have better build one
mobFD: REF MA.FieldDesc ¬ NIL; -- tentative
WITH vi.idBody.idInfoAndValue
SELECT
FROM
fd: REF MA.FieldDesc => mobFD ¬ fd;
ENDCASE => NULL;
IF mobFD =
NIL
THEN
-- unexpected situation, seh is not a var?
vi.varLoc ¬ NullVarLoc["mobFD = NIL"]
ELSE
IF vi.idBody.flags.valid
AND vi.idBody.flags.upLevel
THEN
-- known to be in frame extension
vi.varLoc ¬ NEW[ObjF.VarLocBody¬[bitSize: mobFD.bitSize, where: frameExtension[bitOffset: mobFD.bitOffset]]]
ELSE
IF vi.associatedStabs #
NIL
THEN {
-- it is represented as a C var
FOR stabs:
LIST
OF StabInfo ¬ vi.associatedStabs, stabs.rest
WHILE stabs #
NIL
DO
stab: ObjF.Stab ¬ stabs.first.stab;
IF vi.varLoc #
NIL
THEN {
-- we have seeen at least one previous stab
(We assume that the stabs are ordered as they appear in the dotO, hence the PSym will occur before any modifying RSym.)
baseCase: ObjF.VarLocCase ~
WITH vi.varLoc
SELECT
FROM
x: ObjF.IndirectVarLoc => x.base.case,
ENDCASE => vi.varLoc.case;
SELECT
TRUE
FROM
baseCase = register => NULL; -- let it stand
baseCase # register
AND stab.stabType = RSym => {
-- overwrite it
bitSize: CARD16 ¬ BitsForBytes[stab.size];
newVarLoc: ObjF.VarLoc;
IF bitSize > 32
THEN newVarLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: indirect[
base:
NEW[ObjF.VarLocBody ¬ [
bitSize: CirioTypes.bitsPerPtr,
where: register[regNum: stab.value]]],
offset: CirioTypes.zeroBA]]]
ELSE newVarLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: register[regNum: stab.value]]];
vi.varLoc ¬ newVarLoc;
};
ENDCASE => CCE[cirioError] -- I dont think this is supposed to happen
}
ELSE {
-- we have seen no previouis stabs
SELECT
TRUE
FROM
stab.stabType = RSym => {
bitSize: CARD16 ¬ BitsForBytes[stab.size];
IF bitSize>32
THEN vi.varLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: indirect[
base:
NEW[ObjF.VarLocBody ¬ [
bitSize: CirioTypes.bitsPerPtr,
where: register[regNum: stab.value]]],
offset: CirioTypes.zeroBA]]]
ELSE vi.varLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: register[regNum: stab.value]]];
};
Note: when we get a corrected C compiler, then this case can again be combined with ObjF.LSym, replacing vi.correctedByteOffset with StabValueAsInt[stab].
stab.stabType = PSym => {
bitSize: CARD16 ¬ BitsForBytes[stab.size];
IF bitSize>32
THEN vi.varLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: indirect[
base:
NEW[ObjF.VarLocBody ¬ [
bitSize: CirioTypes.bitsPerPtr,
where: frame[bitOffset: BitsForBytes[vi.correctedByteOffset]]]],
offset: CirioTypes.zeroBA]]]
ELSE vi.varLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: frame[bitOffset: BitsForBytes[vi.correctedByteOffset]]]];
};
stab.stabType = LSym => {
bitSize: CARD16 ¬ BitsForBytes[stab.size];
vi.varLoc ¬
NEW[ObjF.VarLocBody ¬ [
bitSize: bitSize,
where: frame[bitOffset: BitsForBytes[StabValueAsInt[stab]]]]];
};
ENDCASE => NULL; -- ignore it
};
ENDLOOP;
IF vi.varLoc =
NIL
THEN
-- nothing filled it in
vi.varLoc ¬ NullVarLoc["not in any associated stab"];
}
ELSE
-- hmm... perhaps the mob forgot to mark it as uplevel (this issue should go away eventually) So, we use exactly the same code as the above uplevel case.
vi.varLoc ¬ NEW[ObjF.VarLocBody¬[bitSize: mobFD.bitSize, where: frameExtension[bitOffset: mobFD.bitOffset]]];
IF vi.varLoc.bitSize#0
AND mobFD#
NIL
AND vi.varLoc.bitSize#mobFD.bitSize
THEN
CCE[cirioError,
IO.PutFR["mob and .o disagree on bit size of \"%q\" (codedSei=%g=%xH)", [rope[vi.name]], [cardinal[vi.codedSei]], [cardinal[vi.codedSei]] ]];
note: gnu symbols seem to include register symbols with bitsize = 0. So, we only check for consistency when bitSize (in the dotO) is non-zero.
};
RETURN[vi.varLoc]};
BitsForBytes:
PROC[bytes:
INT]
RETURNS[
INT] =
{RETURN[Basics.bitsPerByte*bytes]};
StabValueAsInt:
PROC[stab: ObjF.Stab]
RETURNS[
INT] =
TRUSTED
{RETURN[LOOPHOLE[stab.value, INT]]};
FullShowOneAnalyzedCBI:
PROC[cbi: CallableBodyInfo, depth:
CARD, on:
IO.
STREAM] =
BEGIN
Tab: PROC[added: CARD] = {FOR I: CARD IN [0..depth+added) DO IO.PutRope[on, " "] ENDLOOP};
Tab[0]; IO.PutRope[on, "arguments\N"];
FOR vis:
LIST
OF VarInfo ¬ cbi.args, vis.rest
WHILE vis #
NIL
DO
ShowOneVI[vis.first, depth+5, on];
ENDLOOP;
IO.PutRope[on, "\N"];
Tab[0]; IO.PutRope[on, "results\N"];
FOR vis:
LIST
OF VarInfo ¬ cbi.results, vis.rest
WHILE vis #
NIL
DO
ShowOneVI[vis.first, depth+5, on];
ENDLOOP;
IO.PutRope[on, "\N"];
IF cbi.globalLink =
NIL
THEN
{Tab[0]; IO.PutRope[on, "(no global link var)\N"]}
ELSE
{Tab[0]; IO.PutF1[on, "global link var coded sei = %g\N", IO.card[cbi.globalLink.codedSei]]};
IF cbi.staticLink =
NIL
THEN
{Tab[0]; IO.PutRope[on, "(no static link var)\N"]}
ELSE
{Tab[0]; IO.PutF1[on, "static link var coded sei = %g\N", IO.card[cbi.staticLink.codedSei]]};
IF cbi.frameExtension =
NIL
THEN
{Tab[0]; IO.PutRope[on, "(no frame extension var)\N"]}
ELSE
{Tab[0]; IO.PutF1[on, "frame extension var coded sei = %g\N", IO.card[cbi.frameExtension.codedSei]]};
FullShowOneBI[cbi.bi, depth, on, TRUE];
IF cbi.unMatchedStabs #
NIL
THEN
BEGIN
Tab[0]; IO.PutRope[on, "unmatched stabs\N"];
ShowStabList[on, depth+5, cbi.unMatchedStabs];
IO.PutRope[on, "\N"];
END;
IF cbi.topStabs #
NIL
THEN
BEGIN
Tab[0]; IO.PutRope[on, "top-level stabs\N"];
ShowStabList[on, depth+5, cbi.topStabs];
IO.PutRope[on, "\N"];
END;
END;
always show details will be true for the root callable body of a tree
FullShowOneBI:
PROC[bi: BodyInfo, depth:
CARD, on:
IO.
STREAM, alwaysShowDetails:
BOOLEAN] =
BEGIN
Tab: PROC[added: CARD] = {FOR I: CARD IN [0..depth+added) DO IO.PutRope[on, " "] ENDLOOP};
Tab[0]; IO.PutF1[on, "body for coded bti = %g\N", IO.card[bi.codedBti]];
IF bi.invalid
THEN
BEGIN
Tab[0]; IO.PutRope[on, "invalid"];
IF bi.bodyOccurredTwice THEN IO.PutRope[on, " bodyOccurredTwice"];
IO.PutRope[on, "\N"];
END;
Tab[5];
WITH bi.btr.extension
SELECT
FROM
c:
REF Callable
MA.BTRExtension =>
BEGIN
idSer: SER ¬ MA.FetchSER[c.id];
IF idSer #
NIL
THEN
WITH idSer.body
SELECT
FROM
id: REF id MA.BodySE => IO.PutF1[on, "name: %g", IO.rope[id.hash]];
cons: REF cons MA.BodySE => IO.PutRope[on, "(c.id is not an id)"];
ENDCASE => IO.PutRope[on, "(c.id is impossible)"]
ELSE
IO.PutRope[on, "(c.id is NIL)"];
IO.PutF1[on, ", bodyKind: %g, ",
IO.rope[
SELECT c.kind
FROM
Outer => "Outer",
Inner => "Inner",
Catch => "Catch",
Other => "Other",
ENDCASE => "impossible"]];
END;
o: REF Other MA.BTRExtension => NULL;
ENDCASE => ERROR;
IO.PutF1[on, "level: %g", IO.card[bi.btr.level]];
IO.PutRope[on, "\N"];
Tab[5];
SELECT bi.btr.link.which
FROM
sibling => IO.PutF1[on, "sibling: %g", IO.card[MA.GetCodedBTIFromBTH[bi.btr.link.index]]];
parent => IO.PutF1[on, "parent: %g", IO.card[MA.GetCodedBTIFromBTH[bi.btr.link.index]]];
ENDCASE => ERROR;
IO.PutRope[on, "\N"];
IF bi.associatedBps =
NIL
AND (alwaysShowDetails
OR
NOT bi.callable)
THEN
{Tab[5]; IO.PutRope[on, "WARNING: no associated CBlocks\N"]}
ELSE
IF bi.associatedBps #
NIL
AND bi.associatedBps.rest #
NIL
THEN
{Tab[5]; IO.PutRope[on, "WARNING: multiple associated CBlocks\N"]};
IF bi.associatedBps #
NIL
THEN
BEGIN
Tab[5]; IO.PutRope[on, "associated CBlock PC ranges\N"];
FOR knownBPIs:
LIST
OF BPInfo ¬ bi.associatedBps, knownBPIs.rest
WHILE knownBPIs #
NIL
DO
pcRange: ObjF.PCRange ¬ ObjF.GetPCRange[knownBPIs.first.bp];
Tab[7];
IO.PutF[on, "[%g..%g)\N", IO.card[pcRange.first], IO.card[pcRange.limit]];
ENDLOOP;
END;
IF alwaysShowDetails
OR
NOT bi.callable
THEN
BEGIN
Tab[5]; IO.PutRope[on, "BEGIN\N"];
FOR vis:
LIST
OF VarInfo ¬ bi.vars, vis.rest
WHILE vis #
NIL
DO
ShowOneVI[vis.first, depth+5, on];
ENDLOOP;
FOR bis:
LIST
OF BodyInfo ¬ bi.subBodies, bis.rest
WHILE bis #
NIL
DO
IO.PutRope[on, "\N"];
FullShowOneBI[bis.first, depth+5, on, FALSE];
ENDLOOP;
Tab[5]; IO.PutRope[on, "END\N"];
END;
END;
ShowOneVI:
PROC[vi: VarInfo, depth:
CARD, on:
IO.
STREAM] =
BEGIN
Tab: PROC[added: CARD] = {FOR I: CARD IN [0..depth+added) DO IO.PutRope[on, " "] ENDLOOP};
Tab[0]; IO.PutF1[on, "var for codedSei = %g\N", IO.card[vi.codedSei]];
Tab[2]; IO.PutRope[on, "mob reports:\N"];
IF Rope.Length[vi.name] = 0
THEN
{Tab[4]; IO.PutRope[on, "(unnamed)\N"]}
ELSE {Tab[4]; IO.PutF1[on, "name = %g\N", IO.rope[vi.name]]};
IF vi.idBody.extended THEN {Tab[4]; IO.PutRope[on, "extended\N"]};
IF vi.idBody.public THEN {Tab[4]; IO.PutRope[on, "public\N"]};
IF vi.idBody.immutable THEN {Tab[4]; IO.PutRope[on, "immutable\N"]};
IF vi.idBody.constant THEN {Tab[4]; IO.PutRope[on, "constant\N"]};
IF vi.idBody.linkSpace THEN {Tab[4]; IO.PutRope[on, "linkSpace\N"]};
IF vi.idBody.flags.valid
THEN
BEGIN
IF vi.idBody.flags.used THEN {Tab[4]; IO.PutRope[on, "used\N"]};
IF vi.idBody.flags.addressed THEN {Tab[4]; IO.PutRope[on, "addressed\N"]};
IF vi.idBody.flags.assigned THEN {Tab[4]; IO.PutRope[on, "assigned\N"]};
IF vi.idBody.flags.upLevel THEN {Tab[4]; IO.PutRope[on, "upLevel\N"]};
IF vi.idBody.flags.sized THEN {Tab[4]; IO.PutRope[on, "sized\N"]};
IF vi.idBody.flags.spare1 THEN {Tab[4]; IO.PutRope[on, "spare1\N"]};
IF vi.idBody.flags.spare2 THEN {Tab[4]; IO.PutRope[on, "spare2\N"]};
END;
IF vi.idBody.special # normal
THEN
BEGIN
text: Rope.
ROPE ¬
SELECT vi.idBody.special
FROM
globalLink => "globalLink",
staticLink => "staticLink",
frameExtension => "frameExtension",
memoryLink => "memoryLink",
returnLink => "returnLink",
argLink => "argLink",
returnVar => "returnVar",
argVar => "argVar",
globalVar => "globalVar",
extensionVar=> "extensionVar",
invalid => "invalid",
ENDCASE => IO.PutFR1["specialKind = %g", IO.card[ORD[vi.idBody.special]]];
Tab[4]; IO.PutF1[on, "%g\N", IO.rope[text]];
END;
WITH vi.idBody.idInfoAndValue
SELECT
FROM
fd:
REF
MA.FieldDesc =>
{Tab[4]; IO.PutF[on, "(bitSize: %g, bitOffset: %g)\N", IO.card[fd.bitSize], IO.int[fd.bitOffset]]};
td:
REF
MA.TypeDesc =>
{Tab[4]; IO.PutRope[on, "(TypeDesc)\N"]};
bd:
REF
MA.BlockDesc =>
{Tab[4]; IO.PutRope[on, "(BlockDesc)\N"]};
cv:
REF
MA.ConstVal =>
{Tab[4]; IO.PutF1[on, "cv = %g\N", IO.card[cv.value]]};
ENDCASE =>
{Tab[4]; IO.PutRope[on, "(unexpected idInfoAndValue)\N"]};
Tab[2]; IO.PutF1[on, "correctedByteOffset: %g\N", IO.int[vi.correctedByteOffset]];
[] ¬ GetVarLocFromVarInfo[vi];
IF vi.varLoc =
NIL
THEN
{Tab[2]; IO.PutRope[on, "(no varLoc)\N"]}
ELSE
BEGIN
Tab[2]; IO.PutF1[on, "varLoc[bitSize: %g, ", IO.card[vi.varLoc.bitSize]];
WITH vi.varLoc
SELECT
FROM
reg:
REF register
MOF.VarLocBody =>
IO.PutF1[on, "register[regNum: %g]]]\N", IO.card[reg.regNum]];
frm:
REF frame
MOF.VarLocBody =>
IO.PutF1[on, "frame[bitOffset: %g]]]\N", IO.int[frm.bitOffset]];
frmExt:
REF frameExtension
MOF.VarLocBody =>
IO.PutF1[on, "frameExtension[bitOffset: %g]]]\N", IO.int[frmExt.bitOffset]];
seg:
REF fSegment
MOF.VarLocBody =>
BEGIN
kindRope: Rope.ROPE ¬ seg.fSeg.fSegName;
kindRope: Rope.ROPE ← SELECT seg.kind FROM
patch => "patch",
text => "text",
data => "data",
bss => "bss",
common => "common",
ENDCASE => "ILLEGAL";
IO.PutF[on, "segment[kind: %g, bitOffset: %g]]]\N", IO.rope[kindRope], IO.int[seg.bitOffset]];
END;
unk:
REF unknown
MOF.VarLocBody =>
IO.PutRope[on, "unknown[]]]\N"];
ENDCASE =>
IO.PutRope[on, "ILLEGAL]]\N"];
END;
IF vi.associatedStabs #
NIL
THEN
BEGIN
Tab[2];
IO.PutRope[on, "stabs\N"];
ShowStabInfoList[on, depth+4, vi.associatedStabs];
END;
IO.PutRope[on, "\N"];
END;
ShowStabList:
PROC[on:
IO.
STREAM, depth:
CARD, stabs:
LIST
OF ObjF.Stab] =
BEGIN
Tab: PROC[added: CARD] = {FOR I: CARD IN [0..depth+added) DO IO.PutRope[on, " "] ENDLOOP};
FOR ss:
LIST
OF ObjF.Stab ¬ stabs, ss.rest
WHILE ss #
NIL
DO
stab: ObjF.Stab ¬ ss.first;
stabRope: Rope.ROPE ¬ stab.rope;
fieldsRope: Rope.ROPE ¬ RopeForStabFields[stab];
Tab[0]; IO.PutF1[on, "%g\N", IO.rope[fieldsRope]];
Tab[2]; IO.PutF1[on, "%g\N", IO.rope[stabRope]];
ENDLOOP;
END;
ShowStabInfoList:
PROC[on:
IO.
STREAM, depth:
CARD, list:
LIST
OF StabInfo] =
BEGIN
Tab: PROC[added: CARD] = {FOR I: CARD IN [0..depth+added) DO IO.PutRope[on, " "] ENDLOOP};
FOR ss:
LIST
OF StabInfo ¬ list, ss.rest
WHILE ss #
NIL
DO
stabInfo: StabInfo ¬ ss.first;
stabRope: Rope.ROPE ¬ stabInfo.stab.rope;
fieldsRope: Rope.ROPE ¬ RopeForStabFields[stabInfo.stab];
pcRange: ObjF.PCRange ¬ ObjF.GetPCRange[stabInfo.owningBp];
Tab[0]; IO.PutF1[on, "stab: %g\N", IO.rope[fieldsRope]];
Tab[2]; IO.PutF[on, "OwningBPI-PCRange: [%g..%g)\N", IO.card[pcRange.first], IO.card[pcRange.limit]];
Tab[2]; IO.PutF1[on, "%g\N", IO.rope[stabRope]];
ENDLOOP;
END;
RopeForStabFields:
PROC[stab: ObjF.Stab]
RETURNS[Rope.
ROPE] =
BEGIN
fields: Rope.ROPE ¬ NIL;
fields ¬ Rope.Concat[fields, IO.PutFR1["stabX: %g, ", IO.card[stab.stabX]]];
fields ¬ Rope.Concat[fields, IO.PutFR1["stabType: %g, ", IO.rope[RopeForStabType[stab.stabType]]]];
fields ¬ Rope.Concat[fields, IO.PutFR1["size: %g, ", IO.card[stab.size]]];
fields ¬ Rope.Concat[fields, IO.PutFR1["value: %g, ", IO.card[stab.value]]];
RETURN[fields];
RopeForStabType:
PROC[stabType: ObjF.StabType]
RETURNS[Rope.
ROPE] =
BEGIN
RETURN[
SELECT stabType
FROM
LBrac => "LBrac",
RBrac => "RBrac",
SLine => "SLine",
Fun => "Fun",
PSym => "PSym",
LSym => "LSym",
RSym => "RSym",
ENDCASE => ""];
END;
Callable Bodies analysis
jmpi.callableBodies is a hash table that maps from coded bti to CallableBodyInfo
CallableBodyInfo: TYPE = REF CallableBodyInfoBody;
CallableBodyInfoBody:
TYPE =
RECORD[
bth: BTH,
codedBti: CARD,
jmpi: JointMobParsedInfo,
fun: ObjF.FunHandle,
bi: BodyInfo ¬ NIL, -- will be filled in when needed
args: LIST OF VarInfo ¬ NIL, -- filled in when bi is filled in
results: LIST OF VarInfo ¬ NIL, -- filled in when bi is filled in
globalLink: VarInfo ¬ NIL, -- filled in when bi is filled in
staticLink: VarInfo ¬ NIL, -- filled in when bi is filled in
frameExtension: VarInfo ¬ NIL, -- filled in when bi is filled in
unMatchedStabs, topStabs: LIST OF ObjF.Stab ¬ NIL,
invalid: BOOLEAN ¬ FALSE,
multiFuns: BOOLEAN ¬ FALSE,
bodyOccurredTwice: BOOLEAN ¬ FALSE];
AnalyzeCallableBodySet:
PROC[jmpi: JointMobParsedInfo] =
BEGIN
first, we walk the body tree in the mob, creating an entry for each callable body
BEGIN
SeeOneBody:
PROC[callableBody:
BTH] =
BEGIN
key: RefTab.Key ¬ CreateBTKeyFromBTH[callableBody];
codedBti: CARD ¬ NARROW[key, REF CARD];
cbi: CallableBodyInfo ¬ NEW[CallableBodyInfoBody¬[callableBody, codedBti, jmpi, NIL]];
IF
NOT RefTab.Insert[jmpi.callableBodies.table, key, cbi]
THEN
BEGIN
oldCbi: CallableBodyInfo ¬ NARROW[RefTab.Fetch[jmpi.callableBodies.table, key].val];
oldCbi.bodyOccurredTwice ¬ oldCbi.invalid ¬ TRUE;
SystemInterface.ShowReport[IO.PutFR1["callable body with coded bti = %g occured more than once", IO.card[codedBti]], $debug];
END;
END;
MA.GenCallableBodies[jmpi.mob, SeeOneBody];
END;
second, we walk the Funs in the DotO, updating the appropriate entry (if any) in the hash table
BEGIN
SeeOneFun:
PROC[fun: ObjF.FunHandle]
RETURNS[
--stop--
BOOLEAN] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForFun[jmpi, fun];
IF cbi #
NIL
THEN
BEGIN
IF cbi.fun =
NIL
THEN cbi.fun ¬ fun
ELSE
BEGIN
cbi.multiFuns ¬ cbi.invalid ¬ TRUE;
SystemInterface.ShowReport[IO.PutFR1["callable body with coded bti = %g has more than one corresponding fun", IO.card[cbi.codedBti]], $debug];
END;
END;
RETURN[FALSE]
END;
ObjF.GenFuns[jmpi.module, SeeOneFun];
END;
END;
returns NIL if not a callable body
not valid until first part of AnalyzeCallableBodySet has been completed
GetCBIForBth:
PROC[jmpi: JointMobParsedInfo, bth:
BTH]
RETURNS[CallableBodyInfo] =
BEGIN
key: RefTab.Key ¬ CreateBTKeyFromBTH[bth];
RETURN[NARROW[RefTab.Fetch[jmpi.callableBodies.table, key].val]];
END;
returns NIL if no corresponding callable body
not valid until AnalyzeCallableBodySet has been completed
GetCBIForFun:
PROC[jmpi: JointMobParsedInfo, fun: ObjF.FunHandle]
RETURNS[CallableBodyInfo] =
BEGIN
key: RefTab.Key ¬ CreateBTKeyFromFun[fun];
IF key # NIL THEN RETURN[NARROW[RefTab.Fetch[jmpi.callableBodies.table, key].val]]
ELSE RETURN[NIL];
END;
GetBiFromCbi:
PROC[cbi: CallableBodyInfo]
RETURNS[bi: BodyInfo] =
BEGIN
IF cbi.bi = NIL THEN AnalyzeOneCallableBody[cbi];
RETURN[cbi.bi];
END;
ShowOneCallableBody:
PROC[jmpi: JointMobParsedInfo, callableBody:
BTH, on:
IO.
STREAM] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, callableBody];
IF cbi #
NIL
THEN
BEGIN
IO.PutF1[on, "\Nfor codedBti = %g we have:\N", IO.card[cbi.codedBti]];
IF cbi.fun = NIL THEN IO.PutRope[on, "\Tno Fun\N"]
ELSE
BEGIN
info: ObjF.FunInfo ¬ ObjF.GetFunInfo[cbi.fun];
IO.PutF1[on, "\T Fun CName = %g\N", IO.rope[info.cName]];
END;
IF cbi.invalid
THEN
BEGIN
IO.PutRope[on, "\Tinvalid = TRUE"];
IF cbi.multiFuns THEN IO.PutRope[on, "\TmultiFuns = TRUE"];
IF cbi.bodyOccurredTwice THEN IO.PutRope[on, "\TbodyOccuredTwice = TRUE"];
END;
END
ELSE
BEGIN
key: RefTab.Key ¬ CreateBTKeyFromBTH[callableBody];
codedBti: CARD ¬ NARROW[key, REF CARD];
IO.PutF1[on, "\Nfound NO cbi for coded bti = %g\N", IO.card[codedBti]];
END;
END;
ShowCallableBodiesInfo:
PROC[jmpi: JointMobParsedInfo, on:
IO.
STREAM] =
BEGIN
badFunHeaderPrinted: BOOLEAN ¬ FALSE; -- initial value
ShowOneBody:
PROC[callableBody:
BTH] =
{ShowOneCallableBody[jmpi, callableBody, on]};
CheckOneFun:
PROC[fun: ObjF.FunHandle]
RETURNS[
--stop--
BOOLEAN] =
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForFun[jmpi, fun];
IF cbi =
NIL
THEN
BEGIN
info: ObjF.FunInfo ¬ ObjF.GetFunInfo[fun];
IF
NOT badFunHeaderPrinted
THEN
BEGIN
badFunHeaderPrinted ¬ TRUE;
IO.PutRope[on, "Following Funs have no cbi:\N"];
END;
IO.PutF1[on, "\T%g\N", IO.rope[info.cName]];
END;
RETURN[FALSE]
END;
MA.GenCallableBodies[jmpi.mob, ShowOneBody];
ObjF.GenFuns[jmpi.module, CheckOneFun];
IF
NOT badFunHeaderPrinted
THEN
IO.PutRope[on, "All Funs have corresponding cbis. This is unexpected.\N"];
END;
debugging software
PerformJMDITest:
PUBLIC
PROC[what: Rope.
ROPE, jmpi: JointMobParsedInfo, out:
IO.
STREAM] =
BEGIN
ENABLE ShowOff => {IO.Put1[out, IO.rope[msg]]; RESUME};
SELECT
TRUE
FROM
Rope.Equal[what, "CallableBodies"] => ShowAllCallableBodies[jmpi];
ENDCASE => CCE[cirioError];
END;
ShowAllCallableBodies:
PROC[jmpi: JointMobParsedInfo] =
BEGIN
showOne:
PROC[callableBody:
BTH] =
BEGIN
btr: MA.BTR ¬ MA.FetchBTR[callableBody];
ShowOff[IO.PutFR["\Tbti = %g, at source pos %g\N", IO.card[MA.GetCodedBTIFromBTH[callableBody]], IO.int[btr.sourceIndex]]];
END;
ShowOff["\N\Nall Callable Bodies\N"];
MA.GenCallableBodies[jmpi.mob, showOne];
ShowOff["\N"];
END;
tries to generate one PC for each bracket. That is, a pc within the bounds of the bracket pair, but not within the bounds of any included bracket pair. (It is possible that some bracket pairs are completely covered by their interior brackets.)
GenInterestingPCs:
PUBLIC
PROC[module: ObjF.Module, for:
PROC[bp: ObjF.BracketPair, pc:
CARD]] =
BEGIN
lowestFunPC: CARD ¬ LAST[CARD];
SeeOneFunBracket:
PROC[bp: ObjF.BracketPair]
RETURNS[
--stop--
BOOLEAN] =
BEGIN
pcRange: ObjF.PCRange ¬ ObjF.GetPCRange[bp];
IF pcRange.first < lowestFunPC THEN lowestFunPC ¬ pcRange.first;
GenInterestingPCsWithinABracket[bp, for];
RETURN[FALSE];
END;
ObjF.GenFunBracketPairs[module, SeeOneFunBracket];
IF lowestFunPC > 0 THEN for[NIL, lowestFunPC-1];
END;
The bracket param to for is the tightest bracket containing the pc.
GenInterestingPCsWithinABracket:
PROC[bp: ObjF.BracketPair, for:
PROC[bp: ObjF.BracketPair, pc:
CARD]] =
BEGIN
pcRange: ObjF.PCRange ¬ ObjF.GetPCRange[bp];
tentative: CARD ¬ pcRange.first;
SeeOneSubBracket1:
PROC[bp: ObjF.BracketPair]
RETURNS[
--stop--
BOOLEAN] =
BEGIN
subRange: ObjF.PCRange ¬ ObjF.GetPCRange[bp];
IF subRange.first <= tentative THEN {tentative ¬ subRange.limit; RETURN[FALSE]}
ELSE RETURN[TRUE];
END;
SeeOneSubBracket2:
PROC[bp: ObjF.BracketPair]
RETURNS[
--stop--
BOOLEAN] =
{GenInterestingPCsWithinABracket[bp, for]; RETURN[FALSE]};
ObjF.GenSubBracketPairs[bp, SeeOneSubBracket1];
IF tentative < pcRange.limit THEN for[bp, tentative];
ObjF.GenSubBracketPairs[bp, SeeOneSubBracket2];
END;
DescribeBTHInfo: PROC[info: BTHInfo, jmpi: JointMobParsedInfo] =
BEGIN
IF info = NIL THEN
ShowOff["\TNIL\N"]
ELSE
ShowOff[IO.PutFR["\Tself = %g\N", IO.rope[RopeForBTH[info.self, jmpi]]]];
END;
RopeForBTH: PROC[bth: BTH, jmpi: JointMobParsedInfo] RETURNS[Rope.ROPE] =
BEGIN
IF bth = NIL THEN RETURN["NIL"] ELSE
BEGIN
btr: BTR ← MA.FetchBTR[bth];
bthInfo: BTHInfo ← NARROW[RefTab.Fetch[jmpi.rawBodyInfo.table, bth].val];
bracket: ObjF.BracketPair ← IF bthInfo = NIL THEN NIL ELSE bthInfo.bracketPair;
bthInfoRope: Rope.ROPE ← IF bthInfo = NIL THEN "no info" ELSE IF bracket = NIL THEN "[no associated bracket]" ELSE RopeForBracketPair[bracket, jmpi];
RETURN[IO.PutFR["bti = %g, source position = %g, bthInfo = %g", IO.card[MA.GetCodedBTIFromBTH[bth]], IO.card[btr.sourceIndex], IO.rope[bthInfoRope]]]
END;
END;
DescribeBracketPair: PROC[bp: ObjF.BracketPair, jmpi: JointMobParsedInfo] =
BEGIN
kind: ObjF.BracketPairKind ← ObjF.GetBracketPairKind[bp];
SELECT kind FROM
syntheticOuter => ShowOff["\T\Toutermost pair\N\N"];
syntheticFun =>
BEGIN
stab: ObjF.Stab ← ObjF.GetFunStab[bp];
ShowOff["\T\Tfunction body\N"];
ShowOff[IO.PutFR["\T\T text = %g\N\N", IO.rope[stab.rope]]];
END;
actual =>
BEGIN
pcRange: ObjF.PCRange ← ObjF.GetPCRange[bp];
stabRange: ObjF.StabRange ← ObjF.GetStabRange[bp];
ShowOff["\T\Tblock\N"];
ShowOff[IO.PutFR["\T\T pc range = [%g..%g)\N", IO.card[pcRange.first], IO.card[pcRange.limit]]];
ShowOff[IO.PutFR["\T\T stab range = [%g..%g)\N\N", IO.card[stabRange.first], IO.card[stabRange.first+stabRange.count]]];
END;
ENDCASE => CCE[cirioError];
END;
RopeForBracketPair: PROC[bp: ObjF.BracketPair, jmpi: JointMobParsedInfo] RETURNS[Rope.ROPE] =
BEGIN
kind: ObjF.BracketPairKind ← ObjF.GetBracketPairKind[bp];
SELECT kind FROM
syntheticOuter => RETURN["\T\Toutermost pair"];
syntheticFun =>
BEGIN
stab: ObjF.Stab ← ObjF.GetFunStab[bp];
RETURN[IO.PutFR["function body, text = %g", IO.rope[stab.rope]]];
END;
actual =>
BEGIN
pcRange: ObjF.PCRange ← ObjF.GetPCRange[bp];
stabRange: ObjF.StabRange ← ObjF.GetStabRange[bp];
rope: Rope.ROPE;
rope ← Rope.Cat[rope, "\T\Tblock\N"];
rope ← Rope.Cat[rope, IO.PutFR["\T\T pc range = [%g..%g)\N", IO.card[pcRange.first], IO.card[pcRange.limit]]];
rope ← Rope.Cat[rope, IO.PutFR["\T\T stab range = [%g..%g)\N\N", IO.card[stabRange.first], IO.card[stabRange.first+stabRange.count]]];
RETURN[rope];
END;
ENDCASE => CCE[cirioError];
END;
ShowOff: SIGNAL[msg: Rope.ROPE] = CODE;
ShowMob: Commander.CommandProc =
BEGIN
args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
mobPath: PFSNames.PATH ¬ PFS.PathFromRope[args[1]];
wholePath: PFSNames.PATH ¬ PFS.PathFromRope[args[2]];
relativePC: CARD ¬ IF args.argc < 4 THEN 0 ELSE Convert.CardFromRope[args[3]];
type: Rope.ROPE ¬ IF args.argc < 5 THEN "SunADotOut" ELSE args[4];
fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
mobFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, mobPath];
wholeFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, wholePath];
mob: MA.MobCookie ¬ MA.CreateMobCookie[mobFile];
whole: ObjF.Parsed ¬ ObjF.CreateParsed[wholeFile, type];
module: ObjF.Module ¬ ObjF.ModuleFromParsedAndPC[whole, [[0, ""], relativePC]];
jmpi: JointMobParsedInfo ¬ CreateJointMobParsedInfo[mob, whole, module];
IO.PutF[cmd.out, "\NAllContexts\N"];
PerformJMDITest["AllContexts", jmpi, cmd.out];
IO.PutRope[cmd.out, "\NCallableBodies\N"];
PerformJMDITest["CallableBodies", jmpi, cmd.out];
IO.PutF[cmd.out, "\NFunBracketCounts\N"];
PerformJMDITest["FunBracketCounts", jmpi, cmd.out];
IO.PutF[cmd.out, "\NFunBracketHashTable\N"];
PerformJMDITest["FunBracketHashTable", jmpi, cmd.out];
END;
SystemInterface.CloseFileSet[fileSet];
END;
ShowCallableBodies: Commander.CommandProc =
BEGIN
args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
mobPath: PFSNames.PATH ¬ PFS.PathFromRope[args[1]];
wholePath: PFSNames.PATH ¬ PFS.PathFromRope[args[2]];
relativePC: CARD ¬ IF args.argc < 4 THEN 0 ELSE Convert.CardFromRope[args[3]];
type: Rope.ROPE ¬ IF args.argc < 5 THEN "SunADotOut" ELSE args[4];
fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
mobFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, mobPath];
wholeFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, wholePath];
mob: MA.MobCookie ¬ MA.CreateMobCookie[mobFile];
whole: ObjF.Parsed ¬ ObjF.CreateParsed[wholeFile, type];
module: ObjF.Module ¬ ObjF.ModuleFromParsedAndPC[whole, [[0, ""], relativePC]];
jmpi: JointMobParsedInfo ¬ CreateJointMobParsedInfo[mob, whole, module];
ShowCallableBodiesInfo[jmpi, cmd.out];
END;
SystemInterface.CloseFileSet[fileSet];
END;
ShowOneBody: Commander.CommandProc =
BEGIN
args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
mobPath: PFSNames.PATH ¬ PFS.PathFromRope[args[1]];
wholePath: PFSNames.PATH ¬ PFS.PathFromRope[args[2]];
relativePC: CARD ¬ Convert.CardFromRope[args[3]];
codedBti: CARD ¬ Convert.CardFromRope[args[4]];
type: Rope.ROPE ¬ IF args.argc < 6 THEN "SunADotOut" ELSE args[5];
fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
mobFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, mobPath];
wholeFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, wholePath];
mob: MA.MobCookie ¬ MA.CreateMobCookie[mobFile];
whole: ObjF.Parsed ¬ ObjF.CreateParsed[wholeFile, type];
module: ObjF.Module ¬ ObjF.ModuleFromParsedAndPC[whole, [[0, ""], relativePC]];
jmpi: JointMobParsedInfo ¬ CreateJointMobParsedInfo[mob, whole, module];
BEGIN
btKey: RefTab.Key ¬ NEW[CARD ¬ codedBti];
cbi: CallableBodyInfo ¬ NARROW[RefTab.Fetch[jmpi.callableBodies.table, btKey].val];
bi: BodyInfo ¬ GetBiFromCbi[cbi]; -- forces the analysis of cbi??
FullShowOneAnalyzedCBI[cbi, 0, cmd.out];
END;
END;
SystemInterface.CloseFileSet[fileSet];
END;
CheckAllCallableBodies: Commander.CommandProc =
BEGIN
args: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd];
mobPath: PFSNames.PATH ¬ PFS.PathFromRope[args[1]];
wholePath: PFSNames.PATH ¬ PFS.PathFromRope[args[2]];
relativePC: CARD ¬ IF args.argc < 4 THEN 0 ELSE Convert.CardFromRope[args[3]];
type: Rope.ROPE ¬ IF args.argc < 5 THEN "SunADotOut" ELSE args[4];
fileSet: SystemInterface.FileSet ¬ SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
mobFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, mobPath];
wholeFile: SystemInterface.CirioFile ¬ SystemInterface.GetCirioFile[fileSet, wholePath];
mob: MA.MobCookie ¬ MA.CreateMobCookie[mobFile];
whole: ObjF.Parsed ¬ ObjF.CreateParsed[wholeFile, type];
module: ObjF.Module ¬ ObjF.ModuleFromParsedAndPC[whole, [[0, ""], relativePC]];
jmpi: JointMobParsedInfo ¬ CreateJointMobParsedInfo[mob, whole, module];
CheckOneCallableBody:
PROC[callableBody:
BTH] =
BEGIN
ShowOneCallableBody[jmpi, callableBody, cmd.out];
now, check it
BEGIN
cbi: CallableBodyInfo ¬ GetCBIForBth[jmpi, callableBody];
bi: BodyInfo ¬ GetBiFromCbi[cbi]; -- forces the analysis of cbi??
END;
END;
MA.GenCallableBodies[mob, CheckOneCallableBody];
END;
SystemInterface.CloseFileSet[fileSet];
END;