RTGetSymbolsImpl.mesa
Last Modified By Paul Rovner On March 31, 1983 1:34 pm
Last Modified By Russ Atkinson On June 28, 1983 6:18 pm
altering VersionToReadableFile to spec
DIRECTORY
AMTypes USING[Error],
BcdDefs
USING[VersionStamp, NameRecord, MTIndex, SGIndex, SGNull, FTNull,
FTSelf, VersionID, FTIndex, NullVersion],
BcdOps
USING[BcdBase, NameString, MTHandle, SGHandle, ProcessModules,
FTHandle, ProcessFiles],
BrandXSymbolDefs
USING[rootBodyIndex, nullSymbolIndex, SymbolTableBase,
SymbolModuleIndex],
BrandYSymbolDefs
USING[rootBodyIndex, nullSymbolIndex, SymbolTableBase,
SymbolModuleIndex],
CIFS USING[GetFC, Open, read, dontCheck, OpenFile],
ConvertUnsafe USING[AppendRope, ToRope],
File USING[Capability, nullCapability],
FileSegment USING[Pages],
LongString USING[AppendString],
PilotLoadStateFormat USING[ModuleInfo, ConfigIndex],
PilotLoadStateOps
USING[InputLoadState, GetModule, AcquireBcd, ReleaseBcd,
ReleaseLoadState, EnumerateBcds],
PrincOps USING[GlobalFrameHandle],
NewRCMapOps USING[EstablishOuter],
Rope USING[ROPE, Flatten, Length, Fetch, Concat],
RTFiles USING [SameFile], -- EXPORTS
RTFilesExtra USING [], -- EXPORTS only
RTFlags USING[checking],
RTOS USING[EnumerateGlobalFrames, SameCode, UnRavelUSUs],
RTSymbolDefs
USING[SymbolTableBase, SymbolTableHandle, nullHandle, nullBase,
SymbolModuleIndex],
RTSymbolOps
USING[STBToModuleName, STBVersion, SubStringForHash, NullModuleIndex,
NullSth],
RTSymbols USING[], -- EXPORTS only
RTSymbolsPrivate USING[], -- EXPORTS only
RTTypesBasicPrivate USING[SymbolTableIndex, MapStiStd, FindSTI, STDesc],
Runtime USING[CallDebugger, ValidateGlobalFrame],
Space
USING[Map, LongPointer, Unmap, GetAttributes, GetWindow, GetHandle,
PageFromLongPointer, Handle, Create, virtualMemory, Delete],
Strings
USING[SubStringDescriptor, AppendSubString, AppendString,
EqualSubStrings],
SymbolTable USING[SetCacheSize, Release, Acquire, Forget, anySpan],
Table USING[Base],
VersionMap USING[MapList],
VersionMapDefaults USING[FileNameFromVersion, GetMapList];
RTGetSymbolsImpl:
MONITOR
IMPORTS AMTypes, BcdOps,
CIFS, ConvertUnsafe, LongString,
PilotLoadStateOps, NewRCMapOps, Rope, RTFiles, RTOS, RTSymbolOps, RTTypesBasicPrivate,
Runtime, Space, Strings, SymbolTable, VersionMapDefaults
EXPORTS RTFiles, RTFilesExtra, RTSymbols, RTSymbolsPrivate
SHARES File
=
BEGIN
OPEN bx: BrandXSymbolDefs, by: BrandYSymbolDefs,
XSymbolTable: SymbolTable, YSymbolTable: SymbolTable,
XRCMapOps: NewRCMapOps, YRCMapOps: NewRCMapOps,
RTSymbolDefs, RTSymbolOps;
Variables protected by the monitor
onePageSpace: Space.Handle = Space.Create[size: 1, parent: Space.virtualMemory];
standardBCDSpaces: LIST OF Space.Handle ← NIL;
standardBCDSpacePages: NAT = 20;
standardBCDSpacesInUse: NAT ← 0;
standardBCDSpacesHeld: NAT ← 0;
biggerBCDSpacesInUse: NAT ← 0;
OZ: BOOL ← FALSE;
ROPE: TYPE = Rope.ROPE;
-- PUBLIC PROCS --
Outer:
PUBLIC
PROC[stb: SymbolTableBase,
mdi: SymbolModuleIndex,
inner: PROC[base: SymbolTableBase],
mesaSymbolsOK: BOOL ← FALSE] =
{stb1: SymbolTableBase = AcquireSTBFromMDI[stb, mdi, mesaSymbolsOK];
inner[stb1 ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1]};
AcquireSTBForDefs:
PUBLIC
PROC[fileName:
ROPE
--ends with .bcd--]
RETURNS[stb: SymbolTableBase] =
{ mn:
STRING = [100];
dotFound: BOOL ← FALSE;
FOR i:
NAT
IN [0..Rope.Length[fileName])
DO IF Rope.Fetch[fileName, i] = '. THEN {dotFound ← TRUE; EXIT};
ENDLOOP;
IF NOT dotFound THEN fileName ← Rope.Concat[fileName, ".bcd"];
mn.length ← 0;
ConvertUnsafe.AppendRope[from: fileName, to: LONG[mn]];
IF mn.length<=4 THEN ERROR AMTypes.Error[reason: noSymbols, msg: fileName];
mn.length ← mn.length-4;
stb ← AcquireSTB[GetSTHForModule[stamp: BcdDefs.NullVersion,
fileName: fileName,
moduleName: ConvertUnsafe.ToRope[LONG[mn]]]];
IF
NOT (
WITH stb
SELECT
FROM
t: SymbolTableBase.x => t.e.stHandle.definitionsFile,
t: SymbolTableBase.y => t.e.stHandle.definitionsFile,
ENDCASE => ERROR)
THEN {ReleaseSTB[stb];
ERROR AMTypes.Error[reason: noSymbols,
msg: Rope.Concat[fileName, " not a defs module"]]};
};
AcquireSTB:
PUBLIC
PROC[sth: SymbolTableHandle, mesaSymbolsOK:
BOOL ←
FALSE]
RETURNS[stb: SymbolTableBase] =
{stb ←
WITH sth
SELECT
FROM
t: SymbolTableHandle.x => [x[XSymbolTable.Acquire[t.e]]],
t: SymbolTableHandle.y => [y[YSymbolTable.Acquire[t.e]]]
ENDCASE => ERROR;
IF mesaSymbolsOK
THEN
RETURN[stb];
groan. backward compatibility for limited usage
(for RTSymbols clients only, NOT for AMTypes)
IF
NOT (
WITH stb
SELECT
FROM
t: SymbolTableBase.x => t.e.stHandle.extended,
t: SymbolTableBase.y => t.e.stHandle.extended,
ENDCASE => ERROR) -- symbol table made by an old version of the compiler
OR (
WITH stb
SELECT
FROM
t: SymbolTableBase.x => t.e.bb[bx.rootBodyIndex].type = bx.nullSymbolIndex,
t: SymbolTableBase.y => t.e.bb[by.rootBodyIndex].type = by.nullSymbolIndex,
ENDCASE => ERROR)
THEN {modName:
ROPE = STBToModuleName[stb !
UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
ERROR AMTypes.Error[reason: noSymbols, msg: modName]}
ELSE RETURN[stb]};
ReleaseSTB:
PUBLIC
PROC[stb: SymbolTableBase] =
{
WITH stb
SELECT
FROM
t: SymbolTableBase.x => XSymbolTable.Release[t.e];
t: SymbolTableBase.y => YSymbolTable.Release[t.e]
ENDCASE => ERROR};
STPages:
PUBLIC
PROC[sth: SymbolTableHandle]
RETURNS[
CARDINAL] =
{
RETURN[
WITH sth
SELECT
FROM
t: SymbolTableHandle.x => t.e.span.pages,
t: SymbolTableHandle.y => t.e.span.pages,
ENDCASE => ERROR]};
this may return nullHandle but will not raise any signals
AcquireSTHFromSTX:
PUBLIC
PROC[stx: RTTypesBasicPrivate.SymbolTableIndex]
RETURNS[sth: SymbolTableHandle ← nullHandle, moduleName: ROPE ← NIL] =
{[sth, moduleName] ← DoAcquireSTHFromSTX[stx, TRUE]};
DoAcquireSTHFromSTX:
PROC[stx: RTTypesBasicPrivate.SymbolTableIndex,
invokeGetSTHForModule: BOOL ← FALSE]
RETURNS[sth: SymbolTableHandle ← nullHandle, moduleName: ROPE ← NIL] =
{ symbolsStamp: BcdDefs.VersionStamp;
bcd: BcdOps.BcdBase;
IF
NOT NullSth[RTTypesBasicPrivate.MapStiStd[stx].sth]
THEN RETURN[sth: RTTypesBasicPrivate.MapStiStd[stx].sth];
symbolsStamp ← RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp;
bcd ← RTTypesBasicPrivate.MapStiStd[stx].bcd;
IF bcd =
NIL
THEN {
IF invokeGetSTHForModule
THEN sth ← GetSTHForModule[stamp: symbolsStamp,
fileName: NIL,
moduleName: NIL
! ANY => CONTINUE]
ELSE RETURN}
ELSE
{sgb: Table.Base =
LOOPHOLE[bcd + bcd.sgOffset];
ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset];
fti: BcdDefs.FTIndex;
sgi: BcdDefs.SGIndex = RTTypesBasicPrivate.MapStiStd[stx].sgi;
-- maybe SGNull
(=> search the BCD's file table)
IF sgi = BcdDefs.SGNull
-- search the BCD's file table (find a DEFs)
THEN { findSymbolFTI:
PROC[ffth: BcdOps.FTHandle, ffti: BcdDefs.FTIndex]
RETURNS[stop: BOOL] =
{
IF
NOT EQStamps[ffth.version, symbolsStamp]
THEN
RETURN[
FALSE];
moduleName ← GetModuleName[ssb, ffth.name];
sth ← GetSTHForModule[stamp: symbolsStamp,
fileName: Rope.Concat[moduleName, ".bcd"],
moduleName: moduleName
! AMTypes.Error => CONTINUE];
RETURN[TRUE]};
IF NOT invokeGetSTHForModule THEN RETURN;
[] ← BcdOps.ProcessFiles[bcd, findSymbolFTI];
IF NullSth[sth]
THEN sth ← GetSTHForModule[stamp: symbolsStamp,
fileName: NIL,
moduleName: NIL
! ANY => CONTINUE];
RTTypesBasicPrivate.MapStiStd[stx].sth ← sth;
RETURN}
ELSE fti ← sgb[sgi].file;
IF fti = BcdDefs.FTSelf
THEN {
OPEN Space;
file: File.Capability = FileFromBcdBase[bcd];
IF file # File.nullCapability
THEN
{p: FileSegment.Pages =
[file: file,
span: [base: sgb[sgi].base, pages: sgb[sgi].pages + sgb[sgi].extraPages]];
sth ← IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]};
}
ELSE {
-- look for the specified file
fileName: ROPE = GetFileName[ssb, ftb[fti].name];
moduleName ← GetModuleName[ssb, ftb[fti].name];
sth ← NewSymbolHandle[fileName: fileName,
version: ftb[sgb[sgi].file].version,
of indicated bcd. Should match bcd.version
base: sgb[sgi].base,
pages: sgb[sgi].pages + sgb[sgi].extraPages
! AMTypes.Error => CONTINUE]
};
}; -- end ELSE (i.e. bcd # NIL)
RTTypesBasicPrivate.MapStiStd[stx].sth ← sth;
}; -- end DoAcquireSTHFromSTX
version must match bcd.version
NewSymbolHandle:
PUBLIC
PROC[fileName:
ROPE,
base: CARDINAL,
pages: CARDINAL,
version: BcdDefs.VersionStamp ← BcdDefs.NullVersion]
RETURNS[sth: SymbolTableHandle ← nullHandle] =
{ file: File.Capability ← File.nullCapability;
stb: SymbolTableBase;
symbolsStamp: BcdDefs.VersionStamp;
isXBCD: BOOL = TRUE; -- NOTE XXX
IF EQStamps[version, BcdDefs.NullVersion]
THEN file ← GetReadCapability[fileName ! ANY => CONTINUE]
ELSE file ← AcquireFCFromVersion[version, fileName];
IF file = File.nullCapability THEN ERROR AMTypes.Error[reason: noSymbols, msg: fileName];
here if file is found and version matches
sth ←
IF isXBCD
THEN [x[[file: file, span: [base: base, pages: pages]]]]
ELSE [y[[file: file, span: [base: base, pages: pages]]]];
stb ← AcquireSTB[sth];
symbolsStamp ← STBVersion[stb];
ReleaseSTB[stb];
[] ← RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]];
}; -- end NewSymbolHandle
IsFileInUse:
PUBLIC
PROC[file: File.Capability]
RETURNS[found:
BOOL ←
FALSE] =
{ loadStateHeld:
BOOL;
p:
PROC[c: PilotLoadStateFormat.ConfigIndex]
RETURNS[stop:
BOOL] =
{
OPEN Space;
ptr: LONG POINTER = LOOPHOLE[PilotLoadStateOps.AcquireBcd[c]];
space: Handle ← RTOS.UnRavelUSUs[GetHandle[PageFromLongPointer[ptr]]];
PilotLoadStateOps.ReleaseBcd[LOOPHOLE[ptr]];
IF file.fID = GetWindow[space].file.fID
THEN {found ← TRUE; RETURN[TRUE]}
ELSE RETURN[FALSE];
};
try for the local lockbox first
IF IsFileUsed[file] THEN RETURN [TRUE];
flush the SymbolCache
XSymbolTable.Forget[[file: file, span: XSymbolTable.anySpan]
! ANY => {found ← TRUE; CONTINUE}];
IF found THEN RETURN;
YSymbolTable.Forget[[file: file, span: YSymbolTable.anySpan]
! ANY => {found ← TRUE; CONTINUE}];
IF found THEN RETURN;
enumerate the loadstate
[] ← PilotLoadStateOps.InputLoadState[];
loadStateHeld ← TRUE;
[] ← PilotLoadStateOps.EnumerateBcds[recentfirst, p
!
ANY => {loadStateHeld ←
FALSE;
PilotLoadStateOps.ReleaseLoadState[]}];
IF loadStateHeld THEN PilotLoadStateOps.ReleaseLoadState[];
IF found THEN RETURN;
enumerate MapStiStd
FOR x:
NAT
IN [1..RTTypesBasicPrivate.MapStiStd.length)
DO sth: SymbolTableHandle;
f: File.Capability;
b: BOOL;
IF RTTypesBasicPrivate.MapStiStd[x] = NIL THEN EXIT;
sth ← RTTypesBasicPrivate.MapStiStd[x].sth;
IF NullSth[sth] THEN LOOP;
SELECT sth FROM
t: SymbolTableHandle.x => b ← TRUE;
t: SymbolTableHandle.y => b ← FALSE;
ENDCASE => ERROR;
IF sth.brand = x
THEN f ← NARROW[sth, SymbolTableHandle.x].e.file
ELSE f ← NARROW[sth, SymbolTableHandle.y].e.file;
IF f.fID = file.fID THEN RETURN[TRUE];
ENDLOOP;
};
RCMapOuterX:
PROC[stb: bx.SymbolTableBase,
mdi: bx.SymbolModuleIndex,
inner: PROC[base: bx.SymbolTableBase]] =
{stb1: SymbolTableBase = AcquireSTBFromMDI[[x[stb]], [x[mdi]]];
inner[NARROW[stb1, SymbolTableBase.x].e ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1]};
RCMapOuterY:
PROC[stb: by.SymbolTableBase,
mdi: by.SymbolModuleIndex,
inner: PROC[base: by.SymbolTableBase]] =
{stb1: SymbolTableBase = AcquireSTBFromMDI[[y[stb]], [y[mdi]]];
inner[NARROW[stb1, SymbolTableBase.y].e ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1]};
AcquireSTBFromMDI:
PUBLIC
PROC[stb: SymbolTableBase,
mdi: SymbolModuleIndex,
mesaSymbolsOK: BOOL ← FALSE]
RETURNS[SymbolTableBase] =
{ fileNameDesc, modNameDesc: Strings.SubStringDescriptor;
fileName: STRING = [100];
modName: STRING = [100];
IF NullModuleIndex[mdi] THEN ERROR;
fileName.length ← 0;
modName.length ← 0;
SubStringForHash[stb,
@modNameDesc,
WITH stb
SELECT
FROM
t: SymbolTableBase.x =>
[x[t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].moduleId]],
t: SymbolTableBase.y =>
[y[t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].moduleId]],
ENDCASE => ERROR];
Strings.AppendSubString[modName, @modNameDesc];
SubStringForHash[stb,
@fileNameDesc,
WITH stb
SELECT
FROM
t: SymbolTableBase.x =>
[x[t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].fileId]],
t: SymbolTableBase.y =>
[y[t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].fileId]],
ENDCASE => ERROR];
Strings.AppendSubString[fileName, @fileNameDesc];
RETURN[AcquireSTB[GetSTHForModule
[(
WITH stb
SELECT
FROM
t: SymbolTableBase.x =>
t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].stamp,
t: SymbolTableBase.y =>
t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].stamp,
ENDCASE => ERROR),
ConvertUnsafe.ToRope[LONG[fileName]],
ConvertUnsafe.ToRope[LONG[modName]]],
mesaSymbolsOK]]};
stamp on the MODULE, maybe different than bcd.version
GetSTHForModule:
PUBLIC
PROC[stamp: BcdDefs.VersionStamp,
fileName: ROPE, -- maybe NIL
moduleName: ROPE -- maybe NIL
]
RETURNS[sth: SymbolTableHandle ← nullHandle] =
{ bcd: BcdOps.BcdBase;
newFile: File.Capability ← File.nullCapability;
sgb: Table.Base;
ftb: Table.Base;
ntb: BcdOps.NameString;
versionMapTried: BOOL ← FALSE;
mth: BcdOps.MTHandle;
sSeg: BcdDefs.SGIndex;
modNameDesc: Strings.SubStringDescriptor
← [base:
LOOPHOLE[Rope.Flatten[moduleName]],
offset: 0,
length: Rope.Length[moduleName]];
someNameMatched: BOOL ← FALSE;
FindVersionStampedModule:
PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
RETURNS[stop: BOOL] =
{ umid: BcdDefs.VersionStamp =
IF mth.file = BcdDefs.FTSelf
THEN bcd.version
ELSE ftb[mth.file].version;
nextModNameDesc: Strings.SubStringDescriptor;
namesMatch: BOOL ← TRUE;
IF moduleName #
NIL
THEN {nextModNameDesc ← [base: @ntb.string,
offset: mth.name,
length: ntb.size[mth.name]];
namesMatch ← Strings.EqualSubStrings[@modNameDesc, @nextModNameDesc];
someNameMatched ← someNameMatched OR namesMatch};
RETURN[namesMatch
AND (EQStamps[stamp, BcdDefs.NullVersion]
OR EQStamps[stamp, umid])]
}; -- end FindVersionStampedModule
START GetSTHForModule body here
IF
NOT EQStamps[stamp, BcdDefs.NullVersion]
THEN {found:
BOOL;
stx: RTTypesBasicPrivate.SymbolTableIndex;
[stx, found] ← FindSTX[stamp];
IF found THEN sth ← DoAcquireSTHFromSTX[stx].sth;
IF NOT NullSth[sth] THEN RETURN[sth]};
IF fileName # NIL THEN newFile ← GetReadCapability[fileName ! ANY => CONTINUE];
DO
IF newFile = File.nullCapability
-- no local file with that name
THEN {
IF EQStamps[stamp, BcdDefs.NullVersion]
THEN GOTO noFile
ELSE {
-- look for the module's original file
shortName:
ROPE =
IF moduleName =
NIL
THEN NIL
ELSE Rope.Concat[moduleName, ".bcd"];
cifsFile:
CIFS.OpenFile =
VersionToReadableFile[versionStamp: stamp,
shortNameHint: shortName];
versionMapTried ← TRUE;
IF cifsFile = NIL THEN GOTO noFile;
newFile ←
CIFS.GetFC[cifsFile
!
ANY => {
IF
OZ
THEN Runtime.CallDebugger
["CIFS.GetFC failed"];
CONTINUE}];
IF newFile = File.nullCapability THEN GOTO noFile}};
here with a valid FC
bcd ← AcquireBCDFromCap[newFile];
sgb ← LOOPHOLE[bcd + bcd.sgOffset];
ftb ← LOOPHOLE[bcd + bcd.ftOffset];
ntb ← LOOPHOLE[bcd + bcd.ssOffset];
IF bcd.versionIdent # BcdDefs.VersionID
THEN {
IF versionMapTried
THEN GOTO oldSymbols
ELSE {newFile ← File.nullCapability; LOOP}};
someNameMatched ← FALSE;
mth ← BcdOps.ProcessModules[bcd, FindVersionStampedModule].mth;
IF mth =
NIL
THEN {
IF
NOT versionMapTried
THEN {newFile ← File.nullCapability;
LOOP};
IF someNameMatched
THEN GOTO wrongVersion
ELSE GOTO noSymbols};
sSeg ← mth.sseg;
IF sSeg = BcdDefs.SGNull
OR sgb[sSeg].pages = 0
OR ((NOT bcd.definitions) AND (sgb[sSeg].extraPages = 0)) -- compressed symbols
OR sgb[sSeg].file # BcdDefs.FTSelf
THEN {
IF versionMapTried
THEN GOTO noSymbols
ELSE {newFile ← File.nullCapability; LOOP}};
{p: FileSegment.Pages =
[file: newFile, span: [base: sgb[sSeg].base,
pages: sgb[sSeg].pages + sgb[sSeg].extraPages]];
sth ← IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]};
IF EQStamps[stamp, BcdDefs.NullVersion]
THEN {stb: SymbolTableBase = AcquireSTB[sth];
stamp ← STBVersion[stb];
ReleaseSTB[stb]};
[] ← RTTypesBasicPrivate.FindSTI[[symbolsStamp: stamp, sth: sth]];
ReleaseBCD[bcd];
RETURN[sth];
ENDLOOP;
EXITS
noFile => ERROR AMTypes.Error[reason: noSymbols, msg: fileName];
oldSymbols => ERROR AMTypes.Error[reason: noSymbols, msg: moduleName];
noSymbols =>
ERROR AMTypes.Error[reason: noSymbols,
msg:
IF moduleName =
NIL
THEN fileName
ELSE moduleName];
wrongVersion => ERROR AMTypes.Error[reason: noSymbols, msg: moduleName];
}; -- end GetSTHForModule
raises Error if there are no symbols for the specified module
AcquireSTBFromGFH:
PUBLIC
PROC[gfh: PrincOps.GlobalFrameHandle,
mesaSymbolsOK: BOOL ← FALSE]
RETURNS[stb: SymbolTableBase ← nullBase] =
BEGIN
bcd: BcdOps.BcdBase;
bcdns: BcdOps.NameString;
moduleName: ROPE;
module: PilotLoadStateFormat.ModuleInfo; -- a loadstate.gft entry
mth: BcdOps.MTHandle;
umid: BcdDefs.VersionStamp; -- functional version stamp of the module
ftb: Table.Base;
sth: SymbolTableHandle ← nullHandle;
FindOriginal:
PROCEDURE [f: PrincOps.GlobalFrameHandle]
RETURNS [
BOOL] =
{RETURN[(f # gfh) AND (RTOS.SameCode[gfh, f] = identical) AND (~f.copied)]};
FindModule:
PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex]
RETURNS [
BOOL] =
{RETURN[(mth.gfi <= module.gfi) AND (module.gfi < (mth.gfi + mth.ngfi))]};
IF RTFlags.checking THEN Runtime.ValidateGlobalFrame[gfh];
IF gfh.copied THEN gfh ← RTOS.EnumerateGlobalFrames[FindOriginal];
[] ← PilotLoadStateOps.InputLoadState[];
module ← PilotLoadStateOps.GetModule[gfh.gfi];
bcd ← PilotLoadStateOps.AcquireBcd[module.config];
PilotLoadStateOps.ReleaseLoadState[];
bcdns ← LOOPHOLE[bcd + bcd.ssOffset];
ftb ← LOOPHOLE[bcd + bcd.ftOffset];
[mth,] ← BcdOps.ProcessModules[bcd, FindModule];
IF mth = NIL THEN ERROR;
umid ← (IF mth.file = BcdDefs.FTSelf THEN bcd.version ELSE ftb[mth.file].version);
First look in the umid -> sth map
{found:
BOOL;
stx: RTTypesBasicPrivate.SymbolTableIndex;
[stx, found] ← FindSTX[umid];
IF found THEN sth ← AcquireSTHFromSTX[stx].sth};
IF NullSth[sth]
-- then try for the one referenced in the bcd
THEN sth ← AcquireSTHFromSGI[bcd, mth.sseg];
IF NullSth[sth]
-- then try for the named module's file (locally)
THEN sth ← GetSTHForModule[stamp: umid,
fileName: GetFileName[ssb: bcdns, n: ftb[mth.file].name],
moduleName: GetModuleName[ssb: bcdns, n: mth.name]
! ANY => CONTINUE];
IF NullSth[sth]
-- then try for the original one
THEN [sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[RTTypesBasicPrivate.FindSTI[[symbolsStamp: umid,
bcd: bcd]]];
IF NullSth[sth]
-- then give up.
THEN {sgb: Table.Base =
LOOPHOLE[bcd + bcd.sgOffset];
msg: ROPE ← moduleName;
IF msg = NIL THEN msg ← GetFileName[ssb: bcdns, n: ftb[sgb[mth.sseg].file].name];
ERROR AMTypes.Error[reason: noSymbols, msg: msg]};
stb ← AcquireSTB[sth, mesaSymbolsOK];
RETURN[stb];
END; -- AcquireSTBFromGFH
AcquireSTBFromSGI:
PUBLIC
PROC[bcd: BcdOps.BcdBase,
sgi: BcdDefs.SGIndex, -- of the symbol segment
mesaSymbolsOK: BOOL ← FALSE]
RETURNS[stb: SymbolTableBase ← nullBase] =
{ ftb: Table.Base =
LOOPHOLE[bcd + bcd.ftOffset];
sgh: BcdOps.SGHandle = @LOOPHOLE[bcd + bcd.sgOffset, Table.Base][sgi];
sth: SymbolTableHandle ← AcquireSTHFromSGI[bcd, sgi]; -- try for the referenced one
IF NullSth[sth]
THEN {ssb: BcdOps.NameString =
LOOPHOLE[bcd + bcd.ssOffset];
ERROR AMTypes.Error[reason: noSymbols,
msg: GetFileName[ssb: ssb, n: ftb[sgh.file].name]]};
RETURN[AcquireSTB[sth]]};
-- PRIVATE PROCS --
EQStamps: PROC[s1, s2: BcdDefs.VersionStamp] RETURNS[BOOL] =
INLINE {RETURN[s1.net = s2.net AND s1.host = s2.host AND s1.time = s2.time]};
FindSTX:
PROC[stamp: BcdDefs.VersionStamp]
RETURNS[stx: RTTypesBasicPrivate.SymbolTableIndex, found: BOOL] =
{
FOR stx
IN [1..RTTypesBasicPrivate.MapStiStd.length)
DO
IF RTTypesBasicPrivate.MapStiStd[stx] =
NIL
THEN
EXIT;
IF EQStamps[stamp, RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp]
THEN RETURN[stx, TRUE];
ENDLOOP;
RETURN[0, FALSE]};
returns nullHandle if there are no symbols
AcquireSTHFromSGI:
PROC [bcd: BcdOps.BcdBase, sgi: BcdDefs.SGIndex]
RETURNS [sth: SymbolTableHandle ← nullHandle] =
{ sgb: Table.Base =
LOOPHOLE[bcd + bcd.sgOffset];
ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset];
ssb: BcdOps.NameString = LOOPHOLE[bcd + bcd.ssOffset];
sgh: BcdOps.SGHandle ← @sgb[sgi];
IF sgh.class # symbols THEN ERROR;
IF (sgh.pages = 0)
-- empty symbol segment
OR ((NOT bcd.definitions) AND (sgh.extraPages = 0)) -- compressed symbols
OR sgh.file = BcdDefs.FTNull
THEN RETURN;
IF sgh.file = BcdDefs.FTSelf
THEN {stb: SymbolTableBase;
symbolsStamp: BcdDefs.VersionStamp;
file: File.Capability = FileFromBcdBase[bcd];
IF file = File.nullCapability THEN RETURN;
{p: FileSegment.Pages =
[file: file, span: [base: sgh.base, pages: sgh.pages+sgh.extraPages]];
sth ← IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]};
stb ← AcquireSTB[sth];
symbolsStamp ← STBVersion[stb];
ReleaseSTB[stb];
[] ← RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]];
}
ELSE
{ fileName:
ROPE ← GetFileName[ssb, ftb[sgh.file].name];
sth ← NewSymbolHandle[fileName: fileName,
base: sgh.base,
pages: sgh.pages+sgh.extraPages,
version: ftb[sgh.file].version
version of the specified file, not necessarily of the module
! ANY => CONTINUE]}
}; -- end AcquireSTHFromSGI
GetModuleName:
PROC[ssb: BcdOps.NameString, n: BcdDefs.NameRecord]
RETURNS[
ROPE] =
{nameString:
STRING = [100];
ssd: Strings.SubStringDescriptor ← [base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
nameString.length ← 0;
Strings.AppendSubString[nameString, @ssd];
FOR i:
CARDINAL
IN [0..nameString.length)
DO
IF nameString[i] = '. THEN {nameString.length ← i; EXIT};
ENDLOOP;
RETURN[ConvertUnsafe.ToRope[LONG[nameString]]]};
GetFileName:
PROC[ssb: BcdOps.NameString, n: BcdDefs.NameRecord]
RETURNS[
ROPE] =
{nameString:
STRING = [100];
ssd: Strings.SubStringDescriptor ← [base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
dot: BOOL ← FALSE;
nameString.length ← 0;
Strings.AppendSubString[nameString, @ssd];
FOR i:
CARDINAL
IN [0..nameString.length)
DO
IF nameString[i] = '. THEN {dot ← TRUE; EXIT};
ENDLOOP;
IF ~dot THEN Strings.AppendString[nameString, ".bcd"];
RETURN[ConvertUnsafe.ToRope[LONG[nameString]]]};
FileFromBcdBase:
PROC[bcd: BcdOps.BcdBase]
RETURNS[fc: File.Capability ← File.nullCapability] =
{ ssb: BcdOps.NameString =
LOOPHOLE[bcd + bcd.ssOffset];
fc ← AcquireFCFromVersion[versionStamp: bcd.version,
shortFileNameHint: Rope.Concat[GetModuleName[ssb, bcd.source],
".bcd"]]};
AcquireFCFromVersion:
PROC
[versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPE ← NIL]
RETURNS[file: File.Capability ← File.nullCapability] = {
may return NIL
cifsFile: CIFS.OpenFile ← VersionToReadableFile[versionStamp, shortFileNameHint];
IF cifsFile #
NIL
THEN
file ←
CIFS.GetFC[
cifsFile
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"]; CONTINUE}];
};
AcquireBCDFromVersion:
PUBLIC
PROC
[versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPE ← NIL]
RETURNS[bcd: BcdOps.BcdBase] = {
may return NIL
file: File.Capability ← AcquireFCFromVersion[versionStamp, shortFileNameHint];
IF file = File.nullCapability
THEN RETURN[NIL]
ELSE RETURN[AcquireBCDFromCap[file]]};
AcquireBCDFromCap:
ENTRY
PROC[file: File.Capability]
RETURNS[bcd: BcdOps.BcdBase] = {
ENABLE UNWIND => NULL;
space: Space.Handle;
size: NAT; -- pages
Space.Map[onePageSpace, [file: file, base: 1]];
bcd ← LOOPHOLE[Space.LongPointer[onePageSpace]];
IF bcd.extended
THEN size ← bcd.nPages - bcd.rtPages.pages
ELSE size ← bcd.nPages;
Space.Unmap[onePageSpace];
IF size <= standardBCDSpacePages
THEN {
IF standardBCDSpaces =
NIL
THEN space ← Space.Create[size: standardBCDSpacePages, parent: Space.virtualMemory]
ELSE {space ← standardBCDSpaces.first;
standardBCDSpaces ← standardBCDSpaces.rest;
standardBCDSpacesHeld ← standardBCDSpacesHeld - 1};
standardBCDSpacesInUse ← standardBCDSpacesInUse + 1
}
ELSE {space ← Space.Create[size: size, parent: Space.virtualMemory];
biggerBCDSpacesInUse ← biggerBCDSpacesInUse + 1};
Space.Map[space, [file: file, base: 1]];
bcd ← LOOPHOLE[Space.LongPointer[space]];
};
IsXBCD:
PROC[bcd: BcdOps.BcdBase
--only the first page!!--]
RETURNS[
BOOL] =
{RETURN[TRUE]}; -- NOTE XXX
ReleaseBCD:
PUBLIC
ENTRY
PROC[bcd: BcdOps.BcdBase] =
{
ENABLE
UNWIND =>
NULL;
space: Space.Handle = RTOS.UnRavelUSUs[Space.GetHandle[Space.PageFromLongPointer[bcd]]];
size: NAT ← Space.GetAttributes[space].size;
Space.Unmap[space];
IF size # standardBCDSpacePages
THEN {Space.Delete[space]; biggerBCDSpacesInUse ← biggerBCDSpacesInUse - 1}
ELSE {standardBCDSpaces ←
CONS[space, standardBCDSpaces];
standardBCDSpacesInUse ← standardBCDSpacesInUse - 1;
standardBCDSpacesHeld ← standardBCDSpacesHeld + 1};
};
GetBCDVersionInfo:
ENTRY
PROC[file: File.Capability]
RETURNS[fileVersionIdent:
CARDINAL,
fileVersionStamp: BcdDefs.VersionStamp,
isXBCD: BOOL] =
{
ENABLE
UNWIND =>
NULL;
bcd: BcdOps.BcdBase;
Space.Map[onePageSpace, [file: file, base: 1]];
bcd ← LOOPHOLE[Space.LongPointer[onePageSpace]];
fileVersionIdent ← bcd.versionIdent;
fileVersionStamp ← bcd.version;
isXBCD ← IsXBCD[bcd];
Space.Unmap[onePageSpace];
};
GetReadCapability:
PROC[name:
ROPE]
RETURNS[f: File.Capability ← File.nullCapability] =
{cifsFile:
CIFS.OpenFile ←
NIL;
cifsFile ←
CIFS.Open[Rope.Concat["/local/", name],
CIFS.read
! ANY => CONTINUE];
IF cifsFile = NIL THEN RETURN;
f ←
CIFS.GetFC[cifsFile
!
ANY => {
IF
OZ
THEN Runtime.CallDebugger["CIFS.GetFC failed"];
CONTINUE}]};
VersionToReadableFile:
PUBLIC
PROC
[versionStamp: BcdDefs.VersionStamp, shortNameHint: ROPE ← NIL]
RETURNS [file: CIFS.OpenFile ← NIL] = {
mn: ROPE ← NIL;
IF shortNameHint #
NIL
THEN {
file ←
CIFS.Open[shortNameHint,
CIFS.read +
CIFS.dontCheck
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.Open failed"]; CONTINUE}
];
IF file #
NIL
THEN {
fc: File.Capability ← File.nullCapability;
fc ←
CIFS.GetFC[
file
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"]; CONTINUE}];
IF fc # File.nullCapability
AND GetBCDVersionInfo[fc].fileVersionStamp = versionStamp
THEN RETURN[file];
};
file ← NIL;
};
mn ← VersionMapDefaults.FileNameFromVersion[
which: $Symbols, version: versionStamp
!
ANY => {
IF
OZ THEN
Runtime.CallDebugger["VersionMapDefaults.FileNameFromVersion failed"];
CONTINUE;
}
];
IF mn = NIL THEN RETURN;
file ←
CIFS.Open[
mn, CIFS.read + CIFS.dontCheck
! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.Open failed"]; CONTINUE}
];
GetMapList: PUBLIC PROC RETURNS[VersionMap.MapList] = {RETURN[VersionMapDefaults.GetMapList[$Symbols]]};
The following procedures and data are here to keep track of the files in use
inUseList: InUseList ← NIL; -- protected by the monitor
InUseList: TYPE = LIST OF InUseEntry;
InUseEntry: TYPE = RECORD [file: File.Capability, exclusive: BOOL ← FALSE, count: INT ← 0];
IncFileUse:
PUBLIC ENTRY
SAFE
PROC
[file: File.Capability, exclusive: BOOL ← TRUE] RETURNS [ok: BOOL] = TRUSTED {
... increments # of users of a given file. If exclusive, then the increment only takes place if the initial count was 0. If not exclusive, the increment only takes place if the file is not exclusively open.
ENABLE UNWIND => NULL;
entry: InUseList ← NIL;
FOR each: InUseList ← inUseList, each.rest
WHILE each #
NIL
DO
IF RTFiles.SameFile[file, each.first.file]
THEN {
entry ← each;
EXIT};
ENDLOOP;
IF entry =
NIL
THEN {
inUseList ← CONS[[file: file, exclusive: exclusive, count: 1], inUseList];
RETURN [TRUE]};
IF entry.first.exclusive THEN RETURN [FALSE];
IF exclusive
THEN {
IF entry.first.count # 0 THEN RETURN [FALSE];
entry.first.exclusive ← TRUE;
};
entry.first.count ← entry.first.count + 1;
RETURN [TRUE];
};
DecFileUseError: PUBLIC ERROR = CODE;
DecFileUse:
PUBLIC ENTRY
SAFE
PROC [file: File.Capability] =
TRUSTED {
... decrements # of users of a given file, raising DecFileUseError if the initial count = 0.
ENABLE UNWIND => NULL;
entry: InUseList ← NIL;
FOR each: InUseList ← inUseList, each.rest
WHILE each #
NIL
DO
IF RTFiles.SameFile[file, each.first.file]
THEN {
entry ← each;
EXIT};
ENDLOOP;
IF entry = NIL OR entry.first.count <= 0 THEN ERROR DecFileUseError;
entry.first.exclusive ← FALSE;
entry.first.count ← entry.first.count - 1;
FileUseCount:
PUBLIC ENTRY
SAFE
PROC
[file: File.Capability] RETURNS [count: INT ← 0, exclusive: BOOL ← FALSE] = TRUSTED {
... returns # of users of a given file
ENABLE UNWIND => NULL;
FOR each: InUseList ← inUseList, each.rest
WHILE each #
NIL
DO
IF RTFiles.SameFile[file, each.first.file]
THEN
RETURN [each.first.count, each.first.exclusive];
ENDLOOP;
};
IsFileUsed:
PUBLIC
ENTRY
SAFE
PROC [file: File.Capability]
RETURNS [
BOOL] =
TRUSTED {
... equivalent to FileUseCount[file] > 0
ENABLE UNWIND => NULL;
FOR each: InUseList ← inUseList, each.rest
WHILE each #
NIL
DO
IF RTFiles.SameFile[file, each.first.file]
THEN
RETURN [each.first.count # 0];
ENDLOOP;
RETURN [FALSE];
};
MODULE INITIALIZATION
YRCMapOps.EstablishOuter[RCMapOuterY]; -- NOTE this line should precede the next one
XRCMapOps.EstablishOuter[RCMapOuterX];
YSymbolTable.SetCacheSize[pages: 512];
XSymbolTable.SetCacheSize[pages: 512];
END.