<> <> <> <> <> <> <> <<>> DIRECTORY Alloc: TYPE USING [AddNotify, DropNotify, Notifier], BcdComData: TYPE USING [table], BcdDefs: TYPE USING [Base, BcdBase, fttype, FTIndex, FTNull, FTSelf, lftype, Link, mttype, MTIndex, MTNull, MTRecord, NameRecord, NameString, sgtype, SGIndex, SGNull, sstype, VersionID, VersionStamp], BcdErrorDefs: TYPE USING [InterfaceId], BcdFileDefs: TYPE USING [CapabilityForFile, UnknownFile], ConvertUnsafe: TYPE USING [EqualSubStrings, SubString, SubStringToRope], FileSegment: TYPE USING [Pages], FS: TYPE USING [nullOpenFile, OpenFile, Read, Open, Error], Rope: TYPE USING [Concat, Find, ROPE], Symbols: TYPE USING [ISEIndex, CSEIndex, CTXIndex, BitAddress, ISENull], SymbolTable: TYPE USING [Base, Handle, nullHandle, Acquire, Missing, Release], VM: TYPE USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval]; BcdSymbolPack: PROGRAM IMPORTS Alloc, BcdFileDefs, ConvertUnsafe, FS, Rope, SymbolTable, VM, data: BcdComData EXPORTS BcdErrorDefs = { OPEN BcdDefs; InterfaceId: TYPE ~ BcdErrorDefs.InterfaceId; mtb, lfb, sgb, ftb: BcdDefs.Base; ssb: BcdDefs.NameString; Notifier: Alloc.Notifier ~ { mtb _ base[mttype]; lfb _ base[lftype]; sgb _ base[sgtype]; ftb _ base[fttype]; ssb _ base[sstype]}; nullPages: SymbolTable.Handle ~ SymbolTable.nullHandle; initialized: BOOL _ FALSE; Initialize: PUBLIC PROC ~ { IF initialized THEN Finalize[]; initialized _ TRUE}; Finalize: PUBLIC PROC ~ {initialized _ FALSE}; ExportItemName: PUBLIC PROC[ export: InterfaceId, ep: CARDINAL, userProc: PROC[ConvertUnsafe.SubString]] ~ { symbolPages: SymbolTable.Handle; (data.table).AddNotify[Notifier]; symbolPages _ InterfaceSymbols[export]; IF symbolPages # nullPages THEN PrintNameFromInterface[symbolPages, ep, userProc]; (data.table).DropNotify[Notifier]}; ImportItemName: PUBLIC PROC[ import: InterfaceId, ep: CARDINAL, clientMti: BcdDefs.MTIndex, linkOffset: CARDINAL, userProc: PROC[ConvertUnsafe.SubString]] ~ { symbolPages: SymbolTable.Handle; (data.table).AddNotify[Notifier]; IF clientMti = BcdDefs.MTNull THEN RETURN; symbolPages _ ModuleSymbols[clientMti]; IF symbolPages # nullPages THEN PrintNameFromModule[symbolPages, clientMti, linkOffset, userProc] ELSE { symbolPages _ InterfaceSymbols[import]; IF symbolPages # nullPages THEN PrintNameFromInterface[symbolPages, ep, userProc]}; (data.table).DropNotify[Notifier]}; ModuleSymbols: PROC[mti: BcdDefs.MTIndex] RETURNS[symbolPages: SymbolTable.Handle] ~ { sgi: BcdDefs.SGIndex ~ mtb[mti].sseg; IF sgi = BcdDefs.SGNull THEN symbolPages _ nullPages ELSE { symbolPages.file _ BcdFileDefs.CapabilityForFile[sgb[sgi].file ! BcdFileDefs.UnknownFile => {GO TO notFound}]; symbolPages.span _ [base~sgb[sgi].base-1, pages~sgb[sgi].pages]}; EXITS notFound => RETURN[nullPages]}; PrintNameFromModule: PROC[ symbolPages: SymbolTable.Handle, importerMti: BcdDefs.MTIndex, linkOffset: CARDINAL, userProc: PROC[ConvertUnsafe.SubString]] ~ { symbols: SymbolTable.Base _ NIL; symbols _ SymbolTable.Acquire[symbolPages ! SymbolTable.Missing => {CONTINUE}]; IF symbols # NIL THEN { OPEN Symbols; key: Symbols.BitAddress ~ ComputeAddress[importerMti, linkOffset]; iCtx: CTXIndex ~ symbols.stHandle.importCtx; sei: ISEIndex; type: CSEIndex; Imported: PROC[sei: Symbols.ISEIndex] RETURNS[BOOL] ~ INLINE { RETURN[symbols.seb[sei].linkSpace AND ~symbols.seb[sei].extended]}; FOR iSei: ISEIndex _ symbols.FirstCtxSe[iCtx], symbols.NextSe[iSei] UNTIL iSei = ISENull DO type _ symbols.UnderType[symbols.seb[iSei].idType]; WITH t~~symbols.seb[type] SELECT FROM definition => FOR sei _ symbols.FirstCtxSe[t.defCtx], symbols.NextSe[sei] UNTIL sei = ISENull DO IF Imported[sei] AND symbols.seb[sei].idValue = key THEN GO TO Found; ENDLOOP; ref => IF Imported[iSei] AND symbols.seb[iSei].idValue = key THEN { sei _ iSei; GO TO Found}; ENDCASE => NULL; REPEAT Found => { d: ConvertUnsafe.SubString; d _ symbols.SubStringForName[symbols.seb[sei].hash]; userProc[d ! UNWIND => { SymbolTable.Release[symbols]; (data.table).DropNotify[Notifier]}]}; ENDLOOP; SymbolTable.Release[symbols]}}; ComputeAddress: PROC[mti: BcdDefs.MTIndex, linkOffset: CARDINAL] RETURNS[Symbols.BitAddress] ~ { linkLength: CARDINAL ~ (WITH m~~mtb[mti] SELECT FROM direct => m.length, indirect => lfb[m.links].length, multiple => lfb[m.links].length, ENDCASE => ERROR); RETURN[[wd~(linkLength-1)-linkOffset, bd~0]]}; InterfaceSymbols: PROC[id: InterfaceId] RETURNS[symbolPages: SymbolTable.Handle] ~ { file: FS.OpenFile _ FS.nullOpenFile; headerInterval: VM.Interval _ VM.nullInterval; DeleteHeader: PROC ~ { IF headerInterval # VM.nullInterval THEN { headerInterval.Free[]; headerInterval _ VM.nullInterval}}; IF id.fti # FTNull THEN { name: Rope.ROPE; name _ GetBcdName[ftb[id.fti].name]; file _ FS.Open[name: name ! FS.Error => CONTINUE]}; IF file = FS.nullOpenFile THEN symbolPages _ nullPages ELSE { ENABLE { UNWIND => {NULL}; ANY => {GO TO badFile}}; BcdBase: PROC[p: LONG POINTER] RETURNS[BcdDefs.Base] ~ INLINE { RETURN[LOOPHOLE[p, BcdDefs.Base]]}; bcd: BcdDefs.BcdBase; bcdPages: CARDINAL _ 8; iMtb, iFtb, iSgb: BcdDefs.Base; iSsb: BcdDefs.NameString; iMti: BcdDefs.MTIndex; iSgi: BcdDefs.SGIndex; d1, d2: ConvertUnsafe.SubString; DO headerInterval _ VM.Allocate[bcdPages]; bcd _ VM.AddressForPageNumber[headerInterval.page]; file.Read[from~0, nPages~bcdPages, to~bcd]; IF bcd.versionIdent # BcdDefs.VersionID THEN GO TO badFile; IF bcdPages >= bcd.nPages THEN EXIT; bcdPages _ bcd.nPages; headerInterval.Free[]; headerInterval _ VM.nullInterval ENDLOOP; IF bcd.nConfigs # 0 OR ~bcd.definitions THEN GO TO badFile; -- no packaged bcd's (for now) iSsb _ LOOPHOLE[bcd + bcd.ssOffset]; iMtb _ BcdBase[bcd + bcd.mtOffset]; iFtb _ BcdBase[bcd + bcd.ftOffset]; iSgb _ BcdBase[bcd + bcd.sgOffset]; d1 _ [base~@ssb.string, offset~id.name, length~ssb.size[id.name]]; d2.base _ @iSsb.string; iMti _ BcdDefs.MTIndex.FIRST; UNTIL iMti = bcd.mtLimit DO d2.offset _ iMtb[iMti].name; d2.length _ iSsb.size[iMtb[iMti].name]; IF d1.EqualSubStrings[d2] THEN EXIT; iMti _ iMti + (WITH m~~iMtb[iMti] SELECT FROM direct => BcdDefs.MTRecord.direct.SIZE + m.length*BcdDefs.Link.SIZE, indirect => BcdDefs.MTRecord.indirect.SIZE, multiple => BcdDefs.MTRecord.multiple.SIZE, ENDCASE => ERROR); REPEAT FINISHED => IF bcd.nModules = 1 THEN iMti _ BcdDefs.MTIndex.FIRST ELSE GOTO badFile; ENDLOOP; iSgi _ iMtb[iMti].sseg; IF iSgi = BcdDefs.SGNull OR iSgb[iSgi].pages = 0 OR iSgb[iSgi].file # BcdDefs.FTSelf OR bcd.version # ftb[id.fti].version THEN GO TO badFile; symbolPages _ [ file~file, span~[base~iSgb[iSgi].base-1, pages~iSgb[iSgi].pages]]; DeleteHeader[]; EXITS badFile => {DeleteHeader[]; symbolPages _ nullPages}}; RETURN}; GetBcdName: PROC[n: NameRecord] RETURNS[name: Rope.ROPE] ~ { dotIndex: INT; d: ConvertUnsafe.SubString _ [base~@ssb.string, offset~n, length~MIN[ssb.size[n], 40]]; name _ d.SubStringToRope; dotIndex _ name.Find["."]; IF dotIndex < 0 THEN name _ name.Concat[".bcd"]}; PrintNameFromInterface: PROC[ symbolPages: SymbolTable.Handle, ep: CARDINAL, userProc: PROC[ConvertUnsafe.SubString]] ~ { symbols: SymbolTable.Base _ NIL; symbols _ SymbolTable.Acquire[symbolPages ! SymbolTable.Missing => {CONTINUE}]; IF symbols # NIL THEN { OPEN Symbols; outerCtx: CTXIndex ~ symbols.stHandle.outerCtx; d: ConvertUnsafe.SubString; FOR sei: ISEIndex _ symbols.FirstCtxSe[outerCtx], symbols.NextSe[sei] UNTIL sei = ISENull DO SELECT symbols.LinkMode[sei] FROM $val, $ref, $type => IF symbols.seb[sei].idValue = ep THEN { d _ symbols.SubStringForName[symbols.seb[sei].hash]; userProc[d ! UNWIND => { SymbolTable.Release[symbols]; (data.table).DropNotify[Notifier]}]}; ENDCASE; ENDLOOP; SymbolTable.Release[symbols]}}; }.