-- ProcBcdsImpl.Mesa, last edit April 5, 1982 10:59 am -- Pilot 6.0/ Mesa 7.0 DIRECTORY BcdDefs: TYPE USING [Base, CTIndex, CTNull, CTRecord, EXPIndex, EXPRecord, FTIndex, FTNull, FTRecord, FTSelf, IMPIndex, IMPRecord, Link, MTIndex, MTRecord, NameRecord, SGIndex, VersionID, VersionStamp], CWF: TYPE USING [SWF0, WF0, WF1, WF3], Directory: TYPE USING [Error, Handle, ignore, Lookup], Environment: TYPE USING [wordsPerPage], File: TYPE USING [Capability, nullCapability, read], FileParms: TYPE USING [nullSymbolSpace, SymbolSpace], LeafSubr: TYPE USING [RemoteMap], LongString: TYPE USING [AppendString, AppendSubString, SubString, SubStringDescriptor], ProcBcds: TYPE USING [Innards, ProcDep, ProcMod], RTBcd: TYPE USING[RTBase], Space: TYPE USING [Create, CreateUniformSwapUnits, Delete, Handle, LongPointer, Map, nullHandle, virtualMemory], String: TYPE USING [AppendString, EquivalentString], Subr: TYPE USING [Any, ControlChars, GetCreateDate, SubStrCopy, strcpy], Symbols: TYPE USING [HTIndex, HTNull, HTRecord, MDIndex, MDRecord, OwnMdi], SymbolSegment: TYPE USING [FGHeader, STHeader, VersionID], Table: TYPE USING [Base], Time: TYPE USING [Current], TimeStamp: TYPE USING [Stamp]; ProcBcdsImpl: PROGRAM IMPORTS CWF, Directory, LeafSubr, LongString, Space, String, Subr, Time EXPORTS ProcBcds = { useonespace: BOOL = TRUE; -- FALSE has never worked -- uses NO MDS!!! InvalidBcd: PUBLIC SIGNAL = CODE; ReadInSegmentsBcd: PUBLIC PROC [innards: ProcBcds.Innards] = { local: BOOL; npages: CARDINAL; IF innards.cap = File.nullCapability AND innards.fh = NIL THEN ERROR; local ← innards.fh = NIL; -- map in at least one page to get total # of pages innards.bcdheaderspace ← Space.Create[size: 10, parent: Space.virtualMemory]; IF local THEN Space.Map[space: innards.bcdheaderspace, window: [file: innards.cap, base: 1]] ELSE LeafSubr.RemoteMap[space: innards.bcdheaderspace, fh: innards.fh, base: 0]; innards.bcd ← Space.LongPointer[innards.bcdheaderspace]; IF innards.bcd.versionIdent ~= BcdDefs.VersionID THEN { -- not a bcd or invalid version ID in header Space.Delete[innards.bcdheaderspace]; innards.bcdheaderspace ← Space.nullHandle; innards.bcd ← NIL; SIGNAL InvalidBcd; RETURN; }; npages ← innards.bcd.nPages; IF npages > 10 THEN { Space.Delete[innards.bcdheaderspace]; -- now map in the right number of pages innards.bcdheaderspace ← Space.Create[size: npages, parent: Space.virtualMemory]; IF local THEN Space.Map[space: innards.bcdheaderspace, window: [file: innards.cap, base: 1]] ELSE LeafSubr.RemoteMap[space: innards.bcdheaderspace, fh: innards.fh, base: 0]; innards.bcd ← Space.LongPointer[innards.bcdheaderspace]; }; Space.CreateUniformSwapUnits[parent: innards.bcdheaderspace, size: 8]; innards.upperLimit ← npages * Environment.wordsPerPage; }; InstallAddressesBcd: PUBLIC PROC[innards: ProcBcds.Innards] = { innards.tb ← LOOPHOLE[innards.bcd]; innards.ssb ← LOOPHOLE[innards.bcd + innards.bcd.ssOffset]; innards.ctb ← innards.tb + innards.bcd.ctOffset; innards.mtb ← innards.tb + innards.bcd.mtOffset; innards.itb ← innards.tb + innards.bcd.impOffset; innards.etb ← innards.tb + innards.bcd.expOffset; innards.sgb ← innards.tb + innards.bcd.sgOffset; innards.ftb ← innards.tb + innards.bcd.ftOffset; innards.ntb ← innards.tb + innards.bcd.ntOffset; innards.evb ← innards.tb + innards.bcd.evOffset; innards.spb ← innards.tb + innards.bcd.spOffset; innards.fpb ← innards.tb + innards.bcd.fpOffset; }; UnstallBcd: PUBLIC PROC [innards: ProcBcds.Innards] = { IF innards.bcdheaderspace = Space.nullHandle THEN ERROR; Space.Delete[innards.bcdheaderspace]; innards↑ ← [bcdheaderspace: Space.nullHandle]; -- others are defaulted }; PrintDepends: PUBLIC PROC[innards: ProcBcds.Innards, procMod: ProcBcds.ProcMod,procDep: ProcBcds.ProcDep, print, calltwice, less: BOOL, bcdfilename: LONG STRING] RETURNS[success, isconfig, isdefns: BOOL, nimp, nexp, ntype: CARDINAL] = BEGIN uns: UNSPECIFIED; sourcefile: STRING ← [100]; interfacename: STRING ← [100]; switches: STRING ← [100]; cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex]; nullstring: STRING ← ""L; altoCode, boundsChecks, cedarSwitch, crossJump, linksInCode, nilChecks, sortByUsage: BOOL ← FALSE; notcodebound: BOOL; symbolSpace: FileParms.SymbolSpace ← FileParms.nullSymbolSpace; rtVersionID: CARDINAL ← 0; success ← isconfig ← isdefns ← FALSE; nexp ← nimp ← ntype ← 0; IF nullstring.length ~= 0 THEN ERROR; IF innards.bcd.versionIdent ~= BcdDefs.VersionID THEN { CWF.WF0[" Error - wrong bcd version.\n"L]; RETURN; }; -- if it is a defs file, we simply record the interface name PutName[innards, innards.bcd.source, sourcefile]; IF sourcefile.length >0 AND sourcefile[sourcefile.length -1] = '. THEN sourcefile.length ← sourcefile.length - 1; -- CWF.WF1["sourcefiles %s\n"L, sourcefile]; IF Subr.ControlChars[sourcefile] THEN { CWF.WF0[" Error - bad sourcefile.\n"L]; RETURN; }; success ← GetModuleName[innards, interfacename]; IF NOT success THEN RETURN; -- at this point, success must always be TRUE since -- this code now calls the procDep and procMod procs isconfig ← innards.bcd.nConfigs > 0; IF NOT isconfig THEN { sSeg: BcdDefs.SGIndex ← innards.mtb[FIRST[BcdDefs.MTIndex]].sseg; altoCode ← innards.mtb[FIRST[BcdDefs.MTIndex]].altoCode; boundsChecks ← innards.mtb[FIRST[BcdDefs.MTIndex]].boundsChecks; crossJump ← innards.mtb[FIRST[BcdDefs.MTIndex]].crossJumped; cedarSwitch ← IF NOT altoCode THEN innards.mtb[FIRST[BcdDefs.MTIndex]].long ELSE FALSE; nilChecks ← innards.mtb[FIRST[BcdDefs.MTIndex]].nilChecks; linksInCode ← innards.mtb[FIRST[BcdDefs.MTIndex]].linkLoc = code; sortByUsage ← NOT innards.mtb[FIRST[BcdDefs.MTIndex]].initial; -- /s switch, initial = FALSE is /s symbolSpace ← [file: innards.cap, span: [base: innards.sgb[sSeg].base, pages: innards.sgb[sSeg].pages]]; }; notcodebound ← IF isconfig THEN NotCodeBound[innards, BcdDefs.CTNull] ELSE TRUE; isdefns ← innards.bcd.definitions; IF isdefns THEN uns ← procMod[sourcefile, interfacename, innards.bcd.version, innards.bcd.sourceVersion, innards.bcd.creator, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, symbolSpace, 0] ELSE { IF innards.bcd.extended AND innards.bcd.rtPages.pages > 0 THEN rtVersionID ← LOOPHOLE[innards.bcd + innards.bcd.rtPages.relPageBase*Environment.wordsPerPage, RTBcd.RTBase].versionIdent; uns ← procMod[sourcefile, interfacename, innards.bcd.version, innards.bcd.sourceVersion, innards.bcd.creator, FALSE, isconfig, NOT notcodebound, innards.bcd.tableCompiled, altoCode, boundsChecks, cedarSwitch, crossJump, linksInCode, nilChecks, sortByUsage, symbolSpace, rtVersionID]; }; IF NOT isconfig THEN { IF innards.bcd.extended THEN ntype ← PrintDirectory[innards, procDep, uns, print, bcdfilename] ELSE [,ntype] ← PrintSymbolsFile[innards, procDep, uns, print, FALSE, less, bcdfilename]; }; IF NOT isdefns THEN nexp ← PrintExports[innards, procDep, uns, print]; IF calltwice AND NOT isdefns AND (ntype > 50 OR nexp > 30) THEN { -- call again to avoid overflow in the database uns ← procMod[sourcefile, interfacename, innards.bcd.version, innards.bcd.sourceVersion, innards.bcd.creator, FALSE, isconfig, NOT notcodebound, innards.bcd.tableCompiled, altoCode, boundsChecks, cedarSwitch, crossJump, linksInCode, nilChecks, sortByUsage, symbolSpace, rtVersionID]; }; nimp ← PrintImports[innards, procDep, uns, print]; IF isconfig THEN { PrintConfigDepends[innards, procDep, uns, notcodebound, FALSE]; IF NOT notcodebound AND print THEN CWF.WF0["(code bound)\n"L]; }; success ← TRUE; RETURN; END; PrintDirectory: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL, bcdfilename: LONG STRING] RETURNS[ntype: CARDINAL] = { modulename: STRING ← [100]; filename: STRING ← [100]; fti: BcdDefs.FTIndex ← FIRST[BcdDefs.FTIndex]; ntype ← 0; UNTIL fti = innards.bcd.ftLimit DO PutName[innards, innards.ftb[fti].name, filename]; IF NOT Subr.Any[filename, '.] THEN String.AppendString[filename, ".bcd"L]; procDep[defstype, GuessModulename[innards, fti, modulename], filename, innards.ftb[fti].version, uns]; ntype ← ntype + 1; fti ← fti + SIZE[BcdDefs.FTRecord]; IF LOOPHOLE[fti, CARDINAL] > LOOPHOLE[innards.bcd.ftLimit, CARDINAL] THEN GO TO Bogus; REPEAT Bogus => { CWF.WF1["Error - Garbage FileTable in %s.\n"L, bcdfilename]; RETURN; }; ENDLOOP; IF print THEN CWF.WF1[" %d types.\n"L, @ntype]; }; -- returns NIL if can't find modulename GuessModulename: PROC[innards: ProcBcds.Innards, fti: BcdDefs.FTIndex, modulename: STRING] RETURNS[STRING] = { iti: BcdDefs.IMPIndex ← FIRST[BcdDefs.IMPIndex]; eti: BcdDefs.EXPIndex ← FIRST[BcdDefs.EXPIndex]; WHILE LOOPHOLE[iti, CARDINAL] < LOOPHOLE[innards.bcd.impLimit, CARDINAL] DO IF innards.itb[iti].file = fti THEN { PutName[innards, innards.itb[iti].name, modulename]; RETURN[modulename]; }; iti ← iti + SIZE[BcdDefs.IMPRecord]; ENDLOOP; WHILE LOOPHOLE[eti, CARDINAL] < LOOPHOLE[innards.bcd.expLimit, CARDINAL] DO IF innards.etb[eti].file = fti THEN { PutName[innards, innards.etb[eti].name, modulename]; RETURN[modulename]; }; eti ← eti + SIZE[BcdDefs.IMPRecord] + innards.etb[eti].size; ENDLOOP; RETURN[NIL]; }; Sym: TYPE = POINTER TO SymRecord; SymRecord: TYPE = RECORD[ stHandle: LONG POINTER TO SymbolSegment.STHeader ← NIL, stHandleSpace: Space.Handle ← Space.nullHandle, -- -- hash table ht: LONG DESCRIPTOR FOR ARRAY Symbols.HTIndex OF Symbols.HTRecord ← NULL, htSpace: Space.Handle ← Space.nullHandle, -- ssb: LONG STRING ← NIL, -- id string ssbSpace: Space.Handle ← Space.nullHandle, -- mdb: Table.Base ← NIL, -- module directory base mdbSpace: Space.Handle ← Space.nullHandle, mdLimit: Symbols.MDIndex ← NULL, -- module directory size -- fgptr: LONG POINTER TO SymbolSegment.FGHeader ← NIL, -- ptr to beginning of fine grain table fgptrSpace: Space.Handle ← Space.nullHandle ]; -- headerseg initted from ReadIn PrintSymbolsFile: PUBLIC PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print, allsyms, less: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL, ntype: CARDINAL] = { mti, mtLimit: BcdDefs.MTIndex; symseg: BcdDefs.SGIndex; symrecord: SymRecord ← []; shortstr: STRING ← [100]; nullstr: STRING ← ""L; ntype ← 0; success ← FALSE; mti ← FIRST[BcdDefs.MTIndex]; mtLimit ← IF allsyms THEN innards.bcd.mtLimit ELSE mti + 1; UNTIL LOOPHOLE[mti, CARDINAL] >= LOOPHOLE[mtLimit, CARDINAL] DO symseg ← innards.mtb[mti].sseg; success ← InitSym[innards, @symrecord, symseg, less, bcdfilename]; IF NOT success THEN EXIT; [success, ntype] ← PrintModuleEntries[innards, @symrecord, procDep, uns, print, bcdfilename]; IF NOT success THEN EXIT; IF NOT less THEN { FindSourceFileName[@symrecord, shortstr]; IF shortstr.length > 0 THEN procDep[sourcefile, nullstr, shortstr, symrecord.stHandle.sourceVersion, uns]; }; FreeSym[@symrecord]; mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link], indirect => SIZE[BcdDefs.MTRecord[indirect]], multiple => SIZE[BcdDefs.MTRecord[multiple]], ENDCASE => ERROR) ENDLOOP; RETURN[success, ntype]; }; -- init from bcd InitSym: PROC[innards: ProcBcds.Innards, sym: Sym, symseg: BcdDefs.SGIndex, less: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL] = { npages: CARDINAL; sfnsym: STRING ← [100]; cap: File.Capability; local: BOOL; base: CARDINAL; p: LONG POINTER; success ← FALSE; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - badly formed symbols.\n"L]; RETURN; }; IF innards.sgb[symseg].pages = 0 THEN { CWF.WF1["Warning - No symbols in %s.\n"L, bcdfilename]; RETURN; }; IF innards.sgb[symseg].file ~= BcdDefs.FTSelf THEN { PrintFileName[innards, innards.sgb[symseg].file, sfnsym]; cap ← Directory.Lookup[fileName: sfnsym, permissions: File.read ! Directory.Error => GOTO err]; EXITS err => { CWF.WF1["Error - can't find '%s'\n"L, sfnsym]; RETURN; }; } ELSE cap ← innards.cap; npages ← innards.sgb[symseg].pages; IF NOT less THEN npages ← npages + innards.sgb[symseg].extraPages; IF useonespace THEN sym.stHandleSpace ← Space.Create[parent: Space.virtualMemory, size: npages] ELSE sym.stHandleSpace ← Space.Create[parent: Space.virtualMemory, size: (SIZE[SymbolSegment.STHeader]/Environment.wordsPerPage) + 1]; local ← innards.fh = NIL; IF local THEN { base ← innards.sgb[symseg].base; Space.Map[space: sym.stHandleSpace, window: [file: cap, base: base]] } ELSE { base ← innards.sgb[symseg].base - 1; LeafSubr.RemoteMap[sym.stHandleSpace, innards.fh, base]; }; sym.stHandle ← Space.LongPointer[sym.stHandleSpace]; IF sym.stHandle.versionIdent ~= SymbolSegment.VersionID THEN { CWF.WF0["Error - Symbols versions do not agree.\n"L]; RETURN; }; -- init symbols header IF useonespace THEN { b: LONG POINTER; tB: Table.Base; b ← LOOPHOLE[sym.stHandle]; tB ← LOOPHOLE[sym.stHandle]; sym.ht ← DESCRIPTOR[b+sym.stHandle.htBlock.offset, sym.stHandle.htBlock.size/SIZE[Symbols.HTRecord]]; sym.ssb ← b + sym.stHandle.ssBlock.offset; sym.mdb ← tB + sym.stHandle.mdBlock.offset; sym.mdLimit ← FIRST[Symbols.MDIndex] + sym.stHandle.mdBlock.size; IF NOT less THEN sym.fgptr ← LOOPHOLE[sym.stHandle + sym.stHandle.fgRelPgBase * Environment.wordsPerPage]; } ELSE { [p, sym.htSpace] ← GetSpace[innards, sym, base, sym.stHandle.htBlock.offset, sym.stHandle.htBlock.size]; sym.ht ← DESCRIPTOR[p, sym.stHandle.htBlock.size/SIZE[Symbols.HTRecord]]; [sym.ssb, sym.ssbSpace] ← GetSpace[innards, sym, base, sym.stHandle.ssBlock.offset, sym.stHandle.ssBlock.size]; [LOOPHOLE[sym.mdb, LONG POINTER], sym.mdbSpace] ← GetSpace[innards, sym, base, sym.stHandle.mdBlock.offset, sym.stHandle.mdBlock.size]; sym.mdLimit ← FIRST[Symbols.MDIndex] + sym.stHandle.mdBlock.size; IF NOT less THEN [LOOPHOLE[sym.fgptr, LONG POINTER], sym.fgptrSpace] ← GetSpace[innards, sym, base, sym.stHandle.fgRelPgBase * Environment.wordsPerPage, Environment.wordsPerPage]; }; RETURN[TRUE]; }; -- offset is # words off # base page number, size is # words in range GetSpace: PROC[innards: ProcBcds.Innards, sym: Sym, pbase, offset, size: CARDINAL] RETURNS[buffer: LONG POINTER, space: Space.Handle] = { pstart, pnum: CARDINAL; pageoffset: CARDINAL ← offset/Environment.wordsPerPage; pstart ← pbase + pageoffset; pnum ← ((size+offset)/Environment.wordsPerPage) - pageoffset + 1; space ← Space.Create[parent: Space.virtualMemory, size: pnum]; IF innards.cap ~= File.nullCapability THEN Space.Map[space, [innards.cap, pstart]] ELSE LeafSubr.RemoteMap[space, innards.fh, pstart]; buffer ← Space.LongPointer[space]; buffer ← buffer + (offset - (pageoffset*Environment.wordsPerPage)); }; PrintModuleEntries: PROC[innards: ProcBcds.Innards, sym: Sym, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL, ntype: CARDINAL] = { -- foreach module entry -- since each filename ends in ".bcd.", we strip the trailing "." off mdi: Symbols.MDIndex ← FIRST[Symbols.MDIndex]; sfn: STRING ← [100]; smodulename: STRING ← [100]; substr: LongString.SubStringDescriptor; ntype ← 0; success ← FALSE; DO -- skip the module itself IF mdi = Symbols.OwnMdi THEN mdi ← mdi + SIZE[Symbols.MDRecord]; IF mdi = sym.mdLimit THEN EXIT; SubStringForHash[sym, @substr, sym.mdb[mdi].moduleId]; smodulename.length ← 0; LongString.AppendSubString[smodulename, @substr]; SubStringForHash[sym, @substr, sym.mdb[mdi].fileId]; sfn.length ← 0; LongString.AppendSubString[sfn, @substr]; IF sfn.length > 0 AND sfn[sfn.length-1] = '. THEN sfn.length ← sfn.length - 1; -- strip "." -- CWF.WF2["module %s file %s\n"L, smodulename, sfn]; ntype ← ntype + 1; procDep[defstype, smodulename, sfn, sym.mdb[mdi].stamp, uns]; mdi ← mdi + SIZE[Symbols.MDRecord]; IF LOOPHOLE[mdi, CARDINAL] > LOOPHOLE[sym.mdLimit, CARDINAL] THEN { CWF.WF1["Warning - symbols MDRecord is garbage in %s.\n"L, bcdfilename]; RETURN; }; ENDLOOP; IF print THEN CWF.WF1["%u types, "L, @ntype]; success ← TRUE; }; FindSourceFileName: PROC[sym: Sym, tostr: STRING] = { -- fine grain table is in sgb[].extrapages IF sym.stHandle.fgRelPgBase > 0 AND sym.stHandle.fgPgCount > 0 THEN { tostr.length ← 0; LongString.AppendString[tostr, @sym.fgptr.sourceFile]; -- remove trailing "." IF tostr.length > 0 AND tostr[tostr.length-1] = '. THEN tostr.length ← tostr.length - 1; -- strip "." } ELSE tostr.length ← 0; -- CWF.WF1["sourcefile <%s>\n"L, tostr]; }; -- free the segment FreeSym: PROC[sym: Sym] = { IF sym.stHandleSpace ~= Space.nullHandle THEN { Space.Delete[sym.stHandleSpace]; sym.stHandleSpace ← Space.nullHandle; }; IF sym.htSpace ~= Space.nullHandle THEN { Space.Delete[sym.htSpace]; sym.htSpace ← Space.nullHandle; }; IF sym.ssbSpace ~= Space.nullHandle THEN { Space.Delete[sym.ssbSpace]; sym.ssbSpace ← Space.nullHandle; }; IF sym.mdbSpace ~= Space.nullHandle THEN { Space.Delete[sym.mdbSpace]; sym.mdbSpace ← Space.nullHandle; }; IF sym.fgptrSpace ~= Space.nullHandle THEN { Space.Delete[sym.fgptrSpace]; sym.fgptrSpace ← Space.nullHandle; }; }; SubStringForHash: PROC [sym: Sym, s: LongString.SubString, hti: Symbols.HTIndex] = { s.base ← sym.ssb; IF hti = Symbols.HTNull THEN s.offset ← s.length ← 0 ELSE s.length ← sym.ht[hti].ssIndex - (s.offset ← sym.ht[hti-1].ssIndex) }; GetModuleName: PUBLIC PROC[innards: ProcBcds.Innards, interfacename: STRING] RETURNS[success: BOOL] = { -- unofficially, a defs file or impl modules name is the first -- index in the module table. Not so for configs. -- they are in the config table cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex]; IF innards.bcd.nConfigs = 0 THEN PutName[innards, innards.mtb[FIRST[BcdDefs.MTIndex]].name, interfacename] ELSE UNTIL cti = innards.bcd.ctLimit DO IF innards.ctb[cti].config = BcdDefs.CTNull THEN { PutName[innards, innards.ctb[cti].name, interfacename]; -- CWF.WF1["Name: %s\n"L, interfacename]; EXIT; }; cti ← cti+innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord]; IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit, CARDINAL] THEN { CWF.WF0["Garbage Garbage Garbage.\n"L]; RETURN[FALSE]; }; ENDLOOP; RETURN[TRUE]; }; PrintExports: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL] RETURNS[nexp: CARDINAL] = { eti: BcdDefs.EXPIndex ← FIRST[BcdDefs.EXPIndex]; nexp ← 0; UNTIL eti = innards.bcd.expLimit DO PrintExport[innards, eti, procDep, uns]; nexp ← nexp + 1; eti ← eti + innards.etb[eti].size + SIZE[BcdDefs.EXPRecord]; IF LOOPHOLE[eti, CARDINAL] > LOOPHOLE[innards.bcd.expLimit, CARDINAL] THEN GO TO Bogus; REPEAT Bogus => { CWF.WF0["Garbage Garbage Garbage.\n"L]; RETURN; }; ENDLOOP; IF print THEN CWF.WF1[" %d exp, "L, @nexp]; }; PrintExport: PROC [innards: ProcBcds.Innards, eti: BcdDefs.EXPIndex, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED] = BEGIN OPEN innards.etb[eti]; stemp: STRING ← [100]; stemp1: STRING ← [100]; vers: BcdDefs.VersionStamp; PutName[innards, name, stemp]; PrintFileName[innards, file, stemp1]; IF stemp.length = 0 OR Subr.ControlChars[stemp] OR stemp1.length = 0 OR Subr.ControlChars[stemp1] THEN { CWF.WF0["name garbaged up\n"L]; RETURN; }; -- CWF.WF1["%s"L, stemp]; -- CWF.WF0[", file: "]; -- CWF.WF1["%s"L, stemp1]; vers ← innards.ftb[file].version; procDep[exports, stemp, stemp1, vers, uns]; END; PrintImports: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL] RETURNS[nimp: CARDINAL] = { iti: BcdDefs.IMPIndex ← FIRST[BcdDefs.IMPIndex]; nullstring: STRING ← ""L; nimp ← 0; UNTIL iti = innards.bcd.impLimit DO PrintImport[innards, iti, procDep, uns]; nimp ← nimp + 1; iti ← iti + SIZE[BcdDefs.IMPRecord]; IF LOOPHOLE[iti, CARDINAL] > LOOPHOLE[innards.bcd.impLimit, CARDINAL] THEN GO TO Bogus; REPEAT Bogus => { CWF.WF0["Garbage Garbage Garbage.\n"L]; RETURN; }; ENDLOOP; IF print THEN CWF.WF1[" %d imp.\n"L, @nimp]; }; PrintImport: PROC [innards: ProcBcds.Innards, iti: BcdDefs.IMPIndex, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED] = { OPEN innards.itb[iti]; stemp: STRING ← [100]; stemp1: STRING ← [100]; vers: BcdDefs.VersionStamp; PutName[innards, name, stemp]; PrintFileName[innards, file, stemp1]; IF stemp.length = 0 OR Subr.ControlChars[stemp] OR stemp1.length = 0 OR Subr.ControlChars[stemp1] THEN { CWF.WF0["name garbaged up\n"L]; RETURN; }; vers ← innards.ftb[file].version; procDep[imports, stemp, stemp1, vers, uns]; }; -- if any one of the bcds ins not codebound, then the config -- is not codebound NotCodeBound: PROC[innards: ProcBcds.Innards, parent: BcdDefs.CTIndex] RETURNS [notcodebound: BOOL] = { cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex]; notcodebound ← FALSE; UNTIL cti = innards.bcd.ctLimit DO IF innards.ctb[cti].config = parent THEN { notcodebound ← notcodebound OR NotCodeBound[innards, cti]; notcodebound ← notcodebound OR NotCodeBoundModule[innards, cti]; }; cti ← cti + innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord]; IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit, CARDINAL] THEN { CWF.WF0["Garbage Config.\n"L]; RETURN; }; ENDLOOP; }; NotCodeBoundModule: PROC[innards: ProcBcds.Innards, cti: BcdDefs.CTIndex] RETURNS[notcodebound: BOOL] = { codeseg: BcdDefs.SGIndex; mti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex]; notcodebound ← FALSE; UNTIL mti = innards.bcd.mtLimit DO IF innards.mtb[mti].config = cti THEN { IF innards.mtb[mti].file ~= BcdDefs.FTSelf THEN { codeseg ← innards.mtb[mti].code.sgi; IF innards.sgb[codeseg].class ~= code THEN { CWF.WF0["Error - not code seg\n"L]; RETURN; }; notcodebound ← notcodebound OR innards.sgb[codeseg].file ~= BcdDefs.FTSelf; }; }; mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link], indirect => SIZE[BcdDefs.MTRecord[indirect]], multiple => SIZE[BcdDefs.MTRecord[multiple]], ENDCASE => ERROR); IF LOOPHOLE[mti, CARDINAL] > LOOPHOLE[innards.bcd.mtLimit, CARDINAL] THEN { CWF.WF0["Garbage Module.\n"L]; RETURN; }; ENDLOOP; }; -- a config .bcd depends on -- itself -- all module entries for itself -- all config entries (not FTSelf) one level away -- module entries for config's that are FTSelf's away from the top -- for each config entry: -- if parent = CTNull, print config and modules -- if parent[parent] = CTNull print config -- if (file = FTSelf)* and parent = CTNull, print modules PrintConfigDepends: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep,uns: UNSPECIFIED, notcodebound, stopnesting: BOOL] = { cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex]; modname: STRING ← [100]; filename: STRING ← [100]; topcti: BcdDefs.CTIndex; ok: BOOL; UNTIL cti = innards.bcd.ctLimit DO ok ← FALSE; topcti ← innards.ctb[cti].config; -- first level parent WHILE topcti ~= BcdDefs.CTNull AND innards.ctb[topcti].file = BcdDefs.FTSelf DO topcti ← innards.ctb[topcti].config; ENDLOOP; IF topcti = BcdDefs.CTNull OR innards.ctb[topcti].config = BcdDefs.CTNull THEN ok ← TRUE; IF ok AND innards.ctb[cti].file ~= BcdDefs.FTSelf THEN { PutName[innards, innards.ctb[cti].name, modname]; PrintFileName[innards, innards.ctb[cti].file, filename]; procDep[IF notcodebound THEN otherdepends ELSE canignore, modname, filename, innards.ftb[innards.ctb[cti].file].version, uns]; }; cti ← cti + innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord]; IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit, CARDINAL] THEN { CWF.WF0["Garbage Config.\n"L]; RETURN; }; ENDLOOP; ProcessModuleTable[innards, procDep, uns, notcodebound]; }; ProcessModuleTable: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, notcodebound: BOOL] ={ symseg, codeseg: BcdDefs.SGIndex; mti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex]; modname: STRING ← [100]; filename: STRING ← [100]; cti: BcdDefs.CTIndex; UNTIL mti = innards.bcd.mtLimit DO cti ← innards.mtb[mti].config; WHILE innards.ctb[cti].file = BcdDefs.FTSelf DO IF innards.ctb[cti].config = BcdDefs.CTNull THEN EXIT; cti ← innards.ctb[cti].config; ENDLOOP; IF innards.ctb[cti].config = BcdDefs.CTNull THEN { symseg ← innards.mtb[mti].sseg; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - not symseg\n"L]; RETURN; }; IF innards.sgb[symseg].file ~= BcdDefs.FTSelf AND innards.sgb[symseg].file ~= BcdDefs.FTNull THEN { PrintFileName[innards, innards.sgb[symseg].file, filename]; PutName[innards, innards.mtb[mti].name,modname]; IF NOT String.EquivalentString[filename, modname] THEN { symfilevers: TimeStamp.Stamp; -- symfilevers ← GetCorrectCreateDate[filename, -- innards.ftb[ -- innards.sgb[symseg].file].version]; symfilevers ← innards.ftb[innards.sgb[symseg].file].version; procDep[symbolsfile, modname, filename, symfilevers, uns]; }; }; IF innards.mtb[mti].file ~= BcdDefs.FTSelf AND innards.mtb[mti].file ~= BcdDefs.FTNull THEN { codeseg ← innards.mtb[mti].code.sgi; IF innards.sgb[codeseg].class ~= code THEN { CWF.WF0["Error - not code seg\n"L]; RETURN; }; PutName[innards, innards.mtb[mti].name, modname]; PrintFileName[innards, innards.mtb[mti].file, filename]; procDep[IF notcodebound THEN otherdepends ELSE canignore, modname,filename, innards.ftb[innards.mtb[mti].file].version, uns]; }; }; mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link], indirect => SIZE[BcdDefs.MTRecord[indirect]], multiple => SIZE[BcdDefs.MTRecord[multiple]], ENDCASE => ERROR); IF LOOPHOLE[mti, CARDINAL] > LOOPHOLE[innards.bcd.mtLimit, CARDINAL] THEN { CWF.WF0["Garbage Module.\n"L]; RETURN; }; ENDLOOP; }; -- skip, since there were too many errors with version stamps -- that were not create dates -- the dates on .Symbols files are off by up to 30 seconds GetCorrectCreateDate: PROC[filename: STRING, verstamp: TimeStamp.Stamp] RETURNS[stamp: TimeStamp.Stamp] = { cap: File.Capability; filetime: LONG CARDINAL; i,j: INT; stamp ← verstamp; -- fix in correct create date cap ← Directory.Lookup[fileName: filename, permissions: Directory.ignore ! Directory.Error => GOTO err]; [create: filetime] ← Subr.GetCreateDate[cap]; -- create date here is actually the time stamp -- if differ by more than 30 seconds, file is no good i ← filetime; j ← verstamp.time; IF IsRealTime[verstamp.time] AND ABS[i - j] > 30 THEN CWF.WF3["Error in symbols file- %s is dated %lt but bound configuration wanted %lt.\n"L, filename, @filetime, @verstamp.time] ELSE stamp.time ← filetime; EXITS err => NULL; -- if its not on the disk, we must assume verstamp }; -- uses heuristics -- note: 1yr = 31,536,000 seconds IsRealTime: PUBLIC PROC[stamp: LONG CARDINAL] RETURNS[isrealtime: BOOL] = { time: LONG CARDINAL ← Time.Current[]; RETURN[time >= stamp AND stamp >= time - 30000000]; }; PutName: PROC [innards: ProcBcds.Innards, n: BcdDefs.NameRecord, stemp: STRING] = BEGIN i: INTEGER; str: STRING ← [100]; ssd: LongString.SubStringDescriptor ← [base: @innards.ssb.string, offset: n, length: MIN[innards.ssb.size[n], 100]]; LongString.AppendSubString[str, @ssd]; -- omit a leading directory name i ← IF str.length > 0 THEN str.length - 1 ELSE 0; WHILE i >= 0 DO IF str[i] = '> OR str[i] = '/ THEN EXIT; i ← i - 1; ENDLOOP; IF i >= 0 THEN Subr.SubStrCopy[stemp, str, i+1] ELSE Subr.strcpy[stemp, str]; RETURN END; -- if no '.' is present, explicitely append ".bcd" at the end of stemp PrintFileName: PROC [innards: ProcBcds.Innards, fti: BcdDefs.FTIndex, stemp: STRING] = { SELECT fti FROM BcdDefs.FTNull => { CWF.SWF0[stemp, "(null)"L]; ERROR; }; BcdDefs.FTSelf => { CWF.SWF0[stemp, "(self)"L]; ERROR; }; ENDCASE => { PutName[innards, innards.ftb[fti].name, stemp]; IF NOT Subr.Any[stemp, '.] THEN String.AppendString[stemp, ".bcd"L]; }; RETURN }; }. OldInitSym: PROC[innards: ProcBcds.Innards, sym: Sym, symseg: BcdDefs.SGIndex, less: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL] = { b: LONG POINTER; tB: Table.Base; success ← FALSE; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - badly formed symbols.\n"L]; RETURN; }; IF innards.sgb[symseg].pages = 0 THEN { CWF.WF1["Error - No symbols in %s.\n"L, bcdfilename]; RETURN; }; IF innards.bcdheaderspace ~= Space.nullHandle THEN { npages: CARDINAL; sfnsym: STRING ← [100]; cap: File.Capability; IF innards.sgb[symseg].file ~= BcdDefs.FTSelf THEN { PrintFileName[innards, innards.sgb[symseg].file, sfnsym]; cap ← Directory.Lookup[fileName: sfnsym, permissions: File.read ! Directory.Error => GOTO err]; EXITS err => { CWF.WF1["Error - can't find '%s'\n"L, sfnsym]; RETURN; }; } ELSE cap ← innards.cap; npages ← innards.sgb[symseg].pages; IF NOT less THEN npages ← npages + innards.sgb[symseg].extraPages; sym.symbolspace ← Space.Create[parent: Space.virtualMemory, size: npages]; Space.Map[space: sym.symbolspace, window: [file: cap, base: innards.sgb[symseg].base]]; sym.stHandle ← Space.LongPointer[sym.symbolspace]; } ELSE { IF ((innards.sgb[symseg].base * Environment.wordsPerPage) + SIZE[SymbolSegment.STHeader]) > innards.upperLimit THEN { CWF.WF0["Error - symbol segment not in memory.\n"L]; RETURN; }; sym.stHandle ← LOOPHOLE[innards.bcd + ((innards.sgb[symseg].base-1) * Environment.wordsPerPage)]; }; -- init symbols header b ← LOOPHOLE[sym.stHandle]; tB ← LOOPHOLE[sym.stHandle]; IF sym.stHandle.versionIdent ~= SymbolSegment.VersionID THEN { CWF.WF0["Error - Symbols versions do not agree.\n"L]; RETURN; }; sym.ht ← DESCRIPTOR[b+sym.stHandle.htBlock.offset, sym.stHandle.htBlock.size/SIZE[Symbols.HTRecord]]; sym.ssb ← b + sym.stHandle.ssBlock.offset; sym.seb ← tB + sym.stHandle.seBlock.offset; sym.ctxb ← tB + sym.stHandle.ctxBlock.offset; sym.mdb ← tB + sym.stHandle.mdBlock.offset; sym.bb ← tB + sym.stHandle.bodyBlock.offset; sym.tb ← tB + sym.stHandle.treeBlock.offset; sym.ltb ← tB + sym.stHandle.litBlock.offset; sym.extb ← tB + sym.stHandle.extBlock.offset; sym.mdLimit ← FIRST[Symbols.MDIndex] + sym.stHandle.mdBlock.size; sym.extLimit ← FIRST[SymbolSegment.ExtIndex] + sym.stHandle.extBlock.size; sym.mainCtx ← sym.stHandle.outerCtx; RETURN[TRUE]; }; -- if the file is code-bound, then we don't want to call -- the modules it depends on PrintConfigDepends: PROC[innards: ProcBcds.Innards, parent: BcdDefs.CTIndex, procDep: ProcBcds.ProcDep,uns: UNSPECIFIED, notcodebound, stopnesting: BOOL] = { cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex]; modname: STRING ← [100]; filename: STRING ← [100]; UNTIL cti = innards.bcd.ctLimit DO IF innards.ctb[cti].config = parent THEN { IF innards.ctb[cti].file ~= BcdDefs.FTSelf THEN { PutName[innards, innards.ctb[cti].name, modname]; PrintFileName[innards, innards.ctb[cti].file, filename]; procDep[IF notcodebound THEN otherdepends ELSE canignore, modname, filename, innards.ftb[innards.ctb[cti].file].version, uns]; }; -- will only print confignames below this level if stopnesting is true -- stopnesting will only be true if the config entry -- is not FTSelf, indicating a config bound in a config -- and not syntactically nested PrintConfigDepends[innards, cti, procDep, uns, notcodebound, NOT notcodebound]; IF notcodebound OR innards.ctb[cti].file = BcdDefs.FTSelf THEN ProcessModuleTable[innards, cti, procDep, uns, notcodebound]; }; cti ← cti + innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord]; IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit, CARDINAL] THEN { CWF.WF0["Garbage Config.\n"L]; RETURN; }; ENDLOOP; }; ProcessModuleTable: PROC[innards: ProcBcds.Innards, cti: BcdDefs.CTIndex, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, notcodebound: BOOL] ={ symseg, codeseg: BcdDefs.SGIndex; mti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex]; modname: STRING ← [100]; filename: STRING ← [100]; UNTIL mti = innards.bcd.mtLimit DO IF innards.mtb[mti].config = cti THEN { symseg ← innards.mtb[mti].sseg; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - not symseg\n"L]; RETURN; }; IF innards.sgb[symseg].file ~= BcdDefs.FTSelf AND innards.sgb[symseg].file ~= BcdDefs.FTNull THEN { PrintFileName[innards, innards.sgb[symseg].file, filename]; PutName[innards, innards.mtb[mti].name,modname]; IF NOT String.EquivalentString[filename, modname] THEN { symfilevers: TimeStamp.Stamp; -- symfilevers ← GetCorrectCreateDate[filename, -- innards.ftb[ -- innards.sgb[symseg].file].version]; symfilevers ← innards.ftb[innards.sgb[symseg].file].version; procDep[symbolsfile, modname, filename, symfilevers, uns]; }; }; IF innards.mtb[mti].file ~= BcdDefs.FTSelf AND innards.mtb[mti].file ~= BcdDefs.FTNull THEN { codeseg ← innards.mtb[mti].code.sgi; IF innards.sgb[codeseg].class ~= code THEN { CWF.WF0["Error - not code seg\n"L]; RETURN; }; PutName[innards, innards.mtb[mti].name, modname]; PrintFileName[innards, innards.mtb[mti].file, filename]; procDep[IF notcodebound THEN otherdepends ELSE canignore, modname,filename, innards.ftb[innards.mtb[mti].file].version, uns]; }; }; mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link], indirect => SIZE[BcdDefs.MTRecord[indirect]], multiple => SIZE[BcdDefs.MTRecord[multiple]], ENDCASE => ERROR); IF LOOPHOLE[mti, CARDINAL] > LOOPHOLE[innards.bcd.mtLimit, CARDINAL] THEN { CWF.WF0["Garbage Module.\n"L]; RETURN; }; ENDLOOP; };