-- file UtilsCold.Mesa -- last modified by Bruce, October 25, 1980 9:00 PM DIRECTORY ComData USING [seAnon, typeBOOL, typeCONDITION, typeLOCK, typeStringBody], Copier USING [ AugmentContext, CompleteContext, CopyUnion, FindExternalCtx, Outer, SEToken, TokenSymbol], DebugOps USING [BitAddress, Foo, GFHandle, Lengthen, LongCopyWRITE, LongREAD, LongWRITE, ReadCodeWord, ShortREAD], DI USING [ AbortWithError, Desc, Foo, GetValue, LongDesc, Normalize, Pad, SearchCtxList, TypeForSe], DIActions USING [], DOutput USING [EOL, Line, Octal, Text], DSyms USING [GFHandle, GFrameMdi], Dump USING [HtiVal], Frames USING [Invalid], Gf USING [AddGfi, Check, Links, NewLink, OldLink, Validate], DHeap USING [AllocFob], Inline USING [LowHalf], Lf USING [GF, NoAccessLink, Validate], Lookup USING [CopyLiteral, Flavor], MachineDefs USING [ControlLink, FieldDescriptor, GFHandle, ProcDesc, WordLength], Mopcodes USING [zWFS], PrincOps USING [ControlLink], State USING [Get], Storage USING [Node], SymbolOps USING [ Cardinality, EnterExtension, FindExtension, FirstCtxSe, FnField, NextSe, TypeForm, UnderType, WordsForType, XferMode], SymbolPack USING [FirstCtxSe, NextSe, seb, XferMode], Symbols USING [ ArraySEIndex, BitAddress, BTIndex, BTNull, CSEIndex, CTXIndex, CTXNull, ctxType, ExtensionType, HTIndex, IncludedCTXIndex, IncludedCTXNull, ISEIndex, ISENull, MDIndex, MDNull, mdType, RecordSEIndex, SEIndex, SENull, SERecord, seType, TransferMode, typeANY, typeTYPE], SymbolTable USING [Base, Missing], Table USING [AddNotify, Base, DropNotify, Notifier], Tree USING [Link, Node, Null, treeType], TreeOps USING [FreeTree]; UtilsCold: PROGRAM IMPORTS com: ComData, Copier, DebugOps, DI, DOutput, DSyms, Dump, Frames, Gf, DHeap, Inline, Lf, Lookup, State, Storage, SymbolOps, myBase: SymbolPack, SymbolTable, Table, TreeOps EXPORTS DI, DIActions, Lookup SHARES Copier = BEGIN OPEN DI, SymbolOps, Symbols; NotAProcedure: PUBLIC ERROR [cl: MachineDefs.ControlLink] = CODE; NotAnArray: PUBLIC ERROR = CODE; NotHere: PUBLIC ERROR = CODE; SizeMismatch: PUBLIC ERROR = CODE; NotRelocated: PUBLIC SIGNAL RETURNS [LONG POINTER] = CODE; CantAssignInDebuggerImage: ERROR = CODE; UnexpectedLiteral: ERROR = CODE; LiteralProblem: ERROR = CODE; OffsetVariableCrossesWordBoundary: ERROR = CODE; ConfusedAboutImports: ERROR = CODE; NoTree: ERROR = CODE; -- tables defining the current symbol table seb: Table.Base; -- se table mdb: Table.Base; -- module table ctxb: Table.Base; -- context table tb: Table.Base; -- tree table Notify: Table.Notifier = BEGIN -- called whenever the main symbol table is repacked seb _ base[seType]; ctxb _ base[ctxType]; mdb _ base[mdType]; tb _ base[Tree.treeType]; END; entryDepth: CARDINAL _ 0; Add: PROCEDURE = BEGIN IF entryDepth = 0 THEN Table.AddNotify[Notify]; entryDepth _ entryDepth + 1; END; Drop: PROCEDURE = BEGIN IF (entryDepth _ entryDepth-1) = 0 THEN Table.DropNotify[Notify]; END; -- finding union and discriminated types VariantUnionType: PUBLIC PROC [type: SEIndex] RETURNS [vType: CSEIndex] = BEGIN rType: CSEIndex; Add[]; rType _ TypeForSe[type]; vType _ WITH seb[rType] SELECT FROM record => IF hints.variant THEN UnderType[TypeForSe[UnionField[LOOPHOLE[rType]]]] ELSE typeANY, ENDCASE => typeANY; Drop[]; RETURN END; SelectVariantType: PUBLIC PROCEDURE [type: SEIndex, tag: HTIndex] RETURNS [sei: ISEIndex] = BEGIN vType: CSEIndex = VariantUnionType[type]; Add[]; WITH seb[vType] SELECT FROM union => sei _ SearchCtxList[tag, caseCtx]; ENDCASE => sei _ ISENull; Drop[]; IF sei = ISENull THEN AbortWithError[unknownVariant, tag]; RETURN END; -- auxiliary procedures UnionField: PROCEDURE [rSei: RecordSEIndex] RETURNS [ISEIndex] = INLINE BEGIN sei, root, next: ISEIndex; ctx: CTXIndex = seb[rSei].fieldCtx; repeated: BOOLEAN; IF ctxb[ctx].ctxType = simple THEN FOR sei _ ctxb[ctx].seList, next UNTIL sei = ISENull DO next _ NextSe[sei]; IF next = ISENull THEN RETURN [sei]; ENDLOOP ELSE BEGIN -- defined elsewhere, UnderType is safe repeated _ FALSE; DO sei _ root _ ctxb[ctx].seList; DO IF sei = ISENull THEN EXIT; IF TypeForm[seb[sei].idType] = union THEN RETURN [sei]; IF (sei _ NextSe[sei]) = root THEN EXIT; ENDLOOP; IF repeated THEN EXIT; Copier.CopyUnion[seb[rSei].fieldCtx]; repeated _ TRUE; ENDLOOP; END; RETURN [com.seAnon] END; MapCtx: PUBLIC PROC [mdi: MDIndex, ctx: CTXIndex] RETURNS [ictx: IncludedCTXIndex] = BEGIN IF mdi = MDNull OR ctx = CTXNull THEN RETURN[IncludedCTXNull]; Add[]; FOR ictx _ mdb[mdi].ctx, ctxb[ictx].chain UNTIL ictx = IncludedCTXNull DO IF ctxb[ictx].map = ctx THEN EXIT; REPEAT FINISHED => ictx _ Copier.FindExternalCtx[mdi,ctx]; ENDLOOP; Drop[]; END; SearchValContext: PROCEDURE [val: UNSPECIFIED, ctx: CTXIndex] RETURNS [ISEIndex] = BEGIN sei: ISEIndex; root: ISEIndex _ ctxb[ctx].seList; sei _ root; DO IF sei = SENull THEN EXIT; IF seb[sei].idValue = val THEN RETURN [sei]; WITH id: seb[sei] SELECT FROM sequential => sei _ sei + SIZE[sequential id SERecord]; linked => IF (sei _ id.link) = root THEN EXIT; ENDCASE => EXIT; ENDLOOP; RETURN [ISENull] END; SearchCtxForProc: PUBLIC PROC [val: UNSPECIFIED, ctx: CTXIndex] RETURNS [sei: ISEIndex] = BEGIN RETURN[SearchCtxForVal[val,ctx,proc]] END; SearchCtxForSignal: PUBLIC PROC [val: UNSPECIFIED, ctx: CTXIndex] RETURNS [sei: ISEIndex] = BEGIN RETURN[SearchCtxForVal[val,ctx,signal]] END; SearchCtxForVal: PUBLIC PROC [ val: UNSPECIFIED, ctx: CTXIndex, tm: TransferMode] RETURNS [sei: ISEIndex] = BEGIN IF ctx = CTXNull THEN RETURN [ISENull]; Add[]; IF (sei _ SearchValContext[val,ctx]) # ISENull AND CheckIsei[myBase,sei,tm] THEN {Drop[]; RETURN}; sei _ ISENull; WITH ctxb[ctx] SELECT FROM included => IF ~complete THEN sei _ Copier.TokenSymbol[ctx, Generator[module,map,val,tm]]; imported => sei _ SearchCtxForVal[val,includeLink,tm]; simple => NULL; ENDCASE; Drop[]; RETURN; END; Generator: PROC [ mdi: MDIndex, ctx: CTXIndex, val: UNSPECIFIED, tm: TransferMode] RETURNS [token: Copier.SEToken] = BEGIN Search: PROC [iBase: SymbolTable.Base] = BEGIN isei: ISEIndex; FOR isei _ iBase.FirstCtxSe[ctx], iBase.NextSe[isei] UNTIL isei = ISENull DO IF (iBase.seb[isei].idValue = val) AND CheckIsei[iBase,isei,tm] THEN EXIT; ENDLOOP; token _ [isei]; END; Copier.Outer[mdi,Search]; END; CheckIsei: PROC [base: SymbolTable.Base, isei: ISEIndex, tm: TransferMode] RETURNS [BOOLEAN] = BEGIN SELECT base.XferMode[base.seb[isei].idType] FROM tm => RETURN[base.seb[isei].constant]; signal => IF tm = error THEN RETURN[base.seb[isei].constant]; error => IF tm = signal THEN RETURN[base.seb[isei].constant]; ENDCASE; RETURN[FALSE]; END; ArraySei: PROC [sei: SEIndex] RETURNS [asei: ArraySEIndex, desc, long: BOOLEAN] = BEGIN csei: CSEIndex _ TypeForSe[sei]; desc _ long _ FALSE; DO WITH seb[csei] SELECT FROM array => {asei _ LOOPHOLE[csei]; EXIT}; arraydesc => BEGIN asei _ LOOPHOLE[SymbolOps.UnderType[describedType]]; desc _ TRUE; EXIT; END; long => {long _ TRUE; csei _ TypeForSe[rangeType]}; ENDCASE => NotAnArray; ENDLOOP; END; GetDesc: PUBLIC PROC [f: Foo] RETURNS [d: LongDesc, asei: ArraySEIndex] = BEGIN desc: BOOLEAN; long: BOOLEAN; Add[]; [asei:asei, desc:desc, long:long] _ ArraySei[f.tsei ! UNWIND => Drop[]]; IF long THEN {Drop[]; ERROR SizeMismatch}; IF ~desc THEN BEGIN IF ~f.there THEN ERROR NotHere; d.base _ f.addr.base; d.length _ SymbolOps.Cardinality[seb[asei].indexType]; END ELSE BEGIN sd: Desc; GetValue[f]; sd _ LOOPHOLE[f.addr.base, LONG POINTER TO Desc]^; d.base _ DebugOps.Lengthen[sd.base]; d.length _ sd.length; END; Drop[]; END; GetLongDesc: PUBLIC PROC [f: Foo] RETURNS [ld: LongDesc, asei: ArraySEIndex] = BEGIN desc: BOOLEAN; long: BOOLEAN; lp: LONG POINTER TO LongDesc; Add[]; [asei:asei, desc:desc, long:long] _ ArraySei[f.tsei ! UNWIND => Drop[]]; IF ~long THEN {Drop[]; ERROR SizeMismatch}; IF ~desc THEN BEGIN IF ~f.there THEN ERROR NotHere; ld.base _ f.addr.base; ld.length _ SymbolOps.Cardinality[seb[asei].indexType]; END ELSE BEGIN GetValue[f]; lp _ f.addr.base; ld _ lp^; END; Drop[]; END; WFS: PROC [UNSPECIFIED, POINTER, MachineDefs.FieldDescriptor] = MACHINE CODE BEGIN Mopcodes.zWFS END; PutValue: PUBLIC PROC [lhs: Foo, from: LONG POINTER] = BEGIN to: LONG POINTER = lhs.addr.base; IF ~lhs.there THEN ERROR CantAssignInDebuggerImage; IF lhs.addr.offset # 0 OR lhs.bits # 0 THEN BEGIN val: UNSPECIFIED _ DebugOps.LongREAD[to]; fd: MachineDefs.FieldDescriptor _ [offset: 0, posn: lhs.addr.offset, size: lhs.bits]; WFS[from^,@val,fd]; DebugOps.LongWRITE[to,val]; END ELSE DebugOps.LongCopyWRITE[from: from, nwords: lhs.words, to: to]; END; GetControlLink: PUBLIC PROC [f: Foo] RETURNS [PrincOps.ControlLink] = BEGIN IF f.there THEN {GetValue[f]; f.addr.base^ _ Gf.NewLink[f.addr.base^]}; RETURN[f.addr.base^]; END; DerefProcDesc: PUBLIC PROC [cl: PrincOps.ControlLink] RETURNS [PrincOps.ControlLink] = BEGIN DO IF cl.gfi = 0 THEN EXIT; SELECT TRUE FROM cl.gfi = 0 => ERROR NotAProcedure[Gf.OldLink[cl]]; cl.proc => EXIT; cl.indirect => cl _ Gf.NewLink[DebugOps.ShortREAD[LOOPHOLE[cl]]]; ENDCASE => ERROR NotAProcedure[Gf.OldLink[cl]]; ENDLOOP; RETURN[cl] END; CopyMore: PUBLIC PROCEDURE [ tsei: Symbols.SEIndex, doVariants: BOOLEAN _ FALSE] = BEGIN OPEN Symbols, SymbolOps, com; csei: CSEIndex; Add[]; DO WITH seb[tsei] SELECT FROM id => tsei _ IF idType = typeTYPE THEN UnderType[tsei] ELSE idType; cons => BEGIN csei _ LOOPHOLE[tsei]; EXIT END; ENDCASE ENDLOOP; WITH seb[csei] SELECT FROM enumerated => IF csei # typeBOOL THEN Complete[valueCtx]; record => SELECT csei FROM typeStringBody, typeLOCK, typeCONDITION => RETURN; ENDCASE => Complete[fieldCtx, doVariants]; ENDCASE; Drop[]; END; Complete: PUBLIC PROCEDURE [ ictx: Symbols.CTXIndex, variants: BOOLEAN _ FALSE] = BEGIN OPEN Symbols, SymbolOps, Copier; CheckUnions: PROCEDURE [isei: ISEIndex] = BEGIN tsei: SEIndex; IF isei = ISENull THEN RETURN; tsei _ seb[isei].idType; IF tsei = typeTYPE THEN RETURN; WITH se: seb[tsei] SELECT FROM cons => WITH se SELECT FROM union => BEGIN Complete[caseCtx]; FOR isei _ SymbolOps.FirstCtxSe[caseCtx], SymbolOps.NextSe[isei] UNTIL isei = ISENull DO CopyMore[isei,TRUE]; ENDLOOP; END; ENDCASE; ENDCASE; RETURN END; Add[]; WITH ctxb[ictx] SELECT FROM included => IF ~complete THEN CompleteContext[LOOPHOLE[ictx], TRUE ! UNWIND => Drop[]]; ENDCASE => {Drop[]; RETURN}; WITH ctxb[ictx] SELECT FROM included => BEGIN p: POINTER _ State.Get[].h.interpretContext; gf: MachineDefs.GFHandle _ IF Lf.Validate[p] THEN Lf.GF[p] ELSE p; mdi: MDIndex; mdi _ DSyms.GFrameMdi[gf ! SymbolTable.Missing => GOTO bailout]; IF ~complete THEN AugmentContext[LOOPHOLE[ictx], TRUE, mdi ! UNWIND => Drop[]]; -- IF ~reset AND ~complete THEN {ResetCtxList[ictx]; closed _ reset _ TRUE}; EXITS bailout => NULL; END; ENDCASE; IF variants THEN BEGIN isei, root: ISEIndex; isei _ root _ ctxb[ictx].seList; DO IF isei = SENull THEN EXIT; CheckUnions[isei]; WITH id: seb[isei] SELECT FROM sequential => isei _ isei + SIZE[sequential id SERecord]; linked => IF (isei _ id.link) = root THEN EXIT; ENDCASE => EXIT; ENDLOOP; END; Drop[]; END; AddDesc: PROCEDURE [f: Foo, cl: PrincOps.ControlLink] = BEGIN p: POINTER TO PrincOps.ControlLink; p _ Storage.Node[1]; p^ _ cl; f.addr.base _ p; f.words _ 1; END; Constant: PROCEDURE [f: Foo, isei: Symbols.ISEIndex] = BEGIN OPEN seb[isei]; val: POINTER; length: CARDINAL _ 1; IF ~extended THEN BEGIN val _ Storage.Node[length]; LOOPHOLE[val, POINTER TO CARDINAL]^ _ idValue; END ELSE BEGIN tree: Tree.Link; type: Symbols.ExtensionType; [type, tree] _ SymbolOps.FindExtension[isei]; IF type # value THEN ERROR UnexpectedLiteral; IF tree = Tree.Null THEN {MakeFooError[noTree,hash]; ERROR NoTree}; WITH tree SELECT FROM subtree => BEGIN IF tb[index].name # mwconst THEN ERROR LiteralProblem; tree _ tb[index].son[1]; END; ENDCASE => ERROR UnexpectedLiteral; WITH tree SELECT FROM literal => [val,length] _ Lookup.CopyLiteral[info]; ENDCASE => ERROR LiteralProblem; END; f.addr.base _ val; f.words _ length; END; Mode: PUBLIC PROCEDURE [isei: Symbols.ISEIndex] RETURNS [Lookup.Flavor] = BEGIN tsei: Symbols.SEIndex _ seb[isei].idType; xfer: BOOLEAN _ SymbolOps.XferMode[tsei] # none; constant: BOOLEAN _ seb[isei].constant; linkspace: BOOLEAN _ seb[isei].linkSpace; SELECT TRUE FROM xfer AND constant => BEGIN bti: Symbols.BTIndex _ seb[isei].idInfo; IF seb[isei].extended THEN RETURN[inline]; IF bti = Symbols.BTNull THEN RETURN[controlLink] ELSE RETURN[unrelocatedControlLink]; END; xfer AND ~constant => IF linkspace THEN RETURN[refProc] ELSE RETURN[val]; constant => RETURN[manifest]; linkspace => RETURN[refVal]; ENDCASE => RETURN[val]; END; MakeFooError: PROCEDURE [err: {links, unbound, noTree}, u: UNSPECIFIED] = BEGIN OPEN DOutput; SELECT err FROM links => {Text[" !Can't find links from frame: "L]; Octal[u]; EOL[]}; unbound => {EOL[]; Dump.HtiVal[u]; Line[" is unbound!"L]}; noTree => {Text[" ! Tree for "L]; Dump.HtiVal[u]; Line[" not in symbol table."L]}; ENDCASE; END; GetLink: PROC [gf: MachineDefs.GFHandle, bits: CARDINAL, proc: BOOLEAN] RETURNS [UNSPECIFIED] = BEGIN OPEN DebugOps; offset: INTEGER _ bits/MachineDefs.WordLength + 1; cl: MachineDefs.ProcDesc; IF ~Gf.Validate[gf] THEN gf _ Lf.GF[LOOPHOLE[gf]]; IF Gf.Links[gf] THEN cl _ ReadCodeWord[gf, -offset] ELSE cl _ ShortREAD[gf-offset]; IF proc THEN RETURN[Gf.NewLink[cl]] ELSE RETURN[cl]; END; FrameAddress: PROC [ ba: DebugOps.BitAddress, isei: Symbols.ISEIndex, sizeInc: CARDINAL] RETURNS [addr: DebugOps.BitAddress, size: CARDINAL] = BEGIN delta: CARDINAL; addr.useStack _ FALSE; addr.local _ ba.local; [delta, addr.offset] _ Normalize[seb[isei].idValue+ba.offset]; addr.base _ ba.base+delta; size _ seb[isei].idInfo+sizeInc; END; StackAddress: PROC [ba: DebugOps.BitAddress, isei: Symbols.ISEIndex] RETURNS [addr: DebugOps.BitAddress, size: CARDINAL] = BEGIN delta: CARDINAL; offset: Symbols.BitAddress; addr.useStack _ TRUE; addr.local _ ba.local; [offset,size] _ SymbolOps.FnField[isei]; [delta, addr.offset] _ Normalize[offset.bd+ba.offset]; addr.base _ ba.base+delta+offset.wd; END; CheckForHiddenPadding: PROC [f: Foo] = INLINE BEGIN csei: Symbols.CSEIndex = DI.TypeForSe[f.tsei]; WITH seb[csei] SELECT FROM array => f.addr.offset _ DI.Pad[f, LOOPHOLE[csei]]; ENDCASE; END; FixupFrame: PROC [p: POINTER] RETURNS [gf: MachineDefs.GFHandle] = BEGIN gf _ IF Lf.Validate[p] THEN Lf.GF[p] ELSE p; Gf.Check[gf]; END; MakeFoo: PUBLIC PROCEDURE [isei: Symbols.ISEIndex, ba: DebugOps.BitAddress _ [NIL, 0, FALSE], sizeInc: CARDINAL _ 0] RETURNS [f: Foo] = BEGIN OPEN DebugOps, MachineDefs, Symbols, seb[isei]; flavor: Lookup.Flavor; gf: GFHandle; IF isei = ISENull THEN RETURN[NIL]; Add[]; f _ DHeap.AllocFob[]; -- initialized to all zero f.hti _ hash; IF idType = Symbols.typeTYPE THEN BEGIN f.typeOnly _ TRUE; f.tsei _ isei; Drop[]; RETURN END; f.tsei _ idType; SELECT (flavor _ Mode[isei]) FROM manifest, inline, controlLink => NULL; ENDCASE => IF ~ba.useStack THEN BEGIN ENABLE UNWIND => Drop[]; IF ba.base = NIL THEN ba.base _ SIGNAL NotRelocated; IF flavor # val THEN gf _ FixupFrame[Inline.LowHalf[ba.base]]; END; SELECT flavor FROM manifest => Constant[f,isei ! NoTree => {f _ NIL; CONTINUE}]; val => BEGIN size: CARDINAL; f.there _ TRUE; IF ba.useStack THEN [f.addr, size] _ StackAddress[ba,isei] ELSE [f.addr, size] _ FrameAddress[ba, isei, sizeInc]; [f.words, f.bits] _ Normalize[size]; IF f.bits + f.addr.offset > MachineDefs.WordLength THEN ERROR OffsetVariableCrossesWordBoundary; CheckForHiddenPadding[f]; END; refProc => BEGIN cl: PrincOps.ControlLink _ GetLink[gf, idValue, TRUE !Frames.Invalid,Lf.NoAccessLink=>{MakeFooError[links,gf];GOTO bad}]; AddDesc[f, cl]; EXITS bad => BEGIN Drop[]; RETURN[NIL] END; END; refVal => BEGIN p: POINTER _ GetLink[gf, idValue, FALSE ! Frames.Invalid, Lf.NoAccessLink => BEGIN MakeFooError[links,gf]; GOTO nolinks END]; IF p = NIL OR p = LOOPHOLE[1] THEN {MakeFooError[unbound, f.hti]; GOTO nolinks}; WITH seb[SymbolOps.UnderType[idType]] SELECT FROM ref => f.tsei _ DI.TypeForSe[refType]; ENDCASE => ERROR ConfusedAboutImports; f.there _ TRUE; f.addr.base _ Lengthen[p]; WITH seb[f.tsei] SELECT FROM id => [f.words, f.bits] _ Normalize[idInfo]; ENDCASE => f.words _ SymbolOps.WordsForType[f.tsei]; EXITS nolinks => BEGIN Drop[]; RETURN[NIL] END; END; inline => BEGIN tree: Tree.Link; type: Symbols.ExtensionType; [type, tree] _ SymbolOps.FindExtension[isei]; SymbolOps.EnterExtension[isei,type,TreeOps.FreeTree[tree]]; DOutput.Line[" !Inline"L]; Drop[]; RETURN[NIL] END; controlLink => AddDesc[f, idValue]; unrelocatedControlLink => AddDesc[f, Gf.AddGfi[gf, idValue]]; ENDCASE; Drop[]; END; END.