-- file DIUtils.Mesa -- last modified by Bruce, May 30, 1980 7:01 PM DIRECTORY ComData: FROM "comdata", ControlDefs: FROM "controldefs", Copier: FROM "copier", DebugOps: FROM "debugops", DI: FROM "DI", DIActions: FROM "DIActions", Gf: FROM "gf", InlineDefs, Lookup, MachineDefs: FROM "machinedefs", Mopcodes USING [zRFS, zWFS], PrincOps: FROM "princops", Storage: FROM "storage", String, Symbols: FROM "symbols", SymbolOps: FROM "symbolops", SymbolPack: FROM "symbolpack", SymbolTable: FROM "symboltable", Table: FROM "table" USING [Base, Notifier, AddNotify, DropNotify]; DIUtils: PROGRAM IMPORTS com: ComData, Copier, DebugOps, DIActions, Gf, InlineDefs, Lookup, Storage, SymbolOps, myBase: SymbolPack, String, Table EXPORTS DI, DIActions, Lookup SHARES Copier = BEGIN OPEN DI, DIActions, SymbolOps, Symbols; NotAProcedure: PUBLIC ERROR [cl: MachineDefs.ControlLink] = CODE; NotAnArray: PUBLIC ERROR = CODE; NotHere: PUBLIC ERROR = CODE; SizeMismatch: PUBLIC ERROR = CODE; CantAssignInDebuggerImage: ERROR = CODE; StrangeRecord: ERROR = CODE; WrongTypeClass: ERROR [f: Foo] = CODE; -- tables defining the current symbol table seb: Table.Base; -- se table mdb: Table.Base; -- module table ctxb: Table.Base; -- context table Notify: Table.Notifier = BEGIN -- called whenever the main symbol table is repacked seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType] END; entryDepth: CARDINAL ← 0; Enter: PROCEDURE = BEGIN IF entryDepth = 0 THEN Table.AddNotify[Notify]; entryDepth ← entryDepth + 1; END; Exit: PROCEDURE = BEGIN IF (entryDepth ← entryDepth-1) = 0 THEN Table.DropNotify[Notify]; END; StringToHti: PUBLIC PROC [s: STRING] RETURNS [HTIndex] = BEGIN OPEN String; desc: SubStringDescriptor ← [base: s, offset: 0, length: s.length]; RETURN[SymbolOps.EnterString[@desc]]; END; HtiToString: PUBLIC PROC [hti: HTIndex, s: STRING] = BEGIN desc: String.SubStringDescriptor; ss: String.SubString ← @desc; SymbolOps.SubStringForHash[ss,hti]; String.AppendSubString[s,ss]; END; -- finding union and discriminated types VariantUnionType: PUBLIC PROC [type: SEIndex] RETURNS [vType: CSEIndex] = BEGIN rType: CSEIndex; Enter[]; rType ← TypeForSe[type]; vType ← WITH seb[rType] SELECT FROM record => IF hints.variant THEN UnderType[TypeForSe[UnionField[LOOPHOLE[rType]]]] ELSE typeANY, ENDCASE => typeANY; Exit[]; RETURN END; SelectVariantType: PUBLIC PROCEDURE [type: SEIndex, tag: HTIndex] RETURNS [sei: ISEIndex] = BEGIN vType: CSEIndex = VariantUnionType[type]; Enter[]; WITH seb[vType] SELECT FROM union => sei ← SearchCtxList[tag, caseCtx]; ENDCASE => sei ← ISENull; Exit[]; 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]; Enter[]; 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; Exit[]; 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]; IF (sei ← SearchValContext[val,ctx]) # ISENull AND CheckIsei[myBase,sei,tm] THEN RETURN; Enter[]; 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 => sei ← ISENull; Exit[]; 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; SearchCtxList: PUBLIC PROC [hti: HTIndex, ctx: CTXIndex] RETURNS [sei: ISEIndex] = BEGIN found: BOOLEAN ← TRUE; IF ctx = CTXNull THEN RETURN [ISENull]; IF (sei ← SymbolOps.SearchContext[hti,ctx]) # ISENull THEN RETURN; Enter[]; WITH ctxb[ctx] SELECT FROM included => IF ~complete THEN [found, sei] ← Copier.SearchFileCtx[hti, LOOPHOLE[ctx]]; imported => sei ← SearchCtxList[hti,includeLink]; simple => NULL; ENDCASE => sei ← ISENull; Exit[]; IF ~found THEN sei ← ISENull; RETURN; END; CheckClass: PUBLIC PROC [tc: TypeClass, f: Foo] RETURNS [UNSPECIFIED] = BEGIN csei: CSEIndex ← TypeForSe[f.tsei]; Enter[]; IF seb[csei].typeTag # tc THEN ERROR WrongTypeClass[f]; Exit[]; RETURN[csei]; END; FindField: PUBLIC PROC [f: Foo, pad: CARDINAL, isei: ISEIndex] RETURNS [field: Foo] = BEGIN IF f.addr.useStack THEN field ← Lookup.MakeFoo[isei,f.addr] ELSE BEGIN Enter[]; field ← Find[f,pad,isei]; Exit[]; END; field.there ← f.there; field.xfer ← f.xfer; field.indent ← f.indent; END; Find: PROC [f: Foo, pad: CARDINAL, isei: ISEIndex] RETURNS [field: Foo] = INLINE BEGIN ba: DebugOps.BitAddress ← f.addr; notNested: BOOLEAN = ba.offset = 0; first: BOOLEAN = seb[isei].idValue = 0; sizeInc: CARDINAL; IF first AND notNested THEN {sizeInc ← pad; ba.offset ← 0} ELSE {sizeInc ← 0; ba.offset ← pad}; field ← Lookup.MakeFoo[isei, ba, sizeInc] END; Pad: PUBLIC PROC [f: Foo, rsei: RecordSEIndex] RETURNS [pad: CARDINAL] = BEGIN size: CARDINAL ← SymbolOps.BitsForType[rsei]; pad ← 0; IF size < 16 THEN BEGIN available: CARDINAL ← IF f.bits # 0 THEN f.bits ELSE 16; IF available < size THEN ERROR StrangeRecord; pad ← f.addr.offset + available - size; END; 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: Desc, asei: ArraySEIndex] = BEGIN desc: BOOLEAN; long: BOOLEAN; lp: LONG POINTER TO Desc; Enter[]; [asei:asei, desc:desc, long:long] ← ArraySei[f.tsei ! UNWIND => Exit[]]; IF long THEN {Exit[]; ERROR SizeMismatch}; IF ~desc THEN BEGIN IF ~f.there THEN ERROR NotHere; d.base ← InlineDefs.LowHalf[f.addr.base]; d.length ← SymbolOps.Cardinality[seb[asei].indexType]; END ELSE BEGIN GetValue[f]; lp ← f.addr.base; d ← lp↑; END; Exit[]; END; GetLongDesc: PUBLIC PROC [f: Foo] RETURNS [ld: LongDesc, asei: ArraySEIndex] = BEGIN desc: BOOLEAN; long: BOOLEAN; lp: LONG POINTER TO LongDesc; Enter[]; [asei:asei, desc:desc, long:long] ← ArraySei[f.tsei ! UNWIND => Exit[]]; IF ~long THEN {Exit[]; 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; Exit[]; END; VariantType: PUBLIC PROC [usei: UnionSEIndex] RETURNS [v: VType] = BEGIN OPEN seb[usei]; Enter[]; IF ~controlled THEN v ← IF overlaid THEN overlaid ELSE computed ELSE v ← controlled; Exit[]; END; TagIsei: PUBLIC PROC [f: Foo, pad: CARDINAL, usei: UnionSEIndex] RETURNS [isei: ISEIndex] = BEGIN OPEN SymbolOps; tag: Foo; val: CARDINAL; ictx: CTXIndex; Enter[]; tag ← FindField[f,pad,seb[usei].tagSei]; ictx ← seb[usei].caseCtx; Exit[]; IF tag.bits + tag.addr.offset > MachineDefs.WordLength THEN ERROR StrangeRecord; GetValue[tag]; val ← tag.addr.base↑; isei ← Copier.TokenSymbol[ictx,Copier.CtxValue[ictx,val]]; END; TypeForSe: PUBLIC PROC [sei: SEIndex] RETURNS [type: CSEIndex] = BEGIN Enter[]; WITH seb[sei] SELECT FROM id => IF idType # typeTYPE THEN BEGIN type ← LOOPHOLE[idType]; Exit[]; RETURN END; ENDCASE; Exit[]; RETURN[UnderType[sei]]; END; RFS: PROC [POINTER, ControlDefs.FieldDescriptor] RETURNS [UNSPECIFIED] = MACHINE CODE BEGIN Mopcodes.zRFS END; ReadField: PROCEDURE [f: Foo] = BEGIN OPEN f; fd: ControlDefs.FieldDescriptor ← [offset: 0, posn: addr.offset, size: bits]; p: POINTER ← InlineDefs.LowHalf[addr.base]; p↑ ← RFS[p,fd]; END; GetValue: PUBLIC PROCEDURE [f: Foo] = BEGIN OPEN f; p: LONG POINTER; cnt: CARDINAL ← words + (IF bits = 0 THEN 0 ELSE 1); IF ~there THEN RETURN; there ← FALSE; p ← Storage.Node[cnt]; DebugOps.LongCopyREAD[from: addr.base, to: p, nwords: cnt]; addr.base ← p; IF bits # 0 THEN ReadField[f]; END; WFS: PROC [UNSPECIFIED, POINTER, ControlDefs.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: ControlDefs.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; Format: PUBLIC PROCEDURE [sei: SEIndex] RETURNS [vf: ValFormat, intSub: BOOLEAN] = BEGIN inSubrange: BOOLEAN ← FALSE; csei: CSEIndex; vf ← [none[]]; intSub ← FALSE; csei ← TypeForSe[sei]; Enter[]; DO WITH seb[csei] SELECT FROM basic => BEGIN SELECT code FROM codeANY => vf ← [card[]]; codeINT => BEGIN intSub ← inSubrange; vf ← [int[]] END; codeCHAR => vf ← [char[]]; ENDCASE; GOTO exit; END; subrange => BEGIN IF csei = com.typeCARDINAL THEN { vf ← [card[]]; GOTO exit }; csei ← UnderType[rangeType]; inSubrange ← TRUE END; enumerated => BEGIN intSub ← FALSE; vf ← [enum[LOOPHOLE[csei]]]; GOTO exit END; ref => BEGIN IF UnderType[refType] = com.typeStringBody THEN vf ← [string[]] ELSE vf ← [pointer[]]; GOTO exit END; relative => BEGIN vf ← [relative[]]; GOTO exit END; ENDCASE => GOTO exit; ENDLOOP; EXITS exit => {Exit[]; RETURN}; END; END.