Reflection.Mod 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  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, x: LONGINT;
  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 := ORD(refs[i]); INC( i );
  78. WHILE x >= 128 DO INC( n, ASH( x - 128, s ) ); INC( s, 7 ); x := ORD(refs[i]); INC( i ) END;
  79. num := n + ASH( x MOD 64 - 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,pc,end: 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. IF FindProcByName(mod,"$$",pc,end) THEN
  149. refpos := FindProc(refs, pc, startpc);
  150. END;
  151. IF refpos # -1 THEN
  152. ch := refs[refpos]; INC(refpos);
  153. WHILE ch # 0X DO ch := refs[refpos]; INC(refpos) END
  154. END
  155. END
  156. END
  157. END InitVar;
  158. PROCEDURE NewObjectFile(refs: Modules.Bytes): BOOLEAN;
  159. BEGIN
  160. RETURN (refs # NIL) & (LEN(refs) >0) & (refs[0]=0FFX);
  161. END NewObjectFile;
  162. (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  163. PROCEDURE FindProc(refs: Modules.Bytes; modpc: ADDRESS; VAR startpc: ADDRESS): LONGINT;
  164. VAR pos, len, t, tstart, tend, proc: LONGINT; ch: CHAR; newObjectFile, found: BOOLEAN;
  165. BEGIN
  166. IF (refs=NIL) OR (LEN(refs) = 0) THEN RETURN -1 END;
  167. newObjectFile := NewObjectFile(refs);
  168. proc := -1; pos := 0; len := LEN(refs^);
  169. IF newObjectFile THEN INC(pos) END;
  170. ch := refs[pos]; INC(pos); tstart := 0;
  171. found := FALSE;
  172. WHILE ~found & (pos < len) & ((ch = 0F8X) OR (ch = 0F9X)) DO (* proc *)
  173. GetNum(refs, pos, tstart); (* procedure offset *)
  174. IF newObjectFile THEN
  175. GetNum(refs,pos,tend);
  176. found := (tstart <=modpc) & (tend > modpc)
  177. ELSE
  178. found := tstart > modpc
  179. END;
  180. IF ch = 0F9X THEN
  181. GetNum(refs, pos, t); (* nofPars *)
  182. INC(pos, 3) (* RetType, procLev, slFlag *);
  183. IF newObjectFile THEN INC(pos,6) END;
  184. END;
  185. IF ~found THEN (* not yet found -- remember startpc and position for next iteration *)
  186. startpc := tstart;
  187. proc := pos; (* remember this position, just before the name *)
  188. REPEAT ch := refs[pos]; INC(pos) UNTIL ch = 0X; (* pname *)
  189. IF pos < len THEN
  190. ch := refs[pos]; INC(pos); (* 1X | 3X | 0F8X | 0F9X *)
  191. WHILE (pos < len) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  192. ch := refs[pos]; INC(pos); (* type *)
  193. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  194. GetNum(refs, pos, t) (* dim/tdadr *)
  195. END;
  196. GetNum(refs, pos, t); (* vofs *)
  197. REPEAT ch := refs[pos]; INC(pos) UNTIL ch = 0X; (* vname *)
  198. IF pos < len THEN ch := refs[pos]; INC(pos) END (* 1X | 3X | 0F8X | 0F9X *)
  199. END
  200. END
  201. END;
  202. END;
  203. IF newObjectFile THEN
  204. IF found THEN
  205. startpc := tstart; proc := pos;
  206. ELSE proc := -1
  207. END;
  208. END;
  209. RETURN proc
  210. END FindProc;
  211. (* Find a procedure in the reference block. Return index of name, or -1 if not found. *)
  212. PROCEDURE FindProcByName*(mod: Modules.Module; CONST name: ARRAY OF CHAR; VAR from, to: ADDRESS): BOOLEAN;
  213. VAR i, namePos, m, t, temp: LONGINT; ch: CHAR; newObjectFile: BOOLEAN;
  214. refs: Modules.Bytes; success: BOOLEAN;
  215. tstart, tend: ADDRESS;
  216. BEGIN
  217. IF mod = NIL THEN RETURN FALSE END;
  218. refs := mod.refs;
  219. IF (refs=NIL) OR (LEN(refs) = 0) THEN RETURN FALSE END;
  220. newObjectFile := NewObjectFile(refs);
  221. i := 0; m := LEN(refs^);
  222. IF newObjectFile THEN INC(i) END;
  223. ch := refs[i]; INC(i); tstart := 0;
  224. success := FALSE;
  225. WHILE (i < m) & ((ch = 0F8X) OR (ch = 0F9X)) & ~success DO (* proc *)
  226. GetNum(refs, i, temp); (* pofs *)
  227. tstart := temp;
  228. IF newObjectFile THEN GetNum(refs,i,temp); tend := temp END;
  229. IF ch = 0F9X THEN
  230. GetNum(refs, i, t); (* nofPars *)
  231. INC(i, 3) (* RetType, procLev, slFlag *);
  232. IF newObjectFile THEN INC(i,6) END;
  233. END;
  234. namePos := 0; success := TRUE;
  235. REPEAT ch := refs[i]; INC(i); success := success & (ch = name[namePos]); INC(namePos); UNTIL ch = 0X; (* pname *)
  236. IF i < m THEN
  237. ch := refs[i]; INC(i); (* 1X | 3X | 0F8X | 0F9X *)
  238. WHILE (i < m) & (ch >= 1X) & (ch <= 3X) DO (* var *)
  239. ch := refs[i]; INC(i); (* type *)
  240. IF (ch >= 81X) OR (ch = 16X) OR (ch = 1DX) THEN
  241. GetNum(refs, i, t) (* dim/tdadr *)
  242. END;
  243. GetNum(refs, i, t); (* vofs *)
  244. REPEAT ch := refs[i]; INC(i) UNTIL ch = 0X; (* vname *)
  245. IF i < m THEN ch := refs[i]; INC(i) END (* 1X | 3X | 0F8X | 0F9X *)
  246. END
  247. END;
  248. END;
  249. IF success & ~newObjectFile THEN
  250. IF (ch = 0F8X) OR (ch = 0F9X) THEN
  251. GetNum(refs, i, temp); tend := temp;
  252. ELSE
  253. tend :=LEN(mod.code);
  254. END;
  255. INC(tstart, ADDRESSOF(mod.code[0]));
  256. INC(tend, ADDRESSOF(mod.code[0]));
  257. END;
  258. from := tstart; to := tend;
  259. RETURN success
  260. END FindProcByName;
  261. PROCEDURE Wait(w: Streams.Writer);
  262. VAR i: LONGINT;
  263. BEGIN
  264. IF LineDelay > 0 THEN
  265. FOR i := 0 TO LineDelay DO END;
  266. w.Update
  267. END;
  268. END Wait;
  269. (* Display variables. *)
  270. PROCEDURE Variables(w: Streams.Writer; refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS);
  271. VAR v: Variable; j, col: LONGINT; name: ARRAY 64 OF CHAR; etc: BOOLEAN;
  272. CONST dense = FALSE;
  273. BEGIN
  274. LOOP
  275. NextVar(refs, refpos, base, name, v);
  276. IF name[0] = 0X THEN EXIT END;
  277. (* write name *)
  278. IF (col # 0 ) & (v.n > 1) & (v.type # 15) THEN (* Ln before array (except string) *)
  279. w.Ln; col := 0; Wait(w);
  280. END;
  281. w.String(Sep); w.String(name); w.Char("=");
  282. j := 0; WHILE name[j] # 0X DO INC(j) END;
  283. INC(col, SepLen+1+j);
  284. (* write variable *)
  285. IF (v.adr >= -4) & (v.adr < 4096) THEN (* must be NIL VAR parameter *)
  286. w.String("NIL ("); w.Hex(v.adr, -8);
  287. w.Char(")"); INC(col, 14)
  288. ELSE
  289. etc := FALSE;
  290. IF v.type = 15 THEN
  291. IF v.n > MaxString THEN etc := TRUE; v.n := MaxString END
  292. ELSE
  293. IF v.n > MaxArray THEN etc := TRUE; v.n := MaxArray END
  294. END;
  295. WriteVar(w, v, col); (* write value *)
  296. IF etc THEN w.String("..."); INC(col, 3) END;
  297. IF ~dense THEN
  298. w.Ln; col := 0; Wait(w);
  299. END;
  300. END;
  301. IF col > MaxCols THEN w.Ln; col := 0; Wait(w); END
  302. END;
  303. IF col # 0 THEN w.Ln; Wait(w) END
  304. END Variables;
  305. (** Write the state of the specified module. *)
  306. PROCEDURE ModuleState*(w: Streams.Writer; mod: Modules.Module);
  307. VAR refpos: LONGINT; base: ADDRESS; refs: Modules.Bytes;
  308. BEGIN
  309. InitVar(mod, refs, refpos, base);
  310. IF refpos # -1 THEN
  311. w.String("State "); w.String(mod.name); w.Char(":"); w.Ln; Wait(w);
  312. Variables(w, refs, refpos, base)
  313. END
  314. END ModuleState;
  315. (* Write the specified procedure name and returns parameters for use with NextVar and Variables. *)
  316. PROCEDURE WriteProc0(w: Streams.Writer; mod: Modules.Module; pc, fp: ADDRESS; VAR refs: Modules.Bytes;
  317. VAR refpos: LONGINT; VAR base: ADDRESS);
  318. VAR ch: CHAR; startpc: ADDRESS;
  319. BEGIN
  320. refpos := -1;
  321. IF mod = NIL THEN
  322. IF pc = 0 THEN w.String("NIL")
  323. ELSE
  324. w.String("Unknown PC="); w.Address(pc); w.Char("H")
  325. END;
  326. IF fp # -1 THEN
  327. w.String(" FP="); w.Address(fp); w.Char("H")
  328. END
  329. ELSE
  330. w.String(mod.name);
  331. IF ~NewObjectFile(mod.refs) THEN
  332. DEC(pc, ADDRESSOF(mod.code[0]));
  333. END;
  334. refs := mod.refs;
  335. IF (refs # NIL) & (LEN(refs) # 0) THEN
  336. refpos := FindProc(refs, pc, startpc);
  337. IF refpos # -1 THEN
  338. w.Char(".");
  339. ch := refs[refpos]; INC(refpos);
  340. IF ch = "$" THEN base := mod.sb ELSE base := fp END; (* for variables *)
  341. WHILE ch # 0X DO w.Char(ch); ch := refs[refpos]; INC(refpos) END;
  342. w.Char(":"); w.Int(LONGINT(pc-startpc),1);
  343. END
  344. END;
  345. w.String(" pc="); w.Int(LONGINT(pc),1); w.String(" ["); w.Address (pc); w.String("H]");
  346. w.String(" = "); w.Int(LONGINT(startpc),1); w.String(" + "); w.Int(LONGINT(pc-startpc),1);
  347. w.String(" crc="); w.Hex(mod.crc,-8);
  348. Wait(w);
  349. END
  350. END WriteProc0;
  351. (** Find procedure name and write it. *)
  352. PROCEDURE WriteProc*(w: Streams.Writer; pc: ADDRESS);
  353. VAR refs: Modules.Bytes; refpos: LONGINT; base: ADDRESS;
  354. BEGIN
  355. WriteProc0(w, Modules.ThisModuleByAdr0(pc), pc, -1, refs, refpos, base)
  356. END WriteProc;
  357. (* Returns the name of the procedure the pc is in. Searchs in m.refs *)
  358. PROCEDURE GetProcedureName*(pc: ADDRESS; VAR name: ARRAY OF CHAR; VAR startpc: ADDRESS);
  359. VAR
  360. methadr, i: LONGINT;
  361. ch: CHAR;
  362. m: Modules.Module;
  363. BEGIN
  364. m := Modules.ThisModuleByAdr0(pc);
  365. IF m # NIL THEN
  366. IF ~NewObjectFile(m.refs) THEN
  367. DEC(pc, ADDRESSOF(m.code[0]));
  368. END;
  369. methadr := FindProc(m.refs, pc, startpc);
  370. IF methadr # -1 THEN
  371. i := 0;
  372. ch := m.refs[methadr]; INC(methadr);
  373. WHILE ch # 0X DO
  374. name[i] := ch;
  375. ch := m.refs[methadr];
  376. INC(methadr);
  377. INC(i);
  378. END;
  379. IF ~NewObjectFile(m.refs) THEN
  380. INC(startpc, ADDRESSOF(m.code[0]));
  381. END;
  382. END;
  383. name[i] := 0X;
  384. ELSE
  385. name := "Unkown"; (* Better: name := "" *)
  386. END;
  387. END GetProcedureName;
  388. (* A simple introspection method, must be adapted if there are any changes to the
  389. refs section in a module. *)
  390. PROCEDURE GetVariableAdr*(pc, fp: ADDRESS; CONST varname: ARRAY OF CHAR): ADDRESS;
  391. VAR
  392. m: Modules.Module;
  393. v: Variable;
  394. pos: LONGINT;
  395. base: ADDRESS;
  396. name: ARRAY 256 OF CHAR;
  397. ch: CHAR;
  398. startpc: ADDRESS;
  399. BEGIN
  400. pos := -1;
  401. m := Modules.ThisModuleByAdr0(pc);
  402. IF m # NIL THEN
  403. IF ~NewObjectFile(m.refs) THEN
  404. DEC(pc, ADDRESSOF(m.code[0]));
  405. END;
  406. pos := FindProc(m.refs, pc, startpc);
  407. IF pos # -1 THEN
  408. ch := m.refs[pos]; INC(pos);
  409. (* for variables *)
  410. IF ch = "$" THEN
  411. base := m.sb;
  412. ELSE
  413. base := fp;
  414. END;
  415. (* Read the name *)
  416. WHILE ch # 0X DO ch := m.refs[pos]; INC(pos) END;
  417. NextVar(m.refs, pos, base, name, v);
  418. WHILE name[0] # 0X DO
  419. IF name = varname THEN
  420. RETURN v.adr;
  421. ELSE
  422. NextVar(m.refs, pos, base, name, v);
  423. END
  424. END
  425. END
  426. END;
  427. RETURN -1;
  428. END GetVariableAdr;
  429. (* "lock free" version of Modules.ThisTypeByAdr *)
  430. PROCEDURE ThisTypeByAdr(adr: ADDRESS; VAR m: Modules.Module; VAR t: Modules.TypeDesc);
  431. BEGIN
  432. IF adr # 0 THEN
  433. SYSTEM.GET (adr + Heaps.TypeDescOffset, adr);
  434. IF CheckHeapAddress(adr) THEN
  435. t := SYSTEM.VAL(Modules.TypeDesc, adr);
  436. m := t.mod;
  437. ELSE
  438. m := NIL; t := NIL
  439. END
  440. ELSE
  441. m := NIL; t := NIL
  442. END
  443. END ThisTypeByAdr;
  444. PROCEDURE WriteType*(w: Streams.Writer; adr: ADDRESS);
  445. VAR module: Modules.Module; typeDesc: Modules.TypeDesc;
  446. BEGIN
  447. IF CheckHeapAddress(adr) THEN
  448. ThisTypeByAdr(adr, module, typeDesc);
  449. IF module # NIL THEN
  450. w.String(module.name);
  451. ELSE
  452. w.String("NIL"); RETURN
  453. END;
  454. w.String(".");
  455. IF typeDesc # NIL THEN
  456. IF typeDesc.name = "" THEN
  457. w.String("ANONYMOUS")
  458. ELSE
  459. w.String(typeDesc.name);
  460. END;
  461. ELSE
  462. w.String("NIL");
  463. END;
  464. ELSE
  465. w.String("UNKNOWN");
  466. END;
  467. END WriteType;
  468. PROCEDURE WriteSimpleVar( w: Streams.Writer; adr, type, tdadr: ADDRESS; VAR col: LONGINT );
  469. VAR ch: CHAR; sval: SHORTINT; ival: INTEGER; lval: LONGINT; rval: REAL; xval: LONGREAL; hval : HUGEINT;
  470. address: ADDRESS; pos0: LONGINT; setval: SET;
  471. BEGIN
  472. pos0 := w.Pos();
  473. IF (adr # 0) OR (type = 22) THEN
  474. CASE type OF
  475. 1, 3: (* BYTE, CHAR *)
  476. SYSTEM.GET( adr, ch );
  477. IF (ch > " ") & (ch <= "~") THEN w.Char( ch ); ELSE w.Hex( ORD( ch ), -2 ); w.Char( "X" ) END;
  478. | 2: (* BOOLEAN *)
  479. SYSTEM.GET( adr, ch );
  480. IF ch = 0X THEN w.String( "FALSE" )
  481. ELSIF ch = 1X THEN w.String( "TRUE" )
  482. ELSE w.Int( ORD( ch ), 1 );
  483. END;
  484. | 4: (* SHORTINT *)
  485. SYSTEM.GET( adr, sval );
  486. w.Int( sval, 1 );
  487. IF sval > 0H THEN w.String(" ("); w.Hex(sval, -2); w.String("H)") END;
  488. | 5: (* INTEGER *)
  489. SYSTEM.GET( adr, ival );
  490. w.Int( ival, 1 );
  491. IF ival > 0H THEN w.String(" (");w.Hex(ival,-4);w.Char("H");w.String(")"); END;
  492. | 6: (* LONGINT *)
  493. SYSTEM.GET( adr, lval );
  494. w.Int( lval, 1 );
  495. IF lval > 0H THEN w.String( " (" ); w.Hex( lval,-8 ); w.String( "H)" ); END;
  496. | 7: (* REAL *)
  497. SYSTEM.GET(adr,rval); SYSTEM.GET(adr,lval);
  498. w.Float(rval,15);
  499. IF lval > 0H THEN w.String(" ("); w.Hex(lval,-8);w.Char( "H" ); w.String(")"); END;
  500. | 8: (* LONGREAL *)
  501. SYSTEM.GET(adr,xval);SYSTEM.GET(adr,hval);
  502. w.Float(xval,15);
  503. IF hval > 0H THEN w.String( " (" ); w.Hex(hval,-16); w.String( "H)" ); END;
  504. | 13,29: (* POINTER *)
  505. SYSTEM.GET( adr, address ); w.Address( address ); w.String( "H" );
  506. (* output type information, if available: *)
  507. w.String(" (");
  508. (* do a check if the address is in the heap range *)
  509. IF CheckHeapAddress(address) THEN
  510. SYSTEM.GET(address + Heaps.TypeDescOffset, address);
  511. WriteType(w,address);
  512. ELSE w.String("NIL");
  513. END;
  514. w.String(")");
  515. | 16: (* HUGEINT *)
  516. SYSTEM.GET( adr , hval );
  517. IF hval = 0 THEN w.Char( '0' );
  518. ELSIF hval > 0 THEN w.Hex( hval, 1 ); w.Char( 'H' )
  519. ELSE w.Hex( hval, -16 );
  520. END;
  521. | 9: (* SET *)
  522. SYSTEM.GET( adr, setval );
  523. w.Set( setval );
  524. | 22: (* RECORD *)
  525. w.String( "Rec@" ); w.Hex( tdadr, -8 ); w.Char( "H" );
  526. | 14: (* PROC *)
  527. SYSTEM.GET( adr, lval ); WriteProc( w, lval );
  528. END;
  529. END;
  530. INC(col,w.Pos()-pos0);
  531. END WriteSimpleVar;
  532. (* Display call trackback. *)
  533. PROCEDURE StackTraceBack*(w: Streams.Writer; pc, bp: ADDRESS; stackhigh: ADDRESS; long, overflow: BOOLEAN);
  534. VAR count,refpos: LONGINT; stacklow: ADDRESS; base: ADDRESS; m: Modules.Module; refs: Modules.Bytes;
  535. BEGIN
  536. count := 0; (* frame count *)
  537. stacklow := bp;
  538. REPEAT
  539. m := Modules.ThisModuleByAdr0(pc);
  540. IF (ShowAllProcs OR (m # NIL) OR (count = 0)) & (bp # 0) & (bp >= stacklow) & (bp <= stackhigh) THEN
  541. IF CheckHeapAddress( pc ) THEN
  542. WriteProc0(w, m, pc, bp, refs, refpos, base); w.Ln;Wait(w); w.Update;
  543. IF long & (~overflow OR (count > 0)) THEN (* show variables *)
  544. IF refpos # -1 THEN Variables(w, refs, refpos, base) END;
  545. IF (m # NIL) & (base # m.sb) & (count = 0) THEN ModuleState(w, m) END
  546. END;
  547. ELSE
  548. w.String( "Unknown external procedure, pc = " ); w.Address( pc ); w.Ln; Wait(w);
  549. END;
  550. SYSTEM.GET(bp + SIZEOF(ADDRESS), pc); (* return addr from stack *)
  551. SYSTEM.GET(bp, bp); (* follow dynamic link *)
  552. INC(count)
  553. ELSE
  554. bp := 0
  555. END;
  556. UNTIL (bp = 0) OR (count = MaxFrames);
  557. IF bp # 0 THEN w.String("...") END
  558. END StackTraceBack;
  559. (** Write a process's state in one line. *)
  560. PROCEDURE WriteProcess*(w: Streams.Writer; p: Objects.Process);
  561. VAR adr: ADDRESS; mode: LONGINT; m: Modules.Module;
  562. BEGIN
  563. IF p # NIL THEN
  564. w.Int(p.id, 5);
  565. mode := p.mode;
  566. IF (mode >= Objects.Ready) & (mode <= Objects.Terminated) THEN
  567. adr := (mode-Objects.Ready)*4;
  568. FOR adr := adr TO adr+3 DO w.Char(modes[adr]) END
  569. ELSE
  570. w.Char(" "); w.Int(mode, 1)
  571. END;
  572. w.Int(p.procID, 2);
  573. w.Int(p.priority, 2);
  574. w.Update;
  575. w.Address (SYSTEM.VAL(ADDRESS, p.obj));
  576. IF p.obj # NIL THEN
  577. SYSTEM.GET(SYSTEM.VAL(ADDRESS, p.obj) - SIZEOF(ADDRESS), adr);
  578. w.Char(":"); WriteType(w, adr)
  579. END;
  580. w.Update;
  581. w.Char(" "); WriteProc(w, p.state.PC);
  582. IF p.mode = Objects.AwaitingLock THEN
  583. adr := SYSTEM.VAL(ADDRESS, p.waitingOn);
  584. w.Address (adr);
  585. w.Update;
  586. IF adr # 0 THEN (* can be 0 when snapshot is taken *)
  587. SYSTEM.GET(adr - SIZEOF(ADDRESS), adr);
  588. IF adr = SYSTEM.TYPECODE(Modules.Module) THEN
  589. w.Char("-");
  590. m := SYSTEM.VAL(Modules.Module, adr);
  591. w.String(m.name)
  592. ELSE
  593. w.Char(":"); WriteType(w, adr)
  594. END;
  595. w.Update;
  596. END
  597. ELSIF p.mode = Objects.AwaitingCond THEN
  598. w.Char(" "); WriteProc(w, SYSTEM.VAL(ADDRESS, p.condition));
  599. w.Address (p.condFP)
  600. END;
  601. w.Char(" "); w.Set(p.flags)
  602. END
  603. END WriteProcess;
  604. BEGIN
  605. modes := " rdy run awl awc awe rip"; (* 4 characters per mode from Objects.Ready to Objects.Terminated *)
  606. END Reflection.