Reflection.Mod 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. MODULE Reflection; (** AUTHOR "fof"; PURPOSE "tools for module, stack and process reflection"; *)
  2. IMPORT Modules,Streams,Machine,Heaps,Objects,SYSTEM;
  3. CONST
  4. ShowAllProcs = TRUE;
  5. MaxFrames = 128;
  6. MaxString = 64;
  7. MaxArray = 8;
  8. MaxCols = 70;
  9. Sep = " ";
  10. SepLen = 2;
  11. LineDelay = 0; (* set this value to the number of cycles of an empty for loop that the reflection should wait after a new line
  12. * useful for screen racing when no persistent trace medium is available
  13. * no timer mechanism used because at low level tracing this may exactly not be available because IRQs do not work any more or so.
  14. *)
  15. TYPE
  16. Variable* = RECORD
  17. adr-: ADDRESS;
  18. type-, size-, n-, tdadr-: LONGINT
  19. END;
  20. VAR
  21. modes: ARRAY 25 OF CHAR;
  22. (*
  23. Reference = {OldRef | ProcRef} .
  24. OldRef = 0F8X offset/n name/s {Variable} .
  25. ProcRef = 0F9X offset/n nofPars/n RetType procLev/1 slFlag/1 name/s {Variable} .
  26. RetType = 0X | Var | ArrayType | Record .
  27. ArrayType = 12X | 14X | 15X . (* static array, dynamic array, open array *)
  28. Record = 16X .
  29. Variable = VarMode (Var | ArrayVar | RecordVar ) offset/n name/s .
  30. VarMode = 1X | 3X . (* direct, indirect *)
  31. Var = 1X .. 0FX . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc, string *)
  32. ArrayVar = (81X .. 8EX) dim/n . (* byte, boolean, char, shortint, integer, longint, real, longreal, set, ptr, proc *)
  33. RecordVar = (16X | 1DX) tdadr/n . (* record, recordpointer *)
  34. *)
  35. (** 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. *)
  36. PROCEDURE WriteVar*(w: Streams.Writer; v: Variable; VAR col: LONGINT);
  37. VAR ch: CHAR;
  38. BEGIN
  39. IF v.type = 15 THEN
  40. w.Char(22X);
  41. LOOP
  42. IF (v.n = 0) OR (~CheckHeapAddress(v.adr)) THEN EXIT END;
  43. SYSTEM.GET(v.adr, ch);
  44. INC(v.adr);
  45. IF (ch < " ") OR (ch > "~") THEN EXIT END;
  46. w.Char(ch); INC(col); DEC(v.n)
  47. END;
  48. w.Char(22X); INC(col, 2);
  49. IF ch # 0X THEN w.Char("!") END
  50. ELSE
  51. WHILE v.n > 0 DO
  52. WriteSimpleVar(w, v.adr, v.type, v.tdadr, col);
  53. DEC(v.n); INC(v.adr, v.size);
  54. IF v.n > 0 THEN
  55. w.String(", "); INC(col, 2)
  56. END
  57. END
  58. END
  59. END WriteVar;
  60. PROCEDURE CheckHeapAddress(address: ADDRESS): BOOLEAN;
  61. BEGIN
  62. RETURN Machine.ValidHeapAddress(address);
  63. END CheckHeapAddress;
  64. (* Get a compressed refblk number. *)
  65. PROCEDURE GetNum( refs: Modules.Bytes; VAR i, num: LONGINT );
  66. VAR
  67. n, s: LONGINT; x: CHAR;
  68. BEGIN
  69. IF NewObjectFile(refs) THEN
  70. (* Copying byte by byte to avoid unaligned memory accesses on ARM *)
  71. SYSTEM.PUT8(ADDRESSOF(num), refs[i]);
  72. SYSTEM.PUT8(ADDRESSOF(num) + 1, refs[i + 1]);
  73. SYSTEM.PUT8(ADDRESSOF(num) + 2, refs[i + 2]);
  74. SYSTEM.PUT8(ADDRESSOF(num) + 3, refs[i + 3]);
  75. INC(i,4);
  76. ELSE
  77. s := 0; n := 0; x := refs[i]; INC( i );
  78. WHILE ORD( x ) >= 128 DO INC( n, ASH( ORD( x ) - 128, s ) ); INC( s, 7 ); x := refs[i]; INC( i ) END;
  79. num := n + ASH( ORD( x ) MOD 64 - ORD( x ) DIV 64 * 64, s )
  80. END;
  81. END GetNum;
  82. (** 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. *)
  83. PROCEDURE NextVar*(refs: Modules.Bytes; VAR refpos: LONGINT; base: ADDRESS; VAR name: ARRAY OF CHAR; VAR v: Variable);
  84. VAR x: Variable; j: LONGINT; ch, mode: CHAR;
  85. BEGIN
  86. name[0] := 0X; (* empty name signals end or error *)
  87. IF refpos < LEN(refs^)-1 THEN
  88. mode := refs[refpos]; INC(refpos);
  89. IF (mode >= 1X) & (mode <= 3X) THEN (* var *)
  90. x.type := ORD(refs[refpos]); INC(refpos);
  91. IF x.type > 80H THEN
  92. IF x.type = 83H THEN x.type := 15 ELSE DEC(x.type, 80H) END;
  93. GetNum(refs, refpos, x.n)
  94. ELSIF (x.type = 16H) OR (x.type = 1DH) THEN
  95. GetNum(refs, refpos, x.tdadr); x.n := 1
  96. ELSE
  97. IF x.type = 15 THEN x.n := MaxString (* best guess *) ELSE x.n := 1 END
  98. END;
  99. (* get address *)
  100. GetNum(refs, refpos, j);
  101. x.adr := base + j; (* convert to absolute address *)
  102. IF x.n = 0 THEN (* open array (only on stack, not global variable) *)
  103. SYSTEM.GET(x.adr+4, x.n) (* real LEN from stack *)
  104. END;
  105. IF mode # 1X THEN SYSTEM.GET(x.adr, x.adr) END; (* indirect *)
  106. (* get size *)
  107. CASE x.type OF
  108. 1..4,15: x.size := 1
  109. |5: x.size := 2
  110. |6..7,9,13,14,29: x.size := 4
  111. |8, 16: x.size := 8
  112. |22: x.size := 0; ASSERT(x.n <= 1)
  113. ELSE x.size := -1
  114. END;
  115. IF x.size >= 0 THEN (* ok, get name *)
  116. ch := refs[refpos]; INC(refpos); j := 0;
  117. WHILE ch # 0X DO
  118. IF j < LEN(name)-1 THEN name[j] := ch; INC(j) END; (* truncate long names *)
  119. ch := refs[refpos]; INC(refpos)
  120. END;
  121. name[j] := 0X; v := x (* non-empty name *)
  122. END
  123. END
  124. END
  125. END NextVar;
  126. (** Find the specified global variable and return its descriptor. Returns TRUE iff the variable is found. *)
  127. PROCEDURE FindVar*(mod: Modules.Module; CONST name: ARRAY OF CHAR; VAR v: Variable): BOOLEAN;
  128. VAR refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS; n: ARRAY 64 OF CHAR;
  129. BEGIN
  130. InitVar(mod, refs, refpos, base);
  131. IF refpos # -1 THEN
  132. LOOP
  133. NextVar(refs, refpos, base, n, v);
  134. IF n = "" THEN EXIT END;
  135. IF n = name THEN RETURN TRUE END
  136. END
  137. END;
  138. RETURN FALSE
  139. END FindVar;
  140. (** 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. *)
  141. PROCEDURE InitVar*(mod: Modules.Module; VAR refs: Modules.Bytes; VAR refpos: LONGINT; VAR base: ADDRESS);
  142. VAR ch: CHAR; startpc: ADDRESS;
  143. BEGIN
  144. refpos := -1;
  145. IF mod # NIL THEN
  146. refs := mod.refs; base := mod.sb;
  147. IF (refs # NIL) & (LEN(refs) # 0) THEN
  148. refpos := FindProc(refs, 0, startpc);
  149. IF refpos # -1 THEN
  150. ch := refs[refpos]; INC(refpos);
  151. WHILE ch # 0X DO ch := refs[refpos]; INC(refpos) END
  152. END
  153. END
  154. END
  155. END InitVar;
  156. PROCEDURE NewObjectFile(refs: Modules.Bytes): BOOLEAN;
  157. BEGIN
  158. RETURN (refs # NIL) & (LEN(refs) >0) & (refs[0]=0FFX);
  159. END NewObjectFile;
  160. (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  161. PROCEDURE FindProc(refs: Modules.Bytes; modpc: ADDRESS; VAR startpc: ADDRESS): LONGINT;
  162. VAR pos, len, t, tstart, tend, proc: LONGINT; ch: CHAR; newObjectFile, found: BOOLEAN;
  163. BEGIN
  164. IF (refs=NIL) OR (LEN(refs) = 0) THEN RETURN -1 END;
  165. newObjectFile := NewObjectFile(refs);
  166. proc := -1; pos := 0; len := LEN(refs^);
  167. IF newObjectFile THEN INC(pos) END;
  168. ch := refs[pos]; INC(pos); tstart := 0;
  169. found := FALSE;
  170. WHILE ~found & (pos < len) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
  171. GetNum(refs, pos, tstart); (* procedure offset *)
  172. IF newObjectFile THEN
  173. GetNum(refs,pos,tend);
  174. found := (tstart <=modpc) & (tend > modpc)
  175. ELSE
  176. found := tstart > modpc
  177. END;
  178. IF ch = 0F9X THEN
  179. GetNum(refs, pos, t); (* nofPars *)
  180. INC(pos, 3) (* RetType, procLev, slFlag *);
  181. IF newObjectFile THEN INC(pos,6) END;
  182. END;
  183. IF ~found THEN (* not yet found -- remember startpc and position for next iteration *)
  184. startpc := tstart;
  185. proc := pos; (* remember this position, just before the name *)
  186. REPEAT ch := refs[pos]; INC(pos) UNTIL ch = 0X; (* pname *)
  187. IF pos < len THEN
  188. ch := refs[pos]; INC(pos); (* 1X | 3X | 0F8X | 0F9X *)
  189. WHILE (pos < len) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  190. ch := refs[pos]; INC(pos); (* type *)
  191. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  192. GetNum(refs, pos, t) (* dim/tdadr *)
  193. END;
  194. GetNum(refs, pos, t); (* vofs *)
  195. REPEAT ch := refs[pos]; INC(pos) UNTIL ch = 0X; (* vname *)
  196. IF pos < len THEN ch := refs[pos]; INC(pos) END (* 1X | 3X | 0F8X | 0F9X *)
  197. END
  198. END
  199. END;
  200. END;
  201. IF newObjectFile THEN
  202. IF found THEN
  203. startpc := tstart; proc := pos;
  204. ELSE proc := -1
  205. END;
  206. END;
  207. RETURN proc
  208. END FindProc;
  209. (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  210. PROCEDURE FindProcByName*(mod: Modules.Module; CONST name: ARRAY OF CHAR; VAR from, to: ADDRESS): BOOLEAN;
  211. VAR i, namePos, m, t, temp: LONGINT; ch: CHAR; newObjectFile: BOOLEAN;
  212. refs: Modules.Bytes; success: BOOLEAN;
  213. tstart, tend: ADDRESS;
  214. BEGIN
  215. IF mod = NIL THEN RETURN FALSE END;
  216. refs := mod.refs;
  217. IF (refs=NIL) OR (LEN(refs) = 0) THEN RETURN FALSE END;
  218. newObjectFile := NewObjectFile(refs);
  219. i := 0; m := LEN(refs^);
  220. IF newObjectFile THEN INC(i) END;
  221. ch := refs[i]; INC(i); tstart := 0;
  222. success := FALSE;
  223. WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) & ~success DO (* proc *)
  224. GetNum(refs, i, temp); (* pofs *)
  225. tstart := temp;
  226. IF newObjectFile THEN GetNum(refs,i,temp); tend := temp END;
  227. IF ch = 0F9X THEN
  228. GetNum(refs, i, t); (* nofPars *)
  229. INC(i, 3) (* RetType, procLev, slFlag *);
  230. IF newObjectFile THEN INC(i,6) END;
  231. END;
  232. namePos := 0; success := TRUE;
  233. REPEAT ch := refs[i]; INC(i); success := success & (ch = name[namePos]); INC(namePos); UNTIL ch = 0X; (* pname *)
  234. IF i < m THEN
  235. ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
  236. WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  237. ch := refs[i]; INC(i); (* type *)
  238. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  239. GetNum(refs, i, t) (* dim/tdadr *)
  240. END;
  241. GetNum(refs, i, t); (* vofs *)
  242. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
  243. IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
  244. END
  245. END;
  246. END;
  247. IF success & ~newObjectFile THEN
  248. IF (ch = 0F8X) OR (ch = 0F9X) THEN
  249. GetNum(refs, i, temp); tend := temp;
  250. ELSE
  251. tend :=LEN(mod.code);
  252. END;
  253. INC(tstart, ADDRESSOF(mod.code[0]));
  254. INC(tend, ADDRESSOF(mod.code[0]));
  255. END;
  256. from := tstart; to := tend;
  257. RETURN success
  258. END FindProcByName;
  259. PROCEDURE Wait(w: Streams.Writer);
  260. VAR i: LONGINT;
  261. BEGIN
  262. IF LineDelay > 0 THEN
  263. FOR i := 0 TO LineDelay DO END;
  264. w.Update
  265. END;
  266. END Wait;
  267. (* Display variables. *)
  268. PROCEDURE Variables(w: Streams.Writer; refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS);
  269. VAR v: Variable; j, col: LONGINT; name: ARRAY 64 OF CHAR; etc: BOOLEAN;
  270. CONST dense = FALSE;
  271. BEGIN
  272. LOOP
  273. NextVar(refs, refpos, base, name, v);
  274. IF name[0] = 0X THEN EXIT END;
  275. (* write name *)
  276. IF (col # 0 ) & (v.n > 1) & (v.type # 15) THEN (* Ln before array (except string) *)
  277. w.Ln; col := 0; Wait(w);
  278. END;
  279. w.String(Sep); w.String(name); w.Char("=");
  280. j := 0; WHILE name[j] # 0X DO INC(j) END;
  281. INC(col, SepLen+1+j);
  282. (* write variable *)
  283. IF (v.adr >= -4) & (v.adr < 4096) THEN (* must be NIL VAR parameter *)
  284. w.String("NIL ("); w.Hex(v.adr, -8);
  285. w.Char(")"); INC(col, 14)
  286. ELSE
  287. etc := FALSE;
  288. IF v.type = 15 THEN
  289. IF v.n > MaxString THEN etc := TRUE; v.n := MaxString END
  290. ELSE
  291. IF v.n > MaxArray THEN etc := TRUE; v.n := MaxArray END
  292. END;
  293. WriteVar(w, v, col); (* write value *)
  294. IF etc THEN w.String("..."); INC(col, 3) END;
  295. IF ~dense THEN
  296. w.Ln; col := 0; Wait(w);
  297. END;
  298. END;
  299. IF col > MaxCols THEN w.Ln; col := 0; Wait(w); END
  300. END;
  301. IF col # 0 THEN w.Ln; Wait(w) END
  302. END Variables;
  303. (** Write the state of the specified module. *)
  304. PROCEDURE ModuleState*(w: Streams.Writer; mod: Modules.Module);
  305. VAR refpos: LONGINT; base: ADDRESS; refs: Modules.Bytes;
  306. BEGIN
  307. InitVar(mod, refs, refpos, base);
  308. IF refpos # -1 THEN
  309. w.String("State "); w.String(mod.name); w.Char(":"); w.Ln; Wait(w);
  310. Variables(w, refs, refpos, base)
  311. END
  312. END ModuleState;
  313. (* Write the specified procedure name and returns parameters for use with NextVar and Variables. *)
  314. PROCEDURE WriteProc0(w: Streams.Writer; mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Modules.Bytes;
  315. VAR refpos: LONGINT; VAR base: ADDRESS);
  316. VAR ch: CHAR; startpc: ADDRESS;
  317. BEGIN
  318. refpos := -1;
  319. IF mod = NIL THEN
  320. IF pc = 0 THEN w.String("NIL")
  321. ELSE
  322. w.String("Unknown PC="); w.Address(pc); w.Char("H")
  323. END;
  324. IF fp # -1 THEN
  325. w.String(" FP="); w.Address(fp); w.Char("H")
  326. END
  327. ELSE
  328. w.String(mod.name);
  329. IF ~NewObjectFile(mod.refs) THEN
  330. DEC(pc, ADDRESSOF(mod.code[0]));
  331. END;
  332. refs := mod.refs;
  333. IF (refs # NIL) & (LEN(refs) # 0) THEN
  334. refpos := FindProc(refs, pc, startpc);
  335. IF refpos # -1 THEN
  336. w.Char(".");
  337. ch := refs[refpos]; INC(refpos);
  338. IF ch = "$" THEN base := mod.sb ELSE base := fp END; (* for variables *)
  339. WHILE ch # 0X DO w.Char(ch); ch := refs[refpos]; INC(refpos) END;
  340. w.Char(":"); w.Int(LONGINT(pc-startpc),1);
  341. END
  342. END;
  343. w.String(" pc="); w.Int(LONGINT(pc),1); w.String(" ["); w.Address (pc); w.String("H]");
  344. w.String(" = "); w.Int(LONGINT(startpc),1); w.String(" + "); w.Int(LONGINT(pc-startpc),1);
  345. w.String(" crc="); w.Hex(mod.crc,-8);
  346. Wait(w);
  347. END
  348. END WriteProc0;
  349. (** Find procedure name and write it. *)
  350. PROCEDURE WriteProc*(w: Streams.Writer; pc: ADDRESS);
  351. VAR refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS;
  352. BEGIN
  353. WriteProc0(w, Modules.ThisModuleByAdr0(pc), pc, -1, refs, refpos, base)
  354. END WriteProc;
  355. (* Returns the name of the procedure the pc is in. Searchs in m.refs *)
  356. PROCEDURE GetProcedureName*(pc: ADDRESS; VAR name: ARRAY OF CHAR; VAR startpc: ADDRESS);
  357. VAR
  358. methadr, i: LONGINT;
  359. ch: CHAR;
  360. m: Modules.Module;
  361. BEGIN
  362. m := Modules.ThisModuleByAdr0(pc);
  363. IF m # NIL THEN
  364. IF ~NewObjectFile(m.refs) THEN
  365. DEC(pc, ADDRESSOF(m.code[0]));
  366. END;
  367. methadr := FindProc(m.refs, pc, startpc);
  368. IF methadr # -1 THEN
  369. i := 0;
  370. ch := m.refs[methadr]; INC(methadr);
  371. WHILE ch # 0X DO
  372. name[i] := ch;
  373. ch := m.refs[methadr];
  374. INC(methadr);
  375. INC(i);
  376. END;
  377. IF ~NewObjectFile(m.refs) THEN
  378. INC(startpc, ADDRESSOF(m.code[0]));
  379. END;
  380. END;
  381. name[i] := 0X;
  382. ELSE
  383. name := "Unkown"; (* Better: name := "" *)
  384. END;
  385. END GetProcedureName;
  386. (* A simple introspection method, must be adapted if there are any changes to the
  387. refs section in a module. *)
  388. PROCEDURE GetVariableAdr*(pc, fp: ADDRESS; CONST varname: ARRAY OF CHAR): ADDRESS;
  389. VAR
  390. m: Modules.Module;
  391. v: Variable;
  392. pos: LONGINT;
  393. base: ADDRESS;
  394. name: ARRAY 256 OF CHAR;
  395. ch: CHAR;
  396. startpc: ADDRESS;
  397. BEGIN
  398. pos := -1;
  399. m := Modules.ThisModuleByAdr0(pc);
  400. IF m # NIL THEN
  401. IF ~NewObjectFile(m.refs) THEN
  402. DEC(pc, ADDRESSOF(m.code[0]));
  403. END;
  404. pos := FindProc(m.refs, pc, startpc);
  405. IF pos # -1 THEN
  406. ch := m.refs[pos]; INC(pos);
  407. (* for variables *)
  408. IF ch = "$" THEN
  409. base := m.sb;
  410. ELSE
  411. base := fp;
  412. END;
  413. (* Read the name *)
  414. WHILE ch # 0X DO ch := m.refs[pos]; INC(pos) END;
  415. NextVar(m.refs, pos, base, name, v);
  416. WHILE name[0] # 0X DO
  417. IF name = varname THEN
  418. RETURN v.adr;
  419. ELSE
  420. NextVar(m.refs, pos, base, name, v);
  421. END
  422. END
  423. END
  424. END;
  425. RETURN -1;
  426. END GetVariableAdr;
  427. (* "lock free" version of Modules.ThisTypeByAdr *)
  428. PROCEDURE ThisTypeByAdr(adr: ADDRESS; VAR m: Modules.Module; VAR t: Modules.TypeDesc);
  429. BEGIN
  430. IF adr # 0 THEN
  431. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  432. IF CheckHeapAddress(adr) THEN
  433. t := SYSTEM.VAL(Modules.TypeDesc, adr);
  434. m := t.mod;
  435. ELSE
  436. m := NIL; t := NIL
  437. END
  438. ELSE
  439. m := NIL; t := NIL
  440. END
  441. END ThisTypeByAdr;
  442. PROCEDURE WriteType*(w: Streams.Writer; adr: ADDRESS);
  443. VAR module: Modules.Module; typeDesc: Modules.TypeDesc;
  444. BEGIN
  445. IF CheckHeapAddress(adr) THEN
  446. ThisTypeByAdr(adr, module, typeDesc);
  447. IF module # NIL THEN
  448. w.String(module.name);
  449. ELSE
  450. w.String("NIL"); RETURN
  451. END;
  452. w.String(".");
  453. IF typeDesc # NIL THEN
  454. IF typeDesc.name = "" THEN
  455. w.String("ANONYMOUS")
  456. ELSE
  457. w.String(typeDesc.name);
  458. END;
  459. ELSE
  460. w.String("NIL");
  461. END;
  462. ELSE
  463. w.String("UNKNOWN");
  464. END;
  465. END WriteType;
  466. PROCEDURE WriteSimpleVar( w: Streams.Writer; adr, type, tdadr: ADDRESS; VAR col: LONGINT );
  467. VAR ch: CHAR; sval: SHORTINT; ival: INTEGER; lval: LONGINT; rval: REAL; xval: LONGREAL; hval : HUGEINT;
  468. address: ADDRESS; pos0: LONGINT;
  469. BEGIN
  470. pos0 := w.Pos();
  471. IF (adr # 0) OR (type = 22) THEN
  472. CASE type OF
  473. 1, 3: (* BYTE, CHAR *)
  474. SYSTEM.GET( adr, ch );
  475. IF (ch > " ") & (ch <= "~") THEN w.Char( ch ); ELSE w.Hex( ORD( ch ), -2 ); w.Char( "X" ) END;
  476. | 2: (* BOOLEAN *)
  477. SYSTEM.GET( adr, ch );
  478. IF ch = 0X THEN w.String( "FALSE" )
  479. ELSIF ch = 1X THEN w.String( "TRUE" )
  480. ELSE w.Int( ORD( ch ), 1 );
  481. END;
  482. | 4: (* SHORTINT *)
  483. SYSTEM.GET( adr, sval );
  484. w.Int( sval, 1 );
  485. IF sval > 0H THEN w.String(" ("); w.Hex(sval, -2); w.String("H)") END;
  486. | 5: (* INTEGER *)
  487. SYSTEM.GET( adr, ival );
  488. w.Int( ival, 1 );
  489. IF ival > 0H THEN w.String(" (");w.Hex(ival,-4);w.Char("H");w.String(")"); END;
  490. | 6: (* LONGINT *)
  491. SYSTEM.GET( adr, lval );
  492. w.Int( lval, 1 );
  493. IF lval > 0H THEN w.String( " (" ); w.Hex( lval,-8 ); w.String( "H)" ); END;
  494. | 7: (* REAL *)
  495. SYSTEM.GET(adr,rval); SYSTEM.GET(adr,lval);
  496. w.Float(rval,15);
  497. IF lval > 0H THEN w.String(" ("); w.Hex(lval,-8);w.Char( "H" ); w.String(")"); END;
  498. | 8: (* LONGREAL *)
  499. SYSTEM.GET(adr,xval);SYSTEM.GET(adr,hval);
  500. w.Float(xval,15);
  501. IF hval > 0H THEN w.String( " (" ); w.Hex(hval,-16); w.String( "H)" ); END;
  502. | 13,29: (* POINTER *)
  503. SYSTEM.GET( adr, address ); w.Address( address ); w.String( "H" );
  504. (* output type information, if available: *)
  505. w.String(" (");
  506. (* do a check if the address is in the heap range *)
  507. IF CheckHeapAddress(address) THEN
  508. SYSTEM.GET(address + Heaps.TypeDescOffset, address);
  509. WriteType(w,address);
  510. ELSE w.String("NIL");
  511. END;
  512. w.String(")");
  513. | 16: (* HUGEINT *)
  514. SYSTEM.GET( adr , hval );
  515. w.Hex(hval,1);
  516. IF hval < 0 THEN w.String( "H (" ); w.Hex(hval,-16); w.String(")") END;
  517. | 9: (* SET *)
  518. SYSTEM.GET( adr, lval );
  519. w.Set( SYSTEM.VAL( SET, lval ) );
  520. | 22: (* RECORD *)
  521. w.String( "Rec@" ); w.Hex( tdadr, -8 ); w.Char( "H" );
  522. | 14: (* PROC *)
  523. SYSTEM.GET( adr, lval ); WriteProc( w, lval );
  524. END;
  525. END;
  526. INC(col,w.Pos()-pos0);
  527. END WriteSimpleVar;
  528. (* Display call trackback. *)
  529. PROCEDURE StackTraceBack*(w: Streams.Writer; pc, bp: ADDRESS; stackhigh: ADDRESS; long, overflow: BOOLEAN);
  530. VAR count,refpos: LONGINT; stacklow: ADDRESS; base: ADDRESS; m: Modules.Module; refs: Modules.Bytes;
  531. BEGIN
  532. count := 0; (* frame count *)
  533. stacklow := bp;
  534. REPEAT
  535. m := Modules.ThisModuleByAdr0(pc);
  536. IF (ShowAllProcs OR (m # NIL) OR (count = 0)) & (bp # 0) & (bp >= stacklow) & (bp <= stackhigh) THEN
  537. IF CheckHeapAddress( pc ) THEN
  538. WriteProc0(w, m, pc, bp, refs, refpos, base); w.Ln;Wait(w); w.Update;
  539. IF long & (~overflow OR (count > 0)) THEN (* show variables *)
  540. IF refpos # -1 THEN Variables(w, refs, refpos, base) END;
  541. IF (m # NIL) & (base # m.sb) & (count = 0) THEN ModuleState(w, m) END
  542. END;
  543. ELSE
  544. w.String( "Unknown external procedure, pc = " ); w.Address( pc ); w.Ln; Wait(w);
  545. END;
  546. SYSTEM.GET(bp + SIZEOF(ADDRESS), pc); (* return addr from stack *)
  547. SYSTEM.GET(bp, bp); (* follow dynamic link *)
  548. INC(count)
  549. ELSE
  550. bp := 0
  551. END;
  552. UNTIL (bp = 0) OR (count = MaxFrames);
  553. IF bp # 0 THEN w.String("...") END
  554. END StackTraceBack;
  555. (** Write a process's state in one line. *)
  556. PROCEDURE WriteProcess*(w: Streams.Writer; p: Objects.Process);
  557. VAR adr: ADDRESS; mode: LONGINT; m: Modules.Module;
  558. BEGIN
  559. IF p # NIL THEN
  560. w.Int(p.id, 5);
  561. mode := p.mode;
  562. IF (mode >= Objects.Ready) & (mode <= Objects.Terminated) THEN
  563. adr := (mode-Objects.Ready)*4;
  564. FOR adr := adr TO adr+3 DO w.Char(modes[adr]) END
  565. ELSE
  566. w.Char(" "); w.Int(mode, 1)
  567. END;
  568. w.Int(p.procID, 2);
  569. w.Int(p.priority, 2);
  570. w.Update;
  571. w.Address (SYSTEM.VAL(ADDRESS, p.obj));
  572. IF p.obj # NIL THEN
  573. SYSTEM.GET(SYSTEM.VAL(ADDRESS, p.obj) - SIZEOF(ADDRESS), adr);
  574. w.Char(":"); WriteType(w, adr)
  575. END;
  576. w.Update;
  577. w.Char(" "); WriteProc(w, p.state.PC);
  578. IF p.mode = Objects.AwaitingLock THEN
  579. adr := SYSTEM.VAL(ADDRESS, p.waitingOn);
  580. w.Address (adr);
  581. w.Update;
  582. IF adr # 0 THEN (* can be 0 when snapshot is taken *)
  583. SYSTEM.GET(adr - SIZEOF(ADDRESS), adr);
  584. IF adr = SYSTEM.TYPECODE(Modules.Module) THEN
  585. w.Char("-");
  586. m := SYSTEM.VAL(Modules.Module, adr);
  587. w.String(m.name)
  588. ELSE
  589. w.Char(":"); WriteType(w, adr)
  590. END;
  591. w.Update;
  592. END
  593. ELSIF p.mode = Objects.AwaitingCond THEN
  594. w.Char(" "); WriteProc(w, SYSTEM.VAL(ADDRESS, p.condition));
  595. w.Address (p.condFP)
  596. END;
  597. w.Char(" "); w.Set(p.flags)
  598. END
  599. END WriteProcess;
  600. BEGIN
  601. modes := " rdy run awl awc awe rip"; (* 4 characters per mode from Objects.Ready to Objects.Terminated *)
  602. END Reflection.