-- RTGetSymbolsImpl.mesa -- Last Modified By Paul Rovner On December 21, 1982 2:57 pm 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], CIFS USING[GetFC, Open, read, dontCheck, OpenFile], ConvertUnsafe USING[AppendRope, ToRope], File USING[Capability, nullCapability], LongString USING[AppendString], PilotLoadStateFormat USING[ModuleInfo, ConfigIndex], PilotLoadStateOps USING[InputLoadState, GetModule, AcquireBcd, ReleaseBcd, ReleaseLoadState, EnumerateBcds], PrincOps USING[GlobalFrameHandle], RCMapOps USING[EstablishOuter], Rope USING[ROPE, Flatten, Length, Fetch, Concat], RTFiles USING[], -- EXPORTS only RTFlags USING[checking], RTOS USING[EnumerateGlobalFrames, SameCode, UnRavelUSUs], RTSymbolDefs USING[SymbolTableBase, SymbolTableHandle, nullHandle, SymbolModuleIndex, nullModuleIndex, rootBodyIndex, nullSymbolIndex], RTSymbolOps USING[STBToModuleName], 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[Release, Acquire, Forget, anySpan], Table USING[Base], VersionMap USING[RestoreMapFromFile, VersionToName, MapList]; RTGetSymbolsImpl: MONITOR IMPORTS AMTypes, BcdOps, CIFS, ConvertUnsafe, LongString, PilotLoadStateOps, RCMapOps, Rope, RTOS, RTSymbolOps, RTTypesBasicPrivate, Runtime, Space, Strings, SymbolTable, VersionMap EXPORTS RTFiles, RTSymbols, RTSymbolsPrivate SHARES File = BEGIN OPEN 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; versionMapList: VersionMap.MapList _ NIL; OZ: BOOL _ FALSE; ROPE: TYPE = Rope.ROPE; -- PUBLIC PROCS -- Outer: PUBLIC PROC[stb: SymbolTableBase, mdi: SymbolModuleIndex, inner: PROC[base: SymbolTableBase], mesaSymbolsOK: BOOLEAN _ FALSE] = {stb1: SymbolTableBase = AcquireSTBFromMDI[stb, mdi, mesaSymbolsOK]; inner[stb1 ! UNWIND => ReleaseSTB[stb1]]; ReleaseSTB[stb1]}; AcquireSTBForDefs: PUBLIC PROC[fileName: ROPE--ends with .bcd--] RETURNS[SymbolTableBase] = { mn: STRING = [100]; dotFound: BOOLEAN _ 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; RETURN[AcquireSTB[GetSTHForModule[stamp: BcdDefs.NullVersion, fileName: fileName, moduleName: ConvertUnsafe.ToRope[LONG[mn]]]]]}; AcquireSTB: PUBLIC PROC[sth: SymbolTableHandle, mesaSymbolsOK: BOOLEAN _ FALSE] RETURNS[stb: SymbolTableBase] = {stb _ SymbolTable.Acquire[sth]; IF mesaSymbolsOK THEN RETURN[stb]; -- groan. backward compatibility for limited usage -- (for RTSymbols clients only, NOT for AMTypes) IF NOT stb.stHandle.extended -- symbol table made by an old version of the compiler OR stb.bb[rootBodyIndex].type = nullSymbolIndex 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] = {SymbolTable.Release[stb]}; STPages: PUBLIC PROC[sth: SymbolTableHandle] RETURNS[CARDINAL] = {RETURN[sth.span.pages]}; -- 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 RTTypesBasicPrivate.MapStiStd[stx].sth # nullHandle 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: BOOLEAN] = { IF 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 sth = nullHandle 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]; sth _ [file: file, span: [base: sgb[sgi].base, pages: sgb[sgi].pages + sgb[sgi].extraPages]]} 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[SymbolTableHandle] = { file: File.Capability _ File.nullCapability; fileVersionIdent: CARDINAL; fileVersionStamp: BcdDefs.VersionStamp; sth: SymbolTableHandle _ nullHandle; stb: SymbolTableBase; symbolsStamp: BcdDefs.VersionStamp; file _ GetReadCapability[fileName ! ANY => CONTINUE]; IF file = File.nullCapability AND version # BcdDefs.NullVersion THEN {cifsFile: CIFS.OpenFile = VersionToReadableFile[versionStamp: version, shortNameHint: fileName]; IF cifsFile = NIL THEN GOTO noFile; file _ CIFS.GetFC[cifsFile ! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"]; CONTINUE}]; IF file = File.nullCapability THEN GOTO noFile}; IF file = File.nullCapability THEN GOTO noFile; -- now check the version info within the file [fileVersionIdent, fileVersionStamp] _ GetBCDVersionInfo[file]; IF fileVersionIdent # BcdDefs.VersionID THEN GOTO noFile; IF version # BcdDefs.NullVersion AND version # fileVersionStamp THEN GOTO noFile; -- here if file is found and version matches sth _ [file: file, span: [base: base, pages: pages]]; stb _ AcquireSTB[sth]; symbolsStamp _ stb.stHandle.version; ReleaseSTB[stb]; [] _ RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]]; RETURN[sth]; EXITS noFile => ERROR AMTypes.Error[reason: noSymbols, msg: fileName]; }; -- end NewSymbolHandle RCMapOuter: PROC[stb: SymbolTableBase, mdi: SymbolModuleIndex, inner: PROC[base: SymbolTableBase]] = {stb1: SymbolTableBase = AcquireSTBFromMDI[stb, mdi]; inner[stb1 ! UNWIND => ReleaseSTB[stb1]]; ReleaseSTB[stb1]}; AcquireSTBFromMDI: PUBLIC PROC[stb: SymbolTableBase, mdi: SymbolModuleIndex, mesaSymbolsOK: BOOLEAN _ FALSE] RETURNS[SymbolTableBase] = { fileNameDesc, modNameDesc: Strings.SubStringDescriptor; fileName: STRING = [100]; modName: STRING = [100]; IF mdi = nullModuleIndex THEN ERROR; fileName.length _ 0; modName.length _ 0; stb.SubStringForHash[@modNameDesc, stb.mdb[mdi].moduleId]; Strings.AppendSubString[modName, @modNameDesc]; stb.SubStringForHash[@fileNameDesc, stb.mdb[mdi].fileId]; Strings.AppendSubString[fileName, @fileNameDesc]; RETURN[AcquireSTB[GetSTHForModule[stb.mdb[mdi].stamp, ConvertUnsafe.ToRope[LONG[fileName]], ConvertUnsafe.ToRope[LONG[modName]]], mesaSymbolsOK]]}; 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; mth: BcdOps.MTHandle _ NIL; sSeg: BcdDefs.SGIndex; modNameDesc: Strings.SubStringDescriptor _ [base: LOOPHOLE[Rope.Flatten[moduleName]], offset: 0, length: Rope.Length[moduleName]]; someNameMatched: BOOLEAN _ FALSE; FindVersionStampedModule: PROC[mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS[stop: BOOLEAN] = { umid: BcdDefs.VersionStamp = IF mth.file = BcdDefs.FTSelf THEN bcd.version ELSE ftb[mth.file].version; nextModNameDesc: Strings.SubStringDescriptor; namesMatch: BOOLEAN _ 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 (stamp = BcdDefs.NullVersion OR stamp = umid)] }; -- end FindVersionStampedModule -- START GetSTHForModule loop body here IF stamp # BcdDefs.NullVersion THEN {found: BOOLEAN; stx: RTTypesBasicPrivate.SymbolTableIndex; [stx, found] _ FindSTX[stamp]; IF found THEN sth _ DoAcquireSTHFromSTX[stx].sth; IF sth # nullHandle THEN RETURN[sth]}; IF fileName # NIL THEN newFile _ GetReadCapability[fileName ! ANY => CONTINUE]; IF newFile = File.nullCapability THEN {IF stamp = BcdDefs.NullVersion THEN GOTO noFile ELSE {shortName: ROPE = IF moduleName = NIL THEN NIL ELSE Rope.Concat[moduleName, ".bcd"]; cifsFile: CIFS.OpenFile = VersionToReadableFile[versionStamp: stamp, shortNameHint: shortName]; 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}}; bcd _ AcquireBCDFromCap[newFile]; sgb _ LOOPHOLE[bcd + bcd.sgOffset]; ftb _ LOOPHOLE[bcd + bcd.ftOffset]; ntb _ LOOPHOLE[bcd + bcd.ssOffset]; IF bcd.versionIdent # BcdDefs.VersionID THEN GOTO oldSymbols; mth _ BcdOps.ProcessModules[bcd, FindVersionStampedModule].mth; IF mth = NIL THEN 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 GOTO noSymbols; sth _ [file: newFile, span: [base: sgb[sSeg].base, pages: sgb[sSeg].pages + sgb[sSeg].extraPages]]; IF stamp = BcdDefs.NullVersion THEN {stb: SymbolTableBase = AcquireSTB[sth]; stamp _ stb.stHandle.version; ReleaseSTB[stb]}; [] _ RTTypesBasicPrivate.FindSTI[[symbolsStamp: stamp, sth: sth]]; ReleaseBCD[bcd]; RETURN[sth]; 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: BOOLEAN _ FALSE] RETURNS[stb: SymbolTableBase _ NIL] = 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 [BOOLEAN] = {RETURN[(f # gfh) AND (RTOS.SameCode[gfh, f] = identical) AND (~f.copied)]}; FindModule: PROC [mth: BcdOps.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOLEAN] = {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: BOOLEAN; stx: RTTypesBasicPrivate.SymbolTableIndex; [stx, found] _ FindSTX[umid]; IF found THEN sth _ AcquireSTHFromSTX[stx].sth}; IF sth = nullHandle -- then try for the one referenced in the bcd THEN sth _ AcquireSTHFromSGI[bcd, mth.sseg]; IF sth = nullHandle -- 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 sth = nullHandle -- then try for the original one THEN [sth: sth, moduleName: moduleName] _ AcquireSTHFromSTX[RTTypesBasicPrivate.FindSTI[[symbolsStamp: umid, bcd: bcd]]]; IF sth = nullHandle -- 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: BOOLEAN _ FALSE] RETURNS[stb: SymbolTableBase _ NIL] = { 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 sth = nullHandle 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]]}; IsFileInUse: PUBLIC PROC[file: File.Capability] RETURNS[found: BOOLEAN _ FALSE] = { loadStateHeld: BOOLEAN; p: PROC[c: PilotLoadStateFormat.ConfigIndex] RETURNS[stop: BOOLEAN] = {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]; }; -- flush the SymbolCache SymbolTable.Forget[[file: file, span: SymbolTable.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 IF RTTypesBasicPrivate.MapStiStd[x] = NIL THEN EXIT; IF RTTypesBasicPrivate.MapStiStd[x].sth = nullHandle THEN LOOP; IF RTTypesBasicPrivate.MapStiStd[x].sth.file.fID = file.fID THEN RETURN[TRUE]; ENDLOOP; }; -- PRIVATE PROCS -- FindSTX: PROC[stamp: BcdDefs.VersionStamp] RETURNS[stx: RTTypesBasicPrivate.SymbolTableIndex, found: BOOLEAN] = {FOR stx IN [1..RTTypesBasicPrivate.MapStiStd.length) DO IF RTTypesBasicPrivate.MapStiStd[stx] = NIL THEN EXIT; IF RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp = stamp 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; sth _ [file: FileFromBcdBase[bcd], span: [base: sgh.base, pages: sgh.pages+sgh.extraPages]]; stb _ AcquireSTB[sth]; symbolsStamp _ stb.stHandle.version; 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: BOOLEAN _ 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"]]}; -- may return NIL AcquireFCFromVersion: PROC[versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPE _ NIL] RETURNS[file: File.Capability _ File.nullCapability] = { cifsFile: CIFS.OpenFile; IF shortFileNameHint # NIL THEN file _ GetReadCapability[shortFileNameHint]; IF file # File.nullCapability THEN {IF GetBCDVersionInfo[file].fileVersionStamp = versionStamp THEN RETURN[file]; file _ File.nullCapability}; cifsFile _ VersionToReadableFile[versionStamp: versionStamp]; IF cifsFile = NIL THEN RETURN; file _ CIFS.GetFC[cifsFile ! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.GetFC failed"]; CONTINUE}]; }; -- may return NIL AcquireBCDFromVersion: PUBLIC PROC[versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPE _ NIL] RETURNS[bcd: BcdOps.BcdBase] = { 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]]; }; 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] = { ENABLE UNWIND => NULL; bcd: BcdOps.BcdBase; Space.Map[onePageSpace, [file: file, base: 1]]; bcd _ LOOPHOLE[Space.LongPointer[onePageSpace]]; fileVersionIdent _ bcd.versionIdent; fileVersionStamp _ bcd.version; 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 versionMapList = NIL THEN IncludeSymbolsVersionMap["CedarSymbols.VersionMap"]; IF versionMapList = NIL THEN RETURN; mn _ VersionMap.VersionToName[list: versionMapList, stamp: versionStamp ! ANY => {IF OZ THEN Runtime.CallDebugger["VersionMap.VersionToName failed"]; CONTINUE}].name; IF mn = NIL THEN RETURN; file _ CIFS.Open[mn, CIFS.read + CIFS.dontCheck ! ANY => {IF OZ THEN Runtime.CallDebugger["CIFS.Open failed"]; CONTINUE}]; }; IncludeSymbolsVersionMap: PUBLIC PROC[fileName: ROPE] = {versionMapList _ CONS[VersionMap.RestoreMapFromFile [name: fileName, assumeImmutable: TRUE ! ANY => {IF OZ THEN Runtime.CallDebugger ["VersionMap.RestoreMapFromFile failed"]; CONTINUE}], versionMapList]}; GetMapList: PUBLIC PROC RETURNS[VersionMap.MapList] = {RETURN[versionMapList]}; -- MODULE INITIALIZATION RCMapOps.EstablishOuter[RCMapOuter]; END.