DIRECTORY Basics USING[BITXOR, LongNumber], CCTypes USING[CCError, CCErrorCase], CirioTypes USING[bitsPerPtr, zeroBA], Commander USING[CommandProc, Register], CommandTool USING[ArgumentVector, Parse], Convert USING[CardFromRope], IO USING[card, int, Put, PutF, PutFR, rope, STREAM], 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], PBasics USING[bitsPerByte], 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]; MobObjectFilesImpl: CEDAR PROGRAM IMPORTS Basics, CCTypes, Commander, CommandTool, Convert, IO, MobAccess, ObjectFiles, PFS, RefTab, Rope, SystemInterface EXPORTS MobObjectFiles = BEGIN OPEN ObjF:ObjectFiles, MA:MobAccess, MOF:MobObjectFiles, MobObjectAccessPrivate; BTH: TYPE = MA.BTH; BTR: TYPE = MA.BTR; CTXH: TYPE = MA.CTXH; CTXR: TYPE = MA.CTXR; SEH: TYPE = MA.SEH; SER: TYPE = MA.SER; CCE: ERROR[case: CCTypes.CCErrorCase, msg: Rope.ROPE _ NIL] _ CCTypes.CCError; JointMobParsedInfo: TYPE = REF JointMobParsedInfoBody; JointMobParsedInfoBody: PUBLIC TYPE = MobObjectAccessPrivate.JointMobParsedInfoBody; CreateJointMobParsedInfo: PUBLIC PROC[mob: MA.MobCookie, whole: ObjF.Parsed, module: ObjF.Module] RETURNS[JointMobParsedInfo] = BEGIN jmpi: JointMobParsedInfo _ NEW[JointMobParsedInfoBody_[ mob, whole, module, CreateBTHashTable[], CreateBTHashTable[], CreateVarHashTable[], CreateBpHashTable[] ]]; AnalyzeCallableBodySet[jmpi]; RETURN[jmpi]; END; GetSPOffset: PUBLIC PROC[callableBTH: BTH, jmpi: JointMobParsedInfo] RETURNS[INT] = { entryRelativePC: CARD _ GetEntryPCofCallableBTH[callableBTH, jmpi]; spOffset: INT _ ObjF.GetSPOffset[jmpi.module, [[0, ""], entryRelativePC]]; RETURN[spOffset]; }; 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]; 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]; END; 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]; 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; 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]]]]}; 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; 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.PutFR["seh with coded sei = %g occurred more than once", IO.card[codedSei]], $debug]; END; SELECT idBody.special FROM globalLink => cbi.globalLink _ vi; staticLink => cbi.staticLink _ vi; frameExtension => cbi.frameExtension _ vi; ENDCASE => NULL; RETURN[vi]}; 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]; }; }; IF cbi.bi # NIL THEN RETURN; 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 => { cbi.args _ NIL; cbi.results _ NIL}; ENDCASE => CCE[cirioError]; ENDCASE => CCE[cirioError]}; ENDCASE => CCE[cirioError]; END; { 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 { 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.PutFR["body with coded bti = %g occured more than once", IO.card[codedBti]], $debug]; }; bi.vars _ VisitAllVarSehsInAContext[bi, btr.localCtx]; { 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]; }; { 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] = { 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.PutFR["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]; IF stab.stabType = PSym THEN vi.correctedByteOffset _ cumByteOffset; } ELSE cbi.unMatchedStabs _ CONS[stab, cbi.unMatchedStabs]; IF top THEN cbi.topStabs _ CONS[stab, cbi.topStabs]; IF stab.stabType = PSym THEN cumByteOffset _ cumByteOffset + 4; }; 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]; }; }; UnderTypeSeh: PROC[seh: SEH] RETURNS[SEH] = BEGIN ser: MA.SER _ MA.FetchSER[seh]; WITH ser.body SELECT FROM id: REF id MA.BodySE => BEGIN 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; 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 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]]]; }; 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]] ]]; }; RETURN[vi.varLoc]}; BitsForBytes: PROC[bytes: INT] RETURNS[INT] = {RETURN[PBasics.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.PutF[on, " "] ENDLOOP}; Tab[0]; IO.PutF[on, "arguments\N"]; FOR vis: LIST OF VarInfo _ cbi.args, vis.rest WHILE vis # NIL DO ShowOneVI[vis.first, depth+5, on]; ENDLOOP; IO.PutF[on, "\N"]; Tab[0]; IO.PutF[on, "results\N"]; FOR vis: LIST OF VarInfo _ cbi.results, vis.rest WHILE vis # NIL DO ShowOneVI[vis.first, depth+5, on]; ENDLOOP; IO.PutF[on, "\N"]; IF cbi.globalLink = NIL THEN {Tab[0]; IO.PutF[on, "(no global link var)\N"]} ELSE {Tab[0]; IO.PutF[on, "global link var coded sei = %g\N", IO.card[cbi.globalLink.codedSei]]}; IF cbi.staticLink = NIL THEN {Tab[0]; IO.PutF[on, "(no static link var)\N"]} ELSE {Tab[0]; IO.PutF[on, "static link var coded sei = %g\N", IO.card[cbi.staticLink.codedSei]]}; IF cbi.frameExtension = NIL THEN {Tab[0]; IO.PutF[on, "(no frame extension var)\N"]} ELSE {Tab[0]; IO.PutF[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.PutF[on, "unmatched stabs\N"]; ShowStabList[on, depth+5, cbi.unMatchedStabs]; IO.PutF[on, "\N"]; END; IF cbi.topStabs # NIL THEN BEGIN Tab[0]; IO.PutF[on, "top-level stabs\N"]; ShowStabList[on, depth+5, cbi.topStabs]; IO.PutF[on, "\N"]; END; END; 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.PutF[on, " "] ENDLOOP}; Tab[0]; IO.PutF[on, "body for coded bti = %g\N", IO.card[bi.codedBti]]; IF bi.invalid THEN BEGIN Tab[0]; IO.PutF[on, "invalid"]; IF bi.bodyOccurredTwice THEN IO.PutF[on, " bodyOccurredTwice"]; IO.PutF[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.PutF[on, "name: %g", IO.rope[id.hash]]; cons: REF cons MA.BodySE => IO.PutF[on, "(c.id is not an id)"]; ENDCASE => IO.PutF[on, "(c.id is impossible)"] ELSE IO.PutF[on, "(c.id is NIL)"]; IO.PutF[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.PutF[on, "level: %g", IO.card[bi.btr.level]]; IO.PutF[on, "\N"]; Tab[5]; SELECT bi.btr.link.which FROM sibling => IO.PutF[on, "sibling: %g", IO.card[MA.GetCodedBTIFromBTH[bi.btr.link.index]]]; parent => IO.PutF[on, "parent: %g", IO.card[MA.GetCodedBTIFromBTH[bi.btr.link.index]]]; ENDCASE => ERROR; IO.PutF[on, "\N"]; IF bi.associatedBps = NIL AND (alwaysShowDetails OR NOT bi.callable) THEN {Tab[5]; IO.PutF[on, "WARNING: no associated CBlocks\N"]} ELSE IF bi.associatedBps # NIL AND bi.associatedBps.rest # NIL THEN {Tab[5]; IO.PutF[on, "WARNING: multiple associated CBlocks\N"]}; IF bi.associatedBps # NIL THEN BEGIN Tab[5]; IO.PutF[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.PutF[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.PutF[on, "\N"]; FullShowOneBI[bis.first, depth+5, on, FALSE]; ENDLOOP; Tab[5]; IO.PutF[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.PutF[on, " "] ENDLOOP}; Tab[0]; IO.PutF[on, "var for codedSei = %g\N", IO.card[vi.codedSei]]; Tab[2]; IO.PutF[on, "mob reports:\N"]; IF Rope.Length[vi.name] = 0 THEN {Tab[4]; IO.PutF[on, "(unnamed)\N"]} ELSE {Tab[4]; IO.PutF[on, "name = %g\N", IO.rope[vi.name]]}; IF vi.idBody.extended THEN {Tab[4]; IO.PutF[on, "extended\N"]}; IF vi.idBody.public THEN {Tab[4]; IO.PutF[on, "public\N"]}; IF vi.idBody.immutable THEN {Tab[4]; IO.PutF[on, "immutable\N"]}; IF vi.idBody.constant THEN {Tab[4]; IO.PutF[on, "constant\N"]}; IF vi.idBody.linkSpace THEN {Tab[4]; IO.PutF[on, "linkSpace\N"]}; IF vi.idBody.flags.valid THEN BEGIN IF vi.idBody.flags.used THEN {Tab[4]; IO.PutF[on, "used\N"]}; IF vi.idBody.flags.addressed THEN {Tab[4]; IO.PutF[on, "addressed\N"]}; IF vi.idBody.flags.assigned THEN {Tab[4]; IO.PutF[on, "assigned\N"]}; IF vi.idBody.flags.upLevel THEN {Tab[4]; IO.PutF[on, "upLevel\N"]}; IF vi.idBody.flags.sized THEN {Tab[4]; IO.PutF[on, "sized\N"]}; IF vi.idBody.flags.spare1 THEN {Tab[4]; IO.PutF[on, "spare1\N"]}; IF vi.idBody.flags.spare2 THEN {Tab[4]; IO.PutF[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.PutFR["specialKind = %g", IO.card[ORD[vi.idBody.special]]]; Tab[4]; IO.PutF[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.PutF[on, "(TypeDesc)\N"]}; bd: REF MA.BlockDesc => {Tab[4]; IO.PutF[on, "(BlockDesc)\N"]}; cv: REF MA.ConstVal => {Tab[4]; IO.PutF[on, "cv = %g\N", IO.card[cv.value]]}; ENDCASE => {Tab[4]; IO.PutF[on, "(unexpected idInfoAndValue)\N"]}; Tab[2]; IO.PutF[on, "correctedByteOffset: %g\N", IO.int[vi.correctedByteOffset]]; [] _ GetVarLocFromVarInfo[vi]; IF vi.varLoc = NIL THEN {Tab[2]; IO.PutF[on, "(no varLoc)\N"]} ELSE BEGIN Tab[2]; IO.PutF[on, "varLoc[bitSize: %g, ", IO.card[vi.varLoc.bitSize]]; WITH vi.varLoc SELECT FROM reg: REF register MOF.VarLocBody => IO.PutF[on, "register[regNum: %g]]]\N", IO.card[reg.regNum]]; frm: REF frame MOF.VarLocBody => IO.PutF[on, "frame[bitOffset: %g]]]\N", IO.int[frm.bitOffset]]; frmExt: REF frameExtension MOF.VarLocBody => IO.PutF[on, "frameExtension[bitOffset: %g]]]\N", IO.int[frmExt.bitOffset]]; seg: REF fSegment MOF.VarLocBody => BEGIN kindRope: Rope.ROPE _ seg.fSeg.fSegName; IO.PutF[on, "segment[kind: %g, bitOffset: %g]]]\N", IO.rope[kindRope], IO.int[seg.bitOffset]]; END; unk: REF unknown MOF.VarLocBody => IO.PutF[on, "unknown[]]]\N"]; ENDCASE => IO.PutF[on, "ILLEGAL]]\N"]; END; IF vi.associatedStabs # NIL THEN BEGIN Tab[2]; IO.PutF[on, "stabs\N"]; ShowStabInfoList[on, depth+4, vi.associatedStabs]; END; IO.PutF[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.PutF[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.PutF[on, "%g\N", IO.rope[fieldsRope]]; Tab[2]; IO.PutF[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.PutF[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.PutF[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.PutF[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.PutFR["stabX: %g, ", IO.card[stab.stabX]]]; fields _ Rope.Concat[fields, IO.PutFR["stabType: %g, ", IO.rope[RopeForStabType[stab.stabType]]]]; fields _ Rope.Concat[fields, IO.PutFR["size: %g, ", IO.card[stab.size]]]; fields _ Rope.Concat[fields, IO.PutFR["value: %g, ", IO.card[stab.value]]]; RETURN[fields]; END; 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; 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 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.PutFR["callable body with coded bti = %g occured more than once", IO.card[codedBti]], $debug]; END; END; MA.GenCallableBodies[jmpi.mob, SeeOneBody]; END; 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.PutFR["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; GetCBIForBth: PROC[jmpi: JointMobParsedInfo, bth: BTH] RETURNS[CallableBodyInfo] = BEGIN key: RefTab.Key _ CreateBTKeyFromBTH[bth]; RETURN[NARROW[RefTab.Fetch[jmpi.callableBodies.table, key].val]]; END; 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.PutF[on, "\Nfor codedBti = %g we have:\N", IO.card[cbi.codedBti]]; IF cbi.fun = NIL THEN IO.PutF[on, "\Tno Fun\N"] ELSE BEGIN info: ObjF.FunInfo _ ObjF.GetFunInfo[cbi.fun]; IO.PutF[on, "\T Fun CName = %g\N", IO.rope[info.cName]]; END; IF cbi.invalid THEN BEGIN IO.PutF[on, "\Tinvalid = TRUE"]; IF cbi.multiFuns THEN IO.PutF[on, "\TmultiFuns = TRUE"]; IF cbi.bodyOccurredTwice THEN IO.PutF[on, "\TbodyOccuredTwice = TRUE"]; END; END ELSE BEGIN key: RefTab.Key _ CreateBTKeyFromBTH[callableBody]; codedBti: CARD _ NARROW[key, REF CARD]^; IO.PutF[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.PutF[on, "Following Funs have no cbi:\N"]; END; IO.PutF[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.PutF[on, "All Funs have corresponding cbis. This is unexpected.\N"]; END; CreateBTHashTable: PROC RETURNS[BTHashTable] = {RETURN[NEW[BTHashTableBody _ [RefTab.Create[equal: BTKeyEqualProc, hash: BTKeyHashProc]]]]}; CreateBTKeyFromCodedBTI: PROC[codedBti: CARD] RETURNS[RefTab.Key] = BEGIN RETURN[NEW[CARD _ codedBti]]; END; CreateBTKeyFromFun: PROC[fun: ObjF.FunHandle]RETURNS[RefTab.Key] = BEGIN info: ObjF.FunInfo _ ObjF.GetFunInfo[fun]; funStab: ObjF.Stab _ info.stab; nameAndNumber: ObjF.NameAndNumber _ ObjF.ParseNameRope[funStab]; IF nameAndNumber.valid AND nameAndNumber.char # 'L AND nameAndNumber.number >= 0 THEN BEGIN codedBti: CARD _ nameAndNumber.number; key: RefTab.Key _ NEW[CARD _ codedBti]; RETURN[key]; END ELSE RETURN[NIL] END; CreateBTKeyFromBTH: PROC[bth: BTH] RETURNS[RefTab.Key] = BEGIN codedBti: CARD _ MA.GetCodedBTIFromBTH[bth]; RETURN[NEW[CARD _ codedBti]]; END; BTKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN codedBti1Ref: REF CARD _ NARROW[key1]; codedBti2Ref: REF CARD _ NARROW[key2]; RETURN[codedBti1Ref^ = codedBti2Ref^]; END; BTKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN codedBtiRef: REF CARD _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[codedBtiRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; CreateVarHashTable: PROC RETURNS[VarHashTable] = {RETURN[NEW[VarHashTableBody _ [RefTab.Create[equal: VarKeyEqualProc, hash: VarKeyHashProc]]]]}; CreateVarKeyFromCodedSEI: PROC[codedSei: CARD] RETURNS[RefTab.Key] = BEGIN RETURN[NEW[CARD _ codedSei]]; END; CreateVarKeyFromVarStab: PROC[stab: ObjF.Stab]RETURNS[RefTab.Key] = BEGIN nameAndNumber: ObjF.NameAndNumber _ ObjF.ParseNameRope[stab]; IF nameAndNumber.valid AND (nameAndNumber.char = 'v OR nameAndNumber.char = 'c) AND nameAndNumber.number > 0 THEN BEGIN codedSei: CARD _ nameAndNumber.number; key: RefTab.Key _ NEW[CARD _ codedSei]; RETURN[key]; END ELSE RETURN[NIL] END; CreateVarKeyFromSEH: PROC[seh: SEH] RETURNS[RefTab.Key] = BEGIN codedSei: CARD _ MA.GetCodedSeiFromSEH[seh]; RETURN[NEW[CARD _ codedSei]]; END; VarKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN codedSei1Ref: REF CARD _ NARROW[key1]; codedSei2Ref: REF CARD _ NARROW[key2]; RETURN[codedSei1Ref^ = codedSei2Ref^]; END; VarKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN codedSeiRef: REF CARD _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[codedSeiRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; CreateBpHashTable: PROC RETURNS[BPHashTable] = {RETURN[NEW[BPHashTableBody _ [RefTab.Create[]]]]}; PerformJMDITest: PUBLIC PROC[what: Rope.ROPE, jmpi: JointMobParsedInfo, out: IO.STREAM] = BEGIN ENABLE ShowOff => {IO.Put[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[IO.PutFR["\N\Nall Callable Bodies\N"]]; MA.GenCallableBodies[jmpi.mob, showOne]; ShowOff[IO.PutFR["\N"]]; END; 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; 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; ShowOff: SIGNAL[msg: Rope.ROPE] = CODE; ShowMob: Commander.CommandProc = BEGIN args: CommandTool.ArgumentVector _ CommandTool.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, "\NCallableBodies\N"]; PerformJMDITest["CallableBodies", jmpi, cmd.out]; END; SystemInterface.CloseFileSet[fileSet]; END; ShowCallableBodies: Commander.CommandProc = BEGIN args: CommandTool.ArgumentVector _ CommandTool.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: CommandTool.ArgumentVector _ CommandTool.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: CommandTool.ArgumentVector _ CommandTool.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]; 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; Commander.Register["ShowMob", ShowMob, "usage:\N\TShowMob fullPathMobName fullPathDotOName relPC [format]\N\Twhere\N\T\TfullPathMobName is the mob\N\T\TfullPathDotOName is name of the containing whole\N\T\TrelPC is a containingDotO-relative PC within the desired embeddedd DotO\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["ShowCallableBodies", ShowCallableBodies, "usage:\N\TShowCallableBodies fullPathMobName fullPathDotOName relPC [format]\N\Twhere\N\T\TfullPathMobName is the mob\N\T\TfullPathDotOName is name of the containing whole\N\T\TrelPC is a containingDotO-relative PC within the desired embeddedd DotO\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["ShowOneCallableBody", ShowOneBody, "usage:\N\TShowOneCallableBody fullPathMobName fullPathDotOName relPC codedBti [format]\N\Twhere\N\T\TfullPathMobName is the mob\N\T\TfullPathDotOName is name of the containing whole\N\T\TrelPC is a containingDotO-relative PC within the desired embeddedd DotO\N\T\TcodedBti is the codedBti of a callable block\N\T\Tformat is XCOFF or SunADotOut"]; Commander.Register["CheckAllCallableBodies", CheckAllCallableBodies, "usage:\TCheckAllCallableBodies fullPathMobName fullPathDotOName relPC [format]\N\Twhere\N\T\TfullPathMobName is the mob\N\T\TfullPathDotOName is name of the containing whole\N\T\TrelPC is a containingDotO-relative PC within the desired embeddedd DotO\N\T\Tformat is XCOFF or SunADotOut"]; END.. ,φ 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, May 27, 1992 8:48 am 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 This module provides information that requires joint inspection of mob and dotO files. 1) Given a pc, delivers the bth of the block most tightly enclosing the given pc. (Actually, the most tightly enclosing recognized block.) In addition, ensures that an association between bracket pairs and bths is constructed for the result bth and for all enclosing bths. (In so far as the association can be constructed from the dotO and mob.) 2) Given a bth and the seh for a variable occurring in the context of the bth, returns the field offset information for that variable. (This works only for blocks for which the bracket-pair-bth association has been constructed.) [Not yet installed] CreateFBHashTable[], CreateRawBodyHashTable[], CreateSEHInfoHashTable[]] AnalyzeDotOBrackets[jmpi]; Stack Pointer Offset New Code starts here and continues upto debugging software February 28, 1990 9:04:08 am PST 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. (maybe I should do FindTightestRecognizedBP[nest.rest.rest??) Public procs for special variables ENABLE scopes are translated into C procedures of one argument, whose codedSei is negative (ie, not from Mimosa), so there's no corresponding SEH. 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. 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 containingBody is either BodyInfo or CallableBodyInfo Create a VarInfo for the codedSei. show them to be embedded in containingBody (other cases probably should be added) (should I test for multiple instances?) containingBody is either BodyInfo or CallableBodyInfo Create VarInfos for each. show them to be embedded in containingBody (0) we exit if the analysis has already been done (1) we begin by creating VarInfos for the args and results 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. (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. we record this new block now we visit the variables of the block next, we visit the sub bodies, if any. (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?) 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 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. for correcting param byte offsets due to errors in C compiler For correcting param byte offsets due to errors in C compiler. We assume that each fun param occupies 4 bytes or 1 word. this is adapted from RMTWAtomics.UnderTypeSEH. I hope this version works here. we simply spin deeper into the Mob type structure 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. (We assume that the stabs are ordered as they appear in the dotO, hence the PSym will occur before any modifying RSym.) Note: when we get a corrected C compiler, then this case can again be combined with ObjF.LSym, replacing vi.correctedByteOffset with StabValueAsInt[stab]. 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. always show details will be true for the root callable body of a tree kindRope: Rope.ROPE _ SELECT seg.kind FROM patch => "patch", text => "text", data => "data", bss => "bss", common => "common", ENDCASE => "ILLEGAL"; Callable Bodies analysis jmpi.callableBodies is a hash table that maps from coded bti to CallableBodyInfo first, we walk the body tree in the mob, creating an entry for each callable body second, we walk the Funs in the DotO, updating the appropriate entry (if any) in the hash table returns NIL if not a callable body not valid until first part of AnalyzeCallableBodySet has been completed returns NIL if no corresponding callable body not valid until AnalyzeCallableBodySet has been completed body table hash table bodies will be indexed by their coded body table index returns NIL if fun name improperly formed var hash table vars will be indexed by their coded sei returns NIl if no apparent codedSei December 10, 1989, MJS thinks, after experimenting and reading C2CNamingDoc.tioga of December 11, 1989, that char = 'v means means variables declared in the mesa source, and char = 'c or 'w means generated names for links, extensions, and so on. The number will either be a valid ISei or negative. BPI hash table BracketPairs will be indexed by their REF. Thus, we assume that DotOAccess provides unique REFs. (This is sufficient, because we shall never wish to look up BPInfo by some more specific key.) debugging software 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.) The bracket param to for is the tightest bracket containing the pc. 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; IO.PutF[cmd.out, "\NAllContexts\N"]; PerformJMDITest["AllContexts", 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]; now, check it main code ShowMob [Menhir-ux]sturgis>cirio>SymbolFindingImpl.mob [Menhir-ux]sturgis>cirio>sun4>SymbolFindingImpl.c2c.o 0 ShowCallableBodies StackCirioImpl.mob sun4>StackCirioImpl.c2c.o 0 ShowOneCallableBody StackCirioImpl.mob sun4>StackCirioImpl.c2c.o 0 xxx CheckAllCallableBodies StackCirioImpl.mob sun4>StackCirioImpl.c2c.o 0 Κ>-•NewlineDelimiter ™codešœ™K™HKšœ#™#K™?K™#K™'K™,K™#K™+—K˜šΟk ˜ Kšœœœ˜!Kšœœ˜$Kšœ œ˜%Kšœ œ˜'Kšœ œ˜)Kšœœ˜Kšœœ$œ˜4Kšœ œœœ+œœ«œœ˜―Kšœ˜Kšœœ˜)Kšœ œ˜‘Kšœœ˜Kšœœ˜Kšœ œœ˜Kšœœ"˜.Kšœœœ˜(KšœœL˜a—˜K™—šΟnœœ˜!Kšœ3œœ˜xKšœ˜—š œœœžœœ œ(˜XK™VK™K™άK™K™ϊK™—K™Kšœœœœ˜Kšœœœœ˜K˜Kšœœœœ˜Kšœœœœ˜K˜Kšœœœœ˜Kšœœœœ˜K˜Kšœœ&œœ˜NK˜Kšœœœ˜6šœœœ1˜TK˜—K˜š žœœœœ5œ˜Kš˜šœœ˜7K˜Kšœ˜K˜K˜K˜K˜KšœΟtœ˜Kšœ™Kšœ™Kšœ™Kšœ˜K˜—Kšœ™Kšœ˜Kšœ˜ Kšœ˜K˜—K˜™K˜š ž œœœœœœ˜UKšœœ.˜CKšœ œ=˜JKšœ ˜Kšœ˜K˜——K™K™[K˜™)˜Jšœz™z—šž œœœœœœœ ˜ZKš˜Kšœœœœ˜6šœ˜Kš˜Kšœ.˜.Kšœœ,˜@K˜šœœœΟc5˜FKš˜Kšœ œœœ.˜DKšœ<˜˜>Kšœ=™=K™—K™Kšœœœœœœ)œœœœ œœ˜‘K˜Kš œœœœœ˜/Kšœ?˜EK˜Kšœ˜—K˜šžœœœœœœœœ˜fKš˜Kšœœœ˜'Kšœ0˜6Kšœ˜—K˜š ž œœœœœ˜AKšœœœ˜"—K˜š žœœœœœœ˜`Kš˜Kšœ8˜8Kš œœœœœœ ˜9Kš œœœœœ œ˜TK˜Kšœœœ ˜4K˜Kšœ˜Kšœ˜—K˜šžœœœœœœœ˜hKš˜Kšœ œœ˜'Kš œœœœœ˜&K˜š˜Kšœœœ˜*KšœOœœœ˜gKšœœœ#˜1Kšœ˜—Kšœ˜——K˜K™"™š žœœœœœœ˜YKš˜Kšœ0˜0Kš œœœœœ˜Kšœ˜Kš œœœœœ˜-Kšœ˜šœ˜K˜——š žœœœœœœ˜PKš˜Kšœ0˜0Kš œœœœœ˜Kšœ˜Kš œœœœœ˜)Kšœ˜Kšœ˜—K™š žœœœœœœ˜PKš˜Kšœ0˜0Kš œœœœœ˜Kšœ˜Kš œœœœœ˜)Kšœ˜Kšœ˜—K˜š žœœœœœœ ˜aKšœ0˜0Kš œœœœœ˜Kšœ˜šœœœœœœœœœ)˜”K™’—Kšœœ˜ —K˜š ž#œœœœœœ ˜lKšœ0˜0Kš œœœœœ˜Kšœ˜š(œœœœœœœœœœœœ"œœœ:œœ œœœ˜ΖK™ΐ—Kšœœ˜—š žœœœœœ˜OKšœœ)˜2—K˜š ž œœ œœœ ˜9Kšœœœ(˜3K˜—K˜—™K™K™@K™=K™KK™K™7K™Kšœ±™±K™Kšœ`™`K™™9Kšœb™bK™2K™0K™ Kšœ6™6K™[Kšœc™c—K™Kšœ œœ˜"šœœœ˜Kšœœ˜ Kšœ œ˜Kšœœ˜ Kšœ œ˜Kšœ˜Kšœœœ ₯˜ΆKšœ$ 2˜VKšœœœ  G˜fKšœœœ ˜Kšœ œœ ˜Kšœ œœ˜Kšœœœ˜$—K˜Kšœ œœ ˜ šœ œœ˜Kšœœ˜ Kšœ œ˜Kšœœœ˜Kšœ œ˜Kšœœœ l˜…Kšœœœ ˜"Kšœœ ³˜ΝKšœœ˜Kšœ œœ˜Kšœœœ˜"—K˜Kšœ œœ.˜EK˜Kšœœœ ˜šœ œœ˜Kšœ˜Kšœ˜Kšœœ N˜uKšœ˜—K™K™šžœœ˜7Kšœ$˜$˜Kšœ5™5K™"Kšœ*™*—šžœœœœœœ œœ œ ˜pKšœ œœ˜,Kš œœœœœ ˜&šœœ˜Kšœ ˜ K˜K˜K˜Kšœ˜Kšœœ˜Kšœ˜Kšœœ˜—šœœ,˜6Kš˜Kšœœ,˜CKšœ(œ˜-Kšœœ:œ˜sKšœ˜K™K™&K™'—šœ˜Kšœ"˜"Kšœ"˜"Kšœ*˜*Kšœœ˜—Kšœ˜ —˜Kšœ5™5K™Kšœ*™*—šžœœœœœœœœ ˜aKšœœœ˜ Kš œœœœœœœ ˜3Kšœ œœ œ˜Kšœ œœ œ˜"K˜šœœ˜Kšœœœ˜šœ œ˜šœœœ ˜Kš˜Kšœ?˜?K˜Kšœœœ œ˜#Kšœ œœœ˜EKšœ˜K˜K˜Kš˜—Kšœœ˜—Kšœ˜—Kšœ ˜—K˜šžœœœœœœœœ ˜dKš œœœœœ˜šœ˜Kšœ˜Kšœ œ˜"Kšœ œœ˜&šœœ˜šœœœ ˜šœœ˜šœœœ˜#Kšœ9˜?—Kšœœ ˜——Kšœœ ˜—Kšœ˜—Kšœ˜—K˜™1Kšœ œœœ˜—K˜™:Kš˜Kšœœœ˜ šœœ˜šœœ œ˜&Kšœ œœ˜)šœœ˜šœœœ ˜šœœ˜šœ œ œ˜-Kšœ@˜@KšœF˜F—šœœœ˜'K™·Kšœ œ˜Kšœœ˜—Kšœœ˜——Kšœœ˜——Kšœœ ˜—Kšœ˜—K˜šœL™Lšœ˜K™W—š ž œœœœœ˜[Kšœ.˜.Kš œ œœ œœ˜,Kšœœœœ˜šœœ˜šœœ˜Kšœ œ œœ˜/Kšœœœœ˜*Kšœœ˜——šœœ˜!Kšœ ˜ K˜ Kšœ˜Kšœ˜K˜ Kšœ˜Kšœ˜Kšœœ˜Kšœœ˜ Kšœ œ˜K˜—š œœœ œ ˜>Kšœ˜K˜K™šœœ/˜9Kšœ˜Kšœœ/˜GKšœ*œ˜/Kšœœ:œ˜sKšœ˜—K˜™'Kšœ6˜6—K˜™&Kšœ˜Kšœœ˜Kšœ œœ œ˜$K˜šœ œ˜Kšœœœ˜"Kšœ)œ˜0Kšœ œœ œ˜&Kšœœœœ˜RKšœ˜K˜Kš œ œœœœ˜GKšœ˜—Kšœ˜—Kšœ˜—K™Kšœ˜ Kšœ˜—Kšœœ œ˜*Kšœ˜—K™K™šœο™οKšœ˜˜Kšœƒ™ƒKšœR™R™K™LK™P——Kšœœ˜Kšœœœ˜K˜š žœœœ œ˜KKšœœ˜Kšœœ˜—K˜šžœœœ˜=šœ τ™†KšœŒ™Œ—šžœœœœ˜7šœœ˜šœ˜Kšœœ3˜HKšœœœ  ˜2K˜šœœœ˜Kšœœœ˜'Kšœœ5œœ ˜PKšœ˜—K˜šœœ˜"Kšœ,˜,Kšœœvœœ˜ΜKšœ%œ˜*Kšœ˜—K˜š œ œœ+œ œ˜YKšœœœœ˜BKšœ˜—K˜šœœœ˜!šœœ˜KšœœQœ˜—Kšœœ˜0Kšœ˜—Kšœ˜K˜—Kšœœ ±˜ΠKšœœ˜—Kšœ˜—K˜š ž œœœ œœ˜@šœœœœ˜NKšœ3˜3Kšœ œœ œœœœ œœ˜GKš œœ œœœœœ,˜^šœœœ˜2Kšœ @˜BKšœœ˜Kšœ%˜%Kšœ˜—šœœœœœœœœœœœ˜hKšœœœ)œ˜;š œœœœ œ˜$Kšœœœ˜šœœœ˜&šœœœ œœœœœ'œœœœ˜ΏKšœ*˜*Kšœœ-˜8—Kšœœ˜—K˜—K˜—šœœœ˜Kšœœ!˜:Kšœœœœ˜%šœ ˜&˜(™(K™8K™(—K™%——šœœ(˜DKš =™=—Kšœ˜—Kšœœœ˜:Kšœœœ˜4šœœ#˜?Kš =œ™>K™9—Kšœ˜—Kšœœ˜—Kšœ%˜%Kšœ0˜0Kšœ˜—K˜Kšœ˜Kšœ6˜6K˜Kšœ"œ˜(Kšœ˜—K˜K™Kšœ˜—˜KšœO™O—š ž œœœœœ˜+Kš˜Kšœœœœ˜šœ œ˜šœœœ ˜Kš˜K™1šœœ˜"šœœœ ˜Kšœ˜!—Kšœœ˜—Kšœ˜—Kšœœœ œ˜(Kšœœ˜—Kšœ˜—˜Kšœ±™±K™[K™K™7K™Kšœή™ή—šžœœœœ ˜?šœ œœ ˜4Jšœœœ œ  ˜+K˜šœœ˜)Kšœœœ˜#Kšœœ˜—K˜šœ œœ *˜>Kšœ%˜%—š œœœœœ !˜aKšœ œ]˜l—š œœœœœ ˜Gš œœœ+œ œ˜QKšœ#˜#šœ œœ +˜DK™wšœœ œ˜6Kšœ&˜&Kšœ˜—šœœ˜Kšœœ ˜,šœœ ˜@Kšœ œ˜*Kšœ˜Kšœ ˜šœ œ˜(Kšœ˜šœ˜šœœ˜Kšœ˜Kšœ&˜&—Kšœ˜——šœ œ˜(Kšœ˜Kšœ&˜&—Kšœ˜Kšœ˜—Kšœœ  *˜E—K˜—šœœ "˜*šœœ˜šœ˜Kšœ œ˜*Kšœ ˜šœ œ˜(Kšœ˜šœ˜šœœ˜Kšœ˜Kšœ&˜&—Kšœ˜——šœ œ˜(Kšœ˜Kšœ&˜&—Kšœ˜—˜KšœTœA™š—šœ˜Kšœ œ˜*Kšœ ˜šœ œ˜(Kšœ˜šœ˜šœœ˜Kšœ˜Kšœ@˜@—Kšœ˜——šœ œ˜(Kšœ˜Kšœ@˜@—Kšœ˜—K˜šœ˜Kšœ œ˜*šœ œ˜#Kšœ˜Kšœ>˜>—Kšœ˜—Kšœœ  ˜—Kšœ˜—Kšœ˜—šœ œœ ˜/Kšœ5˜5—Kšœ˜—šœœ š˜ Kšœ œ^˜m—K˜šœœœœ!œœ œ‹˜λK™—Kšœ˜—Kšœ ˜K˜—š ž œœœœœ˜-Kšœœ˜$—K˜š žœœœœ˜Kšœ œœ œ !˜AKšœœ !˜Kš˜Kšœœ3˜TKšœ,œ˜1KšœœCœ˜|Kšœ˜—Kšœ˜—Kšœ)˜+Kšœ˜—K™™`Kš˜š ž œœœ œœ˜@Kš˜Kšœ0˜0šœœ˜Kš˜šœ œœœ˜)Kš˜Kšœœ˜#KšœœPœ˜Kšœ˜—Kšœ˜—Kšœœ˜ Kšœ˜—Kšœ%˜%Kšœ˜—K˜Kšœ˜—K˜˜K™"KšœG™G—šž œœ œœ˜RKš˜Kšœ*˜*Kšœœ4˜AKšœ˜—˜K™-Kšœ9™9—šž œœ0œ˜]Kš˜Kšœ*˜*Kš œœœœœ3˜RKšœœœœ˜Kšœ˜K˜—šž œœœ˜AKš˜Kšœ œœ˜1Kšœ ˜Kšœ˜—K˜š žœœ)œœœ˜WKš˜Kšœ9˜9K˜šœœ˜Kš˜Kšœ,œ˜EKšœ œœœ˜/šœ˜Kš˜Kšœ.˜.Kšœ!œ˜8Kšœ˜—šœ ˜Kš˜Kšœ˜ Kšœœœ ˜8Kšœœœ'˜GKšœ˜—Kš˜—šœ˜Kš˜Kšœ3˜3Kš œ œœœœ˜(Kšœ1œ˜FKšœ˜—Kšœ˜—K˜šžœœœœ˜GKš˜Kšœœœ ˜6K˜šž œœœ˜&Kšœ.˜.K˜—š ž œœœ œœ˜BKš˜Kšœ0˜0šœœ˜Kš˜Kšœ*˜*šœœ˜Kš˜Kšœœ˜Kšœ+˜-Kšœ˜—Kšœœ˜+Kšœ˜—Kšœœ˜ Kšœ˜—Kšœ*˜,Kšœ'˜'šœœ˜KšœE˜G—Kšœ˜—K˜—K˜™K™K™6K˜šžΠntŸΠktŸ’Ÿ˜.KšœœœŸ œF˜]—K˜K˜šžœœ œœ˜CKš˜Kšœœœ˜Kšœ˜—˜K™)—šžœœœ˜BKš˜Kšœ*˜*Kšœ˜Kšœ@˜@šœœœ˜UKš˜Kšœ œ˜&Kšœœœ ˜'Kšœ˜ Kš˜—Kšœœœœ˜Kšœ˜—K˜šžœœœœ˜8Kš˜Kšœ œœ˜,Kšœœœ˜Kšœ˜—K˜šžœœœœ˜=Kš˜Kšœœœœ˜&Kšœœœœ˜&Kšœ ˜&Kšœ˜K˜—šž œœœœ˜9Kš˜Kšœ œœœ˜$Kšœ"œ˜9Kšœœ$˜8Kšœ˜—K˜—™K™K™'K˜šž‘Ÿ’Ÿ’Ÿ˜0KšœœœŸ œH˜`—K˜K˜šžœœ œœ˜DKš˜Kšœœœ˜Kšœ˜—˜K™#—šžœœœ˜CKš˜šœ=˜=Kšœͺ™ͺK˜—š œœœœ˜qKš˜Kšœ œ˜&Kšœœœ ˜'Kšœ˜ Kš˜—Kšœœœœ˜Kšœ˜—K˜šžœœœœ˜9Kš˜Kšœ œœ˜,Kšœœœ˜Kšœ˜—K˜šžœœœœ˜>Kš˜Kšœœœœ˜&Kšœœœœ˜&Kšœ ˜&Kšœ˜K˜—šžœœœœ˜:Kš˜Kšœ œœœ˜$Kšœ"œ˜9Kšœœ$˜8Kšœ˜——K™K™šœ™K™KšœΑ™ΑK˜šž‘Ÿ’Ÿ’Ÿ˜.KšœœœŸ œ˜3—K™—K™™K˜š žœœœ œ!œœ˜YKš˜Kšœ œ œ œ˜6šœœ˜KšœB˜BKšœœ ˜—Kšœ˜—K˜K˜šžœœ˜7Kš˜šœ œœ˜"Kš˜Kšœœœœ˜(Kš œœ)œœ$œ˜{Kšœ˜—Kšœœ%˜/Kšœ&˜(Kšœœ˜Kšœ˜—K™˜Kšœœέ™υ—š žœœœœœ˜`Kš˜Kšœ œœœ˜š žœœœ œœ˜HKš˜Kšœ,˜,Kšœœ˜@K˜)Kšœœ˜Kšœ˜—Kšœ2˜2Kšœœœ˜0Kšœ˜K˜—˜K™C—šžœœœœ˜hKš˜Kšœ,˜,Kšœ œ˜ š žœœœ œœ˜IKš˜Kšœ-˜-Kšœœœœ˜OKšœœœœ˜Kšœ˜—š žœœœ œœ˜IKšœ+œœ˜:—Kšœ/˜/Kšœœ˜5Kšœ/˜/Kšœ˜—K˜K˜šžœœ+™@Kš™šœœ™K™—šœ™Kšœœœ%™I—Kšœ™—K™š ž œœœœœ™IKš™š œœœœ™$Kš™Kšœœœ™Kšœœ0™IKš œ œœ œœœœ™OKšœœœ œœ œœ œœœ#™•Kš œœ7œœœœ™•Kšœ™—Kšœ™—K™šžœœœ(™KKš™Kšœœœ™9šœ™K™4™Kš™Kšœœœ™&K™Kšœœœ™=Kšœ™—™ Kš™Kšœ œ œ™,Kšœ œ œ™2K™Kšœœ&œœ™aKšœœ*œœ)™yKšœ™—Kšœœ ™—Kšœ™—K™š žœœœ'œœ™]Kš™Kšœœœ™9šœ™Kšœœ™/™Kš™Kšœœœ™&Kšœœ#œ™AKšœ™—™ Kš™Kšœ œ œ™,Kšœ œ œ™2Kšœ œ™K™%Kšœœ&œœ™oKšœœ*œœ)™‡Kšœ™ Kšœ™—Kšœœ ™—Kšœ™—K™K™Kšžœœ œœ˜'K˜K˜šžœ˜!Kš˜Kšœ:˜:Kšœœœ˜3Kšœœœ˜5Kš œ œœœœ˜NKš œ œœœœ ˜BšœC˜CKšœœœ*˜=KšœT˜TKšœX˜XKšœœ œ˜0Kšœ8˜8KšœO˜OKšœH˜HK˜Kšœ"™$K™.Kšœ%˜'Kšœ1˜1Kšœ'™)Kšœ3™3Kšœ*™,Kšœ6™6Kšœ˜—Kšœ&˜&Kšœ˜—K˜šžœ˜,Kš˜Kšœ:˜:Kšœœœ˜3Kšœœœ˜5Kš œ œœœœ˜NKš œ œœœœ ˜BšœC˜CKšœœœ*˜=KšœT˜TKšœX˜XKšœœ œ˜0Kšœ8˜8KšœO˜OKšœH˜HK˜Kšœ&˜&Kšœ˜—Kšœ&˜&Kšœ˜—K˜šž œ˜%Kš˜Kšœ:˜:Kšœœœ˜3Kšœœœ˜5Kšœ œ!˜1Kšœ œ!˜/Kš œ œœœœ ˜BšœC˜CKšœœœ*˜=KšœT˜TKšœX˜XKšœœ œ˜0Kšœ8˜8KšœO˜OKšœH˜H˜Kš˜Kšœœœ ˜)Kšœœ5˜SKšœ" ˜AKšœ(˜(Kšœ˜—K˜Kšœ˜—Kšœ&˜&Kšœ˜—K˜šžœ˜0Kš˜Kšœ:˜:Kšœœœ˜3Kšœœœ˜5Kš œ œœœœ˜NKš œ œœœœ ˜BšœC˜CKšœœœ*˜=KšœT˜TKšœX˜XKšœœ œ˜0Kšœ8˜8KšœO˜OKšœH˜HK˜šžœœœ˜/Kš˜Kšœ1˜1™ Kš˜Kšœ9˜9Kšœ" ˜AKšœ˜—Kšœ˜—K˜Kšœ.˜0Kšœ˜—Kšœ&˜&Kšœ˜——K˜™ K˜šœ»˜»Kšœ~™~—K™šœά˜άKšœA™A—K™šœ’˜’KšœF™F—K™šœζ˜ζKšœE™E—K˜—K™Kšœ˜—…—ͺ¨Λ