DIRECTORY BasicTime USING[ToNSTime], CardTab USING[Create, Fetch, Insert, Ref, Store], Commander USING[CommandProc, Register], CommandTool USING[ArgumentVector, Parse], Convert USING[RopeFromCard], ConvertUnsafe USING[SubString, SubStringToRope], CountedVM USING[Handle, SimpleAllocate], IO USING[card, GetLength, PutF, PutFR, PutRope, rope, RopeFromROS, ROS, SetIndex, STREAM, UnsafeGetBlock, Value], MobAccess, MobDefs USING[Base, FTSelf, MobBase, MTIndex, NullVersion, SGHandle, SGNull, VersionID, VersionStamp], MobMapper USING[AlterMob], MobUtilDefs USING[MobHandle, MobObject], PBasics USING[BITLSHIFT, BITRSHIFT, BITXOR, LongNumber], PFS USING [UniqueID, PathFromRope, RopeFromPath], PFSNames USING [PATH], RefTab USING[Create, Fetch, Key, Insert, Ref], Rope USING[Cat, Equal, ROPE], Symbols, SymbolSegment USING[Base, biases, bodyType, ctxType, ExtFirst, extType, FGHeader, htType, ltType, mdType, seType, ssType, stType, STHeader, treeType, VersionID], SymbolTablePrivate USING[SymbolTableBaseRep], SystemInterface USING[FileSet, CirioFile, GetStreamForFile, ReleaseStreamForFile, GetFileInfo, CirioFileInfo, CreateFileSet, GetCirioFile, CloseFileSet, GetNameOfFile], VM USING[PagesForBytes, WordsForPages]; MobAccessImpl: CEDAR PROGRAM IMPORTS BasicTime, CardTab, Commander, CommandTool, Convert, ConvertUnsafe, CountedVM, IO, MobMapper, PBasics, PFS, RefTab, Rope, SystemInterface, VM EXPORTS MobAccess = BEGIN MobError: PUBLIC ERROR[msg: Rope.ROPE] = CODE; MobCookie: TYPE = REF MobCookieBody; MobCookieBody: PUBLIC TYPE = RECORD[ file: SystemInterface.CirioFile, mobHandle: MobUtilDefs.MobHandle, -- contains some of the table bases mobBase: MobDefs.MobBase, sym: SymbolTableBase, leftShift: CARD, rightShift: CARD, recentBtiParent: Symbols.BTIndex _ Symbols.BTFirst, seiTable: RefTab.Ref, ctxTable: RefTab.Ref, btTable: RefTab.Ref, mdTable: CardTab.Ref, stringTable: CardTab.Ref, lostSeis: CardTab.Ref ]; GetFileForMobCookie: PUBLIC PROC [mc: MobCookie] RETURNS [SystemInterface.CirioFile] = {RETURN [mc.file]}; CreateMobCookie: PUBLIC PROC[f: SystemInterface.CirioFile] RETURNS[MobCookie] = { newCookie: MobCookie _ NEW[MobCookieBody]; stream: IO.STREAM _ SystemInterface.GetStreamForFile[f]; ctxh: CTXH; ctxr: CTXR; seh: SEH; BEGIN ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[f, stream]; newCookie.file _ f; newCookie.seiTable _ RefTab.Create[equal: SEIKeyEqualProc, hash: SEIKeyHashProc]; newCookie.ctxTable _ RefTab.Create[equal: CTXKeyEqualProc, hash: CTXKeyHashProc]; newCookie.btTable _ RefTab.Create[equal: BTKeyEqualProc, hash: BTKeyHashProc]; newCookie.mdTable _ CardTab.Create[]; newCookie.stringTable _ CardTab.Create[]; newCookie.lostSeis _ CardTab.Create[]; TRUSTED { [newCookie.mobHandle, newCookie.mobBase] _ ReadMob[stream]}; TRUSTED{newCookie.sym _ GetSymbols[newCookie.mobBase]; newCookie.leftShift _ SELECT TRUE FROM BITS[UNIT] >= newCookie.mobBase.format.bitsPerUnit[0] => 0, BITS[UNIT] = 8 AND newCookie.mobBase.format.bitsPerUnit[0] = 16 => 1, ENDCASE => ERROR MobError["can't adjust mob"]; newCookie.rightShift _ SELECT TRUE FROM BITS[UNIT] <= newCookie.mobBase.format.bitsPerUnit[0] => 0, BITS[UNIT] = 16 AND newCookie.mobBase.format.bitsPerUnit[0] = 8 => 1, ENDCASE => ERROR MobError["can't adjust mob"]}; END; SystemInterface.ReleaseStreamForFile[f, stream]; ctxh _ ReallyMakeCTXH[newCookie, Symbols.CTXNull]; ctxr _ FetchCTXR[ctxh]; IF ctxr#NIL THEN seh _ ctxr.seList; WHILE seh#NIL DO ser: SER ~ FetchSER[seh]; WITH ser.body SELECT FROM idser: REF id BodySE => { IF idser.idCtx=NIL OR idser.idCtx=ctxh THEN [] _ newCookie.lostSeis.Store[LOOPHOLE[seh.sei], $T]; seh _ idser.ctxLink}; ENDCASE => NULL; ENDLOOP; RETURN[newCookie]}; IsLost: PUBLIC PROC[seh: SEH] RETURNS[BOOL] ~ {RETURN [seh.mob.lostSeis.Fetch[LOOPHOLE[seh.sei]].found]}; ReadMobVersionStamp: PUBLIC PROC[mob: MobCookie] RETURNS[MobDefs.VersionStamp] = BEGIN versionStamp: MobDefs.VersionStamp _ ALL[0]; LookForVersionStamp: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED {versionStamp _ mobBase.version}; ExamineMob[mob, LookForVersionStamp]; RETURN[versionStamp]; END; ReadSourceVersionStamp: PUBLIC PROC[mob: MobCookie] RETURNS[MobDefs.VersionStamp] = BEGIN versionStamp: MobDefs.VersionStamp _ ALL[0]; LookForSourceVersionStamp: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED {versionStamp _ mobBase.sourceVersion}; ExamineMob[mob, LookForSourceVersionStamp]; RETURN[versionStamp]; END; ComputeSourceVersionStamp: PUBLIC PROC[mesaSourceFile: SystemInterface.CirioFile] RETURNS[MobDefs.VersionStamp] = BEGIN fileInfo: SystemInterface.CirioFileInfo _ SystemInterface.GetFileInfo[mesaSourceFile]; vs: MobDefs.VersionStamp _ MobDefs.NullVersion; vs[0] _ BasicTime.ToNSTime[fileInfo.uniqueID.egmt.time]; RETURN[vs]; END; ExamineMob: PROC[cookie: MobCookie, examiner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase]] = {examiner[cookie.mobHandle, cookie.mobBase, cookie.sym]}; VSKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS[BOOL] = BEGIN vs1AsKey: REF MobDefs.VersionStamp _ NARROW[key1]; vs2AsKey: REF MobDefs.VersionStamp _ NARROW[key2]; RETURN[vs1AsKey^ = vs2AsKey^]; END; VSKeyHashProc: PROC[key: RefTab.Key] RETURNS[CARDINAL] = TRUSTED BEGIN vsAsKey: REF MobDefs.VersionStamp _ NARROW[key]; word0: PBasics.LongNumber _ LOOPHOLE[vsAsKey^[0]]; word1: PBasics.LongNumber _ LOOPHOLE[vsAsKey^[1]]; RETURN[PBasics.BITXOR[PBasics.BITXOR[word0.lo, word0.hi], PBasics.BITXOR[word1.lo, word1.hi]]]; END; bytesPerWord: CARD = BYTES[WORD]; bytesPerVMWord: CARD = BYTES[WORD]; ReadMob: PROC [stream: IO.STREAM] RETURNS [h: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase] = TRUSTED { bytes: INT _ IO.GetLength[stream]; allocatedBytes: CARD _ VM.WordsForPages[VM.PagesForBytes[bytes]] * bytesPerVMWord; vmh: CountedVM.Handle; IF bytes = 0 THEN ERROR MobError["empty mob file"]; vmh _ CountedVM.SimpleAllocate[allocatedBytes/bytesPerWord]; IO.SetIndex[stream, 0]; [] _ IO.UnsafeGetBlock[ self: stream, block: [base: vmh.pointer, startIndex: 0, count: bytes]]; mobBase _ LOOPHOLE[vmh.pointer]; IF MobMapper.AlterMob[mobBase, LOOPHOLE[mobBase], bytes/BYTES[UNIT]] = badVersion THEN ERROR MobError["MobMapper.AlterMob failed in MobUtilities.ReadMob"]; IF mobBase.versionIdent # MobDefs.VersionID THEN MobError["not a MOB file"]; h _ NEW[MobUtilDefs.MobObject _ [ bHeader: mobBase, countedVMHandle: vmh, bases: [ ctb: LOOPHOLE[mobBase + mobBase.ctOffset.units], mtb: LOOPHOLE[mobBase + mobBase.mtOffset.units], lfb: LOOPHOLE[mobBase + mobBase.lfOffset.units], rfb: LOOPHOLE[mobBase + mobBase.rfOffset.units], tfb: LOOPHOLE[mobBase + mobBase.tfOffset.units], etb: LOOPHOLE[mobBase + mobBase.expOffset.units], itb: LOOPHOLE[mobBase + mobBase.impOffset.units], sgb: LOOPHOLE[mobBase + mobBase.sgOffset.units], ftb: LOOPHOLE[mobBase + mobBase.ftOffset.units], ssb: LOOPHOLE[mobBase + mobBase.ssOffset.units], evb: LOOPHOLE[mobBase + mobBase.evOffset.units], tyb: LOOPHOLE[mobBase + mobBase.typOffset.units], tmb: LOOPHOLE[mobBase + mobBase.tmOffset.units], ntb: LOOPHOLE[mobBase + mobBase.ntOffset.units], spb: LOOPHOLE[mobBase + mobBase.spOffset.units], fpb: LOOPHOLE[mobBase + mobBase.fpOffset.units] ], limits: [ ct: mobBase.ctLimit, mt: mobBase.mtLimit, et: mobBase.expLimit, it: mobBase.impLimit, sg: mobBase.sgLimit, ft: mobBase.ftLimit, tm: mobBase.tmLimit, nt: mobBase.ntLimit, sp: mobBase.spLimit, fp: mobBase.fpLimit] ]]; }; SymbolTableBase: TYPE = REF SymbolTableBaseRep; SymbolTableBaseRep: TYPE = SymbolTablePrivate.SymbolTableBaseRep; GetSymbols: PROC[mob: MobDefs.MobBase] RETURNS[SymbolTableBase] = TRUSTED BEGIN sgb: MobDefs.Base = LOOPHOLE[mob+mob.sgOffset.units]; mtb: MobDefs.Base = LOOPHOLE[mob+mob.mtOffset.units]; sgh: MobDefs.SGHandle = IF mtb[FIRST[MobDefs.MTIndex]].sseg = MobDefs.SGNull THEN ERROR MobError["NoSymbols"] ELSE @sgb[mtb[FIRST[MobDefs.MTIndex]].sseg]; stb: LONG POINTER TO SymbolSegment.STHeader = LOOPHOLE[mob+sgh.base.units]; IF mob.nConfigs # 0 THEN ERROR MobError["Can't get symbols from a config"]; IF sgh.file # MobDefs.FTSelf OR sgh.units.units = 0 THEN ERROR MobError["funny looking mob"]; --NoSymbols; IF stb.versionIdent # SymbolSegment.VersionID THEN ERROR MobError["invalid-looking mob"]; -- WrongSymbolsVersion; RETURN[InstallSymbolTable[stb]] END; InstallSymbolTable: PROC [node: LONG POINTER] RETURNS [SymbolTableBase] = TRUSTED { b: LONG POINTER = node; tB: SymbolSegment.Base = LOOPHOLE[b]; p: LONG POINTER TO SymbolSegment.STHeader = b; base: SymbolTableBase _ NEW[SymbolTableBaseRep]; base.cacheInfo _ LOOPHOLE[node]; base.hashVec _ b+p.hvBlock.offset; base.htb _ tB + p.htBlock.offset - SymbolSegment.biases[SymbolSegment.htType]; base.ssb _ b + p.ssBlock.offset - SymbolSegment.biases[SymbolSegment.ssType]; base.seb _ tB + p.seBlock.offset - SymbolSegment.biases[SymbolSegment.seType]; base.ctxb _ tB + p.ctxBlock.offset - SymbolSegment.biases[SymbolSegment.ctxType]; base.mdb _ tB + p.mdBlock.offset - SymbolSegment.biases[SymbolSegment.mdType]; base.bb _ tB + p.bodyBlock.offset - SymbolSegment.biases[SymbolSegment.bodyType]; base.tb _ tB + p.treeBlock.offset - SymbolSegment.biases[SymbolSegment.treeType]; base.ltb _ tB + p.litBlock.offset - SymbolSegment.biases[SymbolSegment.ltType]; base.stb _ tB + p.sLitBlock.offset - SymbolSegment.biases[SymbolSegment.stType]; base.extb _ tB + p.extBlock.offset - SymbolSegment.biases[SymbolSegment.extType]; base.mdLimit _ Symbols.MDFirst + p.mdBlock.size; base.extLimit _ SymbolSegment.ExtFirst + p.extBlock.size; base.mainCtx _ p.outerCtx; base.stHandle _ p; IF p.fgRelBase = 0 OR p.fgCount = 0 THEN { base.sourceFile _ NIL; base.fgTable _ NIL; } ELSE { q: LONG POINTER TO SymbolSegment.FGHeader = LOOPHOLE[b + p.fgRelBase]; source: LONG STRING = LOOPHOLE[q + SIZE[SymbolSegment.FGHeader[0]] - SIZE[StringBody[0]]]; base.sourceFile _ source; base.fgTable _ DESCRIPTOR[q + q.offset, q.length]; }; RETURN [base]; }; BTR: TYPE = MobAccess.BTR; BTRBody: TYPE = MobAccess.BTRBody; BodyLinkRcd: TYPE = MobAccess.BodyLinkRcd; BTH: TYPE = REF BTHBody; BTHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, bti: Symbols.BTIndex, btr: BTR]; BTHDetails: PUBLIC PROC [bth: BTH] RETURNS [mob: MobCookie, bti: Symbols.BTIndex] ~ {RETURN [bth.mob, bth.bti]}; MakeBTH: PUBLIC PROC[mob: MobCookie, bti: Symbols.BTIndex] RETURNS[BTH] = BEGIN IF bti = Symbols.BTNull THEN RETURN[NIL] ELSE BEGIN btiAsKey: REF Symbols.BTIndex _ NEW[Symbols.BTIndex _ bti]; bth: BTH _ NARROW[RefTab.Fetch[mob.btTable, btiAsKey].val]; IF bth # NIL THEN RETURN[bth]; bth _ NEW[BTHBody_[mob, bti, NIL]]; IF NOT RefTab.Insert[mob.btTable, btiAsKey, bth] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[bth] END END; MakeBTHFromCodedBti: PUBLIC PROC[mob: MobCookie, codedBti: CARD] RETURNS[BTH] = BEGIN tentativeResult: BTH _ NIL; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN shiftedBti: CARD _ SELECT TRUE FROM mob.leftShift # 0 => PBasics.BITLSHIFT[codedBti, mob.leftShift], mob.rightShift # 0 => PBasics.BITRSHIFT[codedBti, mob.rightShift], ENDCASE => codedBti; tentativeBti: Symbols.BTIndex _ LOOPHOLE[shiftedBti]; tentativeBtiAsKey: REF Symbols.BTIndex _ NEW[Symbols.BTIndex _ tentativeBti]; tentativeResult _ NARROW[RefTab.Fetch[mob.btTable, tentativeBtiAsKey].val]; IF tentativeResult = NIL THEN -- we have to build it from scratch BEGIN [] _ CheckTentativeBti[tentativeBti, mob, sym, 0 ! BadTentativeBti => {GOTO failure}]; tentativeResult _ MakeBTH[mob, tentativeBti]; EXITS failure => NULL; -- thus, leaving result = NIL END; END; ExamineMob[mob, Inner]; RETURN[tentativeResult]; END; GetRootBTH: PUBLIC PROC[mob: MobCookie] RETURNS[BTH] ~ {RETURN MakeBTH[mob, Symbols.BTFirst]}; CheckTentativeBti: PROC[tentativeBti: Symbols.BTIndex, mob: MobCookie, sym: SymbolTableBase, checkDepth: CARD] RETURNS[Symbols.BTIndex] = TRUSTED BEGIN IF checkDepth > 15 THEN BadTentativeBti[tentativeBti]; [] _ BoundsCheckTentativeBti[tentativeBti, sym]; IF tentativeBti = Symbols.BTFirst THEN RETURN[tentativeBti]; IF tentativeBti = mob.recentBtiParent THEN RETURN[tentativeBti]; BEGIN counter: INT _ 0; scan: Symbols.BTIndex _ tentativeBti; parent: Symbols.BTIndex; DO IF sym.bb[scan].link.which = parent THEN EXIT; IF counter > 1000 THEN BadTentativeBti[tentativeBti]; counter _ counter + 1; IF sym.bb[scan].link.which = sibling THEN {scan _ BoundsCheckTentativeBti[sym.bb[scan].link.index, sym]; LOOP}; BadTentativeBti[tentativeBti]; ENDLOOP; parent _ CheckTentativeBti[sym.bb[scan].link.index, mob, sym, checkDepth+1]; scan _ BoundsCheckTentativeBti[sym.bb[parent].firstSon, sym]; DO IF counter > 1000 THEN BadTentativeBti[tentativeBti]; counter _ counter + 1; IF scan = tentativeBti THEN {mob.recentBtiParent _ parent; RETURN[tentativeBti]}; IF sym.bb[scan].link.which = parent THEN BadTentativeBti[tentativeBti]; IF sym.bb[scan].link.which = sibling THEN scan _ BoundsCheckTentativeBti[sym.bb[scan].link.index, sym]; ENDLOOP; END; END; BoundsCheckTentativeBti: PROC[tentativeBti: Symbols.BTIndex, sym: SymbolTableBase] RETURNS[Symbols.BTIndex] = TRUSTED BEGIN -- this must act like a relative pointer that lands within the body table addr: CARD _ LOOPHOLE[sym.bb, CARD] + LOOPHOLE[tentativeBti, CARD]; tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.bodyBlock.offset, CARD]; IF addr < tableBase THEN BadTentativeBti[tentativeBti]; IF addr >= tableBase+sym.stHandle.bodyBlock.size THEN BadTentativeBti[tentativeBti]; RETURN[tentativeBti]; END; BadTentativeBti: ERROR[Symbols.BTIndex] = CODE; GenCallableBodies: PUBLIC PROC[mob: MobCookie, for: PROC[callableBody: BTH]] = TRUSTED BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN Visit: PROC[bti: Symbols.BTIndex] = TRUSTED {IF sym.bb[bti].kind = Callable THEN for[MakeBTH[mob, bti]]}; ScanSubTree: PROC[treeRoot: Symbols.BTIndex] = TRUSTED BEGIN IF sym.bb[treeRoot].firstSon # Symbols.BTNull THEN FOR scan: Symbols.BTIndex _ sym.bb[treeRoot].firstSon, sym.bb[scan].link.index WHILE scan # treeRoot DO ScanSubTree[scan]; Visit[scan]; ENDLOOP; END; ScanSubTree[Symbols.RootBti]; Visit[Symbols.RootBti]; END; ExamineMob[mob, Inner]; END; GetParentOfBTH: PUBLIC PROC[bth: BTH] RETURNS[BTH] = BEGIN result: BTH _ NIL; -- tentative Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN IF bth.bti = Symbols.RootBti THEN {result _ NIL} ELSE BEGIN x: Symbols.BTIndex _ bth.bti; WHILE sym.bb[x].link.which # parent DO x _ sym.bb[x].link.index ENDLOOP; result _ MakeBTH[bth.mob, sym.bb[x].link.index]; END; END; ExamineMob[bth.mob, Inner]; RETURN[result]; END; GetCodedBTIFromBTH: PUBLIC PROC[bth: BTH] RETURNS[CARD] = BEGIN result: CARD _ 0; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN result _ SELECT TRUE FROM bth.mob.leftShift # 0 => PBasics.BITRSHIFT[LOOPHOLE[bth.bti], bth.mob.leftShift], bth.mob.rightShift # 0 => PBasics.BITLSHIFT[LOOPHOLE[bth.bti], bth.mob.rightShift], ENDCASE => LOOPHOLE[bth.bti]; END; ExamineMob[bth.mob, Inner]; RETURN[result] END; BTKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN bti1Ref: REF Symbols.BTIndex _ NARROW[key1]; bti2Ref: REF Symbols.BTIndex _ NARROW[key2]; RETURN[bti1Ref^ = bti2Ref^]; END; BTKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN btiRef: REF Symbols.BTIndex _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[btiRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; FetchBTR: PUBLIC PROC[bth: BTH] RETURNS[BTR] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN bth.btr _ NEW[BTRBody_[ link: [ which: IF sym.bb[bth.bti].link.which = sibling THEN sibling ELSE parent, index: MakeBTH[bth.mob, sym.bb[bth.bti].link.index]], firstSon: MakeBTH[bth.mob, sym.bb[bth.bti].firstSon], type: MakeSEH[bth.mob, sym.bb[bth.bti].type], localCtx: MakeCTXH[bth.mob, sym.bb[bth.bti].localCtx], sourceIndex: sym.bb[bth.bti].sourceIndex, info: MakeBTInfo[bth, mobHandle, mobBase, sym], level: sym.bb[bth.bti].level, class: sym.bb[bth.bti].class, extension: MakeBTExtension[bth, mobHandle, mobBase, sym]]]; END; IF bth = NIL THEN RETURN[NIL]; IF bth.btr = NIL THEN ExamineMob[bth.mob, Inner]; RETURN[bth.btr]; END; MakeBTInfo: PROC[bth: BTH, mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] RETURNS[REF MobAccess.BodyInfo] = TRUSTED BEGIN WITH info: sym.bb[bth.bti].info SELECT FROM Internal => RETURN[NEW[Internal MobAccess.BodyInfo _ [Internal[info.frameSize]]]]; External => RETURN[NEW[External MobAccess.BodyInfo _ [External[ bytes: info.bytes, startIndex: info.startIndex, indexLength: info.indexLength]]]]; ENDCASE => ERROR MobError["invalid BodyInfo.mark"]; END; MakeBTExtension: PROC[bth: BTH, mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] RETURNS[REF MobAccess.BTRExtension] = TRUSTED BEGIN WITH extension: sym.bb[bth.bti] SELECT FROM Callable => RETURN[NEW[Callable MobAccess.BTRExtension _ [Callable[ id: MakeSEH[bth.mob, extension.id], ioType: MakeSEH[bth.mob, extension.ioType], frameOffset: extension.frameOffset, entryIndex: extension.entryIndex, hints: [extension.hints.safe, extension.hints.argUpdated, extension.hints.nameSafe, extension.hints.noStrings], entry: extension.entry, internal: extension.internal, inline: extension.inline, monitored: extension.monitored, noXfers: extension.noXfers, resident: extension.resident, kind: SELECT extension.kind FROM Outer => Outer, Inner => Inner, Catch => Catch, Other => Other, ENDCASE => ERROR MobError["invalid Callable BodyRecord BodyKind"] ]]]]; Other => RETURN[NEW[Other MobAccess.BTRExtension _ [Other[extension.relOffset]]]]; ENDCASE => ERROR MobError["invalid BodyRecord kind"]; END; GenBodiesWithDepth: PROC[mob: MobCookie, body: BTH, baseDepth: INT, for: PROC[body: BTH, depth: INT]] = TRUSTED BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN Visit: PROC[bti: Symbols.BTIndex] = TRUSTED BEGIN bth: BTH _ MakeBTH[mob, bti]; for[bth, baseDepth+1]; GenBodiesWithDepth[mob, bth, baseDepth+1, for]; END; ScanSubTree: PROC[treeRoot: Symbols.BTIndex] = TRUSTED BEGIN IF sym.bb[treeRoot].firstSon # Symbols.BTNull THEN FOR scan: Symbols.BTIndex _ sym.bb[treeRoot].firstSon, sym.bb[scan].link.index WHILE scan # treeRoot DO ScanSubTree[scan]; Visit[scan]; ENDLOOP; END; ScanSubTree[body.bti]; END; ExamineMob[mob, Inner]; END; MobBodyTreeToRope: PROC[mob: MobCookie] RETURNS[Rope.ROPE] = {RETURN[BodyTreeToRope[mob, MakeBTH[mob, Symbols.RootBti]]]}; BodyTreeToRope: PROC[mob: MobCookie, body: BTH] RETURNS[Rope.ROPE] = BEGIN rope: Rope.ROPE _ NIL; eachBody: PROC[body: BTH, depth: INT] = BEGIN rope _ Rope.Cat[rope, BodyToRope[body, depth], "\N"]; END; eachBody[body, 0]; GenBodiesWithDepth[mob, body, 1, eachBody]; RETURN[rope]; END; BodyToRope: PROC[body: BTH, depth: INT] RETURNS[Rope.ROPE] = BEGIN btr: BTR _ FetchBTR[body]; st: IO.STREAM _ IO.ROS[]; putDepth: PROC[d: INT_0] = {FOR I: INT IN [0..depth+d) DO IO.PutF[st, " "] ENDLOOP}; rope: PROC[r: Rope.ROPE, d: INT _ 0] = {putDepth[d]; IO.PutRope[st, r]}; put: PROC[d: INT, f: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]]] = BEGIN putDepth[d]; IO.PutF[st, f, v1, v2, v3, v4, v5]; END; rope["body"]; put[0, " source index = %g\N", IO.card[btr.sourceIndex]]; rope[CTXToRope[btr.localCtx, depth+5]]; RETURN[IO.RopeFromROS[st]]; END; MDR: TYPE = MobAccess.MDR; MDRBody: TYPE = MobAccess.MDRBody; MDH: TYPE = REF MDHBody; MDHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, mdi: Symbols.MDIndex, mdr: MDR]; MakeMDH: PUBLIC PROC[mob: MobCookie, mdi: Symbols.MDIndex] RETURNS[MDH] = BEGIN IF mdi = Symbols.MDNull THEN RETURN[NIL] ELSE BEGIN mdiAsKey: CARD ~ LOOPHOLE[mdi]; mdh: MDH _ NARROW[CardTab.Fetch[mob.mdTable, mdiAsKey].val]; IF mdh # NIL THEN RETURN[mdh]; mdh _ NEW[MDHBody_[mob, mdi, NIL]]; IF NOT CardTab.Insert[mob.mdTable, mdiAsKey, mdh] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[mdh] END END; FetchMDR: PUBLIC PROC[mdh: MDH] RETURNS[MDR] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN raw: LONG POINTER TO Symbols.MDRecord ~ @sym.mdb[mdh.mdi]; mdh.mdr _ NEW[MDRBody_[ stamp: raw.stamp, moduleId: RopeForName[mdh.mob, mobHandle, mobBase, sym, raw.moduleId], fileId: RopeForName[mdh.mob, mobHandle, mobBase, sym, raw.fileId], shared: raw.shared, exported: raw.exported, ctx: MakeCTXH[mdh.mob, raw.ctx], defaultImport: MakeCTXH[mdh.mob, raw.defaultImport] ]]; END; IF mdh = NIL THEN RETURN[NIL]; IF mdh.mdr = NIL THEN ExamineMob[mdh.mob, Inner]; RETURN[mdh.mdr]; END; GetMobForMDH: PUBLIC PROC[mdh: MDH] RETURNS[MobCookie] = {RETURN[mdh.mob]}; GetMdiForMDH: PUBLIC PROC[mdh: MDH] RETURNS[Symbols.MDIndex] = {RETURN[mdh.mdi]}; CTXR: TYPE = MobAccess.CTXR; CTXRBody: TYPE = MobAccess.CTXRBody; CTXH: TYPE = REF CTXHBody; CTXHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, ctx: Symbols.CTXIndex, ctxr: CTXR]; MakeCTXH: PUBLIC PROC[mob: MobCookie, ctx: Symbols.CTXIndex] RETURNS[CTXH] = { IF ctx = Symbols.CTXNull THEN RETURN[NIL] ELSE RETURN ReallyMakeCTXH[mob, ctx]}; ReallyMakeCTXH: PROC[mob: MobCookie, ctx: Symbols.CTXIndex] RETURNS[CTXH] = { ctxAsKey: REF Symbols.CTXIndex _ NEW[Symbols.CTXIndex _ ctx]; ctxh: CTXH _ NARROW[RefTab.Fetch[mob.ctxTable, ctxAsKey].val]; IF ctxh # NIL THEN RETURN[ctxh]; ctxh _ NEW[CTXHBody_[mob, ctx, NIL]]; IF NOT RefTab.Insert[mob.ctxTable, ctxAsKey, ctxh] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[ctxh]}; MakeStdCtxh: PUBLIC PROC[mob: MobCookie] RETURNS[CTXH] ~ {RETURN MakeCTXH[mob, Symbols.FirstStandardCtx]}; BoundsCheckTentativeCTX: PROC[tentativeCTX: Symbols.CTXIndex, sym: SymbolTableBase] RETURNS[Symbols.CTXIndex] = TRUSTED BEGIN addr: CARD _ LOOPHOLE[sym.ctxb, CARD] + LOOPHOLE[tentativeCTX, CARD]; tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.ctxBlock.offset, CARD]; IF tentativeCTX = Symbols.CTXNull THEN BadTentativeCTX[tentativeCTX]; IF addr < tableBase THEN BadTentativeCTX[tentativeCTX]; IF addr >= tableBase+sym.stHandle.ctxBlock.size THEN BadTentativeCTX[tentativeCTX]; RETURN[tentativeCTX]; END; BadTentativeCTX: ERROR[Symbols.CTXIndex] = CODE; CTXKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN ctx1Ref: REF Symbols.CTXIndex _ NARROW[key1]; ctx2Ref: REF Symbols.CTXIndex _ NARROW[key2]; RETURN[ctx1Ref^ = ctx2Ref^]; END; CTXKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN ctxRef: REF Symbols.CTXIndex _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[ctxRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; FetchCTXR: PUBLIC PROC[ctxh: CTXH] RETURNS[CTXR] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN seH: SEH ~ MakeSEH[ctxh.mob, sym.ctxb[ctxh.ctx].seList]; lvl: Symbols.ContextLevel ~ sym.ctxb[ctxh.ctx].level; varUpdated: BOOL ~ sym.ctxb[ctxh.ctx].varUpdated; WITH x: sym.ctxb[ctxh.ctx] SELECT FROM simple => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: simple[copied: x.copied] ]]; included => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: included[ chain: MakeCTXH[ctxh.mob, x.chain], module: MakeMDH[ctxh.mob, x.module], map: x.map, copied: x.copied, reset: x.reset, closed: x.closed, complete: x.complete, restricted: x.restricted ] ]]; imported => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: imported[MakeCTXH[ctxh.mob, x.includeLink]] ]]; nil => ctxh.ctxr _ NEW[CTXRBody_[seList: seH, level: lvl, varUpdated: varUpdated, extension: nil[] ]]; ENDCASE => ERROR MobError["invalid CTXRecord ctxType"]; END; IF ctxh = NIL THEN RETURN[NIL]; IF ctxh.ctxr = NIL THEN ExamineMob[ctxh.mob, Inner]; RETURN[ctxh.ctxr]; END; GetMobForCTXH: PUBLIC PROC[ctxh: CTXH] RETURNS[MobCookie] = {RETURN[ctxh.mob]}; GetCtxForCTXH: PUBLIC PROC[ctxh: CTXH] RETURNS[Symbols.CTXIndex] = {RETURN[ctxh.ctx]}; CTXToRope: PROC[ctxh: CTXH, depth: INT] RETURNS[Rope.ROPE] = BEGIN IF ctxh = NIL THEN RETURN[NIL] ELSE BEGIN ctxr: CTXR _ FetchCTXR[ctxh]; st: IO.STREAM _ IO.ROS[]; seh: SEH _ ctxr.seList; putDepth: PROC[d: INT_0] = {FOR I: INT IN [0..depth+d) DO IO.PutF[st, " "] ENDLOOP}; putDepth[]; IO.PutF[st, "ctx = %g, level = %g\N", IO.rope[Convert.RopeFromCard[LOOPHOLE[ctxh.ctx]]], IO.card[ctxr.level]]; WHILE seh # NIL DO ser: SER _ FetchSER[seh]; IO.PutF[st, "%g", IO.rope[SEHToRope[seh, depth+2]]]; WITH ser.body SELECT FROM id: REF id BodySE => seh _ id.ctxLink; ENDCASE => seh _ NIL; ENDLOOP; RETURN[IO.RopeFromROS[st]]; END END; SER: TYPE = MobAccess.SER; SERBody: TYPE = MobAccess.SERBody; BodySE: TYPE = MobAccess.BodySE; TypeInfoConsSE: TYPE = MobAccess.TypeInfoConsSE; SEH: TYPE = REF SEHBody; SEHBody: PUBLIC TYPE = RECORD[ mob: MobCookie, sei: Symbols.SEIndex, ser: SER]; MakeSEH: PUBLIC PROC[mob: MobCookie, sei: Symbols.SEIndex] RETURNS[SEH] = BEGIN IF sei = Symbols.SENull THEN RETURN[NIL] ELSE BEGIN seiAsKey: REF Symbols.SEIndex _ NEW[Symbols.SEIndex _ sei]; seh: SEH _ NARROW[RefTab.Fetch[mob.seiTable, seiAsKey].val]; IF seh # NIL THEN RETURN[seh]; seh _ NEW[SEHBody_[mob, sei, NIL]]; IF NOT RefTab.Insert[mob.seiTable, seiAsKey, seh] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[seh] END; END; MakeSEHFromCodedSei: PUBLIC PROC[mob: MobCookie, codedSei: CARD, name: Rope.ROPE] RETURNS[SEH] = TRUSTED BEGIN tentativeResult: SEH _ NIL; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN seNull: CARD ~ LOOPHOLE[Symbols.SENull]; shiftedSei: CARD _ SELECT TRUE FROM mob.leftShift # 0 => PBasics.BITLSHIFT[codedSei, mob.leftShift], mob.rightShift # 0 => PBasics.BITRSHIFT[codedSei, mob.rightShift], ENDCASE => codedSei; tentativeSei: Symbols.SEIndex _ LOOPHOLE[shiftedSei+seNull]; tentativeSeiAsKey: REF Symbols.SEIndex _ NEW[Symbols.SEIndex _ tentativeSei]; tentativeResult _ NARROW[RefTab.Fetch[mob.seiTable, tentativeSeiAsKey].val]; IF tentativeResult = NIL THEN -- we have to build it from scratch BEGIN CheckTentativeISei[tentativeSei, sym ! BadTentativeSei, BadTentativeCTX => {GOTO failure}]; tentativeResult _ MakeSEH[mob, tentativeSei]; EXITS failure => NULL; -- thus, leaving result = NIL END; END; ExamineMob[mob, Inner]; IF tentativeResult # NIL THEN RETURN[CheckSEHName[tentativeResult, name]] ELSE RETURN[NIL]; END; GetCodedSeiFromSEH: PUBLIC PROC[seh: SEH] RETURNS[CARD] = BEGIN result: CARD _ 0; Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN nominal: CARD _ LOOPHOLE[seh.sei, CARD] - LOOPHOLE[Symbols.SENull, CARD]; result _ SELECT TRUE FROM seh.mob.leftShift # 0 => PBasics.BITRSHIFT[nominal, seh.mob.leftShift], seh.mob.rightShift # 0 => PBasics.BITLSHIFT[nominal, seh.mob.rightShift], ENDCASE => nominal; END; ExamineMob[seh.mob, Inner]; RETURN[result] END; CheckSEHName: PROC[seh: SEH, name: Rope.ROPE] RETURNS[SEH] = BEGIN ser: SER _ FetchSER[seh]; body: REF BodySE _ ser.body; IF name = NIL THEN RETURN[seh]; -- client didn't really want to check WITH body SELECT FROM id: REF id BodySE => IF Rope.Equal[name, id.hash] THEN RETURN[seh] ELSE RETURN[NIL]; -- name didn't check ENDCASE => RETURN[NIL]; -- was expecting an id seh END; CheckTentativeISei: PROC[tentativeISei: Symbols.SEIndex, sym: SymbolTableBase] = TRUSTED BEGIN [] _ BoundsCheckTentativeSei[tentativeISei, sym]; WITH body: sym.seb[tentativeISei] SELECT FROM id => -- at least its got the right tag BEGIN tentativeCtx: Symbols.CTXIndex _ BoundsCheckTentativeCTX[body.idCtx, sym]; firstSei: Symbols.SEIndex _ BoundsCheckTentativeSei[sym.ctxb[tentativeCtx].seList, sym]; nextSei: Symbols.SEIndex _ firstSei; DO sei: Symbols.SEIndex _ BoundsCheckTentativeSei[nextSei, sym]; IF sei = tentativeISei THEN RETURN; WITH body: sym.seb[sei] SELECT FROM id => -- at least its got the right tag BEGIN WITH lnk: body SELECT FROM terminal => BadTentativeSei[tentativeISei]; sequential => {nextSei _ sei + Symbols.SERecord.id.sequential.SIZE; LOOP}; linked => {nextSei _ lnk.link; LOOP}; embedded => BadTentativeSei[tentativeISei]; -- I am not sure if this is what I should do here ENDCASE => BadTentativeSei[tentativeISei]; END ENDCASE => BadTentativeSei[tentativeISei]; ENDLOOP; END; ENDCASE => BadTentativeSei[tentativeISei]; END; BoundsCheckTentativeSei: PROC[tentativeSei: Symbols.SEIndex, sym: SymbolTableBase] RETURNS[Symbols.SEIndex] = TRUSTED BEGIN -- this must act like a relative pointer that lands within the se table addr: CARD _ LOOPHOLE[sym.seb, CARD] + LOOPHOLE[tentativeSei, CARD]; tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.seBlock.offset, CARD]; IF addr < tableBase THEN BadTentativeSei[tentativeSei]; IF addr >= tableBase+sym.stHandle.seBlock.size THEN BadTentativeSei[tentativeSei]; RETURN[tentativeSei]; END; BadTentativeSei: ERROR[tentativeSei: Symbols.SEIndex] = CODE; CheckTentativeName: PROC[name: Symbols.Name, sym: SymbolTableBase] = TRUSTED BEGIN addr: CARD _ LOOPHOLE[sym.htb, CARD] + LOOPHOLE[name, CARD]; tableBase: CARD _ LOOPHOLE[sym.stHandle, CARD] + LOOPHOLE[sym.stHandle.htBlock.offset, CARD]; IF addr < tableBase THEN BadTentativeName[name]; IF addr >= tableBase+sym.stHandle.htBlock.size THEN BadTentativeName[name]; IF (addr-tableBase) MOD SIZE[Symbols.HTRecord] # 0 THEN BadTentativeName[name]; END; BadTentativeName: SIGNAL[Symbols.Name] ~ CODE; SEIKeyEqualProc: PROC[key1, key2: RefTab.Key] RETURNS [BOOL] = BEGIN sei1Ref: REF Symbols.SEIndex _ NARROW[key1]; sei2Ref: REF Symbols.SEIndex _ NARROW[key2]; RETURN[sei1Ref^ = sei2Ref^]; END; SEIKeyHashProc: PROC[key: RefTab.Key] RETURNS [CARDINAL] = BEGIN seiRef: REF Symbols.SEIndex _ NARROW[key]; asLongNumber: Basics.LongNumber _ LOOPHOLE[seiRef^]; RETURN[Basics.BITXOR[asLongNumber.lo, asLongNumber.hi]]; END; FetchSER: PUBLIC PROC[seh: SEH] RETURNS[SER] = BEGIN Inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = TRUSTED BEGIN IF seh.sei-Symbols.SEFirst<0 OR CARD[seh.sei-Symbols.SEFirst]>=sym.stHandle.seBlock.size THEN ERROR MobError[IO.PutFR["bogus SEI %x into %g", [cardinal[LOOPHOLE[seh.sei]]], [rope[PFS.RopeFromPath[SystemInterface.GetNameOfFile[seh.mob.file]]]] ]]; seh.ser _ NEW[SERBody _ [ body: WITH body: sym.seb[seh.sei] SELECT FROM id => NEW[BodySE _ [id[ extended: body.extended, public: body.public, immutable: body.immutable, constant: body.constant, linkSpace: body.linkSpace, idDecl: body.idDecl, idCtx: MakeCTXH[seh.mob, body.idCtx], idType: MakeSEH[seh.mob, body.idType], idInfoAndValue: NIL, -- filled in below hash: RopeForName[seh.mob, mobHandle, mobBase, sym, body.hash], flags: body.flags, special: body.special, ctxLink: WITH lnk: body SELECT FROM terminal => NIL, sequential => MakeSEH[seh.mob, seh.sei + Symbols.SERecord.id.sequential.SIZE], linked => MakeSEH[seh.mob, lnk.link], embedded => ERROR MobError["MobAccessImpl can't handle embedded ISEIs"], ENDCASE => ERROR MobError["invalid id SERecord linkTag"] ]]], cons => NEW[BodySE _ [cons[ align: body.align, typeInfo: WITH cons: body SELECT FROM mode => NEW[TypeInfoConsSE _ [mode[]]], basic => NEW[TypeInfoConsSE _ [basic[ ordered: cons.ordered, code: cons.code, length: cons.length]]], signed => NEW[TypeInfoConsSE _ [signed[cons.length]]], unsigned => NEW[TypeInfoConsSE _ [unsigned[cons.length]]], real => NEW[TypeInfoConsSE _ [real[cons.length]]], enumerated => NEW[TypeInfoConsSE _ [enumerated[ range: cons.range, valueCtx: MakeCTXH[seh.mob, cons.valueCtx], empty: cons.empty, sparse: cons.sparse, painted: cons.painted, ordered: cons.ordered, machineDep: cons.machineDep]]], record => NEW[TypeInfoConsSE _ [record[ length: cons.length, fieldCtx: MakeCTXH[seh.mob, cons.fieldCtx], bitOrder: MyifyBitOrder[cons.bitOrder], grain: cons.grain, hints: [ comparable: cons.hints.comparable, assignable: cons.hints.assignable, unifield: cons.hints.unifield, variant: cons.hints.variant, privateFields: cons.hints.privateFields, refField: cons.hints.refField, default: cons.hints.default, voidable: cons.hints.voidable], packed: cons.packed, list: cons.list, argument: cons.argument, monitored: cons.monitored, machineDep: cons.machineDep, painted: cons.painted, linkPart: WITH link: cons SELECT FROM notLinked => NIL, linked => MakeSEH[seh.mob, link.linkType], ENDCASE => ERROR MobError["invalid record cons SERecord linkTag"] ]]], ref => NEW[TypeInfoConsSE _ [ref[ refType: MakeSEH[seh.mob, cons.refType], counted: cons.counted, ordered: cons.ordered, readOnly: cons.readOnly, list: cons.list, var: cons.var, basing: cons.basing, length: cons.length ]]], array => NEW[TypeInfoConsSE _ [array[ componentType: MakeSEH[seh.mob, cons.componentType], indexType: MakeSEH[seh.mob, cons.indexType], packed: cons.packed, bitOrder: MyifyBitOrder[cons.bitOrder]]]], arraydesc => NEW[TypeInfoConsSE _ [arraydesc[ describedType: MakeSEH[seh.mob, cons.describedType], var: cons.var, readOnly: cons.readOnly, bitOrder: MyifyBitOrder[cons.bitOrder], length: cons.length]]], transfer => NEW[TypeInfoConsSE _ [transfer[ safe: cons.safe, mode: SELECT cons.mode FROM proc => proc, port => port, signal => signal, error => error, process => process, program => program, none => none, ENDCASE => ERROR MobError["invalid transfer cons SERecord mode"], typeIn: MakeSEH[seh.mob, cons.typeIn], typeOut: MakeSEH[seh.mob, cons.typeOut], length: cons.length]]], definition => NEW[TypeInfoConsSE _ [definition[ defCtx: MakeCTXH[seh.mob, cons.defCtx], slots: cons.slots, named: cons.named]]], union => NEW[TypeInfoConsSE _ [union[ caseCtx: MakeCTXH[seh.mob, cons.caseCtx], tagSei: MakeSEH[seh.mob, cons.tagSei], hints: [ equalLengths: cons.hints.equalLengths, refField: cons.hints.refField, default: cons.hints.default, voidable: cons.hints.voidable], overlaid: cons.overlaid, controlled: cons.controlled, machineDep: cons.machineDep, bitOrder: MyifyBitOrder[cons.bitOrder], grain: cons.grain]]], sequence => NEW[TypeInfoConsSE _ [sequence[ parentType: MakeSEH[seh.mob, cons.parentType], tagSei: MakeSEH[seh.mob, cons.tagSei], componentType: MakeSEH[seh.mob, cons.componentType], packed: cons.packed, controlled: cons.controlled, machineDep: cons.machineDep, bitOrder: MyifyBitOrder[cons.bitOrder], grain: cons.grain]]], relative => NEW[TypeInfoConsSE _ [relative[ baseType: MakeSEH[seh.mob, cons.baseType], offsetType: MakeSEH[seh.mob, cons.offsetType], resultType: MakeSEH[seh.mob, cons.resultType]]]], subrange => NEW[TypeInfoConsSE _ [subrange[ empty: cons.empty, biased: cons.biased, filled: cons.filled, rangeType: MakeSEH[seh.mob, cons.rangeType], origin: cons.origin, range: cons.range]]], opaque => NEW[TypeInfoConsSE _ [opaque[ id: MakeSEH[seh.mob, cons.id], length: cons.length, lengthKnown: cons.lengthKnown]]], zone => NEW[TypeInfoConsSE _ [zone[ counted: cons.counted, mds: cons.mds, length: cons.length]]], any => NEW[TypeInfoConsSE _ [any[]]], nil => NEW[TypeInfoConsSE _ [nil[]]], ENDCASE => ERROR MobError["invalid cons SERecord typeTag"] ]]], ENDCASE => ERROR MobError["invalid SERecord seTag"] ]]; WITH bodySource: sym.seb[seh.sei] SELECT FROM id => WITH bodyTarget: seh.ser.body SELECT FROM id => BEGIN IF bodySource.idType = Symbols.typeTYPE THEN BEGIN idInfoSEI: Symbols.SEIndex _ LOOPHOLE[bodySource.idInfo]; idInfoSEH: SEH _ MakeSEH[seh.mob, idInfoSEI]; bodyTarget.idInfoAndValue _ NEW[MobAccess.TypeDesc _ [idInfoSEH, LOOPHOLE[bodySource.idValue]]]; GOTO installed; END; BEGIN entrySEI: Symbols.SEIndex _ UnderType[bodySource.idType, sym]; isBTI: BOOLEAN _ FALSE; WITH entryTypeBody: sym.seb[entrySEI] SELECT FROM cons => SELECT TRUE FROM bodySource.constant AND NOT bodySource.extended => WITH etb: entryTypeBody SELECT FROM transfer => SELECT etb.mode FROM proc, signal, error, program => isBTI _ TRUE; ENDCASE => NULL; ENDCASE => NULL; bodySource.constant AND bodySource.extended => WITH etb: entryTypeBody SELECT FROM transfer => SELECT etb.mode FROM proc => isBTI _ TRUE; ENDCASE => NULL; ENDCASE => NULL ENDCASE => NULL; ENDCASE => ERROR MobError["Can't happen: UnderType returned a non-cons sei"]; IF isBTI THEN BEGIN bodyTarget.idInfoAndValue _ NEW [MobAccess.BlockDesc _ [MakeBTH[seh.mob, LOOPHOLE[bodySource.idInfo]], LOOPHOLE[bodySource.idValue]]]; GOTO installed; END; END; IF bodySource.constant THEN -- we are dealing with a constant BEGIN bodyTarget.idInfoAndValue _ NEW[MobAccess.ConstVal _ [LOOPHOLE[bodySource.idValue]]]; GOTO installed; END; BEGIN bitSize: CARD _ LOOPHOLE[bodySource.idInfo, CARD]; -- size of field (in bits) bitOffset: INT _ LOOPHOLE[bodySource.idValue, INT]; -- offset of field from the appropriate base (in bits) bodyTarget.idInfoAndValue _ NEW[MobAccess.FieldDesc _ [bitSize, bitOffset]]; GOTO installed; END; EXITS installed => NULL; END; ENDCASE => ERROR MobError["can't happen: we just made it the other way"]; ENDCASE => NULL; END; IF seh = NIL THEN RETURN[NIL]; IF seh.ser = NIL THEN ExamineMob[seh.mob, Inner]; RETURN[seh.ser] END; MyifyBitOrder: ARRAY Symbols.BitOrder OF MobAccess.BitOrder = [msBit: msBit, lsBit: lsBit]; GetMobForSEH: PUBLIC PROC[seh: SEH] RETURNS[MobCookie] = {RETURN[seh.mob]}; GetSeiForSEH: PUBLIC PROC[seh: SEH] RETURNS[sei: Symbols.SEIndex] = {RETURN[seh.sei]}; UnderType: PROC[sei: Symbols.SEIndex, sym: SymbolTableBase] RETURNS [Symbols.SEIndex] = TRUSTED BEGIN DO WITH se: sym.seb[sei] SELECT FROM id => IF se.idType = Symbols.typeTYPE THEN {sei _ LOOPHOLE[se.idInfo]; LOOP}; cons => RETURN [sei]; ENDCASE; ERROR MobError["BadMobContents"]; ENDLOOP; END; SEHToRope: PROC[seh: SEH, depth: INT] RETURNS[Rope.ROPE] = BEGIN ser: SER _ FetchSER[seh]; st: IO.STREAM _ IO.ROS[]; putDepth: PROC[d: INT_0] = {FOR I: INT IN [0..depth+d) DO IO.PutF[st, " "] ENDLOOP}; rope: PROC[r: Rope.ROPE, d: INT _ 0] = {putDepth[d]; IO.PutRope[st, r]}; put: PROC[d: INT, f: Rope.ROPE, v1, v2, v3, v4, v5: IO.Value _ [null[]]] = BEGIN putDepth[d]; IO.PutF[st, f, v1, v2, v3, v4, v5]; END; put[0, "sei = %g\N", IO.rope[Convert.RopeFromCard[LOOPHOLE[seh.sei]]]]; WITH ser.body SELECT FROM id: REF id BodySE => BEGIN put[0, "id = %g\N", [rope[id.hash]]]; put[0, "ctx = %g\N", [rope[IF id.idCtx = NIL THEN "NIL" ELSE Convert.RopeFromCard[LOOPHOLE[id.idCtx.ctx]]]]]; SELECT id.special FROM normal => rope[" normal\N"]; globalLink => rope[" globalLink\N"]; staticLink => rope[" staticLink\N"]; frameExtension => rope[" frameExtension\N"]; memoryLink => rope[" memoryLink\N"]; returnLink => rope[" returnLink\N"]; ENDCASE => rope[" unknown special\N"]; IF id.flags.valid THEN BEGIN IF id.flags.used THEN rope[" used"] ELSE rope[" not-used"]; IF id.flags.addressed THEN rope[" addressed"] ELSE rope[" not-addressed"]; IF id.flags.assigned THEN rope[" assigned"] ELSE rope[" not-assigned"]; IF id.flags.upLevel THEN rope[" upLevel\N"] ELSE rope[" not-upLevel\N"]; END; END; cons: REF cons BodySE => rope["cons\N"]; ENDCASE => rope["unknown ser\N"]; RETURN[IO.RopeFromROS[st]]; END; RopeHolder: TYPE = REF RopeHolderBody; RopeHolderBody: TYPE = RECORD[rope: Rope.ROPE]; RopeForName: PROC[cookie: MobCookie, mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase, name: Symbols.Name] RETURNS[Rope.ROPE] = BEGIN IF name = Symbols.nullName THEN RETURN[NIL] ELSE TRUSTED BEGIN ropeHolder: RopeHolder _ NARROW[CardTab.Fetch[cookie.stringTable, sym.htb[name].ssIndex].val]; IF ropeHolder # NIL THEN RETURN[ropeHolder.rope] ELSE BEGIN offset: CARDINAL _ sym.htb[name-Symbols.HTRecord.SIZE].ssIndex+1; ss: ConvertUnsafe.SubString _ [ base: sym.ssb, offset: offset, length: sym.htb[name].ssIndex - offset]; rope: Rope.ROPE; IF ss.offset > ss.base.length OR ss.length > CARD[ss.base.length-ss.offset] THEN ERROR MobError["bogus name"]; rope _ ConvertUnsafe.SubStringToRope[ss]; -- The current DMachine Cedar version of this routine allocates new storage for the rope. I.E., we do not end up pointing back into the symbol table. This is good, because if we ended up pointing back into the symbol table, we would be in deep trouble if the symbol table left the symbol table cache. ropeHolder _ NEW[RopeHolderBody_[rope]]; IF NOT CardTab.Insert[cookie.stringTable, sym.htb[name].ssIndex, ropeHolder] THEN ERROR MobError["MobAccessImpl confused (by concurrent access?)"]; RETURN[rope]; END; END; END; ViewMob: Commander.CommandProc = BEGIN args: CommandTool.ArgumentVector _ CommandTool.Parse[cmd]; path: PFSNames.PATH _ PFS.PathFromRope[args[1]]; fileSet: SystemInterface.FileSet _ SystemInterface.CreateFileSet[]; BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet]; file: SystemInterface.CirioFile _ SystemInterface.GetCirioFile[fileSet, path]; mob: MobCookie _ CreateMobCookie[file]; inner: PROC[mobHandle: MobUtilDefs.MobHandle, mobBase: MobDefs.MobBase, sym: SymbolTableBase] = BEGIN ERROR; -- so that we can look around with the debugger END; ExamineMob[mob, inner]; END; SystemInterface.CloseFileSet[fileSet]; END; Commander.Register["ViewMob", ViewMob]; END..  MobAccessImpl.mesa Copyright Ó 1991 by Xerox Corporation. All rights reserved. Sturgis, March 1, 1990 10:16 am PST Last tweaked by Mike Spreitzer on December 17, 1991 9:42 am PST Coolidge, July 17, 1990 2:45 pm PDT Laurie Horton, November 30, 1990 11:49 am PST Note: one can learn a lot by looking at [PCedar2.0]MobMapperImpl.mesa MobCookies This implementation holds them open forever. We probably want to do better. In principle, they need only be in memory during an ExamineMob call. the following fields are valid only when the mob is in memory the following values are used for correcting coded index values that appear in DotO files the following value is used to accelerate validity checks on coded btis. the following fields are valid at all times the following could be delayed until an ExamineMob call but it must be protected by an UNWIND => SystemInterface.ReleaseStreamForFile[f, stream] for the convenience of clients this is adapted from [PCedar2.0]CcDeps.mesa MobStampFromTime The following is copied from [PCedar1.2]MobUtilities.mesa PBasics.Fill[where: vmh.pointer, nWords: allocatedWord32s, value: CARD.LAST]; actually, MobMapper.AlterMob will already have made the above check, so we should never fail. Following is adapted from [PCedar1.2]KLister.mesa ProcessSymbols Body Tables See numerous comments on MakeSEHFromCodedSei. They apply here with slight variations. This Loophole is effectively what SymbolOpsExtras.CBTIndexFromCard does. we accept this BTI if it bounds checks, we can find our way to the root from it, and we can find our way back to it from the root. We maintain an accelerator in the cookie, so that we do not necessarily have to go all the way back to the root each time. I believe that Mobs have an even more conservative limit than 15 we are not the root, nor are we a recent parent, so find our parent more than 1000 blocks in a module? now see if we can find ourselves from our supposed parent more than 1000 blocks in a module? this is what mob.sym.bb[card] would deliver addr too low addr far too high (this check will not prevent a bad pointer that is too close to the end of the table) generated depth first Note: we shift in the opposite direction from that which we would shift during decoding Module Directory Context Tables this is what mob.sym.seb[card] would deliver addr too low addr far too high (this check will not prevent a bad pointer that is too close to the end of the table) typical use in the D-machine debugger IO.PutRope[&H.tsOutStream, MobAccessImpl.CTXToRope[ctx, 0]] Semantic Entries code (my own invention) This code assumes that a codedSei is obtained from an octal encoding of the offset of an se entry from the start of the se table (i.e., sei-seNull). Further, we assume that this subtraction followed by subsequent conversion into octal was performed in the same addressing units as on the machine on which the Mob was written. Most of this computation must be inside Inner so that mob.leftShift and mob.rightShift will be valid the following shifts are suggested by code in MobMapperImpl further: the are are able to perform this correction here, in MobAccessImpl, rather than in DotOAccess because we assume that the C file (from which the DotO file was ultimately obtained) was written at the same time (and hence on the same machine) as this Mob file. Hence, the corrections for addressing unit size will be the same for both files. In addition, we must determine the correction from the Mob file, because there is no correction information recorded in the DotO file. The above computation is adapted from SymbolOpsExtrasImpl.SEIndexFromOffset, as suggested by MSImplE.C2CParse Note: we shift in the opposite direction from that which we would shift during decoding returns NIL if doesn't check checks to see if tentativeSei leads to a (supposed) context that includes self. This is not a perfect check, but it is pretty good. Requires a lot of accidents to succeed if the tentativeSei is actually incorrect. Further, we don't have to depend on the client supplying a name. we scan through the context looking for ourselves we found ourselves This check is only a bounds check, and is not precise at that. So, the contents of the record should not be trusted. this is what mob.sym.seb[card] would deliver addr too low addr far too high (this check will not prevent a bad pointer that is too close to the end of the table) This check is complete, the name can be trusted if no signal generated. Hence the string pointer can be followed without checking. addr too low addr far too high (this check will not prevent a bad pointer that is too close to the end of the table) addr not exactly on an entry Note: I don't think that I can remove the two loopholes in this procedure, since [Mimosa]Mimosa>SymbolOpsImpl.UnderType contains a LOOPHOLE under similar circumstances. delayed fill in of the idInfoAndValue field (We delay because we must compute the idType SEH first, and we can't guarantee the order in which the fields are computed) (Further, as this is a complicated computation, it must be done offline, either in a procedure, or a separate statement.) if we get here, then there is an idInfoAndValue field to be filled in first we check to see if we are dealing with a TYPE name lets check to see if it is a bti This computation is adapted from [PCedar2.0]MobMapperImpl.AlterSERecord2 not a type or bti if the constant occupies one word or less, then the following will be meaningful. Otherwise we should examine the extension table? I think that we are dealing with a field offset, either a variable with an offset from the frame pointer (valid only if in the frame extension, then it is really an offset within the frame extension) or a field in a record (in which case it is an offset from the start of the record). I may still be missing some cases. One might be able to sort them out by looking at [PCedar2.0]MobMapperImpl.AlterSERecord2, although that code is really trying to decide whether to do some alterations or not, and stops its analysis as soon as it knows. Names Experimental for the moment We assume that this will be called during the fetching of some symbol table record. WE MUST reduce the number of params to what we actually need for debugging main code example for using ViewMob ViewMob Test.mob Ê4&•NewlineDelimiter ™codešœ™K™Kšœœ ˜K˜——™K™K™Kšœœ œ˜Kšœ œ˜$K˜K˜Kšœœœ ˜šœ œœœ˜Kšœ˜K˜Kšœœ˜ —K˜š žœœœ(œœ˜Nšœ˜Kšœœœ˜Kšœœ˜&——K˜šžœœ(œœ˜MKšœ œœ˜=Kšœœœ+˜>K˜šœœœœ˜ K˜—Kšœœœ˜%Kšœœ-œœ<˜yKšœ˜—K˜š ž œœœœœ˜6Kšœœ*˜3—K˜šžœœ7œ˜wKš˜š œœœ œœœ˜EKšœ,™,—Kš œ œœœœœ˜^Kšœ œ˜Ešœ˜Kšœ ™ Kšœ˜—šœ.˜4Kšœg™gKšœ˜—Kšœ˜Kšœ˜—K˜Kšžœœœ˜0K˜šžœœœœ˜>Kš˜Kšœ œœ˜-Kšœ œœ˜-Kšœ˜Kšœ˜K˜—šžœœœœ˜:Kš˜Kšœœœ˜+Kšœ"œ ˜4Kšœœ$˜8Kšœ˜—K˜š ž œœœœœœ˜2Kš˜šžœœU˜gKš˜Kšœœ0˜8Kšœ5˜5Kšœ œ!˜1šœœ˜&šœœ#˜Kšœ˜šœ˜K˜#K˜$K˜Kšœ!˜!Kšœ.˜.K˜——šœœ#˜>Kšœ˜Kšœ:˜:—šœœ#˜9Kšœ˜Kšœ˜—Kšœœ'˜7—Kšœ˜—Kš œœœœœ˜Kšœ œœ˜4Kšœ ˜Kšœ˜—K˜š ž œœœœœ ˜;Kšœœ ˜K˜—š ž œœœœœ˜BKšœœ ˜K˜—K˜˜™%Kšœ9™;——š ž œœœ œœœ˜Kš˜Kšœ œœ˜,Kšœ œœ˜,Kšœ˜Kšœ˜K˜—šžœœœœ˜:Kš˜Kšœœœ˜*Kšœ"œ ˜4Kšœœ$˜8Kšœ˜K˜K™Kšžœˆœ™±—š žœœœœœœ˜.Kš˜šžœœU˜gKš˜Kšœœœ5œœ œ)œœ@˜öK˜šœ œ ˜šœœœ˜-šœœ˜Kšœ-˜-Kšœ3˜3Kšœ/˜/Kšœ%˜%Kšœ&˜&KšœœŸ˜'Kšœ?˜?K˜Kšœ˜šœ œ œ˜#Kšœ œ˜KšœHœ˜NKšœ%˜%Kšœ œ7˜HKšœœ-˜=——šœœ˜K˜šœ œ œ˜%Kšœœ˜'šœ œ˜%K˜K˜K˜—Kšœ œ)˜6Kšœ œ,˜;Kšœœ'˜2šœœ˜/K˜Kšœ+˜+K˜K˜K˜K˜K˜—šœ œ˜'Kšœ˜Kšœ+˜+Kšœ'˜'Kšœ˜šœ˜Kšœ"˜"Kšœ"˜"Kšœ˜Kšœ˜Kšœ(˜(Kšœ˜Kšœ˜Kšœ˜—Kšœ˜K˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜šœ œ œ˜%Kšœ œ˜Kšœ*˜*Kšœœ6˜F——šœœ˜!Kšœ(˜(Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜K˜—šœ œ˜%Kšœ4˜4Kšœ,˜,Kšœ˜Kšœ*˜*—šœ œ˜-Kšœ4˜4Kšœ'˜'Kšœ'˜'Kšœ˜—šœ œ˜+Kšœ˜šœœ ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ ˜ Kšœœ1˜A—Kšœ&˜&Kšœ(˜(Kšœ˜—šœœ˜/Kšœ'˜'Kšœ˜Kšœ˜—šœ œ˜%Kšœ)˜)Kšœ&˜&šœ˜Kšœ&˜&Kšœ˜Kšœ˜Kšœ˜—Kšœ5˜5Kšœ˜Kšœ'˜'Kšœ˜—šœ œ˜+Kšœ.˜.Kšœ&˜&Kšœ4˜4Kšœ˜Kšœ˜Kšœ˜Kšœ'˜'Kšœ˜—šœ œ˜+Kšœ*˜*Kšœ.˜.Kšœ1˜1—šœ œ˜+Kšœ˜Kšœ˜Kšœ˜Kšœ,˜,K˜K˜—šœ œ˜'Kšœ˜Kšœ˜Kšœ!˜!—šœœ˜#Kšœ˜Kšœ˜Kšœ˜—Kšœœ˜%Kšœœ˜%Kšœœ*˜:—Kšœ˜—Kšœœ'˜7˜K™+Kšœ-œJ™z—K™y—šœœ˜-šœœœ˜/˜Kš˜KšœE™EK˜Kšœ/œ™8K˜šœ&˜,š˜Kšœœ˜9Kšœ œ˜-Kšœœ"œ˜`Kšœ ˜Kšœ˜——K˜K˜™ KšœP™P—™Kš˜Kšœ>˜>Kšœœœ˜šœ"œ˜1˜šœœ˜šœœœ˜2šœœ˜#šœ œ ˜ Kšœ(œ˜-Kšœœ˜—Kšœœ˜——šœœ˜.šœœ˜#šœ œ ˜ Kšœœ˜Kšœœ˜—Kšœ˜——Kšœœ˜——Kšœœ=˜M—K˜šœ˜ Kš˜Kšœœ*œœ˜†Kšœ ˜Kšœ˜—Kšœ˜—K˜K™K™šœœ¢!˜=K™ƒKš˜Kšœœœ˜UKšœ ˜Kšœ˜—K™K™™œK˜Kš˜Kš œ œœœŸ¢˜MKšœ œœœ¢6˜jKšœœ-˜LKšœ ˜Kšœ˜—K˜Kšœ†™†˜K™—š˜Kšœ œ˜—K˜Kšœ˜—Kšœœ9˜I—Kšœœ˜—K˜K˜Kšœ˜—K˜K˜—Kš œœœœœ˜Kšœ œœ˜1Kšœ ˜Kšœ˜—K˜Kšž œœœ3˜[K˜š ž œœœœœ ˜8Kšœœ ˜K˜—š ž œœœœœ˜CKšœœ ˜K˜—šž œœ-œ˜_Kš˜š˜šœœ˜!Kš œœœœ œ˜MKšœœ˜Kšœ˜—Kšœ˜!Kšœ˜—Kšœ˜—K˜š ž œœœ œœœ˜:Kš˜Kšœœ˜Kš œœœœœ˜Kšœ œœœžœœœœœœ˜Tšœœ œœ˜&Kšœœ˜!—š œœœ œœ˜JKš˜K˜ Kšœ!˜#Kšœ˜—Kšœœœ ˜Gšœ œ˜šœœ ˜Kš˜K˜%Kš œœ œœœœ˜mšœ ˜Kšœ˜Kšœ$˜$Kšœ$˜$Kšœ,˜,Kšœ$˜$Kšœ$˜$Kšœ˜&—šœ˜KšÐkt˜Kšœœœ˜;Kšœœœ˜JKšœœœ˜GKšœœœ˜HKšœ˜—Kšœ˜—Kšœœ˜(Kšœ˜!—Kšœœ˜Kšœ˜K˜——™K™K˜Kšœ œœ˜&Kšœœœ œ˜/˜K™SKšœœ5™<—šž œœzœœ˜ŸKš˜š œœœœœ˜8Kš˜Kšœœ@˜_Kšœœœœ˜0šœ˜Kš˜Kšœœ!œ ˜A˜K˜Kšœ˜Kšœ(˜(—Kšœ œ˜Kš œœ œœœ˜nKšœ*¢®˜ØKšœ œ˜(KšœœGœœ<˜“Kšœ˜ Kšœ˜—Kšœ˜—Kšœ˜——K˜K˜™ K˜šžœ˜!Kš˜Kšœ:˜:Kšœœœ˜0šœC˜CKšœœœ*˜=KšœN˜NKšœ'˜'šœœT˜_Kš˜KšœŸ/˜6Kšœ˜—Kšœ˜Kšœ˜—Kšœ&˜&Kšœ˜——K˜™ K˜Kšœ'˜'˜™K™Kš¡™———Kšœ˜——…—¡dî–