BIOS.AMD64.Traps.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. MODULE Traps; (** AUTHOR "pjm"; PURPOSE "Trap handling and symbolic debugging"; *)
  2. IMPORT SYSTEM, Machine, KernelLog, Streams, Modules, Objects, Kernel, Reflection, TrapWriters;
  3. CONST
  4. RecursiveLimit = 2; (* normally 1 or 2 - how many recursive traps to display before stopping *)
  5. TraceVerbose = FALSE;
  6. TestTrap = TRUE;
  7. (* Process termination halt codes *)
  8. halt* = Objects.halt;
  9. haltUnbreakable* = Objects.haltUnbreakable;
  10. TYPE
  11. Variable* = RECORD (** variable descriptor *)
  12. adr-: ADDRESS;
  13. type-, size-, n-, tdadr-: LONGINT
  14. END;
  15. VAR
  16. trapState: ARRAY Machine.MaxCPU OF LONGINT; (* indexed by Machine.ID() *)
  17. modes: ARRAY 25 OF CHAR;
  18. flags: ARRAY 13 OF CHAR;
  19. (* Write flag values. *)
  20. PROCEDURE Flags(w: Streams.Writer; s: SET);
  21. VAR i: SHORTINT; ch: CHAR;
  22. BEGIN
  23. FOR i := 0 TO 11 DO
  24. ch := flags[i];
  25. IF ch # "!" THEN
  26. IF i IN s THEN ch := CAP(ch) END;
  27. w.Char(ch)
  28. END
  29. END;
  30. w.String(" iopl"); w.Int(ASH(SYSTEM.VAL(LONGINT, s * {12,13}), -12), 1)
  31. END Flags;
  32. (** Display trap state. *)
  33. PROCEDURE Show*(p: Objects.Process; VAR int: Machine.State; VAR exc: Machine.ExceptionState; long: BOOLEAN);
  34. VAR id: LONGINT; overflow: BOOLEAN; w: Streams.Writer;
  35. PROCEDURE Val(CONST s: ARRAY OF CHAR; val: HUGEINT);
  36. BEGIN
  37. w.Char(" "); w.String(s); w.Char("="); w.Hex(val, -8)
  38. END Val;
  39. BEGIN
  40. overflow := FALSE;
  41. w := TrapWriters.GetWriter();
  42. w.Update; (* flush previous output stuck in global writer w *)
  43. w.Char(1X); (* "start of trap" *)
  44. id := Machine.ID();
  45. INC(trapState[id]);
  46. IF trapState[id] > RecursiveLimit THEN
  47. w.String(" [Recursive TRAP]")
  48. ELSE
  49. (* output first line *)
  50. w.String("["); w.Int(trapState[id], 1); w.String("] ");
  51. w.String("TRAP "); w.Int(LONGINT(exc.halt), 1);
  52. w.String(" PL"); w.Int(LONGINT(int.CS) MOD 4, 2); w.Char(" ");
  53. CASE exc.halt OF
  54. -14: (* page fault *)
  55. IF (int.CS MOD 4 > Machine.KernelLevel) & (exc.pf+4 = int.SP) THEN
  56. w.String("stack overflow"); overflow := TRUE
  57. END
  58. |0: w.String("division error")
  59. |1: w.String("WITH guard failed")
  60. |2: w.String("CASE invalid")
  61. |3: w.String("RETURN missing")
  62. |4: w.String("integer overflow")
  63. |5: w.String("implicit type guard failed")
  64. |6: w.String("type guard failed")
  65. |7: w.String("index out of range")
  66. |8: w.String("ASSERT failed")
  67. |9: w.String("array dimension error")
  68. |14: w.String("out of memory")
  69. |16: w.String("procedure returned")
  70. ELSE
  71. IF (exc.halt > MAX(INTEGER)+1) OR (exc.halt < MIN(INTEGER)) THEN
  72. w.String("module freed?")
  73. END
  74. END;
  75. IF exc.locks # {} THEN
  76. w.String(", Locks: "); w.Set(exc.locks)
  77. END;
  78. w.Char(" "); w.String(Machine.version);
  79. IF long THEN
  80. w.Char(0EX); (* "fixed font" *)
  81. w.Ln;
  82. (* output values *)
  83. Val("CS:", int.CS); Val("CR0", exc.CR[0]);
  84. Val("FPU", SYSTEM.VAL(LONGINT, exc.FPU[1] * {0..15} + LSH(exc.FPU[2], 16))); w.Ln;
  85. Val("PC", int.PC); Val("RSI", int.RSI); Val("RDI", int.RDI); Val("SP", exc.SP); Val("CR2", exc.CR[2]);
  86. Val("PID", id); w.Ln;
  87. Val("RAX", int.RAX); Val("RBX", int.RBX); Val("RCX", int.RCX); Val("RDX", int.RDX); Val("CR3", exc.CR[3]);
  88. Val("LCK", SYSTEM.VAL(LONGINT, exc.locks)); w.Ln;
  89. Val("BP", int.BP); Val("ERR", int.ERR); Val("CR4", exc.CR[4]);
  90. Val("TMR", Kernel.GetTicks()); w.Ln;
  91. IF SYSTEM.VAL(CHAR, exc.DR[7]) # 0X THEN (* some breakpoints enabled *)
  92. Val("DR0", exc.DR[0]); Val("DR1", exc.DR[1]); Val("DR2", exc.DR[2]); Val("DR3", exc.DR[3]);
  93. Val("DR6", exc.DR[6]); Val("DR7", exc.DR[7]); w.Ln
  94. END;
  95. w.String(" FLAGS: "); Flags(w, int.FLAGS);
  96. w.Char(0FX); (* "proportional font" *)
  97. w.Char(" "); w.Set(int.FLAGS); w.Ln;
  98. (*IF int.INT = Machine.UD THEN KernelLog.Memory(int.PC, 16) END*) (* show bad instruction *)
  99. ELSE
  100. w.Ln
  101. END;
  102. w.String("Process:"); Reflection.WriteProcess(w, p); w.Ln;
  103. (*IF exc.halt = 1301 THEN (* lock timeout - see Machine *)
  104. KernelLog.Memory(ADDRESSOF(Machine.trapState[0]), LEN(Machine.trapState) *
  105. (ADDRESSOF(Machine.trapState[1]) - ADDRESSOF(Machine.trapState[0])));
  106. w.Hex(SYSTEM.VAL(LONGINT, Machine.trapLocksBusy), 8); w.Ln
  107. END;
  108. IF (int.INT = Machine.PF) & (ABS(int.PC-exc.CR[2]) < 100H) THEN (* PF close to PC *)
  109. KernelLog.Memory(int.ESP-16, 64) (* show stack *)
  110. END;*)
  111. Reflection.StackTraceBack(w, int.PC, int.BP, Objects.GetStackBottom(p), long, overflow);
  112. END;
  113. w.String("---------------------------------"); w.Ln;
  114. w.Char(02X); (* "end of trap" *)
  115. w.Update;
  116. TrapWriters.Trapped();
  117. trapState[id] := 0
  118. END Show;
  119. PROCEDURE SetLastExceptionState(ex: Machine.ExceptionState);
  120. VAR id: LONGINT;
  121. BEGIN
  122. id := Machine.AcquirePreemption();
  123. Objects.running[id].exp := ex;
  124. Machine.ReleasePreemption;
  125. END SetLastExceptionState;
  126. PROCEDURE GetLastExceptionState*(): Machine.ExceptionState;
  127. VAR
  128. id: LONGINT;
  129. ex: Machine.ExceptionState;
  130. BEGIN
  131. id := Machine.AcquirePreemption();
  132. ex := Objects.running[id].exp;
  133. Machine.ReleasePreemption;
  134. RETURN ex;
  135. END GetLastExceptionState;
  136. (** Handles an exception. Interrupts are on during this procedure. *)
  137. PROCEDURE HandleException(VAR int: Machine.State; VAR exc: Machine.ExceptionState; VAR handled: BOOLEAN);
  138. VAR
  139. bp, sp, pc, handler: ADDRESS;
  140. BEGIN
  141. bp := int.BP; sp := int.SP; pc := int.PC;
  142. handler := Modules.GetExceptionHandler(pc);
  143. IF handler # -1 THEN (* Handler in the current PAF *)
  144. int.PC := handler; handled := TRUE;
  145. SetTrapVariable(pc, bp); SetLastExceptionState(exc)
  146. ELSE
  147. WHILE (bp # 0) & (handler = -1) DO
  148. SYSTEM.GET(bp + 4, pc);
  149. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  150. handler := Modules.GetExceptionHandler(pc);
  151. sp := bp; (* Save the old basepointer into the stack pointer *)
  152. SYSTEM.GET(bp, bp) (* Unwind PAF *)
  153. END;
  154. IF handler = -1 THEN
  155. handled := FALSE;
  156. ELSE
  157. int.PC := handler; int.BP := bp; int.SP := sp;
  158. SetTrapVariable(pc, bp); SetLastExceptionState(exc);
  159. handled := TRUE
  160. END
  161. END
  162. END HandleException;
  163. PROCEDURE SetTrapVariable(pc, fp: ADDRESS);
  164. VAR
  165. varadr: ADDRESS;
  166. BEGIN
  167. varadr := Reflection.GetVariableAdr(pc, fp, "trap");
  168. IF varadr # -1 THEN
  169. SYSTEM.PUT8(varadr, 1)
  170. END
  171. END SetTrapVariable;
  172. (* Unbreakable stack trace back with regard to every FINALLY on the way *)
  173. PROCEDURE Unbreakable(p: Objects.Process; VAR int: Machine.State; VAR exc: Machine.ExceptionState; VAR handled: BOOLEAN);
  174. VAR
  175. bp, bpSave, pc, handler, bpBottom:ADDRESS;
  176. hasFinally : BOOLEAN;
  177. BEGIN
  178. bp := int.BP;
  179. pc := int.PC;
  180. hasFinally := FALSE;
  181. handler := Modules.GetExceptionHandler(pc);
  182. (* Handler in the current PAF *)
  183. IF handler # -1 THEN
  184. int.PC := handler;
  185. hasFinally := TRUE;
  186. SetTrapVariable(pc, bp);
  187. END;
  188. (* The first waypoint is the bp of the top PAF *)
  189. bpSave := bp;
  190. WHILE (bp # 0) DO
  191. (* Did we reach the last PAF? *)
  192. SYSTEM.GET(bp, pc);
  193. IF (pc = 0) THEN
  194. bpBottom := bp; (* Save the FP of the last PAF *)
  195. END;
  196. (* Get the return pc *)
  197. SYSTEM.GET(bp + SIZEOF(ADDRESS), pc);
  198. handler := Modules.GetExceptionHandler(pc);
  199. (* Save the last framepointer as stackpointer *)
  200. IF ~hasFinally THEN
  201. int.SP := bp;
  202. END;
  203. SYSTEM.GET(bp, bp);
  204. (* Here bp may be 0. *)
  205. IF (handler # -1) & (bp # 0) THEN (* If Objects.Terminate has a FINALLY this doesn't work !!! *)
  206. IF hasFinally THEN
  207. (* Connect Finally to Finally *)
  208. SYSTEM.PUT(bpSave + SIZEOF(ADDRESS), handler); (* Adapt the return pc *)
  209. SYSTEM.PUT(bpSave, bp); (* Adapt the dynamic link *)
  210. bpSave := bp;
  211. ELSE
  212. int.PC := handler;
  213. int.BP := bp;
  214. bpSave := bp;
  215. hasFinally := TRUE;
  216. END;
  217. SetTrapVariable(pc, bp)
  218. END
  219. END;
  220. (* Now bp = 0, bottom of the stack, so link the last known return PC to the Termination *)
  221. IF ~hasFinally THEN
  222. SYSTEM.GET(bpBottom + SIZEOF(ADDRESS), pc); (* PC of the Terminate *)
  223. int.PC := pc;
  224. int.BP := bpBottom;
  225. ELSIF bpSave # bpBottom THEN
  226. SYSTEM.GET(bpBottom + SIZEOF(ADDRESS), pc); (* PC of the Terminate *)
  227. SYSTEM.PUT(bpSave + SIZEOF(ADDRESS), pc);
  228. SetLastExceptionState(exc)
  229. END;
  230. handled := TRUE; (* If FALSE the process could be restarted, may be this is the meaning? *)
  231. END Unbreakable;
  232. (* General exception handler. *)
  233. PROCEDURE Exception(VAR int: Machine.State);
  234. VAR t: Objects.Process; exc: Machine.ExceptionState; user, traceTrap, handled: BOOLEAN;
  235. BEGIN (* interrupts off *)
  236. t := Objects.running[Machine.ID()]; (* t is running process *)
  237. handled := FALSE;
  238. Machine.GetExceptionState(int, exc);
  239. user := (int.CS MOD 4 > Machine.KernelLevel);
  240. traceTrap := (exc.locks = {}) & (exc.halt >= MAX(INTEGER)) & (exc.halt <= MAX(INTEGER)+1);
  241. Show(t, int, exc, exc.halt # MAX(INTEGER)+1); (* Always show the trap info!*)
  242. IF exc.halt = haltUnbreakable THEN
  243. Unbreakable(t, int, exc, handled)
  244. ELSIF ~ traceTrap THEN
  245. HandleException( int, exc, handled)
  246. END;
  247. IF ~handled THEN
  248. (* Taken from Machine to allow the FINALLY in the kernel *)
  249. exc.locks := Machine.BreakAll();
  250. Machine.Sti();
  251. IF ~traceTrap THEN (* trap *)
  252. IF user THEN (* return to outer level *)
  253. IF TraceVerbose THEN
  254. KernelLog.Enter;
  255. KernelLog.String("Jump"); KernelLog.Hex(t.restartPC, 9);
  256. KernelLog.Hex(t.restartSP, 9); KernelLog.Hex(t.stack.high, 9);
  257. KernelLog.Exit
  258. END;
  259. INCL(int.FLAGS, Machine.IFBit); (* enable interrupts *)
  260. int.BP := 0; int.SP := t.restartSP; (* reset stack *)
  261. int.PC := t.restartPC; (* restart object body or terminate *)
  262. ELSE (* trap was in kernel (interrupt handler) *) (* fixme: recover from trap in stack traceback *)
  263. KernelLog.Enter; KernelLog.String("Kernel halt"); KernelLog.Exit;
  264. Machine.Shutdown(FALSE)
  265. END
  266. END
  267. END;
  268. IF Objects.PleaseHalt IN t.flags THEN
  269. EXCL(t.flags, Objects.PleaseHalt);
  270. IF Objects.Unbreakable IN t.flags THEN EXCL(t.flags, Objects.Unbreakable) END;
  271. IF Objects.SelfTermination IN t.flags THEN EXCL(t.flags, Objects.SelfTermination) END
  272. END
  273. END Exception;
  274. (* Page fault handler. *)
  275. PROCEDURE PageFault(VAR state: Machine.State);
  276. VAR t: Objects.Process;
  277. BEGIN
  278. t := Objects.running[Machine.ID()];
  279. IF Machine.IFBit IN state.FLAGS THEN (* enable interrupts again if they were enabled *)
  280. Machine.Sti() (* avoid Processors.StopAll deadlock when waiting for locks below (fixme: remove) *)
  281. END;
  282. IF (t = NIL) OR ~Machine.ExtendStack(t.stack, Machine.CR2()) THEN
  283. IF TraceVerbose THEN
  284. IF t = NIL THEN
  285. KernelLog.Enter; KernelLog.String("GrowStack running=NIL");
  286. KernelLog.Hex(state.PC, 9); KernelLog.Exit
  287. ELSE
  288. KernelLog.Enter;
  289. KernelLog.String("GrowStack failed, pf="); KernelLog.Hex(Machine.CR2(), 8);
  290. KernelLog.String(" adr="); KernelLog.Hex(t.stack.adr, 8);
  291. KernelLog.String(" high="); KernelLog.Hex(t.stack.high, 8);
  292. (*KernelLog.Ln; KernelLog.Memory(t.stack.adr, 256);*)
  293. KernelLog.Exit
  294. END
  295. END;
  296. Exception(state)
  297. ELSE
  298. IF TraceVerbose THEN
  299. KernelLog.Enter; KernelLog.String("GrowStack");
  300. KernelLog.Hex(t.stack.adr, 9); KernelLog.Hex(t.stack.high, 9); KernelLog.Exit
  301. END
  302. END
  303. END PageFault;
  304. PROCEDURE Init;
  305. VAR i: LONGINT; s: ARRAY 8 OF CHAR;
  306. BEGIN
  307. IF TestTrap THEN
  308. Machine.GetConfig("TestTrap", s);
  309. IF s[0] = "1" THEN HALT(98) END
  310. END;
  311. FOR i := 0 TO Machine.MaxCPU-1 DO trapState[i] := 0 END;
  312. Machine.InstallHandler(PageFault, Machine.PF);
  313. FOR i := 0 TO 31 DO
  314. IF ~(i IN {Machine.PF}) THEN (* PF handler above *)
  315. Machine.InstallHandler(Exception, i)
  316. END
  317. END;
  318. IF TestTrap & (s[0] = "2") THEN HALT(99) END
  319. END Init;
  320. BEGIN
  321. modes := " rdy run awl awc awe rip"; (* 4 characters per mode from Objects.Ready to Objects.Terminated *)
  322. flags := "c!p!a!zstido"; (* bottom flags, !=reserved *)
  323. Init
  324. END Traps.
  325. (*
  326. 12.03.1998 pjm Started
  327. 06.08.1998 pjm Exported Show and removed AosException upcall installation & Modules lock
  328. 10.12.1998 pjm New refblk
  329. 23.06.1999 pjm State added
  330. *)
  331. (*
  332. to do:
  333. o stack overflow message is not correctly displayed in case of dynamic arrays (EDI = CR2, ESP # CR2)
  334. o fix KernelLog.Memory calls removed when switching to Streams
  335. o fix use of KernelLog lock in Show
  336. o if allowing modification of variables using their descriptors, it should also have reference to module to avoid gc after free.
  337. *)