-- DumpHot.mesa; modified by Johnsson, July 16, 1980 8:33 AM
-- modified by Bruce, October 25, 1980 8:16 PM
DIRECTORY
Ascii USING [CR, DEL, LF, NUL, SP, TAB],
Commands USING [WriteError],
DebugFormat USING [BitAddress, Fob, Foo, LongSubString],
DebugOps USING [
Foo, FooProc, Lengthen, LongCopyREAD, LongREAD, NotImplemented, ShortREAD,
InvalidAddress, UserAborted],
DI USING [
CheckClass, CSEIndex, CTXIndex, EnumeratedSEIndex, FindField, Foo,
Format, GetValue, ISEIndex, LongSEIndex, Normalize, Pad, SearchCtxForVal,
SEIndex, SubrangeSEIndex, TagIsei, TypeForSe, UnionSEIndex, ValFormat, VariantType],
DOutput USING [
Blanks, Char, Decimal, EOL, LongDecimal, LongOctal, Number, Octal, SubString, Text],
Strings USING [SubString, SubStringDescriptor],
Dump USING [
Array, ArrayDesc, LongArrayDesc, Opaque, Printer, printers, PrintRec, Real,
Type, Xfer, CompareSes, Sequence],
DHeap USING [AllocFob],
Init USING [],
Lookup USING [CopyMore],
State USING [GetGS, GSHandle],
String USING [SubString],
SymbolOps USING [BitsForType, RecordRoot, SubStringForHash],
Symbols USING [
CSEIndex, CTXIndex, HTIndex, HTNull, ISEIndex, ISENull, RecordSEIndex,
RecordSENull, SEIndex, SENull, SERecord, TransferMode, TypeClass, typeTYPE],
SymbolSegment USING [bodyType, ctxType, seType],
Table USING [AddNotify, Base, DropNotify, Notifier],
UserInput USING [ResetUserAbort, userAbort];
DumpHot: PROGRAM
IMPORTS
Commands, DebugOps, DI, DOutput, Dump, DHeap, Lookup,
State, SymbolOps, Table, UserInput
EXPORTS DebugOps, Dump, Init =
BEGIN OPEN DI, Dump, SymbolOps, Symbols;
NoTypeInfo: PUBLIC ERROR [sei: SEIndex] = CODE;
StrangeRecord: ERROR = CODE;
seb: Table.Base;
ctxb: Table.Base;
bb: Table.Base;
data: State.GSHandle ← State.GetGS[];
entryDepth: CARDINAL ← 0;
StringLimit: PUBLIC CARDINAL ← LAST[CARDINAL];
Enter: PROCEDURE = {
IF entryDepth = 0 THEN Table.AddNotify[Notify];
entryDepth ← entryDepth + 1};
Exit: PROC = {IF (entryDepth ← entryDepth-1) = 0 THEN Table.DropNotify[Notify]};
Notify: Table.Notifier =
BEGIN OPEN SymbolSegment;
seb ← base[seType];
ctxb ← base[ctxType];
bb ← base[bodyType];
END;
UserPrint: PROCEDURE [f: Foo] RETURNS [BOOLEAN] =
BEGIN
p: POINTER TO PrintRec;
IF f.tsei = SENull THEN RETURN[FALSE];
FOR p ← printers, p.link UNTIL p = NIL DO
IF ~CompareSes[p.tsei, f.tsei] THEN LOOP;
p.proc[f !ANY => BEGIN p.tsei ← SENull; CONTINUE END];
RETURN [TRUE];
ENDLOOP;
RETURN[FALSE];
END;
DisplayFoo: PUBLIC DebugOps.FooProc = {Display[f]};
Display: PUBLIC PROCEDURE [f: Foo, rec: BOOLEAN ← FALSE] =
BEGIN
csei: CSEIndex;
IF f = NIL THEN RETURN;
Enter[];
IF f.typeOnly THEN
WITH seb[f.tsei] SELECT FROM
id => Type[LOOPHOLE[f.tsei]];
ENDCASE => {Exit[]; ERROR NoTypeInfo[f.tsei]}
ELSE
BEGIN ENABLE {
DebugOps.InvalidAddress => {
Commands.WriteError[badAddress,FALSE];
DOutput.LongOctal[address]; DOutput.Char[']];
CONTINUE};
UNWIND => Exit[]};
IF f.hti # HTNull THEN {
IF f.indent # 0 THEN DOutput.Blanks[f.indent];
HtiVal[f.hti];
DOutput.Text[IF rec THEN ":"L ELSE " = "L]};
IF ~UserPrint[f] THEN {
csei ← DI.TypeForSe[f.tsei];
WITH seb[csei] SELECT FROM
basic, enumerated, ref, arraydesc,
relative, subrange, long, real, zone => GetValue[f];
transfer, record, array, union, opaque => NULL;
ENDCASE;
WITH seb[csei] SELECT FROM
basic, ref, enumerated => TypedNum[f.addr.base↑, f.tsei];
zone => Zone[f, mds];
relative => Relative[f];
record => Record[f];
array => Array[f];
arraydesc => ArrayDesc[f];
transfer => Xfer[f];
union => UnionErr[];
subrange => Subrange[f];
long => Long[f];
real => Real[f];
opaque => Opaque[f];
ENDCASE};
END;
Exit[];
IF ~rec THEN DOutput.EOL[];
END;
UnionErr: PROC = {SIGNAL DebugOps.NotImplemented[" Printing entire variant parts"L]};
Zone: PUBLIC PROCEDURE [f: Foo, short: BOOLEAN] =
BEGIN
lp: LONG POINTER TO LONG UNSPECIFIED = f.addr.base;
IF short THEN TypedNum[f.addr.base↑, f.tsei] ELSE TypedLongNum[lp↑, f.tsei];
END;
Basic: PUBLIC PROCEDURE [f: Foo] =
BEGIN
[] ← CheckClass[basic, f];
TypedNum[f.addr.base↑, f.tsei];
END;
Pointer, StringPrinter: PUBLIC PROCEDURE [f: Foo] =
BEGIN
[] ← CheckClass[ref, f];
TypedNum[f.addr.base↑, f.tsei];
END;
Relative: PUBLIC PROCEDURE [f: Foo] =
BEGIN
type: {p, long, desc};
csei: Symbols.CSEIndex ← DI.TypeForSe[f.tsei];
[] ← CheckClass[relative, f];
Enter[];
WITH seb[csei] SELECT FROM
arraydesc => {f.tsei ← csei; DOutput.Text[" RELATIVE "L]; type ← desc};
long => {
csei: Symbols.CSEIndex ← DI.TypeForSe[rangeType];
IF seb[csei].typeTag = arraydesc THEN {f.tsei ← csei; DOutput.Text[" RELATIVE "L]};
type ← long};
ENDCASE => type ← p;
Exit[];
SELECT type FROM
long => Long[f];
desc => ArrayDesc[f];
ENDCASE => TypedNum[f.addr.base↑, f.tsei];
END;
Enumerated: PUBLIC PROCEDURE [f: Foo] =
BEGIN
[] ← CheckClass[enumerated, f];
TypedNum[f.addr.base↑, f.tsei];
END;
Record: PUBLIC PROCEDURE [f: Foo] = {
variant: RecordSEIndex ← CheckClass[record, f];
root: RecordSEIndex ← SymbolOps.RecordRoot[variant];
VariantType: PROC RETURNS [RecordSEIndex] = {RETURN[variant]};
IF root # RecordSENull THEN f.tsei ← root;
IF root = variant THEN variant ← RecordSENull;
RecordCommon[f,VariantType]};
NullVariant: PUBLIC PROC RETURNS [Symbols.RecordSEIndex] = {RETURN[Symbols.RecordSENull]};
RecordCommon: PROC [f: Foo, variant: PROC RETURNS [Symbols.RecordSEIndex]] =
BEGIN
rsei: RecordSEIndex ← CheckClass[record, f];
Lookup.CopyMore[rsei];
Enter[];
WITH seb[f.tsei] SELECT FROM
id => HtiVal[hash];
ENDCASE;
FieldCtx[f, seb[rsei].fieldCtx, Pad[f,rsei], variant, rsei !UNWIND => Exit[]];
Exit[];
END;
FieldCtx: PUBLIC PROCEDURE [
f: Foo, ctx: Symbols.CTXIndex, pad: CARDINAL,
variant: PROC RETURNS [Symbols.RecordSEIndex] ← NullVariant,
rsei: Symbols.RecordSEIndex ← Symbols.RecordSENull] =
BEGIN
notXfer: BOOLEAN ← ~f.xfer;
root,isei: ISEIndex;
first: BOOLEAN ← TRUE;
csei: CSEIndex;
GetNextSe: PROC =
BEGIN
WITH id: seb[isei] SELECT FROM
sequential => isei ← isei + SIZE[sequential id Symbols.SERecord];
linked => IF (isei ← id.link) = root THEN isei ← Symbols.ISENull;
ENDCASE => isei ← Symbols.ISENull;
END;
Enter[];
isei ← root ← ctxb[ctx].seList;
IF notXfer THEN DOutput.Char['[];
DO
IF isei = Symbols.ISENull THEN EXIT;
IF seb[isei].constant OR seb[isei].idType = Symbols.typeTYPE OR seb[isei].idCtx # ctx THEN
{GetNextSe[]; LOOP};
IF notXfer AND ~first THEN DOutput.Text[", "L];
csei ← DI.TypeForSe[isei];
SELECT seb[csei].typeTag FROM
union => Variant[f, pad, LOOPHOLE[csei], variant];
sequence => {
HashVal[isei]; DOutput.Char[':]; Sequence[f, pad, LOOPHOLE[csei], variant]};
ENDCASE =>
BEGIN ENABLE UNWIND => Exit[];
temp: Foo ← FindField[f,pad,isei];
IF temp.typeOnly THEN {GetNextSe[]; LOOP};
temp.addr.useStack ← temp.xfer ← FALSE;
IF notXfer THEN temp.indent ← 0;
Display[temp, notXfer];
END;
IF first THEN first ← FALSE;
GetNextSe[];
ENDLOOP;
WITH ctxb[ctx] SELECT FROM
included => IF ~complete THEN {
IF notXfer AND ~first THEN DOutput.Text[", "L] ELSE DOutput.Blanks[f.indent];
DOutput.Text["..."L]};
ENDCASE;
IF notXfer THEN DOutput.Char[']];
Exit[];
END;
Variant: PUBLIC PROCEDURE [f: Foo, pad: CARDINAL, usei: UnionSEIndex,
variant: PROC RETURNS [Symbols.RecordSEIndex] ← NullVariant] =
BEGIN
isei: ISEIndex;
bound: RecordSEIndex ← variant[];
SELECT VariantType[usei] FROM
controlled =>
BEGIN
IF (isei ← TagIsei[f,pad,usei]) = ISENull THEN
BEGIN DOutput.Text["UnknownVariant[...]"L]; RETURN END;
HashVal[isei];
RecordCommon[MakeVarFoo[f, pad, DI.TypeForSe[isei], bound], NullVariant];
END;
overlaid => {
DOutput.Text["OVERLAID"L];
IF bound = Symbols.RecordSENull THEN DOutput.Text["[...]"L]
ELSE RecordCommon[MakeVarFoo[f, pad, bound, Symbols.RecordSENull], NullVariant]};
computed => {
DOutput.Text["COMPUTED"L];
IF bound = Symbols.RecordSENull THEN DOutput.Text["[...]"L]
ELSE RecordCommon[MakeVarFoo[f, pad, bound, Symbols.RecordSENull], NullVariant]};
ENDCASE => ERROR StrangeRecord;
END;
MakeVarFoo: PROC [r: Foo, pad: CARDINAL, tag, bound: CSEIndex]
RETURNS [f: Foo] =
BEGIN
-- IF bound # Symbols.RecordSENull AND bound # tag THEN
-- DOutput.Text[" ! Incorrect tag for bound variant. "L];
f ← DHeap.AllocFob[];
f.tsei ← tag;
f.there ← r.there;
f.addr.base ← r.addr.base;
f.addr.offset ← pad;
[f.words, f.bits] ← Normalize[BitsForType[f.tsei]];
END;
Subrange: PUBLIC PROCEDURE [f: Foo] =
BEGIN
sei: SubrangeSEIndex ← CheckClass[subrange, f];
vf: ValFormat ← Format[sei].vf;
org,end,val: INTEGER;
Enter[];
org ← seb[sei].origin;
end ← org + seb[sei].range;
Exit[];
val ← org+f.addr.base↑;
WITH vf SELECT FROM
card,none => NULL;
ENDCASE => SELECT org FROM
< end => IF val ~IN [org..end] THEN vf ← [none[]];
> end => IF LOOPHOLE[val,CARDINAL]
~IN [LOOPHOLE[org,CARDINAL]..LOOPHOLE[end,CARDINAL]] THEN vf ← [none[]];
ENDCASE;
Num[val, vf];
END;
Long: PUBLIC PROCEDURE [f: Foo] =
BEGIN
sei: LongSEIndex ← CheckClass[long, f];
p: LONG POINTER TO LONG UNSPECIFIED ← LOOPHOLE[f.addr.base];
rsei: SEIndex;
Enter[];
rsei ← seb[sei].rangeType;
WITH seb[DI.TypeForSe[rsei]] SELECT FROM
arraydesc => LongArrayDesc[f !UNWIND => Exit[]];
ENDCASE => TypedLongNum[p↑, rsei];
Exit[];
END;
Char: PUBLIC PROCEDURE [c: UNSPECIFIED] =
BEGIN OPEN Ascii;
SELECT c FROM
NUL => DOutput.Text["NUL"L];
TAB => DOutput.Text["TAB"L];
LF => DOutput.Text["LF"L];
14C => DOutput.Text["FF"L];
CR => DOutput.Text["CR"L];
33C => DOutput.Text["ESC"L];
IN CHARACTER[NUL..SP) =>
BEGIN DOutput.Char['↑]; DOutput.Char[LOOPHOLE[c+100B, CHARACTER]] END;
SP => DOutput.Text["SP"L];
DEL => DOutput.Text["DEL"L];
ENDCASE =>
IF c ~IN CHARACTER[NUL..DEL] THEN DOutput.Octal[c]
ELSE BEGIN DOutput.Char['']; DOutput.Char[c] END;
RETURN
END;
HashVal: PUBLIC PROCEDURE [sei: ISEIndex] =
BEGIN
Enter[];
HtiVal[IF sei = SENull THEN HTNull ELSE seb[sei].hash];
Exit[];
END;
HtiVal: PUBLIC PROCEDURE [hti: HTIndex] =
BEGIN
IF hti = HTNull THEN DOutput.Text["(anon)"L]
ELSE
BEGIN OPEN Strings;
desc: SubStringDescriptor;
ss: SubString ← @desc;
SubStringForHash[ss,hti];
DOutput.SubString[ss];
END;
END;
EnumVal: PUBLIC PROCEDURE [val: UNSPECIFIED, esei: EnumeratedSEIndex] =
BEGIN
ictx: CTXIndex = seb[esei].valueCtx;
sei: ISEIndex = DI.SearchCtxForVal[val,ictx,none];
IF sei # ISENull THEN HashVal[sei] ELSE BadNum[val];
END;
TypedNum: PUBLIC PROCEDURE [val: UNSPECIFIED, tsei: SEIndex] =
BEGIN Num[val, Format[tsei].vf] END;
Num: PUBLIC PROCEDURE [val: UNSPECIFIED, vf: ValFormat] =
BEGIN
WITH vf SELECT FROM
card => DOutput.Octal[val];
int => MyDecimal[val];
char => Char[val];
pointer => IF val = NIL THEN DOutput.Text["NIL"L]
ELSE BEGIN DOutput.Octal[val]; DOutput.Char['↑]; END;
relative => {
DOutput.Number[val, [base: 10, zerofill: FALSE, unsigned: TRUE, columns: 0]];
DOutput.Text["↑R"L]};
string => StringCommon[DebugOps.Lengthen[val]];
enum => EnumVal[val, esei];
ENDCASE => BadNum[val];
END;
BadNum: PUBLIC PROCEDURE [val: UNSPECIFIED] =
BEGIN DOutput.Text["?["L]; DOutput.Octal[val]; DOutput.Char[']] END;
TypedLongNum: PUBLIC PROCEDURE [val: LONG UNSPECIFIED, tsei: SEIndex] =
BEGIN LongNum[val, Format[tsei].vf] END;
LongNum: PUBLIC PROCEDURE [val: LONG UNSPECIFIED, vf: ValFormat] =
BEGIN
WITH vf SELECT FROM
card => DOutput.LongOctal[val];
int => DOutput.LongDecimal[LOOPHOLE[val, LONG INTEGER]];
pointer => IF val = NIL THEN DOutput.Text["NIL"L]
ELSE BEGIN DOutput.LongOctal[val]; DOutput.Char['↑]; END;
relative =>
{DOutput.LongDecimal[LOOPHOLE[val, LONG INTEGER]]; DOutput.Text["R↑"L]};
string => StringCommon[val];
ENDCASE => BadLongNum[val];
END;
BadLongNum: PROCEDURE [val: LONG UNSPECIFIED] =
BEGIN DOutput.Text["?["L]; DOutput.LongOctal[val]; DOutput.Char[']] END;
MyDecimal: PROCEDURE [u: UNSPECIFIED] = INLINE
BEGIN DOutput.Decimal[LOOPHOLE[u,INTEGER]] END;
StringCommon: PROCEDURE [ls: LONG STRING] =
BEGIN OPEN DOutput;
sb: StringBody;
IF ls = NIL THEN BEGIN DOutput.Text["NIL"L]; RETURN END;
DebugOps.LongCopyREAD[from: ls, nwords: SIZE[StringBody], to: @sb];
Char['(]; MyDecimal[sb.length]; Char[',];
MyDecimal[sb.maxlength]; Text[")"""L];
UserLongText[ls ! DebugOps.UserAborted => {ControlDel[]; CONTINUE}];
Char['"];
END;
-- write strings from user world
UserText: PUBLIC PROCEDURE [s: STRING] =
BEGIN
length: CARDINAL ← DebugOps.ShortREAD[@s.length];
UserDump[DebugOps.Lengthen[s], 0, length];
RETURN
END;
UserSubString: PUBLIC PROCEDURE[ss: String.SubString] =
BEGIN UserDump[DebugOps.Lengthen[ss.base], ss.offset, ss.length] END;
UserLongText: PUBLIC PROCEDURE [s: LONG STRING] =
BEGIN
length: CARDINAL = DebugOps.LongREAD[@s.length];
UserDump[s, 0, length];
RETURN
END;
UserLongSubString: PUBLIC PROCEDURE [ls: DebugFormat.LongSubString] =
BEGIN UserDump[ls.base, ls.offset, ls.length] END;
UserDump: PROCEDURE [base: LONG STRING, offset, length: CARDINAL] =
BEGIN
i: CARDINAL;
s: PACKED ARRAY [0..1] OF CHARACTER;
p: POINTER = @s;
bad: BOOLEAN ← offset > 5000 OR length > 5000 OR
LONG[offset]+LONG[length] > LAST[CARDINAL];
IF offset MOD 2 # 0 THEN p↑ ← DebugOps.LongREAD[@base.text+offset/2];
FOR i IN [offset..offset+length) DO
IF i MOD 2 = 0 THEN p↑ ← DebugOps.LongREAD[@base.text+i/2];
DOutput.Char[s[i MOD 2]];
IF i - offset > StringLimit THEN RETURN;
IF UserInput.userAbort THEN {ControlDel[]; RETURN};
ENDLOOP;
RETURN
END;
ControlDel: PROC ={UserInput.ResetUserAbort[]; DOutput.Text[" ... aborted"L]};
END.