RMTWModules.mesa
Copyright Ó 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved.
Sturgis, April 1, 1990 2:58 pm PDT
Last tweaked by Mike Spreitzer on April 10, 1992 7:28 pm PDT
Last changed by Theimer on November 29, 1989 4:07:25 am PST
Linda Howe December 28, 1989 8:25:20 am PST
Coolidge, August 15, 1990 9:35 am PDT
Laurie Horton, February 25, 1993 4:24 pm PST
Philip James, January 6, 1992 10:47 am PST
Katsuyuki Komatsu January 2, 1993 5:50 pm PST
DIRECTORY
Basics USING[Comparison],
BasicTime USING[earliestGMT, GMT, Now, Period],
CirioNubAccess USING[CreateRemoteNub, DestroyNub, Handle],
Commander USING[CommandProc, Register],
CommanderOps USING[NextArgument, NumArgs],
CommandTool USING[ArgumentVector, Parse],
Convert USING[CardFromRope, Error],
ObjectFiles USING[BracketNest, BracketPair, CreateParsed, FileSegmentPC, FindVersionStamp, GetBracketNestForPC, GetLineNumForPC, GetModuleInfo, GetObjectFile, GetPCForLineNum, GetPCRange, Module, ModuleFromParsedAndPC, ModuleInfo, Parsed, PCRange, VersionStampInfo],
IO USING[card, EndOf, GetLine, PutF, PutFLR, PutFR, rope, STREAM],
List USING[Sort],
LoadStateAccess USING[BasicPCInfo, CreateLoadStateHandle, GetBasicPCInfo, GetLoadedModuleInfoFromAbsPC, GetLoadedModuleInfoFromStemName, GetRopeForBasicPCInfo, GetRopeListForBasicPCInfo, GetRopeListForLoadedModuleInfo, LoadedModuleInfo, LoadStateHandle],
MobAccess USING[ComputeSourceVersionStamp, CreateMobCookie, MobCookie, MobError, ReadMobVersionStamp, ReadSourceVersionStamp],
MobDefs USING[NullVersion, VersionStamp],
MobObjectFiles USING[CreateJointMobParsedInfo, JointMobParsedInfo],
MorePfsNames,
NewRMTW USING[CedarBreakAddress, CedarSourcePosition, LoadedModuleInfo],
PFS,
PFSNames,
RMTWBackdoor,
RMTWPrivate USING [NameParts],
PBasics USING[BITXOR, LongNumber],
RefTab USING[Create, Fetch, Key, Ref, Store],
Rope,
RopeParts,
RuntimeError USING[BoundsFault],
SourceFileOpsExtras,
SystemInterface USING[CirioFile, CirioFileInfo, CloseFileSet, CreateFileSet, FileSet, GenCirioFilesForInfo, GenVersionMapFilesForInfo, GetCirioFile, GetFileInfo, GetNameOfFile, GetStreamForFile, ReleaseStreamForFile, ShowReport, VersionStampToUniqueID],
UserProfile USING [Token];
In this module we tackle the issue of mesa modules. A mesa module is (roughly) a quintuple:
mesa file, mob file, C file, object file (perhaps component), and memory locations.
These files must satisfy certain consistency conditions with respect to version stamps.
Using a module one can compute the absolute address at which to set a break point and one can compute a source position.
An issue not resolved in current implementation: there may be more than one mob with the same source version stamp. I simply take the first one I find.
STILL NEED loaded version of this stuff and the action routines
NOTE: November 10, 1989 10:42:22 am PST. heavy changes underway. Pervious implementation got mesaSOurce => dotO working. New implementation recognizes source version stamps, and I am editing in GetMesa. Must repair getMob to either check source version stamp, or mob versoin stamp, depending on which is present.
Note: April 9, 1990 3:40:24 pm PDT. more heavy changes underway. Issue is the inability to set breakpoints starting from a mesa file for a previously unvisited module. This frequntly results in long serach times involving finding embedded dot Os that always seem to fail. In the past, the searces were short, always seemed to fail, but the breakpoint succeeded. Now the searches are long, and breakpoints fail to be planted. First step: reorder procedures so that all calls go "down" and all public procs are at top.
RMTWModules:
CEDAR
MONITOR
LOCKS modules USING modules: CedarModuleSet
IMPORTS BasicTime, CirioNubAccess, Commander, CommanderOps, CommandTool, Convert, IO, List, LoadStateAccess, MobAccess, MobObjectFiles, MorePfsNames, ObjectFiles, PBasics, PFS, PFSNames, RefTab, Rope, RopeParts, RuntimeError, SourceFileOpsExtras, SystemInterface, UserProfile
EXPORTS NewRMTW, RMTWBackdoor, RMTWPrivate =
BEGIN OPEN LSA:LoadStateAccess, ObjF:ObjectFiles, MA:MobAccess, MOF:MobObjectFiles, MPfsN:MorePfsNames, RMTWPrivate;
ROPE: TYPE ~ Rope.ROPE;
PATH: TYPE ~ PFSNames.PATH;
CirioFile: TYPE = SystemInterface.CirioFile;
CedarModuleSet: TYPE = REF CedarModuleSetBody;
CedarModuleSetBody:
PUBLIC
TYPE =
MONITORED
RECORD[
fileSet: SystemInterface.FileSet,
searchPaths: LIST OF PATH,
otherDirectories: LIST OF PATH,
remoteServer: Rope.ROPE,
table: RefTab.Ref,
loadedTable: RefTab.Ref,
flushTime: BasicTime.GMT,
vsHash: VSHashTable,
defMobs: VSHashTable];
the following extra level of indirection allows for the discovery that two partially built modules are actually the same.
These modules will be looked up starting from a mesaSource or starting from a Module.
CedarModule: TYPE = REF CedarModuleHandle;
CedarModuleHandle: TYPE = REF CedarModuleBody;
CedarModuleBody:
TYPE =
RECORD[
moduleSet: CedarModuleSet,
mobStamp: REF MobDefs.VersionStamp,
sourceStamp: REF MobDefs.VersionStamp,
possiblePrincipalDirectories: LIST OF PATH,
originalPossibleNameStems: LIST OF PATH,
possibleNameStems: LIST OF PATH,
failureTime: BasicTime.GMT,
mesaSourceFailed: BOOLEAN,
mobFileFailed: BOOLEAN,
mobFailed: BOOLEAN,
cSourceFailed: BOOLEAN,
jmpiFailed: BOOLEAN,
moduleFailed: BOOLEAN,
wholeFailed: BOOLEAN,
loadedJmpiFailed: BOOLEAN,
mesaSource: CirioFile,
jmpi: MOF.JointMobParsedInfo,
mobFile: CirioFile,
mob: MA.MobCookie,
cInfo: CFileInfo,
module: ObjF.Module,
whole: ObjF.Parsed,
loadedJmpi: MOF.JointMobParsedInfo,
loadedModule: ObjF.Module,
loadedWhole: ObjF.Parsed,
loadedModuleInfo: REF LoadStateAccess.LoadedModuleInfo];
no need for entry as this is a create proc
CreateCedarModuleSet:
PUBLIC
PROC[fileSet: SystemInterface.FileSet, remoteServer: Rope.
ROPE ←
NIL]
RETURNS[CedarModuleSet] =
BEGIN
table: RefTab.Ref ← RefTab.Create[];
loadedTable: RefTab.Ref ← RefTab.Create[];
vsHash: VSHashTable ← CreateVSHashTable[];
defMobs: VSHashTable ← CreateVSHashTable[];
RETURN[NEW[CedarModuleSetBody←[ , fileSet, NIL, NIL, remoteServer, table, loadedTable, BasicTime.Now[], vsHash, defMobs]]];
END;
ResetSearchPaths:
PUBLIC
ENTRY
PROC[modules: CedarModuleSet, searchPaths:
LIST
OF
PATH, flushTime: BasicTime.
GMT] =
BEGIN
ENABLE UNWIND => NULL;
modules.searchPaths ← searchPaths;
modules.flushTime ← flushTime;
END;
FlushUnknownFileCache:
PUBLIC
ENTRY
PROC[modules: CedarModuleSet, flushTime: BasicTime.
GMT] =
BEGIN
ENABLE UNWIND => NULL;
modules.flushTime ← flushTime;
END;
CedarSourcePosition: TYPE = NewRMTW.CedarSourcePosition;
GetCedarSourcePosition:
PUBLIC
ENTRY
PROC[modules: CedarModuleSet, loadedModule:
REF LoadStateAccess.LoadedModuleInfo, absPC:
CARD]
RETURNS[
REF CedarSourcePosition] ~ {
ENABLE UNWIND => NULL;
module: CedarModule ~ GetCedarModuleForLoadedModule[modules, loadedModule];
moduleRelativePC: CARD ~ IF loadedModule # NIL THEN absPC - (loadedModule.lsi[text].base + loadedModule.moduleRelativeBaseAddr) ELSE 0;
RETURN[ComputeCedarSourcePosition[module, [[0, ""], moduleRelativePC]]]};
ComputeCedarSourcePosition:
PROC[module: CedarModule, spc: ObjF.FileSegmentPC]
RETURNS[
REF CedarSourcePosition] =
BEGIN
IF module = NIL THEN RETURN[NEW[CedarSourcePosition←[spc.relPC, NIL, 0, NIL, 0, "unknown mesa module"]]]
ELSE
BEGIN
embeddedModule: ObjF.Module ← GetModule[module];
moduleInfo: REF ObjF.ModuleInfo ← IF embeddedModule # NIL THEN ObjF.GetModuleInfo[embeddedModule] ELSE NIL;
parsedRelativePC: ObjF.FileSegmentPC ← [[0, ""], IF moduleInfo # NIL THEN 0--pj moduleInfo.startPC--+spc.relPC ELSE 0];
cLine: CARD ← IF moduleInfo # NIL THEN ObjF.GetLineNumForPC[embeddedModule, parsedRelativePC] ELSE 0;
cInfo: CFileInfo ← GetCFileInfo[module];
cFile: CirioFile ← IF cInfo # NIL THEN cInfo.file ELSE NIL;
mesaPosition: CARD ← IF cInfo # NIL THEN LookupCLineNum[cInfo, cLine] ELSE 0;
remarks: Rope.ROPE ← NIL;
IF embeddedModule #
NIL
AND cInfo #
NIL
THEN
-- check back with parsed
BEGIN
correspondingcLine: CARD ← LookupMesaSourcePos[cInfo, mesaPosition];
correspondingPC: ObjF.FileSegmentPC ← ObjF.GetPCForLineNum[embeddedModule, correspondingcLine];
originalNest: ObjF.BracketNest ← ObjF.GetBracketNestForPC[embeddedModule, correspondingPC];
originalPair: ObjF.BracketPair ← IF originalNest = NIL THEN NIL ELSE originalNest.rest.first;
pcRange: ObjF.PCRange ← IF originalPair = NIL THEN [0, 0] ELSE ObjF.GetPCRange[originalPair];
IF originalPair = NIL OR correspondingPC.relPC < pcRange.first OR pcRange.limit <= correspondingPC.relPC THEN remarks ← IO.PutFR["Source location is potentially erroneous (because it corresponds to c line number %g as well as %g, and the two are in distinct C blocks).", [cardinal[correspondingcLine]], [cardinal[cLine]]];
END;
RETURN[NEW[CedarSourcePosition←[spc.relPC, GetMesaFile[module], mesaPosition, cFile, cLine, remarks]]];
END
END;
no need for ENTRY because info^ is a constant
GetRopesForSourcePosInfo:
PUBLIC
PROC[info:
REF CedarSourcePosition]
RETURNS[
LIST
OF Rope.
ROPE] =
BEGIN
ropes: LIST OF Rope.ROPE ← NIL;
mesaName: PATH ← IF info.mesa = NIL THEN PFSNames.EmptyPath ELSE SystemInterface.GetNameOfFile[info.mesa];
cName: PATH ← IF info.cFile = NIL THEN PFSNames.EmptyPath ELSE SystemInterface.GetNameOfFile[info.cFile];
IF info.remarks # NIL THEN ropes ← CONS[info.remarks, ropes];
ropes ← CONS[IO.PutFR[" line in %g is %g", IO.rope[PFS.RopeFromPath[cName]], IO.card[info.cLineNum]], ropes];
IF info.mesaPosition # 0 THEN ropes ← CONS[IO.PutFR[" position in %g is %g", IO.rope[PFS.RopeFromPath[mesaName]], IO.card[info.mesaPosition]], ropes];
IF info.mesaPosition = 0 THEN ropes ← CONS[IO.PutFR[" position is somewhere in %g", IO.rope[PFS.RopeFromPath[mesaName]]], ropes];
ropes ← CONS[IO.PutFR["for relative pc: %g", IO.card[info.relativePC]], ropes];
RETURN[ropes]
END;
LoadedModuleInfo: TYPE = NewRMTW.LoadedModuleInfo;
LoadedModule: TYPE = REF LoadedModuleBody;
LoadedModuleBody:
TYPE =
RECORD[
module: CedarModule,
loadedModule: REF LoadStateAccess.LoadedModuleInfo,
loadedModuleFailedTime: BasicTime.GMT];
GetLoadedModuleInfo:
PUBLIC
ENTRY
PROC[modules: CedarModuleSet, loadedModule:
REF LoadStateAccess.LoadedModuleInfo]
RETURNS[
REF LoadedModuleInfo] =
BEGIN
ENABLE UNWIND => NULL;
module: CedarModule ← GetCedarModuleForLoadedModule[modules, loadedModule];
IF module = NIL THEN RETURN[NIL]
ELSE
RETURN[
NEW[LoadedModuleInfo←[
jmpi: GetLoadedJMPI[module],
mob: GetMob[module],
loadedModule: loadedModule]]];
END;
CedarBreakAddress: TYPE = NewRMTW.CedarBreakAddress;
NIL means failure to compute
GetAbsAddressForBreak:
PUBLIC
ENTRY
PROC[modules: CedarModuleSet, mesa: CirioFile, loadState: LoadStateAccess.LoadStateHandle, sourcePos:
CARD]
RETURNS[
REF CedarBreakAddress] =
BEGIN
ENABLE UNWIND => NULL;
lm: LoadedModule ← GetLoadedModuleForMesa[modules, mesa, loadState];
IF lm = NIL OR lm.module = NIL OR lm.loadedModule = NIL THEN RETURN[NIL]
ELSE
BEGIN
cInfo: CFileInfo ← GetCFileInfo[lm.module];
IF cInfo = NIL THEN RETURN[NIL]
ELSE
BEGIN
cLineNum: CARD ← LookupMesaSourcePos[cInfo, sourcePos];
parsedRelativePC: ObjF.FileSegmentPC ← ObjF.GetPCForLineNum[lm.loadedModule.module, cLineNum];
correspondingCLineNum: CARD ← ObjF.GetLineNumForPC[lm.loadedModule.module, parsedRelativePC];
correspondingMesaPos: CARD ← LookupCLineNum[cInfo, correspondingCLineNum];
moduleRelPC: CARD ← parsedRelativePC.relPC - lm.loadedModule.moduleRelativeBaseAddr;
absPC: CARD ← lm.loadedModule.lsi[text].base+parsedRelativePC.relPC;
RETURN[NEW[CedarBreakAddress←[mesa, sourcePos, cInfo.file, cLineNum, [[0, ""], moduleRelPC], correspondingCLineNum, correspondingMesaPos, lm.loadedModule, absPC]]];
END;
END
END;
no need for ENTRY because addr^ is constant
GetRopesForCedarBreakAddress:
PUBLIC
PROC[addr:
REF CedarBreakAddress]
RETURNS[
LIST
OF Rope.
ROPE] =
BEGIN
IF addr = NIL THEN RETURN[LIST["failed to set break"]]
ELSE
BEGIN
mesa: PATH ← SystemInterface.GetNameOfFile[addr.mesa];
cname: PATH ← SystemInterface.GetNameOfFile[addr.cFile];
rope1: Rope.ROPE ← IO.PutFR["setting break in %g at source pos = %g", IO.rope[PFS.RopeFromPath[mesa]], IO.card[addr.mesaPosition]];
rope2: Rope.ROPE ← IO.PutFR[" C line num = %g in %g", IO.card[addr.cLineNum], IO.rope[PFS.RopeFromPath[cname]]];
rope3: Rope.ROPE ← IO.PutFR[" module relative pos = %g", IO.card[addr.moduleRelativePC.relPC]];
rope4: Rope.ROPE ← IO.PutFR[" corresponding C line num = %g", IO.card[addr.correspondingCLineNum]];
rope5: Rope.ROPE ← IO.PutFR[" resulting mesa source pos = %g", IO.card[addr.correspondingMesaPosition]];
rope6: Rope.ROPE ← IO.PutFR[" abs pos = %g", IO.card[addr.absPC]];
RETURN[LIST[rope1, rope2, rope3, rope4, rope5, rope6]];
END;
END;
DefMobHolder: TYPE = RECORD[failureTime: BasicTime.GMT, mob: MA.MobCookie];
returns nil if can't be found
one should try later if search paths change
GetDefinitionMob:
PUBLIC
ENTRY
PROC[modules: CedarModuleSet, vs: MobDefs.VersionStamp, stem:
PATH ←
NIL]
RETURNS[
MA.MobCookie] =
BEGIN
ENABLE UNWIND => NULL;
vsKey: RefTab.Key ← CreateVSKey[vs, emptyRopePart];
mobRef: REF DefMobHolder ← NARROW[RefTab.Fetch[modules.defMobs.table, vsKey].val];
IF mobRef =
NIL
THEN
BEGIN
mobRef ← NEW[DefMobHolder←[modules.flushTime, NIL]];
IF NOT RefTab.Store[modules.defMobs.table, vsKey, mobRef] THEN ERROR;
END;
IF mobRef.mob =
NIL
AND BasicTime.Period[mobRef.failureTime, modules.flushTime] >= 0
THEN
BEGIN
foundMob: MA.MobCookie ← NIL; -- tentative
foundPossibleFile: CirioFile ← NIL; -- tentative
foundCreateTime: BasicTime.GMT ← BasicTime.earliestGMT; -- tentative
AcceptOneFile:
PROC [info: SystemInterface.CirioFileInfo]
RETURNS[thisIsIt:
BOOLEAN ←
FALSE] = {
possibleFile: CirioFile;
mob: MA.MobCookie;
mobStamp: MobDefs.VersionStamp;
possibleFile ← SystemInterface.GetCirioFile[modules.fileSet, info.fullName, info.uniqueID];
mob ←
MA.CreateMobCookie[possibleFile ! MobAccess.MobError => {
SystemInterface.ShowReport[IO.PutFR["\tbad mob %g", [rope[PFS.RopeFromPath[info.fullName]]] ], IF debugSearch THEN $urgent ELSE $debug];
GOTO failure}];
mobStamp ← MA.ReadMobVersionStamp[mob];
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\t?name=%g,\n\tmobStamp=%08x%08x.", [rope[PFS.RopeFromPath[info.fullName]]], [cardinal[mobStamp[0]]], [cardinal[mobStamp[1]]] ], $urgent];
foundMob ← mob;
foundPossibleFile ← possibleFile;
foundCreateTime ← info.uniqueID.egmt.time;
RETURN[TRUE];
EXITS failure => RETURN [FALSE]};
TryOneFile:
PROC[info: SystemInterface.CirioFileInfo]
RETURNS[thisIsIt:
BOOLEAN ←
FALSE] = {
possibleFile: CirioFile;
mob: MA.MobCookie;
mobStamp: MobDefs.VersionStamp;
possibleFile ← SystemInterface.GetCirioFile[modules.fileSet, info.fullName, info.uniqueID];
mob ←
MA.CreateMobCookie[possibleFile ! MobAccess.MobError => {
SystemInterface.ShowReport[IO.PutFR["\tbad mob %g", [rope[PFS.RopeFromPath[info.fullName]]] ], IF debugSearch THEN $urgent ELSE $debug];
GOTO failure}];
mobStamp ← MA.ReadMobVersionStamp[mob];
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\t?name=%g,\n\tmobStamp=%08x%08x.", [rope[PFS.RopeFromPath[info.fullName]]], [cardinal[mobStamp[0]]], [cardinal[mobStamp[1]]] ], $urgent];
IF vs = mobStamp
THEN {
foundMob ← mob;
foundPossibleFile ← possibleFile;
foundCreateTime ← info.uniqueID.egmt.time;
RETURN[TRUE]};
RETURN[FALSE];
EXITS failure => RETURN [FALSE]};
TryOneDir:
PROC[dir:
PATH] =
BEGIN
FIX: Use the PFS extension options when they're available.
mobFileNamePattern: PATH ← PFS.PathFromRope[Rope.Cat[PFS.RopeFromPath[stem], ".mob", "*"]].ExpandName[dir];
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching file pattern %g.", [rope[PFS.RopeFromPath[mobFileNamePattern]]] ], $urgent];
[] ← SystemInterface.GenCirioFilesForInfo[modules.fileSet, mobFileNamePattern, TryOneFile];
END;
SystemInterface.ShowReport[Rope.Cat["searching for mob for ", IF stem#NIL THEN PFS.RopeFromPath[stem] ELSE "???"], $normal];
IF stem=NIL THEN SystemInterface.ShowReport[IO.PutFR["\twith mobStamp=%08x%08x.", [cardinal[vs[0]]], [cardinal[vs[1]]] ], IF debugSearch THEN $urgent ELSE $normal];
IF stem#
NIL
THEN
FOR dirs:
LIST
OF
PATH ← modules.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundPossibleFile =
NIL
DO
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching search dir %g.", [rope[PFS.RopeFromPath[dirs.first]]] ], $urgent];
TryOneDir[dirs.first];
ENDLOOP;
IF foundPossibleFile =
NIL
THEN {
IF debugSearch THEN SystemInterface.ShowReport["\tSearching version maps.", $urgent];
IF stem#NIL
THEN foundPossibleFile ← SystemInterface.GenVersionMapFilesForInfo[modules.fileSet, $Intermediate, vs, LIST[stem], LIST[".mob"], TRUE, AcceptOneFile]
ELSE foundPossibleFile ← SystemInterface.GenVersionMapFilesForInfo[modules.fileSet, $Intermediate, vs, LIST[MPfsN.Cons1[MPfsN.ConstructComponent[["*"], [none]]]], LIST[".mob"], TRUE, AcceptOneFile];
};
IF stem#
NIL
THEN
FOR dirs:
LIST
OF
PATH ← modules.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundPossibleFile =
NIL
DO
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching other dir %g.", [rope[PFS.RopeFromPath[dirs.first]]] ], $urgent];
TryOneDir[dirs.first];
ENDLOOP;
IF foundPossibleFile =
NIL
THEN
BEGIN
mobRef.failureTime ← BasicTime.Now[];
SystemInterface.ShowReport[Rope.Cat["unable to find mob for ", IF stem#NIL THEN PFS.RopeFromPath[stem] ELSE "???"], $urgent];
END
ELSE
BEGIN
mobName: PATH ← SystemInterface.GetNameOfFile[foundPossibleFile];
parts: NameParts ← GetNamePartsFromFullPathName[mobName];
mobRef.mob ← foundMob;
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[mobName]], $normal];
END;
END;
RETURN[mobRef.mob];
END;
here we start assorted procedures that get loaded modules given various starts
GetLoadedModuleForMesa:
PROC[modules: CedarModuleSet, mesa: CirioFile, loadState: LoadStateAccess.LoadStateHandle]
RETURNS[LoadedModule] =
BEGIN
lm: LoadedModule ← NARROW[RefTab.Fetch[modules.loadedTable, mesa].val];
IF lm =
NIL
THEN
BEGIN
lm ← NEW[LoadedModuleBody←[NIL, NIL, modules.flushTime]];
IF NOT RefTab.Store[modules.loadedTable, mesa, lm] THEN ERROR;
END;
IF lm.loadedModule =
NIL
AND (BasicTime.Period[lm.loadedModuleFailedTime, modules.flushTime] >= 0)
THEN
BEGIN
mesaName: PATH ← SystemInterface.GetNameOfFile[mesa];
givenSourceStamp: MobDefs.VersionStamp ← MA.ComputeSourceVersionStamp[mesa];
parts: NameParts ← GetNamePartsFromFullPathName[mesaName];
stemRope: Rope.ROPE ← parts.nameStem;
module: CedarModule ← NIL;
lm.loadedModuleFailedTime ← BasicTime.Now[]; -- if needed
SystemInterface.ShowReport[IO.PutFR["Searching for loaded module %g created at %g (source stamp=%g).", [rope[stemRope]], [time[SystemInterface.GetFileInfo[mesa].uniqueID.egmt.time]], [rope[FmtStamp[givenSourceStamp]]] ], $normal];
IF parts.principalDirectory # PFSNames.EmptyPath THEN modules.otherDirectories ← AddAName[parts.principalDirectory, modules.otherDirectories];
FOR skip:
CARD ← 1
--despite comment under CirioNubAccess.LookupMatchingSymEntryByName, which is inconsistent with the general pattern, 0 and 1 find the same thing(MJS thinks at June 8, 1991)--, skip+1
DO
loadedModule: REF LoadStateAccess.LoadedModuleInfo ← LoadStateAccess.GetLoadedModuleInfoFromStemName[loadState, parts.nameStem, skip, modules];
IF loadedModule=
NIL
THEN {
SystemInterface.ShowReport[IO.PutFR["Giving up search for loaded module %g at skip=%g.", [rope[stemRope]], [cardinal[skip]] ], $normal];
EXIT};
module ← GetCedarModuleForLoadedModule[modules, loadedModule];
IF module#
NIL
THEN {
ldoPath: PATH ~ loadedModule.loadedFile.GetNameOfFile[];
ldoRope: Rope.ROPE ~ PFS.RopeFromPath[ldoPath];
[] ← GetMob[module];
IF module.sourceStamp=NIL THEN SystemInterface.ShowReport[IO.PutFR["Rejecting the one in %g of %g (found at skip=%g) for lack of source version stamp.", [rope[ldoRope]], [time[loadedModule.createTimeOfLoadedFile]], [cardinal[skip]] ], $normal]
ELSE
IF module.sourceStamp^ = givenSourceStamp
THEN {
lm.module ← module;
lm.loadedModule ← loadedModule;
SystemInterface.ShowReport[IO.PutFR["Accepting the one in %g of %g (found at skip=%g).", [rope[ldoRope]], [time[loadedModule.createTimeOfLoadedFile]], [cardinal[skip]] ], $normal];
RETURN [lm]}
ELSE SystemInterface.ShowReport[IO.PutFR["Rejecting the one in %g of %g (found at skip=%g) because source version stamp (%g) isn't right.", [rope[ldoRope]], [time[loadedModule.createTimeOfLoadedFile]], [cardinal[skip]], [rope[FmtStamp[module.sourceStamp^]]] ], $normal]
};
ENDLOOP;
END;
RETURN[lm];
END;
FmtStamp:
PROC [stamp: MobDefs.VersionStamp]
RETURNS [Rope.
ROPE]
~ {RETURN IO.PutFR["%08x%08x", [cardinal[stamp[0]]], [cardinal[stamp[1]]] ]};
GetCedarModuleForLoadedModule:
PROC[modules: CedarModuleSet, info:
REF LoadStateAccess.LoadedModuleInfo]
RETURNS[CedarModule] =
BEGIN
IF info =
NIL
THEN
RETURN[
NIL]
ELSE
BEGIN
tentative: CedarModule ← CreateCedarModuleFromModule[modules, info.parsed, info.module, info.possibleModuleFileNames];
IF tentative#
NIL
AND tentative.loadedModuleInfo=
NIL
THEN
tentative.loadedModuleInfo ← info;
RETURN[tentative];
END
END;
here we have the procedures that get a module from various starts
CreateCedarModuleFromMesa:
PROC[modules: CedarModuleSet, mesa: CirioFile]
RETURNS[CedarModule] =
BEGIN
sourceStamp: REF MobDefs.VersionStamp ← NEW[MobDefs.VersionStamp←MA.ComputeSourceVersionStamp[mesa]];
mesaName: PATH ← SystemInterface.GetNameOfFile[mesa];
parts: NameParts ← GetNamePartsFromFullPathName[mesaName];
base: RopeParts.RopePart ← RopeSequence.Fetch[RopeSequence.ParsePartToSeq[RopeParts.RopePart ← NARROW[parts], '.], 0];
base: RopeParts.RopePart ← RopeParts.InlineMake[parts.nameStem];
vsKey: RefTab.Key ← CreateVSKey[sourceStamp^, base];
module: CedarModule ← NARROW[RefTab.Fetch[modules.vsHash.table, vsKey].val];
IF module =
NIL
THEN
BEGIN
mesaName: PATH ← SystemInterface.GetNameOfFile[mesa];
parts: NameParts ← GetNamePartsFromFullPathName[mesaName];
module ← CreateEmptyCedarModule[modules];
module.possiblePrincipalDirectories ← LIST[parts.principalDirectory];
module.originalPossibleNameStems ← LIST[PFS.PathFromRope[parts.nameStem]];
module.possibleNameStems ← module.originalPossibleNameStems;
module.mesaSource ← mesa;
module.sourceStamp ← sourceStamp;
IF NOT RefTab.Store[modules.vsHash.table, vsKey, module] THEN ERROR;
END;
RETURN[module];
END;
CreateCedarModuleFromModule:
PROC[modules: CedarModuleSet, whole: ObjF.Parsed, embeddedModule: ObjF.Module, possibleModuleFileNames:
LIST
OF
PATH]
RETURNS[CedarModule] =
BEGIN
vsInfo: REF ObjF.VersionStampInfo ← ObjF.FindVersionStamp[embeddedModule];
recoveredStamp: REF RecoveredVersionStamp ← IF vsInfo = NIL OR Rope.IsEmpty[vsInfo.contents] THEN NIL ELSE ConvertDotOFormatVersionStampToMobFormat[vsInfo.contents];
mobStamp: REF MobDefs.VersionStamp ← IF recoveredStamp = NIL THEN NIL ELSE NEW[MobDefs.VersionStamp←recoveredStamp.mobStamp];
vsKey: RefTab.Key ← IF mobStamp = NIL THEN NIL ELSE CreateVSKey[mobStamp^, emptyRopePart];
module: CedarModule ← IF mobStamp = NIL THEN NIL ELSE NARROW[RefTab.Fetch[modules.vsHash.table, vsKey].val];
IF module =
NIL
THEN
BEGIN
moduleInfo: REF ObjF.ModuleInfo ← ObjF.GetModuleInfo[embeddedModule]; -- for SunOS5.x
IF mobStamp = NIL THEN RETURN[NIL];
module ← CreateEmptyCedarModule[modules];
module.module ← embeddedModule;
module.whole ← whole;
module.mobStamp ← mobStamp;
IF whole = moduleInfo.whole
THEN
-- normal case
BEGIN
FOR names:
LIST
OF
PATH ← possibleModuleFileNames, names.rest
WHILE names #
NIL
DO
parts: NameParts ← GetNamePartsFromFullPathName[names.first];
IF parts.nameStem.Length[] # 0 THEN module.originalPossibleNameStems ← AddAName[PFS.PathFromRope[parts.nameStem], module.originalPossibleNameStems];
IF parts.principalDirectory # PFSNames.EmptyPath THEN module.possiblePrincipalDirectories ← AddAName[parts.principalDirectory, module.possiblePrincipalDirectories];
now, lets see if we can learn anything about the dotO location that might be helpful later.
BEGIN
wholeFileName: PATH ← SystemInterface.GetNameOfFile[ObjF.GetObjectFile[whole]];
parts: NameParts ← GetNamePartsFromFullPathName[wholeFileName];
IF parts.principalDirectory # PFSNames.EmptyPath
THEN
BEGIN
modules.otherDirectories ← AddAName[parts.principalDirectory, modules.otherDirectories];
modules.flushTime ← BasicTime.Now[];
END;
END;
END
ELSE
-- SunOS 5.x - couldn't obtain debug information from loaded object module
BEGIN
parts: NameParts ← GetNamePartsFromFullPathName[moduleInfo.fileName];
IF parts.nameStem.Length[] # 0 THEN module.originalPossibleNameStems ← AddAName[PFS.PathFromRope[parts.nameStem], module.originalPossibleNameStems];
IF parts.principalDirectory # PFSNames.EmptyPath THEN module.possiblePrincipalDirectories ← AddAName[parts.principalDirectory, module.possiblePrincipalDirectories];
now, lets see if we can learn anything about the dotO location that might be helpful later.
BEGIN
wholeFileName: PATH ← SystemInterface.GetNameOfFile[ObjF.GetObjectFile[moduleInfo.whole]];
parts: NameParts ← GetNamePartsFromFullPathName[wholeFileName];
IF parts.principalDirectory # PFSNames.EmptyPath
THEN
BEGIN
modules.otherDirectories ← AddAName[parts.principalDirectory, modules.otherDirectories];
modules.flushTime ← BasicTime.Now[];
END;
END;
END;
IF NOT RefTab.Store[modules.vsHash.table, vsKey, module] THEN ERROR;
END;
IF module #
NIL
THEN
-- just in case
BEGIN
IF module.module = NIL THEN module.module ← embeddedModule;
IF module.whole = NIL THEN module.whole ← whole;
END;
RETURN[module];
END;
CreateEmptyCedarModule:
PROC[modules: CedarModuleSet]
RETURNS[CedarModule] =
{RETURN[NEW[CedarModuleHandle←NEW[CedarModuleBody←[modules, NIL, NIL, NIL, NIL, NIL, BasicTime.Now[], FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NIL, NIL, NIL, NIL, NIL, NIL, NIL]]]]};
here are the procedures that get loaded components of modules
GetLoadedJMPI:
PROC[module: CedarModule]
RETURNS[
MOF.JointMobParsedInfo] =
BEGIN
IF module.loadedJmpi =
NIL
AND
NOT (module.loadedJmpiFailed
AND BasicTime.Period[module.failureTime, module.moduleSet.flushTime] < 0)
THEN
BEGIN
mob: MA.MobCookie ← GetMob[module];
loadedModule: ObjF.Module ← GetLoadedModule[module];
loadedDotO: ObjF.Parsed ← GetLoadedParsed[module];
IF mob #
NIL
AND loadedModule #
NIL
AND loadedDotO #
NIL
THEN
module.loadedJmpi ← MOF.CreateJointMobParsedInfo[mob, loadedDotO, loadedModule];
IF module.loadedJmpi =
NIL
THEN
{module.loadedJmpiFailed ← TRUE; module.failureTime ← BasicTime.Now[]}
END;
RETURN[module.loadedJmpi];
END;
GetLoadedParsed:
PROC[module: CedarModule]
RETURNS[ObjF.Parsed] =
BEGIN
IF module.loadedWhole =
NIL
AND module.loadedModuleInfo #
NIL
THEN
module.loadedWhole ← module.loadedModuleInfo.parsed;
RETURN[module.loadedWhole];
END;
GetLoadedModule:
PROC[module: CedarModule]
RETURNS[ObjF.Module] =
BEGIN
IF module.loadedModule =
NIL
AND module.loadedModuleInfo #
NIL
THEN
module.loadedModule ← module.loadedModuleInfo.module;
RETURN[module.loadedModule];
END;
here are the procedures that get (non loaded) components of modules
SeekCSource:
PUBLIC
PROC [cms: CedarModuleSet, basicInfo:
REF
LSA.BasicPCInfo, ledo:
REF
LSA.LoadedModuleInfo]
RETURNS [foundFile: SystemInterface.CirioFile ←
NIL] ~ {
TryOneFile: PROC[info: SystemInterface.CirioFileInfo] RETURNS[thisIsIt: BOOLEAN] = {RETURN[TRUE]};
TryOneDir:
PROC[dir:
PATH] = {
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching directory %g.", [rope[PFS.RopeFromPath[dir]]] ], $urgent];
FOR spats:
LIST
OF
ROPE ← pats, spats.rest
WHILE spats#
NIL
AND foundFile=
NIL
DO
mesaPathName: PATH ← PFS.PathFromRope[spats.first];
mesaPathNamePattern: PATH ← mesaPathName.ExpandName[dir];
foundFile ← SystemInterface.GenCirioFilesForInfo[cms.fileSet, mesaPathNamePattern, TryOneFile];
ENDLOOP;
RETURN};
pats: LIST OF ROPE ← NIL;
paths: LIST OF PATH ← NIL;
descr: ROPE ← NIL;
FOR pmns:
LIST
OF
PATH ← basicInfo.possibleModuleNames, pmns.rest
WHILE pmns#
NIL
DO
short: ROPE ← PFS.RopeFromPath[pmns.first];
sl: INT ← short.Length;
this: ROPE;
IF sl>2
AND short.EqualSubstrs[start1: sl-2, s2: ".o"]
THEN this ← short.Replace[sl-1, 1, "c"]
ELSE this ← short.Concat[".c"];
IF descr=NIL THEN descr ← this ELSE descr ← Rope.Cat[descr, " or ", this];
pats ← CONS[this, pats];
paths ← CONS[PFS.PathFromRope[this], paths];
ENDLOOP;
SystemInterface.ShowReport[Rope.Concat["Searching for C source in ", descr], $normal];
FOR dirs:
LIST
OF
PATH ← cms.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile =
NIL
THEN {
IF debugSearch THEN SystemInterface.ShowReport["\tTrying version maps.", $urgent];
foundFile ← SystemInterface.GenVersionMapFilesForInfo[cms.fileSet, $Source, MobDefs.NullVersion, paths, LIST[""], TRUE, TryOneFile]};
FOR dirs:
LIST
OF
PATH ← cms.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile #
NIL
THEN {
nameRope: PATH ← SystemInterface.GetNameOfFile[foundFile];
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[nameRope]], $normal];
}
ELSE {
SystemInterface.ShowReport[" failed", $normal];
};
RETURN};
GetMesaFile:
PROC[module: CedarModule]
RETURNS[CirioFile] =
BEGIN
IF module.mesaSource =
NIL
AND
NOT (module.mesaSourceFailed
AND BasicTime.Period[module.failureTime, module.moduleSet.flushTime] < 0)
THEN
BEGIN
foundFile: CirioFile ← NIL; -- tentative
mob: MA.MobCookie ← GetMob[module];
sourceUnique: PFS.UniqueID;
this computation of vs is designed to be equivalent to MobAccessImpl.ComputeSourceVersionStamp.
TryOneFile: PROC[info: SystemInterface.CirioFileInfo] RETURNS[thisIsIt: BOOLEAN] = {RETURN[info.uniqueID = sourceUnique]};
TryOneDir:
PROC[dir:
PATH] =
BEGIN
FOR stems:
LIST
OF
PATH ← module.possibleNameStems, stems.rest
WHILE stems #
NIL
AND foundFile =
NIL
DO
mesaPathName: PATH ← PFS.PathFromRope [Rope.Cat [PFS.RopeFromPath[stems.first], ".mesa*"]];
mesaPathNamePattern: PATH ← mesaPathName.ExpandName[dir];
foundFile ← SystemInterface.GenCirioFilesForInfo[module.moduleSet.fileSet, mesaPathNamePattern, TryOneFile];
ENDLOOP;
END;
IF module.sourceStamp#NIL THEN sourceUnique ← SystemInterface.VersionStampToUniqueID[module.sourceStamp^]
ELSE IF mob#NIL THEN sourceUnique ← SystemInterface.VersionStampToUniqueID[MA.ReadSourceVersionStamp[mob]]
ELSE RETURN[NIL];
ShowSearchReport["mesa source", module];
FOR dirs:
LIST
OF
PATH ← module.moduleSet.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile =
NIL
THEN foundFile ← SystemInterface.GenVersionMapFilesForInfo[module.moduleSet.fileSet, $Source, MobDefs.NullVersion, module.possibleNameStems,
LIST[".mesa"],
TRUE, TryOneFile, sourceUnique];
FOR dirs:
LIST
OF
PATH ← module.possiblePrincipalDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
FOR dirs:
LIST
OF
PATH ← module.moduleSet.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile #
NIL
THEN
BEGIN
mesaName: PATH ← SystemInterface.GetNameOfFile[foundFile];
parts: NameParts ← GetNamePartsFromFullPathName[mesaName];
module.possiblePrincipalDirectories ← AddAName[parts.principalDirectory, module.possiblePrincipalDirectories];
module.possibleNameStems ← LIST[PFS.PathFromRope[parts.nameStem]];
module.mesaSource ← foundFile;
module.mesaSourceFailed ← FALSE;
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[mesaName]], $normal];
END
ELSE
BEGIN
module.mesaSourceFailed ← TRUE;
module.failureTime ← BasicTime.Now[];
ShowFailureReport["mesa source", module];
END;
END;
RETURN[module.mesaSource];
END;
GetCFileInfo:
PROC[module: CedarModule]
RETURNS[CFileInfo] =
BEGIN
IF module.cInfo =
NIL
AND
NOT (module.cSourceFailed
AND BasicTime.Period[module.failureTime, module.moduleSet.flushTime] < 0)
THEN
BEGIN
[] ← GetMob[module]; -- always get the mob first. Thus, if we have a mesa source, then the corresponding mob will give us the mob version
IF module.possibleNameStems #
NIL
THEN
BEGIN
foundFile: CirioFile ← NIL; -- tentative
foundCInfo: CFileInfo ← NIL; -- tentative
foundPossibleFile: CirioFile ← NIL; -- tentative
our only effective criterion is the version stamp, if we have one.
TryOneFile:
PROC[info: SystemInterface.CirioFileInfo]
RETURNS[thisIsIt:
BOOLEAN ←
FALSE] =
BEGIN
IF module.mobStamp =
NIL
THEN
no version stamp, so accept any file with the right name
BEGIN
possibleFile: CirioFile ← SystemInterface.GetCirioFile[module.moduleSet.fileSet, info.fullName, info.uniqueID];
cInfo: CFileInfo ← CreateCFileInfo[possibleFile];
foundCInfo ← cInfo;
foundPossibleFile ← possibleFile;
SystemInterface.ShowReport[Rope.Cat["accepting ", PFS.RopeFromPath[info.fullName], " without checking version stamp"], $normal];
RETURN[TRUE]
END
ELSE
BEGIN
possibleFile: CirioFile ← SystemInterface.GetCirioFile[module.moduleSet.fileSet, info.fullName, info.uniqueID];
vsRope: Rope.ROPE ← ScanCFileForVersionStamp[possibleFile];
IF vsRope #
NIL
THEN
BEGIN
parts: NameParts ← GetNamePartsFromFullPathName[info.fullName];
recoveredStamp: REF RecoveredVersionStamp ← ConvertDotOFormatVersionStampToMobFormat[vsRope];
IF recoveredStamp #
NIL
AND module.mobStamp #
NIL
AND module.mobStamp^ = recoveredStamp.mobStamp
THEN
BEGIN
foundCInfo ← CreateCFileInfo[possibleFile];
foundPossibleFile ← possibleFile;
RETURN[TRUE]
END
END;
RETURN[FALSE];
END;
END;
TryOneDir:
PROC[dir:
PATH] =
BEGIN
FOR stems:
LIST
OF
PATH ← module.possibleNameStems, stems.rest
WHILE stems #
NIL
AND foundFile =
NIL
DO
cFileNamePattern1: PATH ← PFS.PathFromRope[Rope.Cat[PFS.RopeFromPath[stems.first], ".c2c.c", "*"]];
cFileNamePattern2: PATH ← PFS.PathFromRope[Rope.Cat[PFS.RopeFromPath[stems.first], ".c", "*"]]; -- perhaps the conventions aren't being followed
cFileNamePattern1 ← cFileNamePattern1.ExpandName[dir];
cFileNamePattern1 ← cFileNamePattern2.ExpandName[dir];
foundFile ← SystemInterface.GenCirioFilesForInfo[module.moduleSet.fileSet, cFileNamePattern1, TryOneFile];
IF foundFile =
NIL
THEN
foundFile ← SystemInterface.GenCirioFilesForInfo[module.moduleSet.fileSet, cFileNamePattern2, TryOneFile]
ENDLOOP;
END;
ShowSearchReport["c source", module];
FOR dirs:
LIST
OF
PATH ← module.moduleSet.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile = NIL THEN foundFile ← SystemInterface.GenVersionMapFilesForInfo[module.moduleSet.fileSet, $Intermediate, MobDefs.NullVersion, module.possibleNameStems, LIST[".c2c.c"], TRUE, TryOneFile];
IF foundFile =
NIL
THEN foundFile ← SystemInterface.GenVersionMapFilesForInfo[module.moduleSet.fileSet, $Source, MobDefs.NullVersion, module.possibleNameStems,
LIST[".c"],
TRUE, TryOneFile];
FOR dirs:
LIST
OF
PATH ← module.possiblePrincipalDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
FOR dirs:
LIST
OF
PATH ← module.moduleSet.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile =
NIL
THEN
BEGIN
module.cSourceFailed ← TRUE;
module.failureTime ← BasicTime.Now[];
ShowFailureReport["c source", module];
END
ELSE
BEGIN
cName: PATH ← SystemInterface.GetNameOfFile[foundFile];
parts: NameParts ← GetNamePartsFromFullPathName[cName];
IF foundFile # foundPossibleFile
THEN
ERROR;
(this depends on the file caching mechanism in FileSet, to that we get only one file for each name.)
module.cInfo ← foundCInfo;
module.possiblePrincipalDirectories ← AddAName[parts.principalDirectory, module.possiblePrincipalDirectories];
module.cSourceFailed ← FALSE;
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[cName]], $normal];
END;
END;
END;
RETURN[module.cInfo];
END;
GetJMPI:
PROC[module: CedarModule]
RETURNS[
MOF.JointMobParsedInfo] =
BEGIN
IF module.jmpi =
NIL
AND
NOT (module.jmpiFailed
AND BasicTime.Period[module.failureTime, module.moduleSet.flushTime] < 0)
THEN
BEGIN
mob: MA.MobCookie ← GetMob[module];
embeddedModule: ObjF.Module ← GetModule[module];
whole: ObjF.Parsed ← GetParsed[module];
IF mob #
NIL
AND embeddedModule #
NIL
AND whole #
NIL
THEN
module.jmpi ← MOF.CreateJointMobParsedInfo[mob, whole, embeddedModule];
IF module.jmpi =
NIL
THEN
{module.jmpiFailed ← TRUE; module.failureTime ← BasicTime.Now[]}
END;
RETURN[module.jmpi];
END;
GetParsed:
PROC[module: CedarModule]
RETURNS[ObjF.Parsed] =
BEGIN
IF module.whole =
NIL
AND
NOT (module.wholeFailed
AND BasicTime.Period[module.failureTime, module.moduleSet.flushTime] < 0)
THEN
BEGIN
[] ← GetModule[module];
IF module.whole =
NIL
THEN
BEGIN
module.wholeFailed ← TRUE;
module.failureTime ← BasicTime.Now[];
ShowFailureReport["whole", module];
END;
END;
RETURN[module.whole];
END;
GetModule:
PROC[module: CedarModule]
RETURNS[ObjF.Module] =
BEGIN
IF module.module =
NIL
AND
NOT (module.moduleFailed
AND BasicTime.Period[module.failureTime, module.moduleSet.flushTime] < 0)
THEN
BEGIN
[] ← GetMob[module];
module must have been created from a mesa file
IF module.possibleNameStems #
NIL
AND module.mob #
NIL
THEN
BEGIN
foundFile: CirioFile ← NIL; -- tentative
foundDotO: ObjF.Parsed ← NIL; -- tentative
foundModule: ObjF.Module ← NIL; -- tentative
foundPossibleFile: CirioFile ← NIL; -- tentative
our only effective criterion is the version stamp, if we have one.
TryOneFile:
PROC[info: SystemInterface.CirioFileInfo]
RETURNS[thisIsIt:
BOOLEAN ←
FALSE] =
BEGIN
IF module.mobStamp =
NIL
THEN
ERROR
ELSE
BEGIN
possibleFile: CirioFile ← SystemInterface.GetCirioFile[module.moduleSet.fileSet, info.fullName, info.uniqueID];
possibleDotO: ObjF.Parsed ← ObjF.CreateParsed[possibleFile];
parts: NameParts ← GetNamePartsFromFullPathName[info.fullName];
possibleModule: ObjF.Module ← FallBackFindModule[possibleDotO, 0];
vsInfo: REF ObjF.VersionStampInfo ← ObjF.FindVersionStamp[possibleModule];
recoveredStamp: REF RecoveredVersionStamp ← IF vsInfo = NIL OR vsInfo.contents = NIL THEN NIL ELSE ConvertDotOFormatVersionStampToMobFormat[vsInfo.contents];
IF recoveredStamp #
NIL
AND module.mobStamp #
NIL
AND recoveredStamp.mobStamp = module.mobStamp^
THEN
BEGIN
foundDotO ← possibleDotO;
foundModule ← possibleModule;
foundPossibleFile ← possibleFile;
RETURN[TRUE]
END
ELSE RETURN[FALSE];
END;
END;
TryOneDir:
PROC[dir:
PATH] =
BEGIN
rdir: Rope.ROPE ← PFS.RopeFromPath[PFSNames.EnsureDirectory[dir]];
FOR stems:
LIST
OF
PATH ← module.possibleNameStems, stems.rest
WHILE stems #
NIL
AND foundFile =
NIL
DO
FIX: Use the PFS Extentions stuff when available.
patterns:
LIST
OF
PATH ←
LIST[
PFS.PathFromRope[Rope.Cat[rdir, "debug/", PFS.RopeFromPath[stems.first], ".c2c.o"]],
PFS.PathFromRope[Rope.Cat[rdir, "debug/", PFS.RopeFromPath[stems.first], ".o"]],
PFS.PathFromRope[Rope.Cat[rdir, "debug/", PFS.RopeFromPath[stems.first]]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4-debug/", PFS.RopeFromPath[stems.first], ".c2c.o", "*"]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4-debug/", PFS.RopeFromPath[stems.first], ".o", "*"]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4-debug/", PFS.RopeFromPath[stems.first], "*"]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4/", PFS.RopeFromPath[stems.first], ".c2c.o", "*"]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4/", PFS.RopeFromPath[stems.first], ".o", "*"]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4/", PFS.RopeFromPath[stems.first], "*"]],
PFS.PathFromRope[Rope.Cat[rdir, PFS.RopeFromPath[stems.first], ".c2c.o", "*"]],
PFS.PathFromRope[Rope.Cat[rdir, PFS.RopeFromPath[stems.first], ".o", "*"]],
PFS.PathFromRope[Rope.Cat[rdir, PFS.RopeFromPath[stems.first], "*"]]];
FOR ps:
LIST
OF
PATH ← patterns, ps.rest
WHILE ps #
NIL
AND foundFile =
NIL
DO
foundFile ← SystemInterface.GenCirioFilesForInfo[module.moduleSet.fileSet, ps.first, TryOneFile];
ENDLOOP;
ENDLOOP;
END;
ShowSearchReport["module", module];
FOR dirs:
LIST
OF
PATH ← module.moduleSet.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile =
NIL
THEN [] ← SystemInterface.GenVersionMapFilesForInfo[module.moduleSet.fileSet, $Executable, <<IF module.mobStamp # NIL THEN module.mobStamp^ ELSE >>MobDefs.NullVersion, module.possibleNameStems,
LIST[".c2c.o", ".o", ""],
TRUE, TryOneFile];
FOR dirs:
LIST
OF
PATH ← module.possiblePrincipalDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
FOR dirs:
LIST
OF
PATH ← module.moduleSet.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile =
NIL
THEN
BEGIN
module.moduleFailed ← TRUE;
module.failureTime ← BasicTime.Now[];
ShowFailureReport["module", module];
END
ELSE
BEGIN
moduleName: PATH ← SystemInterface.GetNameOfFile[foundFile];
parts: NameParts ← GetNamePartsFromFullPathName[moduleName];
IF foundFile # foundPossibleFile
THEN
ERROR;
(this depends on the file caching mechanism in FileSet, to that we get only one file for each name.)
module.module ← foundModule;
module.whole ← foundDotO;
module.possiblePrincipalDirectories ← AddAName[parts.principalDirectory, module.possiblePrincipalDirectories];
module.moduleFailed ← FALSE;
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[moduleName]], $normal];
END;
END;
END;
RETURN[module.module];
END;
GetMob:
PROC[module: CedarModule]
RETURNS[
MA.MobCookie] =
if one is not present and we succeed in finding one, it will be the singleton.
BEGIN
modules: CedarModuleSet ← module.moduleSet;
IF module.mobStamp = NIL AND module.sourceStamp = NIL THEN ERROR;
IF module.mob =
NIL
AND
NOT (module.mobFailed
AND BasicTime.Period[module.failureTime, modules.flushTime] < 0)
THEN
BEGIN
try to find a name for the hash key.
otherModule: CedarModule;
base: RopeParts.RopePart ← emptyRopePart;
mobKey, srcKey: RefTab.Key;
IF module.mobStamp#
NIL
THEN {
mobKey ← CreateVSKey[module.mobStamp^, emptyRopePart];
otherModule ← NARROW[RefTab.Fetch[modules.vsHash.table, mobKey].val];
mobKey ← mobKey};
IF otherModule=
NIL
AND module.sourceStamp#
NIL
THEN {
nameStems: LIST OF PATH ← IF module.possibleNameStems # NIL THEN module.possibleNameStems ELSE module.originalPossibleNameStems;
baseComponent: PFSNames.Component;
FOR stems:
LIST
OF
PATH ← nameStems, stems.rest
WHILE stems#
NIL
AND otherModule=
NIL
DO
baseComponent ← PFSNames.ShortName[stems.first];
base ← [baseComponent.name.base, baseComponent.name.start, baseComponent.name.len];
srcKey ← CreateVSKey[module.sourceStamp^, base];
otherModule ← NARROW[RefTab.Fetch[modules.vsHash.table, srcKey].val];
ENDLOOP;
};
maybe we already have a module with this mob that started from a different direction
IF otherModule #
NIL
AND otherModule # module
THEN
-- good, lets combine info
BEGIN -- we must produce a single module, while checking for inconsistencies
incompatible: BOOLEAN ← FALSE; -- tentative
IF module.moduleSet # otherModule.moduleSet THEN ERROR;
IF module.mobStamp = NIL THEN module.mobStamp ← otherModule.mobStamp;
IF otherModule.mobStamp = NIL THEN otherModule.mobStamp ← module.mobStamp;
IF module.mobStamp # NIL AND module.mobStamp^ # otherModule.mobStamp^ THEN ERROR;
IF module.sourceStamp = NIL THEN module.sourceStamp ← otherModule.sourceStamp;
IF otherModule.sourceStamp = NIL THEN otherModule.sourceStamp ← module.sourceStamp;
IF module.sourceStamp # NIL AND module.sourceStamp^ # otherModule.sourceStamp^ THEN ERROR;
FOR ppds:
LIST
OF
PATH ← otherModule.possiblePrincipalDirectories, ppds.rest
WHILE ppds #
NIL
DO
module.possiblePrincipalDirectories ← AddAName[ppds.first, module.possiblePrincipalDirectories];
ENDLOOP;
FOR ppds:
LIST
OF
PATH ← module.possiblePrincipalDirectories, ppds.rest
WHILE ppds #
NIL
DO
otherModule.possiblePrincipalDirectories ← AddAName[ppds.first, otherModule.possiblePrincipalDirectories];
ENDLOOP;
FOR pns:
LIST
OF
PATH ← otherModule.possibleNameStems, pns.rest
WHILE pns #
NIL
DO
module.possibleNameStems ← AddAName[pns.first, module.possibleNameStems];
ENDLOOP;
FOR pns:
LIST
OF
PATH ← module.possibleNameStems, pns.rest
WHILE pns #
NIL
DO
otherModule.possibleNameStems ← AddAName[pns.first, otherModule.possibleNameStems];
ENDLOOP;
IF BasicTime.Period[module.failureTime, otherModule.failureTime] > 0
THEN
otherModule.failureTime ← module.failureTime
ELSE module.failureTime ← otherModule.failureTime; -- (earliest failure time to both)
IF
NOT module.mesaSourceFailed
OR
NOT otherModule.mesaSourceFailed
THEN
module.mesaSourceFailed ← otherModule.mesaSourceFailed ← FALSE;
IF
NOT module.mobFileFailed
OR
NOT otherModule.mobFileFailed
THEN
module.mobFileFailed ← otherModule.mobFileFailed ← FALSE;
IF
NOT module.mobFailed
OR
NOT otherModule.mobFailed
THEN
module.mobFailed ← otherModule.mobFailed ← FALSE;
IF
NOT module.cSourceFailed
OR
NOT otherModule.cSourceFailed
THEN
module.cSourceFailed ← otherModule.cSourceFailed ← FALSE;
IF
NOT module.jmpiFailed
OR
NOT otherModule.jmpiFailed
THEN
module.jmpiFailed ← otherModule.jmpiFailed ← FALSE;
IF
NOT module.moduleFailed
OR
NOT otherModule.moduleFailed
THEN
module.moduleFailed ← otherModule.moduleFailed ← FALSE;
IF
NOT module.wholeFailed
OR
NOT otherModule.wholeFailed
THEN
module.wholeFailed ← otherModule.wholeFailed ← FALSE;
IF module.mesaSource #
NIL
AND otherModule.mesaSource #
NIL
THEN
incompatible ← module.mesaSource # otherModule.mesaSource;
IF module.mesaSource = NIL THEN module.mesaSource ← otherModule.mesaSource;
IF otherModule.mesaSource = NIL THEN otherModule.mesaSource ← module.mesaSource;
IF module.jmpi #
NIL
AND otherModule.jmpi #
NIL
THEN
incompatible ← module.jmpi # otherModule.jmpi;
IF module.jmpi = NIL THEN module.jmpi ← otherModule.jmpi;
IF otherModule.jmpi = NIL THEN otherModule.jmpi ← module.jmpi;
IF module.mobFile #
NIL
AND otherModule.mobFile #
NIL
THEN
incompatible ← module.mobFile # otherModule.mobFile;
IF module.mobFile = NIL THEN module.mobFile ← otherModule.mobFile;
IF otherModule.mobFile = NIL THEN otherModule.mobFile ← module.mobFile;
IF module.mob #
NIL
AND otherModule.mob #
NIL
THEN
incompatible ← module.mob # otherModule.mob;
IF module.mob = NIL THEN module.mob ← otherModule.mob;
IF otherModule.mob = NIL THEN otherModule.mob ← module.mob;
IF module.cInfo #
NIL
AND otherModule.cInfo #
NIL
THEN
incompatible ← module.cInfo # otherModule.cInfo;
IF module.cInfo = NIL THEN module.cInfo ← otherModule.cInfo;
IF otherModule.cInfo = NIL THEN otherModule.cInfo ← module.cInfo;
IF module.module #
NIL
AND otherModule.module #
NIL
THEN
incompatible ← module.module # otherModule.module;
IF module.module = NIL THEN module.module ← otherModule.module;
IF otherModule.module = NIL THEN otherModule.module ← module.module;
IF module.whole #
NIL
AND otherModule.whole #
NIL
THEN
incompatible ← module.whole # otherModule.whole;
IF module.whole = NIL THEN module.whole ← otherModule.whole;
IF otherModule.whole = NIL THEN otherModule.whole ← module.whole;
IF NOT incompatible THEN module^ ← otherModule^;
END;
now, lets look again
IF module.mob =
NIL
THEN
-- we still have to find the mob
BEGIN
nameStems: LIST OF PATH ← IF module.possibleNameStems # NIL THEN module.possibleNameStems ELSE module.originalPossibleNameStems;
IF nameStems #
NIL
THEN
BEGIN
foundMob: MA.MobCookie ← NIL; -- tentative
foundPossibleFile: CirioFile ← NIL; -- tentative
foundCreateTime: BasicTime.GMT ← BasicTime.earliestGMT; -- tentative
our only effective criterion is the version stamp, if we have one.
TryOneFile:
PROC[info: SystemInterface.CirioFileInfo]
RETURNS[thisIsIt:
BOOLEAN ←
FALSE] =
BEGIN
possibleFile: CirioFile ← SystemInterface.GetCirioFile[modules.fileSet, info.fullName, info.uniqueID];
IF module.mobStamp =
NIL
AND module.sourceStamp =
NIL
THEN
no version stamp, so accept last created file with the right name
BEGIN
mob:
MA.MobCookie ←
MA.CreateMobCookie[possibleFile ! MobAccess.MobError => {
SystemInterface.ShowReport[IO.PutFR["\tbad mob %g", [rope[PFS.RopeFromPath[info.fullName]]] ], IF debugSearch THEN $urgent ELSE $debug];
GOTO failure}];
SystemInterface.ShowReport[Rope.Cat["accepting ", PFS.RopeFromPath[info.fullName], " without any version checking"], $normal];
IF foundPossibleFile =
NIL
OR (BasicTime.Period[foundCreateTime, info.uniqueID.egmt.time] > 0)
THEN
we take the latest created acceptable mob in the same directory
BEGIN
foundMob ← mob;
foundPossibleFile ← possibleFile;
foundCreateTime ← info.uniqueID.egmt.time;
RETURN[TRUE]
END;
RETURN[FALSE]
END
ELSE
BEGIN
mob:
MA.MobCookie ←
MA.CreateMobCookie[possibleFile ! MobAccess.MobError => {
SystemInterface.ShowReport[IO.PutFR["\tbad mob %g", [rope[PFS.RopeFromPath[info.fullName]]] ], IF debugSearch THEN $urgent ELSE $debug];
GOTO failure}];
parts: NameParts ← GetNamePartsFromFullPathName[info.fullName];
mobStamp: MobDefs.VersionStamp ← MA.ReadMobVersionStamp[mob];
mobSourceStamp: MobDefs.VersionStamp ← MA.ReadSourceVersionStamp[mob];
ok: BOOLEAN ← FALSE; -- tentative;
IF module.mobStamp # NIL AND module.mobStamp^ = mobStamp THEN ok ← TRUE;
IF module.sourceStamp # NIL AND module.sourceStamp^ = mobSourceStamp THEN ok ← TRUE;
ok ← ok
AND (foundPossibleFile =
NIL
OR (BasicTime.Period[foundCreateTime, info.uniqueID.egmt.time] > 0));
we take the latest created acceptable mob in the same directory
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFLR["\t?name=%g,\n\tmobStamp=%08x%08x, sourceStamp=%08x%08x,\n\tcreate=%g, ok=%g.", LIST[ [rope[PFS.RopeFromPath[info.fullName]]], [cardinal[mobStamp[0]]], [cardinal[mobStamp[1]]], [cardinal[mobSourceStamp[0]]], [cardinal[mobSourceStamp[1]]], [time[info.uniqueID.egmt.time]], [boolean[ok]] ]], $urgent];
IF ok
THEN
BEGIN
foundMob ← mob;
foundPossibleFile ← possibleFile;
foundCreateTime ← info.uniqueID.egmt.time;
RETURN[TRUE];
END;
RETURN[FALSE];
END;
EXITS failure => RETURN[FALSE];
END;
TryOneDir:
PROC[dir:
PATH] =
BEGIN
FOR stems:
LIST
OF
PATH ← nameStems, stems.rest
WHILE stems #
NIL
AND foundPossibleFile =
NIL
DO
mobFileNamePattern: PATH ← PFS.PathFromRope[Rope.Cat[PFS.RopeFromPath[stems.first], ".mob", "*"]];
mobFileNamePattern ← mobFileNamePattern.ExpandName[dir];
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching file pattern %g.", [rope[PFS.RopeFromPath[mobFileNamePattern]]] ], $urgent];
[] ← SystemInterface.GenCirioFilesForInfo[modules.fileSet, mobFileNamePattern, TryOneFile];
ENDLOOP;
END;
ShowSearchReport["mob", module];
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\twith mob stamp %g and source stamp %g.", [rope[DescribeRefStamp[module.mobStamp]]], [rope[DescribeRefStamp[module.sourceStamp]]] ], $urgent];
FOR dirs:
LIST
OF
PATH ← modules.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundPossibleFile =
NIL
DO
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching search dir %g.", [rope[PFS.RopeFromPath[dirs.first]]] ], $urgent];
TryOneDir[dirs.first];
ENDLOOP;
IF foundPossibleFile =
NIL
THEN {
IF debugSearch THEN SystemInterface.ShowReport["\tSearching version maps.", $urgent];
foundPossibleFile ← SystemInterface.GenVersionMapFilesForInfo[modules.fileSet, $Intermediate, MobDefs.NullVersion, nameStems, LIST[".mob"], TRUE, TryOneFile]};
FOR dirs:
LIST
OF
PATH ← module.possiblePrincipalDirectories, dirs.rest
WHILE dirs #
NIL
AND foundPossibleFile =
NIL
DO
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching possible principle dir %g.", [rope[PFS.RopeFromPath[dirs.first]]] ], $urgent];
TryOneDir[dirs.first];
ENDLOOP;
FOR dirs:
LIST
OF
PATH ← modules.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundPossibleFile =
NIL
DO
IF debugSearch THEN SystemInterface.ShowReport[IO.PutFR["\tSearching other dir %g.", [rope[PFS.RopeFromPath[dirs.first]]] ], $urgent];
TryOneDir[dirs.first];
ENDLOOP;
IF foundPossibleFile =
NIL
THEN
BEGIN
module.mobFailed ← TRUE;
module.failureTime ← BasicTime.Now[];
ShowFailureReport["mob", module];
END
ELSE
BEGIN
mobName: PATH ← SystemInterface.GetNameOfFile[foundPossibleFile];
parts: NameParts ← GetNamePartsFromFullPathName[mobName];
module.mob ← foundMob;
module.possiblePrincipalDirectories ← AddAName[parts.principalDirectory, module.possiblePrincipalDirectories];
module.mobStamp ← NEW[MobDefs.VersionStamp ← MA.ReadMobVersionStamp[module.mob]];
IF module.sourceStamp =
NIL
THEN {
module.sourceStamp ← NEW[MobDefs.VersionStamp ← MA.ReadSourceVersionStamp[module.mob]];
base ← RopeParts.InlineMake[parts.nameStem];
srcKey ← CreateVSKey[module.sourceStamp^, base];
[] ← RefTab.Store[modules.vsHash.table, srcKey, module];
};
IF module.possibleNameStems = NIL THEN module.possibleNameStems ← LIST[PFS.PathFromRope[parts.nameStem]];
module.mobFailed ← FALSE;
mobKey ← CreateVSKey[module.mobStamp^, emptyRopePart];
IF RefTab.Fetch[modules.vsHash.table, mobKey].val =
NIL
THEN
{IF NOT RefTab.Store[modules.vsHash.table, mobKey, module] THEN ERROR};
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[mobName]], $normal];
END;
END;
END;
END;
RETURN[module.mob];
END;
GetDotO:
PUBLIC
PROC [targetData:
REF
ANY, dotOPathRope, dotORope: Rope.
ROPE, dotOId:
CARD, getDotOId:
PROC [ObjF.Parsed]
RETURNS [
CARD]]
RETURNS [ObjF.Parsed] = {
modules: CedarModuleSet ← NARROW[targetData];
RETURN [GetDotOInner[modules, dotOPathRope, dotORope, dotOId, getDotOId]];
};
GetDotOInner:
PROC [moduleSet: CedarModuleSet, dotOPathRope, dotORope: Rope.
ROPE, dotOId:
CARD, getDotOId:
PROC [ObjF.Parsed]
RETURNS [
CARD]]
RETURNS [ObjF.Parsed] = {
foundFile: CirioFile ← NIL; -- tentative
foundDotO: ObjF.Parsed ← NIL; -- tentative
foundPossibleFile: CirioFile ← NIL; -- tentative
TryOneFile:
PROC [info: SystemInterface.CirioFileInfo]
RETURNS [thisIsIt:
BOOLEAN ←
FALSE] = {
possibleFile: CirioFile ← SystemInterface.GetCirioFile[moduleSet.fileSet, info.fullName, info.uniqueID];
possibleDotO: ObjF.Parsed ← ObjF.CreateParsed[possibleFile];
IF getDotOId[possibleDotO] = dotOId
THEN {
foundDotO ← possibleDotO;
foundPossibleFile ← possibleFile;
RETURN[TRUE]
};
RETURN[FALSE];
};
TryOneDir:
PROC [dir:
PATH] = {
rdir: Rope.ROPE ← PFS.RopeFromPath[PFSNames.EnsureDirectory[dir]];
FIX: Use the PFS Extentions stuff when available.
patterns:
LIST
OF
PATH ←
LIST[
PFS.PathFromRope[Rope.Cat[rdir, dotORope]],
PFS.PathFromRope[Rope.Cat[rdir, "debug/", dotORope]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4-debug/", dotORope, "*"]],
PFS.PathFromRope[Rope.Cat[rdir, "sun4/", dotORope, "*"]]
];
FOR ps:
LIST
OF
PATH ← patterns, ps.rest
WHILE ps #
NIL
AND foundFile =
NIL
DO
foundFile ← SystemInterface.GenCirioFilesForInfo[moduleSet.fileSet, ps.first, TryOneFile];
ENDLOOP;
};
SystemInterface.ShowReport[Rope.Concat["searching for ", dotORope], $normal];
FOR dirs:
LIST
OF
PATH ← moduleSet.searchPaths, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile =
NIL
THEN [] ← SystemInterface.GenVersionMapFilesForInfo[moduleSet.fileSet, $Executable, MobDefs.NullVersion,
LIST[
PFS.PathFromRope[dotORope]],
NIL,
TRUE, TryOneFile];
FOR dirs:
LIST
OF
PATH ← moduleSet.otherDirectories, dirs.rest
WHILE dirs #
NIL
AND foundFile =
NIL
DO
TryOneDir[dirs.first];
ENDLOOP;
IF foundFile = NIL THEN SystemInterface.ShowReport[Rope.Cat["unable to find module for ", dotORope], $normal]
ELSE {
moduleName: PATH ← SystemInterface.GetNameOfFile[foundFile];
IF foundFile # foundPossibleFile
THEN
ERROR;
(this depends on the file caching mechanism in FileSet, to that we get only one file for each name.)
SystemInterface.ShowReport[Rope.Cat[" found ", PFS.RopeFromPath[moduleName]], $normal];
};
RETURN [foundDotO];
};
Some other procedures
FallBackFindModule:
PROC[whole: ObjF.Parsed, relativePC:
CARD]
RETURNS[ObjF.Module] =
BEGIN
RETURN[ObjF.ModuleFromParsedAndPC[whole, [[0,""], relativePC]]]
END;
version stamp hashing
VSHashTable: TYPE = REF VSHashTableBody;
VSHashTableBody: TYPE = RECORD[table: RefTab.Ref];
VSHashEntryKey: TYPE = RECORD[versionStamp: MobDefs.VersionStamp, base: RopeParts.RopePart];
emptyRopePart: RopeParts.RopePart ← [base: "", start: 0, len: 0];
CreateVSHashTable:
PROC
RETURNS[VSHashTable] =
{RETURN[NEW[VSHashTableBody ← [table: RefTab.Create[equal: VSKeyEqualProc, hash: VSKeyHashProc]]]]};
CreateVSKey:
PROC[stamp: MobDefs.VersionStamp, base: RopeParts.RopePart]
RETURNS[RefTab.Key] =
{RETURN[NEW[VSHashEntryKey ← [versionStamp: stamp, base: base]]]};
VSKeyEqualProc:
PROC[key1, key2: RefTab.Key]
RETURNS[
BOOL] =
BEGIN
vs1: REF VSHashEntryKey ← NARROW[key1];
vs2: REF VSHashEntryKey ← NARROW[key2];
RETURN[(vs1^.versionStamp = vs2^.versionStamp) AND (RopeParts.Equal[vs1^.base, vs2^.base])];
END;
VSKeyHashProc:
PROC[key: RefTab.Key]
RETURNS[
CARDINAL] =
BEGIN
vs: REF VSHashEntryKey ← NARROW[key];
word0: PBasics.LongNumber ← LOOPHOLE[vs^.versionStamp[0]];
word1: PBasics.LongNumber ← LOOPHOLE[vs^.versionStamp[1]];
RETURN[RopeParts.Hash[base: vs^.base, seed: PBasics.BITXOR[PBasics.BITXOR[word0.lo, word0.hi], PBasics.BITXOR[word1.lo, word1.hi]]]];
END;
name parts
GetNamePartsFromFullPathName:
PUBLIC
PROC [fullPathName:
PATH]
RETURNS [NameParts] = {
principalDirectory: PATH;
sun4: PATH ← PFSNames.EmptyPath; -- tentative
c2c: PATH ← PFSNames.EmptyPath; -- tentative
shortComp: PFSNames.Component ← fullPathName.ShortName;
shortName: ROPE ← shortComp.ComponentRope;
directoryPath: PATH ← fullPathName.Directory;
check for and remove sun4 and sun4-o3
IF directoryPath # PFSNames.EmptyPath
AND directoryPath #
NIL
AND directoryPath.ComponentCount # 0
THEN
BEGIN
lastDirectory: PFSNames.Component ← directoryPath.Fetch[directoryPath.ComponentCount - 1];
Do the comparisons as ropes. Should be safe, and it's easier.
lastDirectoryRope: Rope.ROPE ← lastDirectory.ComponentRope;
IF Rope.Equal["sun4", lastDirectoryRope]
OR Rope.Equal["sun4-o3", lastDirectoryRope]
OR Rope.Equal["sun4o3", lastDirectoryRope,
FALSE]
THEN
Yup, sun4 or sun4-o3 found. Cut it off.
directoryPath ← directoryPath.Parent;
principalDirectory ← directoryPath;
check for and remove twiddle version
{lastDot: INT ← Rope.FindBackward[shortName, "."];
IF lastDot > -1
AND lastDot+1 < Rope.Length[shortName]
AND Rope.Fetch[shortName, lastDot+1] = '~
THEN
-- remove the version
shortName ← Rope.Substr[shortName, 0, lastDot];
};
check for and remove c2c (which must have a following extension)
{lastDot: INT ← Rope.FindBackward[shortName, "."];
secondToLastDot: INT ← IF lastDot <= 0 THEN -1 ELSE Rope.FindBackward[shortName, ".", lastDot-1];
IF secondToLastDot > -1
AND Rope.Equal["c2c", Rope.Substr[shortName, secondToLastDot+1, lastDot-1-secondToLastDot]]
THEN {
shortName ← Rope.Replace[shortName, secondToLastDot, 4, ""];
c2c ← PFS.PathFromRope[".c2c"]};
};
check for and remove extension
{lastDot: INT ← Rope.FindBackward[shortName, "."];
IF lastDot > -1
THEN
shortName ← Rope.Substr[shortName, 0, lastDot];
};
RETURN[[
principalDirectory,
sun4,
shortName
c2c
]];
};
Handle C files
CFileInfo: TYPE = REF CFileInfoBody;
CFileInfoBody:
TYPE =
RECORD[
file: CirioFile,
sourcePosSeq: SourcePosSeq,
lineNumSeq: LineNumSeq,
versionStamp: Rope.ROPE];
SourcePosSeq: TYPE = REF SourcePosSeqBody;
SourcePosSeqBody:
TYPE =
RECORD[
SEQUENCE nSourceMacros: CARDINAL OF SourcePosMacro];
LineNumSeq: TYPE = REF LineNumSeqBody;
LineNumSeqBody:
TYPE =
RECORD[
SEQUENCE nSourceMacros: CARDINAL OF SourcePosMacro];
SourcePosMacro: TYPE = RECORD[pos: CARD, nChars: CARD, lineNum: CARD];
At the time of this writing, Christian was not around to answer questions, but Peter was. Peter says that the pair of numbers in a SOURCE macro are a source position and a char count. They represent nested regions. (However, experiment shows that they do not represent nested regions.) They may not be in monotonic increasing order.
As a starting point, I take a very crude position. I shall map a source position to the line number holding the SOURCE macro containing the largest source position less than or equal to the given source position.
Similarly, given a cLineNum, I shall map to a SOURCE macro containing the largest cLineNum less than or equal to the given cLineNum. (Note that there can only be one source macro per c line.)
probably should make this a binary search, oh well
no need to be monitor locked because nothing modifies contents of info
LookupMesaSourcePos:
PROC[info: CFileInfo, pos:
CARD]
RETURNS[cLineNum:
CARD] =
BEGIN
FOR
I:
CARDINAL
DECREASING
IN [0..info.sourcePosSeq.nSourceMacros)
DO
IF info.sourcePosSeq[I].pos <= pos
THEN
RETURN[info.sourcePosSeq[I].lineNum]
ENDLOOP;
IF info.sourcePosSeq.nSourceMacros = 0 THEN RETURN[0];
RETURN[info.sourcePosSeq[0].lineNum]
END;
no need to be monitor locked because nothing modifies contents of info
LookupCLineNum:
PROC[info: CFileInfo, cLineNum:
CARD]
RETURNS[pos:
CARD] =
BEGIN
FOR
I:
CARDINAL
DECREASING
IN [0..info.lineNumSeq.nSourceMacros)
DO
IF info.lineNumSeq[I].lineNum <= cLineNum
THEN
RETURN[info.lineNumSeq[I].pos]
ENDLOOP;
IF info.lineNumSeq.nSourceMacros = 0 THEN RETURN[0];
RETURN[info.lineNumSeq[0].pos]
END;
CompareSourceMacrosByPos:
PROC[ref1:
REF
ANY, ref2:
REF
ANY]
RETURNS [Basics.Comparison] =
BEGIN
sm1: REF SourcePosMacro ← NARROW[ref1];
sm2: REF SourcePosMacro ← NARROW[ref2];
IF sm1.pos < sm2.pos THEN RETURN[less];
IF sm1.pos > sm2.pos THEN RETURN[greater];
if starting positions are equal, then sort by CLine number
(however, I don't believe that this can happen)
IF sm1.lineNum < sm2.lineNum THEN RETURN[less];
IF sm1.lineNum > sm2.lineNum THEN RETURN[greater];
RETURN[equal];
END;
CompareSourceMacrosByCLineNum:
PROC[ref1:
REF
ANY, ref2:
REF
ANY]
RETURNS [Basics.Comparison] =
BEGIN
sm1: REF SourcePosMacro ← NARROW[ref1];
sm2: REF SourcePosMacro ← NARROW[ref2];
IF sm1.lineNum < sm2.lineNum THEN RETURN[less];
IF sm1.lineNum > sm2.lineNum THEN RETURN[greater];
If c line numbers are the same, then sort by increasing start source position
(I don't believe that this can happen)
IF sm1.pos < sm2.pos THEN RETURN[less];
IF sm1.pos > sm2.pos THEN RETURN[greater];
RETURN[equal];
END;
ScanCFileForVersionStamp:
PROC[cFile: CirioFile]
RETURNS[versionStamp: Rope.
ROPE ←
NIL] =
BEGIN
source:
IO.
STREAM ← SystemInterface.GetStreamForFile[cFile];
BEGIN ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[cFile, source];
buffer: REF TEXT ← NIL;
smKey: Rope.ROPE ← "SOURCE(";
smKeyLength: CARD ← Rope.Length[smKey];
vsKey: Rope.
ROPE ← Rope.Cat["static char versionStamp[] = \"@", "(#)", "mob←version ["];
note: the version stamp key is broken into pieces so that it won't look like a version stamp in the various files.
vsKeyLength: CARD ← Rope.Length[vsKey];
FOR ln:
CARD ← 1, ln+1
WHILE
NOT
IO.EndOf[source]
DO
buffer ← IO.GetLine[source, buffer];
IF buffer[0] = 's
THEN
-- possible version stamp hit
BEGIN
line: Rope.ROPE ← Rope.FromRefText[buffer];
IF Rope.Equal[vsKey, Rope.Substr[line, 0, vsKeyLength]]
THEN
-- we have a hit
BEGIN
quote1: INT ← Rope.Index[line, 0, "\""];
quote2: INT ← Rope.Index[line, quote1+1, "\""];
IF quote2 = Rope.Length[line]-2
THEN
-- a final consistency check
versionStamp ← Rope.Substr[line, quote1+1, quote2-quote1-1];
END
END;
IF versionStamp # NIL THEN EXIT;
ENDLOOP;
END;
SystemInterface.ReleaseStreamForFile[cFile, source];
END;
no need for ENTRY because this is a create routine and doesnt examine modules
CreateCFileInfo:
PROC[cFile: CirioFile]
RETURNS[CFileInfo] =
BEGIN
list1: LIST OF REF ANY ← NIL;
list2: LIST OF REF ANY ← NIL;
nMacros: INTEGER ← 0;
sortedList: LIST OF REF ANY ← NIL;
sourcePosSeq: SourcePosSeq;
lineNumSeq: LineNumSeq;
versionStamp: Rope.ROPE ← NIL;
SeeOnePosition:
PROC[sp:
CARD, nChars:
CARD, ln:
CARD] =
BEGIN
list1 ← CONS[NEW[SourcePosMacro←[sp, nChars, ln]], list1];
list2 ← CONS[NEW[SourcePosMacro←[sp, nChars, ln]], list2];
nMacros ← nMacros+1;
END;
versionStamp ← GenMesaSourcePositionMacros[cFile, SeeOnePosition];
sortedList ← List.Sort[list1, CompareSourceMacrosByPos];
sourcePosSeq ← NEW[SourcePosSeqBody[nMacros]];
FOR
I:
INTEGER
IN [0..nMacros)
DO
macro: REF SourcePosMacro ← NARROW[sortedList.first];
sourcePosSeq[I] ← macro^;
sortedList ← sortedList.rest;
ENDLOOP;
sortedList ← List.Sort[list2, CompareSourceMacrosByCLineNum];
lineNumSeq ← NEW[LineNumSeqBody[nMacros]];
FOR
I:
INTEGER
IN [0..nMacros)
DO
macro: REF SourcePosMacro ← NARROW[sortedList.first];
lineNumSeq[I] ← macro^;
sortedList ← sortedList.rest;
ENDLOOP;
RETURN[NEW[CFileInfoBody←[cFile, sourcePosSeq, lineNumSeq, versionStamp]]]
END;
no need for ENTRY because info^ is constant
GetCFileVersionStamp:
PROC[info: CFileInfo]
RETURNS[Rope.
ROPE] =
{RETURN[info.versionStamp]};
GenMesaSourcePositionMacros:
PROC[cFile: CirioFile,
SeeOnePosition:
PROC[sp:
CARD, nChars:
CARD, ln:
CARD]]
RETURNS[versionStamp: Rope.
ROPE ←
NIL] =
BEGIN
source:
IO.
STREAM ← SystemInterface.GetStreamForFile[cFile];
BEGIN ENABLE UNWIND => SystemInterface.ReleaseStreamForFile[cFile, source];
buffer: REF TEXT ← NIL;
smKey: Rope.ROPE ← "SOURCE(";
smKeyLength: CARD ← Rope.Length[smKey];
vsKey: Rope.
ROPE ← Rope.Cat["static char versionStamp[] = \"@", "(#)", "mob←version ["];
note: the version stamp key is broken into pieces so that it won't look like a version stamp in the various files.
vsKeyLength: CARD ← Rope.Length[vsKey];
FOR ln:
CARD ← 1, ln+1
WHILE
NOT
IO.EndOf[source]
DO
buffer ← IO.GetLine[source, buffer];
IF buffer[0] = 'S
THEN
-- possible SourcePositionMacro hit
BEGIN
line: Rope.ROPE ← Rope.FromRefText[buffer];
IF Rope.Equal[smKey, Rope.Substr[line, 0, smKeyLength]]
THEN
-- we have a hit
BEGIN
x: CARD ← smKeyLength;
sp: CARD ← 0;
nChars: CARD ← 0;
DO
IF buffer[x] = ', THEN EXIT;
sp ← sp*10 + ORD[buffer[x]] - ORD['0];
x ← x+1;
ENDLOOP;
WHILE buffer[x] = ', OR buffer[x] = ' DO x ← x+1 ENDLOOP;
DO
IF buffer[x] = ') THEN EXIT;
nChars ← nChars*10 + ORD[buffer[x]] - ORD['0];
x ← x+1;
ENDLOOP;
SeeOnePosition[sp, nChars, ln];
END;
END;
IF buffer[0] = 's
THEN
-- possible version stamp hit
BEGIN
line: Rope.ROPE ← Rope.FromRefText[buffer];
IF Rope.Equal[vsKey, Rope.Substr[line, 0, vsKeyLength]]
THEN
-- we have a hit
BEGIN
quote1: INT ← Rope.Index[line, 0, "\""];
quote2: INT ← Rope.Index[line, quote1+1, "\""];
IF quote2 = Rope.Length[line]-2
THEN
-- a final consistency check
versionStamp ← Rope.Substr[line, quote1+1, quote2-quote1-1];
END
END;
ENDLOOP;
END;
SystemInterface.ReleaseStreamForFile[cFile, source];
END;
misc
AddAName:
PROC[newName:
PATH, names:
LIST
OF
PATH]
RETURNS[
LIST
OF
PATH] =
BEGIN
FOR nms:
LIST
OF
PATH ← names, nms.rest
WHILE nms #
NIL
DO
IF nms.first.Equal[newName] THEN RETURN[names];
ENDLOOP;
RETURN[CONS[newName, names]];
END;
ShowSearchReport:
PROC[target: Rope.
ROPE, module: CedarModule] =
BEGIN
names: Rope.ROPE ← NIL;
FOR stems:
LIST
OF
PATH ←
IF module.possibleNameStems #
NIL
THEN module.possibleNameStems
ELSE module.originalPossibleNameStems, stems.rest
WHILE stems #
NIL
DO
IF names # NIL THEN names ← Rope.Cat[names, " or "];
names ← Rope.Cat[names, PFS.RopeFromPath[stems.first]];
ENDLOOP;
SystemInterface.ShowReport[Rope.Cat["searching for ", target, " for ", names], $normal];
END;
ShowFailureReport:
PROC[target: Rope.
ROPE, module: CedarModule] =
BEGIN
names: Rope.ROPE ← NIL;
FOR stems:
LIST
OF
PATH ←
IF module.possibleNameStems #
NIL
THEN module.possibleNameStems
ELSE module.originalPossibleNameStems, stems.rest
WHILE stems #
NIL
DO
IF names # NIL THEN names ← Rope.Cat[names, " or"];
names ← Rope.Cat[names, " ", PFS.RopeFromPath[stems.first]];
ENDLOOP;
SystemInterface.ShowReport[Rope.Cat["unable to find ", target, " for ", names], $normal];
END;
RecoveredVersionStamp:
TYPE =
RECORD[
mobStamp: MobDefs.VersionStamp,
stem: PATH];
FIX: Figure this out and use PFS Extensions instead of ROPEs
ConvertDotOFormatVersionStampToMobFormat:
PROC[wholeVersionStamp: Rope.
ROPE]
RETURNS[
REF RecoveredVersionStamp] =
BEGIN
ENABLE
BEGIN
RuntimeError.BoundsFault => GOTO fails;
Convert.Error => GOTO fails;
CantConvert => GOTO fails;
END;
expectedPreamble: Rope.
ROPE ← Rope.Cat["@", "(#)", "mob←version ["];
note: the version stamp key is broken into pieces so that it won't look like a version stamp in the various files.
stemStart: INT ← Rope.Index[wholeVersionStamp, 0, "] "]+2;
stampLength: INT ← Rope.Length[wholeVersionStamp];
preambleLength: INT ← Rope.Length[expectedPreamble];
stemLength: INT ← Rope.Length[wholeVersionStamp]-stemStart;
stem: Rope.ROPE ← IF stemLength > 0 THEN Rope.Substr[wholeVersionStamp, stemStart, stemLength] ELSE NIL;
preamble: Rope.ROPE ← Rope.Substr[wholeVersionStamp, 0, preambleLength];
digits: Rope.ROPE ← Rope.Substr[wholeVersionStamp, preambleLength, stampLength-preambleLength-stemLength-2];
comma: INT ← Rope.Find[digits, ","];
digits1: Rope.ROPE ← Rope.Substr[digits, 0, comma];
digits2: Rope.ROPE ← Rope.Substr[digits, comma+1, Rope.Length[digits]-comma-1];
stamp: MobDefs.VersionStamp ← [Convert.CardFromRope[digits1], Convert.CardFromRope[digits2]];
IF NOT Rope.Equal[preamble, expectedPreamble] THEN RaiseCantConvert[];
IF stem = NIL THEN RaiseCantConvert[];
RETURN[NEW[RecoveredVersionStamp ← [stamp, PFS.PathFromRope[stem]]]];
EXITS
fails => RETURN[NIL];
END;
CantConvert: ERROR = CODE;
RaiseCantConvert: PROC = {CantConvert[]};
DescribeRefStamp:
PROC [rs:
REF MobDefs.VersionStamp]
RETURNS [Rope.
ROPE]
~ {IF rs=NIL THEN RETURN ["NIL"] ELSE RETURN IO.PutFR["%08x%08x", [cardinal[rs[0]]], [cardinal[rs[1]]] ]};
test code
TestGenMesaSourcePositionMacros: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
fileName: PATH ← PFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
file: CirioFile ← SystemInterface.GetCirioFile[fileSet, fileName];
versionStamp: Rope.ROPE ← NIL;
SeeOnePosition:
PROC[sp:
CARD, nChars:
CARD, ln:
CARD] =
{IO.PutF[cmd.out, "sp: %g..%g, ln: %g\N", IO.card[sp], IO.card[sp+nChars], IO.card[ln]]};
versionStamp ← GenMesaSourcePositionMacros[file, SeeOnePosition];
IO.PutF[cmd.out, "\NversionStamp = %g\N", IO.rope[versionStamp]];
END;
SystemInterface.CloseFileSet[fileSet];
TestCreateCFileInfo: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
fileName: PATH ← PFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
file: SystemInterface.CirioFile ← SystemInterface.GetCirioFile[fileSet, fileName];
info: CFileInfo ← CreateCFileInfo[file];
ss: SourcePosSeq ← info.sourcePosSeq;
lns: LineNumSeq ← info.lineNumSeq;
IO.PutF[cmd.out, "versionStamp: %g\N", IO.rope[info.versionStamp]];
IO.PutF[cmd.out, "nSourcePosMacros = %g\n", IO.card[ss.nSourceMacros]];
FOR
I:
CARD
IN [0..ss.nSourceMacros)
DO
IO.PutF[cmd.out, "\T%g..%g CLine: %g\N", IO.card[ss[I].pos], IO.card[ss[I].pos+ss[I].nChars], IO.card[ss[I].lineNum]];
ENDLOOP;
IO.PutF[cmd.out, "\N"];
FOR
I:
CARD
IN [0..lns.nSourceMacros)
DO
IO.PutF[cmd.out, "\T CLine: %g %g..%g\N", IO.card[lns[I].lineNum], IO.card[lns[I].pos], IO.card[lns[I].pos+lns[I].nChars]];
ENDLOOP;
END;
SystemInterface.CloseFileSet[fileSet];
END;
This is used with
CreateButton c TestSetBreak Test.c
for example, when we have Test.mesa open and Test.c available.
TestSetBreak: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
cFileName: PATH ← PFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN ENABLE UNWIND => SystemInterface.CloseFileSet[fileSet];
file: SystemInterface.CirioFile ← SystemInterface.GetCirioFile[fileSet, cFileName];
info: CFileInfo ← CreateCFileInfo[file];
pos: SourceFileOpsExtras.Position ← SourceFileOpsExtras.noPosition;
cLineNum: CARD;
newMesaCharIdx: CARD;
IO.PutF[cmd.out, "versionStamp: %g\N", IO.rope[info.versionStamp]];
pos ← SourceFileOpsExtras.FullGetSelection[primary].pos;
IO.PutF[cmd.out, "%g in %g selected\N", IO.card[pos.index[char].first], IO.rope[PFS.RopeFromPath[pos.fileName]]];
cLineNum ← LookupMesaSourcePos[info, pos.index[char].first];
IO.PutF[cmd.out, "pointing to line %g in %g\N", IO.card[cLineNum], IO.rope[PFS.RopeFromPath[cFileName]]];
newMesaCharIdx ← LookupCLineNum[info, cLineNum];
IO.PutF[cmd.out, "pointing back to pos %g in %g\N", IO.card[newMesaCharIdx], IO.rope[PFS.RopeFromPath[pos.fileName]]];
SourceFileOpsExtras.FullOpenSource[desc: "Break set at ", pos: [fileName: pos.fileName, uniqueID: SourceFileOpsExtras.nullUniqueID, index: [char: [newMesaCharIdx] ] ], feedBack: cmd.out];
IO.PutF[cmd.out, "\N"];
END;
SystemInterface.CloseFileSet[fileSet];
END;
TestFromMesa: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
mesaName: PATH ← PFS.PathFromRope[args[1]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN
ENABLE
BEGIN
UNWIND => SystemInterface.CloseFileSet[fileSet];
SystemInterface.ShowReport =>
{ShowReportByLevel[cmd.out, msgText, priority];
IO.PutF[cmd.out, "%g\N", IO.rope[msgText]];
RESUME};
END;
modules: CedarModuleSet ← CreateCedarModuleSet[fileSet];
mesaFile: CirioFile ← SystemInterface.GetCirioFile[fileSet, mesaName];
module: CedarModule ← CreateCedarModuleFromMesa[modules, mesaFile];
[] ← GetParsed[module];
[] ← GetCFileInfo[module];
[] ← GetMesaFile[module];
[] ← GetJMPI[module];
[] ← GetMob[module];
[] ← GetModule[module];
END;
SystemInterface.CloseFileSet[fileSet];
END;
TestFromDotO: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
wholeName: PATH ← PFS.PathFromRope[args[1]];
pc: CARD ← Convert.CardFromRope[args[2]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN
ENABLE
BEGIN
UNWIND => SystemInterface.CloseFileSet[fileSet];
SystemInterface.ShowReport =>
{ShowReportByLevel[cmd.out, msgText, priority];
IO.PutF[cmd.out, "%g\N", IO.rope[msgText]];
RESUME};
END;
modules: CedarModuleSet ← CreateCedarModuleSet[fileSet];
wholeFile: CirioFile ← SystemInterface.GetCirioFile[fileSet, wholeName];
whole: ObjF.Parsed ← ObjF.CreateParsed[wholeFile];
embeddedModule: ObjF.Module ← FallBackFindModule[whole, pc];
module: CedarModule ← CreateCedarModuleFromModule[modules, whole, embeddedModule, LIST[wholeName]];
sourcePos: REF CedarSourcePosition ← ComputeCedarSourcePosition[module, [[0, ""], pc]];
IF module #
NIL
THEN {
[] ← GetMesaFile[module];
[] ← GetCFileInfo[module];
[] ← GetMesaFile[module];
[] ← GetJMPI[module];
[] ← GetMob[module];
[] ← GetModule[module];
};
ShowIndentedRopes[GetRopesForSourcePosInfo[sourcePos], cmd.out, 5];
END;
SystemInterface.CloseFileSet[fileSet];
END;
ShowIndentedRopes:
PROC[ropes:
LIST
OF Rope.
ROPE, on:
IO.
STREAM, indent:
CARD] =
BEGIN
FOR rps:
LIST
OF Rope.
ROPE ← ropes, rps.rest
WHILE rps #
NIL
DO
FOR
I:
CARD
IN [0..indent]
DO
IO.PutF[on, " "];
ENDLOOP;
IO.PutF[on, "%g\N", IO.rope[rps.first]];
ENDLOOP;
END;
CrudeExp: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
mesaName: PATH ← PFS.PathFromRope[args[1]];
mobName: PATH ← PFS.PathFromRope[args[2]];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN
ENABLE
BEGIN
UNWIND => SystemInterface.CloseFileSet[fileSet];
SystemInterface.ShowReport =>
{ShowReportByLevel[cmd.out, msgText, priority];
IO.PutF[cmd.out, "%g\N", IO.rope[msgText]];
RESUME};
END;
mesaFile: CirioFile ← SystemInterface.GetCirioFile[fileSet, mesaName];
mobFile: CirioFile ← SystemInterface.GetCirioFile[fileSet, mobName];
mob: MA.MobCookie ← MA.CreateMobCookie[mobFile];
mobVersion: MobDefs.VersionStamp ← MA.ReadMobVersionStamp[mob];
mobSourceVersion: MobDefs.VersionStamp ← MA.ReadSourceVersionStamp[mob];
possibleSourceVersion: MobDefs.VersionStamp ← MA.ComputeSourceVersionStamp[mesaFile];
ERROR -- for inspection
END;
SystemInterface.CloseFileSet[fileSet];
END;
this is to be used with
CreateButton tsb NewTestSetBreak menhir 4816
NewTestSetBreak: Commander.CommandProc =
BEGIN
args: CommandTool.ArgumentVector ← CommandTool.Parse[cmd];
remoteName: Rope.ROPE ← args[1];
portNum: CARD ← Convert.CardFromRope[args[2]];
nub: CirioNubAccess.Handle ← CirioNubAccess.CreateRemoteNub[debuggee: remoteName, port: portNum, timeoutMsec: 10000];
fileSet: SystemInterface.FileSet ← SystemInterface.CreateFileSet[];
BEGIN
ENABLE
BEGIN
UNWIND => {SystemInterface.CloseFileSet[fileSet]; CirioNubAccess.DestroyNub[nub]};
SystemInterface.ShowReport =>
{ShowReportByLevel[cmd.out, msgText, priority];
IO.PutF[cmd.out, "%g\N", IO.rope[msgText]];
RESUME};
END;
modules: CedarModuleSet ← CreateCedarModuleSet[fileSet];
loadState: LoadStateAccess.LoadStateHandle ← LoadStateAccess.CreateLoadStateHandle[remoteName, nub, fileSet];
pos: SourceFileOpsExtras.Position;
pos ← SourceFileOpsExtras.FullGetSelection[].pos;
IF pos.fileName #
NIL
THEN
BEGIN
mesaFileName: PATH ~ pos.fileName;
mesaSourcePosition: INT ~ pos.index[char].first;
mesaFile: CirioFile ← SystemInterface.GetCirioFile[fileSet, mesaFileName];
addr: REF CedarBreakAddress ← GetAbsAddressForBreak[modules, mesaFile, loadState, mesaSourcePosition];
ropes: LIST OF Rope.ROPE ← GetRopesForCedarBreakAddress[addr];
ShowIndentedRopes[ropes, cmd.out, 0];
IF addr #
NIL
THEN
BEGIN
basicInfo: REF LoadStateAccess.BasicPCInfo ← LoadStateAccess.GetBasicPCInfo[loadState, addr.absPC];
moreInfo: REF LoadStateAccess.LoadedModuleInfo ← LoadStateAccess.GetLoadedModuleInfoFromAbsPC[loadState, addr.absPC];
rope1: Rope.ROPE ← LoadStateAccess.GetRopeForBasicPCInfo[basicInfo, addr.absPC, TRUE, TRUE, TRUE, TRUE];
ropes2: LIST OF Rope.ROPE ← LoadStateAccess.GetRopeListForBasicPCInfo[basicInfo];
ropes3: LIST OF Rope.ROPE ← LoadStateAccess.GetRopeListForLoadedModuleInfo[moreInfo];
ShowIndentedRopes[LIST[rope1], cmd.out, 0];
ShowIndentedRopes[ropes2, cmd.out, 0];
ShowIndentedRopes[ropes3, cmd.out, 0];
BEGIN
mesaParts: NameParts ← GetNamePartsFromFullPathName[mesaFileName];
ResetSearchPaths[modules,
LIST[mesaParts.principalDirectory], BasicTime.Now[]];
cludge, mechanism should have noticed this added principal directory
BEGIN
resultingModule: CedarModule ← GetCedarModuleForLoadedModule[modules, moreInfo];
moduleRelativeAddr: CARD ← addr.absPC-(moreInfo.lsi[text].base+moreInfo.moduleRelativeBaseAddr);
resultingSourcePos: REF CedarSourcePosition ← ComputeCedarSourcePosition[resultingModule, [[0, ""], moduleRelativeAddr]];
ropes4: LIST OF Rope.ROPE ← GetRopesForSourcePosInfo[resultingSourcePos];
ShowIndentedRopes[ropes4, cmd.out, 0];
IF resultingSourcePos.mesaPosition # addr.correspondingMesaPosition THEN ERROR;
END;
END;
END;
END;
END;
CirioNubAccess.DestroyNub[nub];
SystemInterface.CloseFileSet[fileSet];
END;
SetDebugSearch: Commander.CommandProc ~ {
debugSearch ← cmd.procData.clientData = $True;
msg ← IO.PutFR["debugSearch=%g", [boolean[debugSearch]] ]};
ShowReportByLevel:
PUBLIC
PROC [s:
IO.
STREAM, r: Rope.
ROPE, level:
ATOM] ~ {
SELECT messagesDesired
FROM
$debug => IO.PutF[s, "%g\N", IO.rope[r]];
$normal =>
SELECT level
FROM
$debug => {};
$normal,
$urgent => IO.PutF[s, "%g\N", IO.rope[r]];
ENDCASE => IO.PutF[s, "Bad level for message: %g\N", IO.rope[r]];
$urgent =>
SELECT level
FROM
$debug => {};
$normal => {};
$urgent => IO.PutF[s, "%g\N", IO.rope[r]];
ENDCASE => IO.PutF[s, "Bad level for message: %g\N", IO.rope[r]];
ENDCASE => IO.PutF[s, "Bad desired level for message: %g\N", IO.rope[r]];
};
LevelFromRope:
PROC [r: Rope.
ROPE]
RETURNS [
ATOM] ~ {
SELECT
TRUE
FROM
Rope.Equal[r, "normal", FALSE] => RETURN[$normal];
Rope.Equal[r, "debug", FALSE] => RETURN[$debug];
Rope.Equal[r, "urgent", FALSE] => RETURN[$urgent];
ENDCASE => RETURN[$error];
};
RopeFromLevel:
PROC [l:
ATOM]
RETURNS [Rope.
ROPE ← "ERROR"] ~ {
SELECT l
FROM
$normal => RETURN["normal"];
$debug => RETURN["debug"];
$urgent => RETURN["urgent"];
ENDCASE => RETURN["ERROR"];
};
MessageLevel:
PROC []
RETURNS [
ATOM ← $error] ~ {
levelRope: Rope.ROPE ← UserProfile.Token[key: "Cirio.MessageLevel", default: "normal"];
level: ATOM ← LevelFromRope[levelRope];
IF level = $error
THEN
level ← $normal;
RETURN [level];
};
ChangeLevel: Commander.CommandProc ~ {
numArgs:CARD ← CommanderOps.NumArgs[cmd];
newLevel: ATOM ← NIL;
newLevelRope: Rope.ROPE ← NIL;
IF numArgs > 1
THEN {
newLevelRope ← CommanderOps.NextArgument[cmd];
newLevel ← LevelFromRope[newLevelRope];
SELECT newLevel
FROM
$error => IO.PutF[cmd.out, "level %g is not a valid message level\nValid levels are normal, urgent, and debug.\n", IO.rope[newLevelRope]];
messagesDesired => IO.PutF[cmd.out, "level %g was already the message level.\n", IO.rope[newLevelRope]];
ENDCASE => {
IO.PutF[cmd.out, "level changed from %g to %g.\n", IO.rope[RopeFromLevel[messagesDesired]], IO.rope[newLevelRope]];
messagesDesired ← newLevel;
}
}
ELSE
IO.PutF[cmd.out, "Current level: %g\n", IO.rope[RopeFromLevel[messagesDesired]]];
};
main code
messagesDesired: ATOM ← MessageLevel[];
debugSearch: BOOL ← FALSE;
Commander.Register["ChangeCirioMessageLevel", ChangeLevel, "Change the verbosity level of the messages that Cirio prints out.\n\tUsage: ChangeCirioMessageLevel [level]\n\tValid levels:\n\t\turgent:\tMessages that should always be seen.\n\t\tnormal:\tInformative messages.\n\t\tdebug:\tMore informatation than you want to see.\n\t<none>\tPrint the current setting.\n"];
Commander.Register["TestGenMesaSourcePositionMacros", TestGenMesaSourcePositionMacros];
Commander.Register["TestCreateCFileInfo", TestCreateCFileInfo];
Commander.Register["TestSetBreak", TestSetBreak];
Commander.Register["TestFromMesa", TestFromMesa];
TestFromMesa /pixel1/pcedar2.0/sunterminal/sunterminalimpl.mesa.~23~
Commander.Register["TestFromDotO", TestFromDotO, "file.o file-rel-pc"];
TestFromDotO /pixel1/pcedar2.0/sunterminal/sun4/sunterminalimpl.c2c.o.~23~ 50
Commander.Register["CrudeExp", CrudeExp];
CrudeExp /pixel1/pcedar2.0//sunterminal/sunterminalimpl.mesa.~23~ /pixel1/pcedar2.0//sunterminal/sunterminalimpl.mob.~23~
Commander.Register["NewTestSetBreak", NewTestSetBreak];
this is to be used with
CreateButton tsb NewTestSetBreak menhir 4816
after selecting a position in some mesa file, e.g.,
[palain-ux]<palain>sturgis>Cedar>2.0>System>PlumberImpl.mesa
Commander.Register["Cirio.DebugSearch", SetDebugSearch, "RMTWModules.debugSearch ← TRUE", $True];
Commander.Register["Cirio.DontDebugSearch", SetDebugSearch, "RMTWModules.debugSearch ← FALSE", $False];
END.