123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- MODULE Reflection; (** AUTHOR "fof"; PURPOSE "tools for module, stack and process reflection"; *)
- IMPORT Modules,Streams,Machine,Heaps,Objects,SYSTEM;
- CONST
- ShowAllProcs = TRUE;
- MaxFrames = 128;
- MaxString = 64;
- MaxArray = 8;
- MaxCols = 70;
- Sep = " ";
- SepLen = 2;
- LineDelay = 0; (* set this value to the number of cycles of an empty for loop that the reflection should wait after a new line
- * useful for screen racing when no persistent trace medium is available
- * no timer mechanism used because at low level tracing this may exactly not be available because IRQs do not work any more or so.
- *)
- TYPE
- Variable* = RECORD
- adr-: ADDRESS;
- type-, size-, n-, tdadr-: LONGINT
- END;
- VAR
- modes: ARRAY 25 OF CHAR;
- (*
- Reference = {OldRef | ProcRef} .
- OldRef = 0F8X offset/n name/s {Variable} .
- ProcRef = 0F9X offset/n nofPars/n RetType procLev/1 slFlag/1 name/s {Variable} .
- RetType = 0X | Var | ArrayType | Record .
- ArrayType = 12X | 14X | 15X . (* static array, dynamic array, open array *)
- Record = 16X .
- Variable = VarMode (Var | ArrayVar | RecordVar ) offset/n name/s .
- VarMode = 1X | 3X . (* direct, indirect *)
- Var = 1X .. 0FX . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc, string *)
- ArrayVar = (81X .. 8EX) dim/n . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc *)
- RecordVar = (16X | 1DX) tdadr/n . (* record, recordpointer *)
- *)
- (** Write a variable value. The v parameter is a variable descriptor obtained with NextVar. Parameter col is incremented with the (approximate) number of characters written. *)
- PROCEDURE WriteVar*(w: Streams.Writer; v: Variable; VAR col: LONGINT);
- VAR ch: CHAR;
- BEGIN
- IF v.type = 15 THEN
- w.Char(22X);
- LOOP
- IF (v.n = 0) OR (~CheckHeapAddress(v.adr)) THEN EXIT END;
- SYSTEM.GET(v.adr, ch);
- INC(v.adr);
- IF (ch < " ") OR (ch > "~") THEN EXIT END;
- w.Char(ch); INC(col); DEC(v.n)
- END;
- w.Char(22X); INC(col, 2);
- IF ch # 0X THEN w.Char("!") END
- ELSE
- WHILE v.n > 0 DO
- WriteSimpleVar(w, v.adr, v.type, v.tdadr, col);
- DEC(v.n); INC(v.adr, v.size);
- IF v.n > 0 THEN
- w.String(", "); INC(col, 2)
- END
- END
- END
- END WriteVar;
- PROCEDURE CheckHeapAddress(address: ADDRESS): BOOLEAN;
- BEGIN
- RETURN Machine.ValidHeapAddress(address);
- END CheckHeapAddress;
- (* Get a compressed refblk number. *)
- PROCEDURE GetNum( refs: Modules.Bytes; VAR i, num: LONGINT );
- VAR
- n, s, x: LONGINT;
- BEGIN
- IF NewObjectFile(refs) THEN
- (* Copying byte by byte to avoid unaligned memory accesses on ARM *)
- SYSTEM.PUT8(ADDRESSOF(num), refs[i]);
- SYSTEM.PUT8(ADDRESSOF(num) + 1, refs[i + 1]);
- SYSTEM.PUT8(ADDRESSOF(num) + 2, refs[i + 2]);
- SYSTEM.PUT8(ADDRESSOF(num) + 3, refs[i + 3]);
- INC(i,4);
- ELSE
- s := 0; n := 0; x := ORD(refs[i]); INC( i );
- WHILE x >= 128 DO INC( n, ASH( x - 128, s ) ); INC( s, 7 ); x := ORD(refs[i]); INC( i ) END;
- num := n + ASH( x MOD 64 - x DIV 64 * 64, s )
- END;
- END GetNum;
- (** Step to the next variable in the refs block. The name parameter returns empty if no more variables are found. The attributes are returned in v. Parameter refpos is modified. *)
- PROCEDURE NextVar*(refs: Modules.Bytes; VAR refpos: LONGINT; base: ADDRESS; VAR name: ARRAY OF CHAR; VAR v: Variable);
- VAR x: Variable; j: LONGINT; ch, mode: CHAR;
- BEGIN
- name[0] := 0X; (* empty name signals end or error *)
- IF refpos < LEN(refs^)-1 THEN
- mode := refs[refpos]; INC(refpos);
- IF (mode >= 1X) & (mode <= 3X) THEN (* var *)
- x.type := ORD(refs[refpos]); INC(refpos);
- IF x.type > 80H THEN
- IF x.type = 83H THEN x.type := 15 ELSE DEC(x.type, 80H) END;
- GetNum(refs, refpos, x.n)
- ELSIF (x.type = 16H) OR (x.type = 1DH) THEN
- GetNum(refs, refpos, x.tdadr); x.n := 1
- ELSE
- IF x.type = 15 THEN x.n := MaxString (* best guess *) ELSE x.n := 1 END
- END;
- (* get address *)
- GetNum(refs, refpos, j);
- x.adr := base + j; (* convert to absolute address *)
- IF x.n = 0 THEN (* open array (only on stack, not global variable) *)
- SYSTEM.GET(x.adr+4, x.n) (* real LEN from stack *)
- END;
- IF mode # 1X THEN SYSTEM.GET(x.adr, x.adr) END; (* indirect *)
- (* get size *)
- CASE x.type OF
- 1..4,15: x.size := 1
- |5: x.size := 2
- |6..7,9,13,14,29: x.size := 4
- |8, 16: x.size := 8
- |22: x.size := 0; ASSERT(x.n <= 1)
- ELSE x.size := -1
- END;
- IF x.size >= 0 THEN (* ok, get name *)
- ch := refs[refpos]; INC(refpos); j := 0;
- WHILE ch # 0X DO
- IF j < LEN(name)-1 THEN name[j] := ch; INC(j) END; (* truncate long names *)
- ch := refs[refpos]; INC(refpos)
- END;
- name[j] := 0X; v := x (* non-empty name *)
- END
- END
- END
- END NextVar;
- (** Find the specified global variable and return its descriptor. Returns TRUE iff the variable is found. *)
- PROCEDURE FindVar*(mod: Modules.Module; CONST name: ARRAY OF CHAR; VAR v: Variable): BOOLEAN;
- VAR refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS; n: ARRAY 64 OF CHAR;
- BEGIN
- InitVar(mod, refs, refpos, base);
- IF refpos # -1 THEN
- LOOP
- NextVar(refs, refpos, base, n, v);
- IF n = "" THEN EXIT END;
- IF n = name THEN RETURN TRUE END
- END
- END;
- RETURN FALSE
- END FindVar;
- (** Find global variables of mod (which may be NIL) and return it in the refs, refpos and base parameters for use by NextVar. If not found, refpos returns -1. *)
- PROCEDURE InitVar*(mod: Modules.Module; VAR refs: Modules.Bytes; VAR refpos: LONGINT; VAR base: ADDRESS);
- VAR ch: CHAR; startpc,pc,end: ADDRESS;
- BEGIN
- refpos := -1;
- IF mod # NIL THEN
- refs := mod.refs; base := mod.sb;
- IF (refs # NIL) & (LEN(refs) # 0) THEN
- IF FindProcByName(mod,"$$",pc,end) THEN
- refpos := FindProc(refs, pc, startpc);
- END;
- IF refpos # -1 THEN
- ch := refs[refpos]; INC(refpos);
- WHILE ch # 0X DO ch := refs[refpos]; INC(refpos) END
- END
- END
- END
- END InitVar;
- PROCEDURE NewObjectFile(refs: Modules.Bytes): BOOLEAN;
- BEGIN
- RETURN (refs # NIL) & (LEN(refs) >0) & (refs[0]=0FFX);
- END NewObjectFile;
- (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
- PROCEDURE FindProc(refs: Modules.Bytes; modpc: ADDRESS; VAR startpc: ADDRESS): LONGINT;
- VAR pos, len, t, tstart, tend, proc: LONGINT; ch: CHAR; newObjectFile, found: BOOLEAN;
- BEGIN
- IF (refs=NIL) OR (LEN(refs) = 0) THEN RETURN -1 END;
- newObjectFile := NewObjectFile(refs);
- proc := -1; pos := 0; len := LEN(refs^);
- IF newObjectFile THEN INC(pos) END;
- ch := refs[pos]; INC(pos); tstart := 0;
- found := FALSE;
- WHILE ~found & (pos < len) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
- GetNum(refs, pos, tstart); (* procedure offset *)
- IF newObjectFile THEN
- GetNum(refs,pos,tend);
- found := (tstart <=modpc) & (tend > modpc)
- ELSE
- found := tstart > modpc
- END;
- IF ch = 0F9X THEN
- GetNum(refs, pos, t); (* nofPars *)
- INC(pos, 3) (* RetType, procLev, slFlag *);
- IF newObjectFile THEN INC(pos,6) END;
- END;
- IF ~found THEN (* not yet found -- remember startpc and position for next iteration *)
- startpc := tstart;
- proc := pos; (* remember this position, just before the name *)
- REPEAT ch := refs[pos]; INC(pos) UNTIL ch = 0X; (* pname *)
- IF pos < len THEN
- ch := refs[pos]; INC(pos); (* 1X | 3X | 0F8X | 0F9X *)
- WHILE (pos < len) & (ch >= 1X) & (ch <= 3X) DO (* var *)
- ch := refs[pos]; INC(pos); (* type *)
- IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
- GetNum(refs, pos, t) (* dim/tdadr *)
- END;
- GetNum(refs, pos, t); (* vofs *)
- REPEAT ch := refs[pos]; INC(pos) UNTIL ch = 0X; (* vname *)
- IF pos < len THEN ch := refs[pos]; INC(pos) END (* 1X | 3X | 0F8X | 0F9X *)
- END
- END
- END;
- END;
- IF newObjectFile THEN
- IF found THEN
- startpc := tstart; proc := pos;
- ELSE proc := -1
- END;
- END;
- RETURN proc
- END FindProc;
- (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
- PROCEDURE FindProcByName*(mod: Modules.Module; CONST name: ARRAY OF CHAR; VAR from, to: ADDRESS): BOOLEAN;
- VAR i, namePos, m, t, temp: LONGINT; ch: CHAR; newObjectFile: BOOLEAN;
- refs: Modules.Bytes; success: BOOLEAN;
- tstart, tend: ADDRESS;
- BEGIN
- IF mod = NIL THEN RETURN FALSE END;
- refs := mod.refs;
- IF (refs=NIL) OR (LEN(refs) = 0) THEN RETURN FALSE END;
- newObjectFile := NewObjectFile(refs);
- i := 0; m := LEN(refs^);
- IF newObjectFile THEN INC(i) END;
- ch := refs[i]; INC(i); tstart := 0;
- success := FALSE;
- WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) & ~success DO (* proc *)
- GetNum(refs, i, temp); (* pofs *)
- tstart := temp;
- IF newObjectFile THEN GetNum(refs,i,temp); tend := temp END;
- IF ch = 0F9X THEN
- GetNum(refs, i, t); (* nofPars *)
- INC(i, 3) (* RetType, procLev, slFlag *);
- IF newObjectFile THEN INC(i,6) END;
- END;
- namePos := 0; success := TRUE;
- REPEAT ch := refs[i]; INC(i); success := success & (ch = name[namePos]); INC(namePos); UNTIL ch = 0X; (* pname *)
- IF i < m THEN
- ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
- WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
- ch := refs[i]; INC(i); (* type *)
- IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
- GetNum(refs, i, t) (* dim/tdadr *)
- END;
- GetNum(refs, i, t); (* vofs *)
- REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
- IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
- END
- END;
- END;
- IF success & ~newObjectFile THEN
- IF (ch = 0F8X) OR (ch = 0F9X) THEN
- GetNum(refs, i, temp); tend := temp;
- ELSE
- tend :=LEN(mod.code);
- END;
- INC(tstart, ADDRESSOF(mod.code[0]));
- INC(tend, ADDRESSOF(mod.code[0]));
- END;
- from := tstart; to := tend;
- RETURN success
- END FindProcByName;
- PROCEDURE Wait(w: Streams.Writer);
- VAR i: LONGINT;
- BEGIN
- IF LineDelay > 0 THEN
- FOR i := 0 TO LineDelay DO END;
- w.Update
- END;
- END Wait;
- (* Display variables. *)
- PROCEDURE Variables(w: Streams.Writer; refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS);
- VAR v: Variable; j, col: LONGINT; name: ARRAY 64 OF CHAR; etc: BOOLEAN;
- CONST dense = FALSE;
- BEGIN
- LOOP
- NextVar(refs, refpos, base, name, v);
- IF name[0] = 0X THEN EXIT END;
- (* write name *)
- IF (col # 0 ) & (v.n > 1) & (v.type # 15) THEN (* Ln before array (except string) *)
- w.Ln; col := 0; Wait(w);
- END;
- w.String(Sep); w.String(name); w.Char("=");
- j := 0; WHILE name[j] # 0X DO INC(j) END;
- INC(col, SepLen+1+j);
- (* write variable *)
- IF (v.adr >= -4) & (v.adr < 4096) THEN (* must be NIL VAR parameter *)
- w.String("NIL ("); w.Hex(v.adr, -8);
- w.Char(")"); INC(col, 14)
- ELSE
- etc := FALSE;
- IF v.type = 15 THEN
- IF v.n > MaxString THEN etc := TRUE; v.n := MaxString END
- ELSE
- IF v.n > MaxArray THEN etc := TRUE; v.n := MaxArray END
- END;
- WriteVar(w, v, col); (* write value *)
- IF etc THEN w.String("..."); INC(col, 3) END;
- IF ~dense THEN
- w.Ln; col := 0; Wait(w);
- END;
- END;
- IF col > MaxCols THEN w.Ln; col := 0; Wait(w); END
- END;
- IF col # 0 THEN w.Ln; Wait(w) END
- END Variables;
- (** Write the state of the specified module. *)
- PROCEDURE ModuleState*(w: Streams.Writer; mod: Modules.Module);
- VAR refpos: LONGINT; base: ADDRESS; refs: Modules.Bytes;
- BEGIN
- InitVar(mod, refs, refpos, base);
- IF refpos # -1 THEN
- w.String("State "); w.String(mod.name); w.Char(":"); w.Ln; Wait(w);
- Variables(w, refs, refpos, base)
- END
- END ModuleState;
- (* Write the specified procedure name and returns parameters for use with NextVar and Variables. *)
- PROCEDURE WriteProc0(w: Streams.Writer; mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Modules.Bytes;
- VAR refpos: LONGINT; VAR base: ADDRESS);
- VAR ch: CHAR; startpc: ADDRESS;
- BEGIN
- refpos := -1;
- IF mod = NIL THEN
- IF pc = 0 THEN w.String("NIL")
- ELSE
- w.String("Unknown PC="); w.Address(pc); w.Char("H")
- END;
- IF fp # -1 THEN
- w.String(" FP="); w.Address(fp); w.Char("H")
- END
- ELSE
- w.String(mod.name);
- IF ~NewObjectFile(mod.refs) THEN
- DEC(pc, ADDRESSOF(mod.code[0]));
- END;
- refs := mod.refs;
- IF (refs # NIL) & (LEN(refs) # 0) THEN
- refpos := FindProc(refs, pc, startpc);
- IF refpos # -1 THEN
- w.Char(".");
- ch := refs[refpos]; INC(refpos);
- IF ch = "$" THEN base := mod.sb ELSE base := fp END; (* for variables *)
- WHILE ch # 0X DO w.Char(ch); ch := refs[refpos]; INC(refpos) END;
- w.Char(":"); w.Int(LONGINT(pc-startpc),1);
- END
- END;
- w.String(" pc="); w.Int(LONGINT(pc),1); w.String(" ["); w.Address (pc); w.String("H]");
- w.String(" = "); w.Int(LONGINT(startpc),1); w.String(" + "); w.Int(LONGINT(pc-startpc),1);
- w.String(" crc="); w.Hex(mod.crc,-8);
- Wait(w);
- END
- END WriteProc0;
- (** Find procedure name and write it. *)
- PROCEDURE WriteProc*(w: Streams.Writer; pc: ADDRESS);
- VAR refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS;
- BEGIN
- WriteProc0(w, Modules.ThisModuleByAdr0(pc), pc, -1, refs, refpos, base)
- END WriteProc;
- (* Returns the name of the procedure the pc is in. Searchs in m.refs *)
- PROCEDURE GetProcedureName*(pc: ADDRESS; VAR name: ARRAY OF CHAR; VAR startpc: ADDRESS);
- VAR
- methadr, i: LONGINT;
- ch: CHAR;
- m: Modules.Module;
- BEGIN
- m := Modules.ThisModuleByAdr0(pc);
- IF m # NIL THEN
- IF ~NewObjectFile(m.refs) THEN
- DEC(pc, ADDRESSOF(m.code[0]));
- END;
- methadr := FindProc(m.refs, pc, startpc);
- IF methadr # -1 THEN
- i := 0;
- ch := m.refs[methadr]; INC(methadr);
- WHILE ch # 0X DO
- name[i] := ch;
- ch := m.refs[methadr];
- INC(methadr);
- INC(i);
- END;
- IF ~NewObjectFile(m.refs) THEN
- INC(startpc, ADDRESSOF(m.code[0]));
- END;
- END;
- name[i] := 0X;
- ELSE
- name := "Unkown"; (* Better: name := "" *)
- END;
- END GetProcedureName;
- (* A simple introspection method, must be adapted if there are any changes to the
- refs section in a module. *)
- PROCEDURE GetVariableAdr*(pc, fp: ADDRESS; CONST varname: ARRAY OF CHAR): ADDRESS;
- VAR
- m: Modules.Module;
- v: Variable;
- pos: LONGINT;
- base: ADDRESS;
- name: ARRAY 256 OF CHAR;
- ch: CHAR;
- startpc: ADDRESS;
- BEGIN
- pos := -1;
- m := Modules.ThisModuleByAdr0(pc);
- IF m # NIL THEN
- IF ~NewObjectFile(m.refs) THEN
- DEC(pc, ADDRESSOF(m.code[0]));
- END;
- pos := FindProc(m.refs, pc, startpc);
- IF pos # -1 THEN
- ch := m.refs[pos]; INC(pos);
- (* for variables *)
- IF ch = "$" THEN
- base := m.sb;
- ELSE
- base := fp;
- END;
- (* Read the name *)
- WHILE ch # 0X DO ch := m.refs[pos]; INC(pos) END;
- NextVar(m.refs, pos, base, name, v);
- WHILE name[0] # 0X DO
- IF name = varname THEN
- RETURN v.adr;
- ELSE
- NextVar(m.refs, pos, base, name, v);
- END
- END
- END
- END;
- RETURN -1;
- END GetVariableAdr;
- (* "lock free" version of Modules.ThisTypeByAdr *)
- PROCEDURE ThisTypeByAdr(adr: ADDRESS; VAR m: Modules.Module; VAR t: Modules.TypeDesc);
- BEGIN
- IF adr # 0 THEN
- SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
- IF CheckHeapAddress(adr) THEN
- t := SYSTEM.VAL(Modules.TypeDesc, adr);
- m := t.mod;
- ELSE
- m := NIL; t := NIL
- END
- ELSE
- m := NIL; t := NIL
- END
- END ThisTypeByAdr;
- PROCEDURE WriteType*(w: Streams.Writer; adr: ADDRESS);
- VAR module: Modules.Module; typeDesc: Modules.TypeDesc;
- BEGIN
- IF CheckHeapAddress(adr) THEN
- ThisTypeByAdr(adr, module, typeDesc);
- IF module # NIL THEN
- w.String(module.name);
- ELSE
- w.String("NIL"); RETURN
- END;
- w.String(".");
- IF typeDesc # NIL THEN
- IF typeDesc.name = "" THEN
- w.String("ANONYMOUS")
- ELSE
- w.String(typeDesc.name);
- END;
- ELSE
- w.String("NIL");
- END;
- ELSE
- w.String("UNKNOWN");
- END;
- END WriteType;
- PROCEDURE WriteSimpleVar( w: Streams.Writer; adr, type, tdadr: ADDRESS; VAR col: LONGINT );
- VAR ch: CHAR; sval: SHORTINT; ival: INTEGER; lval: LONGINT; rval: REAL; xval: LONGREAL; hval : HUGEINT;
- address: ADDRESS; pos0: LONGINT; setval: SET;
- BEGIN
- pos0 := w.Pos();
- IF (adr # 0) OR (type = 22) THEN
- CASE type OF
- 1, 3: (* BYTE, CHAR *)
- SYSTEM.GET( adr, ch );
- IF (ch > " ") & (ch <= "~") THEN w.Char( ch ); ELSE w.Hex( ORD( ch ), -2 ); w.Char( "X" ) END;
- | 2: (* BOOLEAN *)
- SYSTEM.GET( adr, ch );
- IF ch = 0X THEN w.String( "FALSE" )
- ELSIF ch = 1X THEN w.String( "TRUE" )
- ELSE w.Int( ORD( ch ), 1 );
- END;
- | 4: (* SHORTINT *)
- SYSTEM.GET( adr, sval );
- w.Int( sval, 1 );
- IF sval > 0H THEN w.String(" ("); w.Hex(sval, -2); w.String("H)") END;
- | 5: (* INTEGER *)
- SYSTEM.GET( adr, ival );
- w.Int( ival, 1 );
- IF ival > 0H THEN w.String(" (");w.Hex(ival,-4);w.Char("H");w.String(")"); END;
- | 6: (* LONGINT *)
- SYSTEM.GET( adr, lval );
- w.Int( lval, 1 );
- IF lval > 0H THEN w.String( " (" ); w.Hex( lval,-8 ); w.String( "H)" ); END;
- | 7: (* REAL *)
- SYSTEM.GET(adr,rval); SYSTEM.GET(adr,lval);
- w.Float(rval,15);
- IF lval > 0H THEN w.String(" ("); w.Hex(lval,-8);w.Char( "H" ); w.String(")"); END;
- | 8: (* LONGREAL *)
- SYSTEM.GET(adr,xval);SYSTEM.GET(adr,hval);
- w.Float(xval,15);
- IF hval > 0H THEN w.String( " (" ); w.Hex(hval,-16); w.String( "H)" ); END;
- | 13,29: (* POINTER *)
- SYSTEM.GET( adr, address ); w.Address( address ); w.String( "H" );
- (* output type information, if available: *)
- w.String(" (");
- (* do a check if the address is in the heap range *)
- IF CheckHeapAddress(address) THEN
- SYSTEM.GET(address + Heaps.TypeDescOffset, address);
- WriteType(w,address);
- ELSE w.String("NIL");
- END;
- w.String(")");
- | 16: (* HUGEINT *)
- SYSTEM.GET( adr , hval );
- IF hval = 0 THEN w.Char( '0' );
- ELSIF hval > 0 THEN w.Hex( hval, 1 ); w.Char( 'H' )
- ELSE w.Hex( hval, -16 );
- END;
- | 9: (* SET *)
- SYSTEM.GET( adr, setval );
- w.Set( setval );
- | 22: (* RECORD *)
- w.String( "Rec@" ); w.Hex( tdadr, -8 ); w.Char( "H" );
- | 14: (* PROC *)
- SYSTEM.GET( adr, lval ); WriteProc( w, lval );
- END;
- END;
- INC(col,w.Pos()-pos0);
- END WriteSimpleVar;
- (* Display call trackback. *)
- PROCEDURE StackTraceBack*(w: Streams.Writer; pc, bp: ADDRESS; stackhigh: ADDRESS; long, overflow: BOOLEAN);
- VAR count,refpos: LONGINT; stacklow: ADDRESS; base: ADDRESS; m: Modules.Module; refs: Modules.Bytes;
- BEGIN
- count := 0; (* frame count *)
- stacklow := bp;
- REPEAT
- m := Modules.ThisModuleByAdr0(pc);
- IF (ShowAllProcs OR (m # NIL) OR (count = 0)) & (bp # 0) & (bp >= stacklow) & (bp <= stackhigh) THEN
- IF CheckHeapAddress( pc ) THEN
- WriteProc0(w, m, pc, bp, refs, refpos, base); w.Ln;Wait(w); w.Update;
- IF long & (~overflow OR (count > 0)) THEN (* show variables *)
- IF refpos # -1 THEN Variables(w, refs, refpos, base) END;
- IF (m # NIL) & (base # m.sb) & (count = 0) THEN ModuleState(w, m) END
- END;
- ELSE
- w.String( "Unknown external procedure, pc = " ); w.Address( pc ); w.Ln; Wait(w);
- END;
- SYSTEM.GET(bp + SIZEOF(ADDRESS), pc); (* return addr from stack *)
- SYSTEM.GET(bp, bp); (* follow dynamic link *)
- INC(count)
- ELSE
- bp := 0
- END;
- UNTIL (bp = 0) OR (count = MaxFrames);
- IF bp # 0 THEN w.String("...") END
- END StackTraceBack;
- (** Write a process's state in one line. *)
- PROCEDURE WriteProcess*(w: Streams.Writer; p: Objects.Process);
- VAR adr: ADDRESS; mode: LONGINT; m: Modules.Module;
- BEGIN
- IF p # NIL THEN
- w.Int(p.id, 5);
- mode := p.mode;
- IF (mode >= Objects.Ready) & (mode <= Objects.Terminated) THEN
- adr := (mode-Objects.Ready)*4;
- FOR adr := adr TO adr+3 DO w.Char(modes[adr]) END
- ELSE
- w.Char(" "); w.Int(mode, 1)
- END;
- w.Int(p.procID, 2);
- w.Int(p.priority, 2);
- w.Update;
- w.Address (SYSTEM.VAL(ADDRESS, p.obj));
- IF p.obj # NIL THEN
- SYSTEM.GET(SYSTEM.VAL(ADDRESS, p.obj) - SIZEOF(ADDRESS), adr);
- w.Char(":"); WriteType(w, adr)
- END;
- w.Update;
- w.Char(" "); WriteProc(w, p.state.PC);
- IF p.mode = Objects.AwaitingLock THEN
- adr := SYSTEM.VAL(ADDRESS, p.waitingOn);
- w.Address (adr);
- w.Update;
- IF adr # 0 THEN (* can be 0 when snapshot is taken *)
- SYSTEM.GET(adr - SIZEOF(ADDRESS), adr);
- IF adr = SYSTEM.TYPECODE(Modules.Module) THEN
- w.Char("-");
- m := SYSTEM.VAL(Modules.Module, adr);
- w.String(m.name)
- ELSE
- w.Char(":"); WriteType(w, adr)
- END;
- w.Update;
- END
- ELSIF p.mode = Objects.AwaitingCond THEN
- w.Char(" "); WriteProc(w, SYSTEM.VAL(ADDRESS, p.condition));
- w.Address (p.condFP)
- END;
- w.Char(" "); w.Set(p.flags)
- END
- END WriteProcess;
- BEGIN
- modes := " rdy run awl awc awe rip"; (* 4 characters per mode from Objects.Ready to Objects.Terminated *)
- END Reflection.
|