-- file Debug.mesa -- last modified by Satterthwaite, March 23, 1983 10:11 am DIRECTORY Alloc: TYPE USING [Base, Handle, Notifier, AddNotify, DropNotify, Top], BcdDefs: TYPE USING [Link, VersionStamp], CharIO: TYPE USING [CR, TAB, PutChar, PutDecimal, PutOctal, PutString], CompilerUtil: TYPE USING [ AcquireStream, AcquireTable, ReleaseStream, ReleaseTable], DebugTable: TYPE USING [CSRptr], Literals: TYPE USING [Base, LitDescriptor, ltType], LiteralOps: TYPE USING [DescriptorValue, MasterString, StringValue], Strings: TYPE USING [String, SubString, SubStringDescriptor], Stream: TYPE USING [Handle], Symbols: TYPE USING [ Base, BitAddress, CTXRecord, TransferMode, TypeClass, Name, SEIndex, ISEIndex, CSEIndex, CTXIndex, BTIndex, nullName, SENull, CTXNull, lG, lZ, RootBti, typeTYPE, seType, ctxType, mdType, bodyType], SymbolOps: TYPE USING [ EnumerateBodies, FindExtension, NameForSe, NextSe, SubStringForName, TypeLink, XferMode], Tree: TYPE USING [Base, Index, Link, NodeName, Scan, NullIndex, treeType], TreeOps: TYPE USING [GetNode, ScanSons]; Debug: PROGRAM IMPORTS Alloc, CharIO, CompilerUtil, LiteralOps, SymbolOps, TreeOps EXPORTS CompilerUtil = { OPEN Symbols; tb: Tree.Base; seb: Symbols.Base; ctxb: Symbols.Base; mdb: Symbols.Base; bb: Symbols.Base; ltb: Literals.Base; definitionsOnly: BOOL; DebugNotify: Alloc.Notifier = { tb ← base[Tree.treeType]; seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType]; bb ← base[bodyType]; ltb ← base[Literals.ltType]}; SubString: TYPE = Strings.SubString; -- basic io errorStream: Stream.Handle ← NIL; WriteChar: PROC [c: CHAR] = {CharIO.PutChar[errorStream, c]}; WriteString: PROC [s: STRING] = {CharIO.PutString[errorStream, s]}; WriteDecimal: PROC [n: INTEGER] = { CharIO.PutDecimal[errorStream, n]}; NewLine: PROC = INLINE {WriteChar[CharIO.CR]}; Indent: PROC [n: CARDINAL] = { NewLine[]; THROUGH [1..n/8] DO WriteChar[CharIO.TAB] ENDLOOP; THROUGH [1..n MOD 8] DO WriteChar[' ] ENDLOOP}; -- errorStream, csrP and desc.base are set by Enter csrP: DebugTable.CSRptr; desc: Strings.SubStringDescriptor; ss: SubString = @desc; LockStringTable: PROC = INLINE { csrP ← CompilerUtil.AcquireTable[debug]; ss.base ← @csrP[csrP.stringOffset]}; UnlockStringTable: PROC = INLINE {CompilerUtil.ReleaseTable[debug]; csrP ← NIL}; Enter: PROC [table: Alloc.Handle] = { table.AddNotify[DebugNotify]; errorStream ← CompilerUtil.AcquireStream[log]; LockStringTable[]}; Exit: PROC [table: Alloc.Handle] = { UnlockStringTable[]; CompilerUtil.ReleaseStream[log]; errorStream ← NIL; table.DropNotify[DebugNotify]}; WriteSubString: PROC [ss: SubString] = { FOR i: CARDINAL IN [ss.offset..ss.offset+ss.length) DO WriteChar[ss.base[i]] ENDLOOP}; -- tree printing PrintLiteral: PROC [t: Tree.Link.literal] = { WITH t.index SELECT FROM string => { s: Strings.String = LiteralOps.StringValue[sti]; WriteChar['"]; FOR i: CARDINAL IN [0..s.length) DO WriteChar[s[i]] ENDLOOP; WriteChar['"]; IF sti # LiteralOps.MasterString[sti] THEN WriteChar['L]}; word => { desc: Literals.LitDescriptor = LiteralOps.DescriptorValue[lti]; v: WORD; IF desc.length # 1 THEN WriteChar['[]; FOR i: CARDINAL IN [0 .. desc.length) DO IF (v ← ltb[desc.offset][i]) < 1000 THEN WriteDecimal[v] ELSE CharIO.PutOctal[errorStream, v]; IF i+1 # desc.length THEN WriteChar[',]; ENDLOOP; IF desc.length # 1 THEN WriteChar[']]}; ENDCASE}; WriteNodeName: PROC [n: Tree.NodeName] = { ss.offset ← csrP.NodePrintName[n].offset; ss.length ← csrP.NodePrintName[n].length; WriteSubString[ss]}; PrintSubTree: PROC [t: Tree.Link, nBlanks: CARDINAL] = { OPEN Tree; Printer: Tree.Scan = { Indent[nBlanks]; WITH s: t SELECT FROM hash => PrintName[s.index]; symbol => {PrintSei[s.index]; WriteChar['[]; PrintIndex[s.index]; WriteChar[']]}; literal => PrintLiteral[s]; subtree => { node: Tree.Index = s.index; IF node = Tree.NullIndex THEN WriteString["<empty>"L] ELSE { OPEN tb[node]; WriteNodeName[name]; WriteChar['[]; PrintIndex[node]; WriteString["] "L]; IF info # 0 THEN {WriteString[" info="L]; PrintIndex[info]}; IF attr1 OR attr2 OR attr3 THEN { IF info = 0 THEN WriteChar[' ]; WriteChar['(]; IF attr1 THEN WriteChar['1]; IF attr2 THEN WriteChar['2]; IF attr3 THEN WriteChar['3]; WriteChar[')]}; nBlanks ← nBlanks + 2; IF name # thread THEN TreeOps.ScanSons[s, Printer] ELSE { WriteString[" link="L]; PrintIndex[TreeOps.GetNode[son[2]]]; Printer[son[1]]}; nBlanks ← nBlanks - 2}}; ENDCASE}; Printer[t]}; PrintTree: PUBLIC PROC [table: Alloc.Handle, root: Tree.Link] = { Enter[table]; PrintSubTree[root, 0]; NewLine[]; NewLine[]; Exit[table]}; PrintBodies: PUBLIC PROC [table: Alloc.Handle] = { Enter[table]; [] ← SymbolOps.EnumerateBodies[RootBti, PrintBody]; NewLine[]; Exit[table]}; PrintBody: PROC [bti: BTIndex] RETURNS [BOOL] = { OPEN body: bb[bti]; WriteString["Body: "L]; WITH b: body SELECT FROM Callable => { PrintSei[b.id]; IF b.inline THEN WriteString[" [inline]"L] ELSE { WriteString[", ep: "L]; WriteDecimal[b.entryIndex]; WITH b SELECT FROM Inner => {WriteString[", frame addr: "L]; WriteDecimal[frameOffset]}; ENDCASE}; WriteString[", attrs: "L]; WriteChar[IF ~b.noXfers THEN 'x ELSE '-]; WriteChar[IF b.hints.safe THEN 's ELSE '-]; WriteChar[IF b.hints.nameSafe THEN 'n ELSE '-]; IF ~b.hints.noStrings THEN {Indent[2]; WriteString["string literals"L]}}; ENDCASE => WriteString["(anon)"L]; Indent[2]; WriteString["context: "L]; PrintIndex[body.localCtx]; WriteString[", level: "L]; WriteDecimal[body.level]; WITH body.info SELECT FROM Internal => { WriteString[", frame size: "L]; WriteDecimal[frameSize]; IF body.kind = Callable THEN PrintSubTree[[subtree[index: bodyTree]], 0] ELSE {WriteString[", tree root: "L]; PrintIndex[bodyTree]}}; ENDCASE; NewLine[]; NewLine[]; RETURN [FALSE]}; PrintSymbols: PUBLIC PROC [table: Alloc.Handle, definitions: BOOL] = { ctx: CTXIndex; limit: CTXIndex; Enter[table]; definitionsOnly ← definitions; limit ← table.Top[Symbols.ctxType]; ctx ← CTXIndex.FIRST + CTXRecord.nil.SIZE; UNTIL ctx = limit DO PrintContext[ctx]; NewLine[]; NewLine[]; ctx ← ctx + (WITH ctxb[ctx] SELECT FROM included => CTXRecord.included.SIZE, imported => CTXRecord.imported.SIZE, ENDCASE => CTXRecord.simple.SIZE); ENDLOOP; NewLine[]; Exit[table]}; PrintContext: PROC [ctx: CTXIndex] = { sei, root: ISEIndex; WriteString["Context: "L]; PrintIndex[ctx]; IF ctxb[ctx].level # lZ THEN {WriteString[", level: "L]; WriteDecimal[ctxb[ctx].level]}; WITH c: ctxb[ctx] SELECT FROM included => { WriteString[", copied from: "L]; PrintName[mdb[c.module].moduleId]; WriteString[" ["L]; PrintName[mdb[c.module].fileId]; WriteString[", "L]; PrintVersion[mdb[c.module].stamp]; WriteString["], context: "L]; PrintIndex[c.map]}; imported => { WriteString[", imported from: "L]; PrintName[mdb[ctxb[c.includeLink].module].moduleId]}; ENDCASE; root ← sei ← ctxb[ctx].seList; DO IF sei = SENull THEN EXIT; PrintSE[sei, 2]; IF (sei ← SymbolOps.NextSe[sei]) = root THEN EXIT; ENDLOOP}; PrintSE: PROC [sei: ISEIndex, nBlanks: CARDINAL] = { OPEN seb[sei]; typeSei: SEIndex; Indent[nBlanks]; PrintSei[sei]; WriteString[" ["L]; PrintIndex[sei]; WriteChar[']]; IF public THEN WriteString[" [public]"L]; IF mark3 THEN { WriteString[", type = "L]; IF idType = typeTYPE THEN { typeSei ← idInfo; WriteString["TYPE, equated to: "L]; PrintType[typeSei]; IF ctxb[idCtx].level = lZ AND SymbolOps.TypeLink[sei] # SENull THEN { WriteString[", tag code: "L]; WriteDecimal[idValue]}} ELSE { typeSei ← idType; PrintType[typeSei]; SELECT TRUE FROM constant => WriteString[" [const]"L]; immutable => WriteString[" [init only]"L]; ENDCASE; IF ~mark4 THEN {WriteString[", # refs: "L]; WriteDecimal[idInfo]} ELSE SELECT TRUE FROM constant => IF ~ extended THEN { WriteString[", value: "L]; SELECT SymbolOps.XferMode[typeSei] FROM proc, program, signal, error => PrintLink[idValue]; ENDCASE => IF LOOPHOLE[idValue, CARDINAL] < 1000 THEN WriteDecimal[idValue] ELSE CharIO.PutOctal[errorStream, idValue]}; (definitionsOnly AND ctxb[idCtx].level = lG) => { WriteString[", index: "L]; WriteDecimal[idValue]}; ENDCASE => { addr: BitAddress = idValue; WriteString[", address: "L]; WriteDecimal[addr.wd]; WriteChar[' ]; WriteChar['[]; WriteDecimal[addr.bd]; WriteChar[':]; WriteDecimal[idInfo]; WriteChar[']]; IF linkSpace THEN WriteChar['*]}}; PrintTypeInfo[typeSei, nBlanks+2]; IF extended THEN PrintSubTree[SymbolOps.FindExtension[sei].tree, nBlanks+4]}}; PrintName: PROC [name: Name] = { desc: Strings.SubStringDescriptor; s: SubString = @desc; IF name = nullName THEN WriteString["(anon)"L] ELSE {SymbolOps.SubStringForName[s, name]; WriteSubString[s]}}; PrintSei: PROC [sei: ISEIndex] = {PrintName[SymbolOps.NameForSe[sei]]}; WriteTypeName: PROC [n: TypeClass] = { ss.offset ← csrP.TypePrintName[n].offset; ss.length ← csrP.TypePrintName[n].length; WriteSubString[ss]}; WriteModeName: PROC [n: TransferMode] = { ss.offset ← csrP.ModePrintName[n].offset; ss.length ← csrP.ModePrintName[n].length; WriteSubString[ss]}; PrintType: PROC [sei: SEIndex] = { tSei: SEIndex; IF sei = SENull THEN WriteChar['?] ELSE WITH t: seb[sei] SELECT FROM cons => WITH t SELECT FROM transfer => WriteModeName[mode]; ENDCASE => WriteTypeName[t.typeTag]; id => FOR tSei ← sei, SymbolOps.TypeLink[tSei] UNTIL tSei = SENull DO WITH seb[tSei] SELECT FROM id => { IF sei # tSei THEN WriteChar[' ]; PrintSei[LOOPHOLE[tSei, ISEIndex]]; IF ~mark3 OR ctxb[idCtx].level # lZ THEN EXIT}; ENDCASE; ENDLOOP; ENDCASE; WriteString[" ["L]; PrintIndex[sei]; WriteChar[']]}; PrintTypeInfo: PROC [sei: SEIndex, nBlanks: CARDINAL] = { IF sei # SENull THEN WITH s: seb[sei] SELECT FROM cons => { Indent[nBlanks]; WriteChar['[]; PrintIndex[sei]; WriteString["] "L]; WITH s SELECT FROM transfer => WriteModeName[mode]; ENDCASE => WriteTypeName[s.typeTag]; WITH t: s SELECT FROM basic => NULL; enumerated => { IF t.machineDep THEN WriteString[" (md)"L] ELSE IF t.unpainted THEN WriteString[" (~painted)"L]; WriteString[", value ctx: "L]; PrintIndex[t.valueCtx]}; record => { IF t.machineDep THEN WriteString[" (md)"L]; IF t.monitored THEN WriteString[" (monitored)"L]; IF t.hints.variant THEN WriteString[" (variant)"L]; OutCtx[", field"L, t.fieldCtx]; WITH ctxb[t.fieldCtx] SELECT FROM included => IF ~complete THEN WriteString[" [partial]"L]; imported => WriteString[" [partial]"L]; ENDCASE; WITH t SELECT FROM linked => {WriteString[", link: "L]; PrintType[linkType]}; ENDCASE}; ref => { SELECT TRUE FROM t.counted => WriteString[" (counted)"L]; t.var => WriteString[" (var)"L]; ENDCASE; IF t.ordered THEN WriteString[" (ordered)"L]; IF t.basing THEN WriteString[" (base)"L]; WriteString[", to: "L]; PrintType[t.refType]; IF t.readOnly THEN WriteString[" (readonly)"L]; PrintTypeInfo[t.refType, nBlanks+2]}; array => { IF t.packed THEN WriteString[" (packed)"L]; WriteString[", index type: "L]; PrintType[t.indexType]; WriteString[", component type: "L]; PrintType[t.componentType]; PrintTypeInfo[t.indexType, nBlanks+2]; PrintTypeInfo[t.componentType, nBlanks+2]}; arraydesc => { WriteString[", described type: "L]; PrintType[t.describedType]; IF t.readOnly THEN WriteString[" (readonly)"L]; PrintTypeInfo[t.describedType, nBlanks+2]}; transfer => { IF t.safe THEN WriteString[" (safe)"L]; OutArgType[", input"L, t.typeIn]; OutArgType[", output"L, t.typeOut]}; definition => { WriteString[", ctx: "L]; PrintIndex[t.defCtx]; WriteString[", ngfi: "L]; WriteDecimal[t.nGfi]}; union => { IF t.overlaid THEN WriteString[" (overlaid)"L]; IF t.controlled THEN {WriteString[", tag: "L]; PrintSei[t.tagSei]}; WriteString[", tag type: "L]; PrintType[seb[t.tagSei].idType]; WriteString[", case ctx: "L]; PrintIndex[t.caseCtx]; IF t.controlled THEN PrintSE[t.tagSei, nBlanks+2]}; sequence => { IF t.packed THEN WriteString[" (packed)"L]; IF t.controlled THEN {WriteString[", tag: "L]; PrintSei[t.tagSei]} ELSE {WriteString[", index type: "L]; PrintType[seb[t.tagSei].idType]}; WriteString[", component type: "L]; PrintType[t.componentType]; IF t.controlled THEN PrintSE[t.tagSei, nBlanks+2] ELSE PrintTypeInfo[seb[t.tagSei].idType, nBlanks+2]; PrintTypeInfo[t.componentType, nBlanks+2]}; relative => { WriteString[", base type: "L]; PrintType[t.baseType]; WriteString[", offset type: "L]; PrintType[t.offsetType]; PrintTypeInfo[t.baseType, nBlanks+2]; PrintTypeInfo[t.offsetType, nBlanks+2]}; opaque => { WriteString[", id: "L]; PrintSei[t.id]; IF t.lengthKnown THEN {WriteString[", size: "L]; WriteDecimal[t.length]}}; zone => { IF t.counted THEN WriteString[" (counted)"L]; IF t.mds THEN WriteString[" (mds)"L]}; subrange => { WriteString[" of: "L]; PrintType[t.rangeType]; IF t.filled THEN { WriteString[" origin: "L]; WriteDecimal[t.origin]; WriteString[", range: "L]; WriteDecimal[t.range]}; PrintTypeInfo[t.rangeType, nBlanks+2]}; long, real => { WriteString[" of: "L]; PrintType[t.rangeType]; PrintTypeInfo[t.rangeType, nBlanks+2]}; ENDCASE}; ENDCASE}; OutCtx: PROC [message: STRING, ctx: CTXIndex] = { WriteString[message]; WriteString[" ctx: "L]; IF ctx = CTXNull THEN WriteString["NIL"L] ELSE PrintIndex[ctx]}; OutArgType: PROC [message: STRING, sei: CSEIndex] = { IF sei = SENull THEN {WriteString[message]; WriteString[": NIL"L]} ELSE WITH t: seb[sei] SELECT FROM record => OutCtx[message, t.fieldCtx]; any => {WriteString[message]; WriteString[": ANY"L]}; ENDCASE}; PrintIndex: PROC [v: UNSPECIFIED] = LOOPHOLE[WriteDecimal]; PrintLink: PROC [link: BcdDefs.Link] = { SELECT TRUE FROM link.proc => { WriteString["proc["L]; WriteDecimal[link.gfi]; WriteChar[',]; WriteDecimal[link.ep]}; link.type => {WriteString["type["L]; PrintIndex[link.typeID]}; ENDCASE => { WriteString["var["L]; WriteDecimal[link.gfi]; WriteChar[',]; WriteDecimal[link.var]}; WriteChar[']]}; PrintVersion: PROC [stamp: BcdDefs.VersionStamp] = { stampWords: CARDINAL = BcdDefs.VersionStamp.SIZE; str: PACKED ARRAY [0..4*stampWords) OF [0..16) = LOOPHOLE[stamp]; digit: STRING = "0123456789abcdef"L; FOR i: NAT IN [0..4*stampWords) DO WriteChar[digit[str[i]]] ENDLOOP}; }.