ARM.Traps.Mod 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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. (** Trap Numbers -- Do not modify: these are related to the compiler code generation. *)
  11. (*
  12. WithTrap* = 1; (* generated when a WITH statement fails *)
  13. CaseTrap* = 2; (* generated when a case statement without else block fails *)
  14. ReturnTrap* = 3;
  15. TypeEqualTrap* = 5;
  16. TypeCheckTrap* = 6;
  17. IndexCheckTrap* = 7; (* generated when index is out of bounds or range is invalid *)
  18. AssertTrap* = 8; (* generated when an assert fails *)
  19. ArraySizeTrap* = 9;
  20. ArrayFormTrap*=10; (* indicates that array cannot be (re-)allocated since shape, type or size does not match *)
  21. SetElementTrap*=11; (* indicates that a set element is out of MIN(SET)...MAX(SET) *)
  22. NegativeDivisorTrap*=12;
  23. NoReturnTrap*=16; (* indicates that a procedure marked no return did return *)
  24. ELSIF code = 13 THEN StrAppend( desc, "Keyboard interrupt" )
  25. ELSIF code = 14 THEN StrAppend( desc, "Out of memory" )
  26. ELSIF code = 15 THEN StrAppend( desc, "Deadlock (active objects)" );
  27. ELSIF code = 16 THEN StrAppend( desc, "Procedure returned" );
  28. ELSIF code = 23 THEN StrAppend( desc, "Exceptions.Raise" )
  29. *)
  30. DivisionError = 0;
  31. WithError = 1; (* Compiler generated *)
  32. CaseError = 2; (* Compiler generated *)
  33. ReturnError = 3; (* Compiler generated *)
  34. IntOverflow = 4;
  35. ImplicitTypeGuardError = 5; (* Compiler generated *)
  36. TypeGuardError = 6; (* Compiler generated *)
  37. IndexOutOfRange = 7; (* Compiler generated *)
  38. AssertError = 8; (* Compiler generated *)
  39. ArraySize = 9; (* Compiler generated *)
  40. ArrayForm = 10; (* Compiler generated *)
  41. SetElement = 11; (* Compiler generated *)
  42. NegativeDivisor = 12; (* Compiler generated *)
  43. KeyboardInt = 13;
  44. OutOfMemory = 14;
  45. Deadlock = 15;
  46. ProcedureReturned = 16; (* Compiler generated *)
  47. UndefinedInstn = 17; (* ARM specific *)
  48. NilPointer = 18; (* ARM specific *)
  49. MemoryError = 19; (* ARM specific *)
  50. ExceptionRaised = 23;
  51. ProcessResurrected = 2201;
  52. RecursiveExclusive = 2203;
  53. AwaitOutsideExclusive = 2204;
  54. (** Trap descriptions, human-readable *)
  55. (*
  56. |0: w.String("division error")
  57. |1: w.String("WITH guard failed")
  58. |2: w.String("CASE invalid")
  59. |3: w.String("RETURN missing")
  60. |4: w.String("integer overflow")
  61. |5: w.String("implicit type guard failed")
  62. |6: w.String("type guard failed")
  63. |7: w.String("index out of range")
  64. |8: w.String("ASSERT failed")
  65. |9: w.String("array dimension error")
  66. |14: w.String("out of memory")
  67. |16: w.String("procedure returned")
  68. *)
  69. DivisionErrorDesc = "division error";
  70. WithErrorDesc = "WITH guard failed";
  71. CaseErrorDesc = "CASE invalid";
  72. ReturnErrorDesc = "RETURN missing";
  73. IntOverflowDesc = "integer overflow";
  74. ImplicitTypeGuardErrorDesc = "implicit type guard failed";
  75. TypeGuardErrorDesc = "type guard failed";
  76. IndexOutOfRangeDesc = "index out of range";
  77. AssertErrorDesc = "ASSERT failed";
  78. ArraySizeDesc = "array dimension error";
  79. ArrayFormDesc = "invalid array shape";
  80. SetElementDesc = "invalid SET element";
  81. NegativeDivisorDesc = "negative divisor";
  82. KeyboardIntDesc = "keyboard interrupt";
  83. OutOfMemoryDesc = "out of memory";
  84. DeadlockDesc = "deadlock";
  85. ProcedureReturnedDesc = "procedure returned";
  86. UndefinedInstnDesc = "undefined instruction";
  87. NilPointerDesc = "NIL pointer";
  88. MemoryErrorDesc = "invalid memory location";
  89. ExceptionRaisedDesc = "exception";
  90. ProcessResurrectedDesc = "process resurrected";
  91. RecursiveExclusiveDesc = "recursive entrance in EXCLUSIVE section";
  92. AwaitOutsideExclusiveDesc = "AWAIT statement outside EXCLUSIVE section";
  93. TYPE
  94. Variable* = RECORD (** variable descriptor *)
  95. adr-: ADDRESS;
  96. type-, size-, n-, tdadr-: LONGINT
  97. END;
  98. VAR
  99. trapState: ARRAY Machine.MaxCPU OF LONGINT; (* indexed by Machine.ID() *)
  100. modes: ARRAY 25 OF CHAR;
  101. flags: ARRAY 13 OF CHAR;
  102. (** Display trap state. *)
  103. PROCEDURE Show*(p: Objects.Process; VAR int: Machine.State; VAR exc: Machine.ExceptionState; long: BOOLEAN);
  104. VAR id: LONGINT; overflow: BOOLEAN; w: Streams.Writer;
  105. PROCEDURE Val(CONST s: ARRAY OF CHAR; val: HUGEINT);
  106. BEGIN
  107. w.Char(" "); w.String(s); w.Char("="); w.Hex(val, -8)
  108. END Val;
  109. BEGIN
  110. overflow := FALSE;
  111. w := TrapWriters.GetWriter();
  112. w.Update; (* flush previous output stuck in global writer w *)
  113. w.Char(1X); (* "start of trap" *)
  114. id := Machine.ID();
  115. INC(trapState[id]);
  116. IF trapState[id] > RecursiveLimit THEN
  117. w.String(" [Recursive TRAP]")
  118. ELSE
  119. (* output first line *)
  120. w.String("["); w.Int(trapState[id], 1); w.String("] ");
  121. w.String("TRAP "); w.Int(SHORT(exc.halt), 1); w.String(" ");
  122. CASE exc.halt OF
  123. DivisionError: w.String(DivisionErrorDesc)
  124. |WithError: w.String(WithErrorDesc)
  125. |CaseError: w.String(CaseErrorDesc)
  126. |ReturnError: w.String(ReturnErrorDesc)
  127. |IntOverflow: w.String(IntOverflowDesc)
  128. |ImplicitTypeGuardError: w.String(ImplicitTypeGuardErrorDesc)
  129. |TypeGuardError: w.String(TypeGuardErrorDesc)
  130. |IndexOutOfRange: w.String(IndexOutOfRangeDesc)
  131. |AssertError: w.String(AssertErrorDesc)
  132. |ArraySize: w.String(ArraySizeDesc)
  133. |ArrayForm: w.String(ArrayFormDesc)
  134. |SetElement: w.String(SetElementDesc)
  135. |NegativeDivisor: w.String(NegativeDivisorDesc)
  136. |KeyboardInt: w.String(KeyboardIntDesc)
  137. |OutOfMemory: w.String(OutOfMemoryDesc)
  138. |Deadlock: w.String(DeadlockDesc)
  139. |ProcedureReturned: w.String(ProcedureReturnedDesc)
  140. |UndefinedInstn: w.String(UndefinedInstnDesc); w.String(": "); w.Hex(exc.instn,-8)
  141. |NilPointer: w.String(NilPointerDesc)
  142. |MemoryError: w.String(MemoryErrorDesc); w.String(" at "); w.Address(exc.pf)
  143. |ExceptionRaised: w.String(ExceptionRaisedDesc)
  144. ELSE
  145. (* To avoid huge sparse case table *)
  146. CASE exc.halt OF
  147. ProcessResurrected: w.String(ProcessResurrectedDesc)
  148. |RecursiveExclusive: w.String(RecursiveExclusiveDesc)
  149. |AwaitOutsideExclusive: w.String(AwaitOutsideExclusiveDesc)
  150. ELSE
  151. w.String("HALT statement: ");
  152. w.Int(exc.halt, 0)
  153. END
  154. END;
  155. IF exc.locks # {} THEN
  156. w.String(", Locks: "); w.Set(exc.locks)
  157. END;
  158. w.Char(" "); w.String(Machine.version);
  159. IF long THEN
  160. w.Char(0EX); (* "fixed font" *)
  161. w.Ln;
  162. (* output values *)
  163. Val("R0", int.R[0]); w.Char(' '); Val("R1", int.R[1]); w.Char(' '); Val("R2", int.R[2]); w.Char(' '); Val("R3", int.R[3]); w.Ln;
  164. Val("R4", int.R[4]); w.Char(' '); Val("R5", int.R[5]); w.Char(' '); Val("R6", int.R[6]); w.Char(' '); Val("R7", int.R[7]); w.Ln;
  165. Val("R8", int.R[8]); w.Char(' '); Val("R9", int.R[9]); w.Char(' '); Val("R10", int.R[10]); Val("R11", int.R[11]); w.Ln;
  166. Val("FP", int.BP); w.Char(' '); Val("SP", int.SP); w.Char(' '); Val("LR", int.LR); w.Char(' '); Val("PC", int.PC); w.Ln;
  167. Val("PSR", int.PSR); w.Ln;
  168. Val("Ticks", Kernel.GetTicks()); Val("Timer", Machine.GetTimer()); w.Ln
  169. ELSE
  170. w.Ln
  171. END;
  172. w.Char(' '); w.String("CPU="); w.Int(1, 0); w.Ln;
  173. IF exc.halt = UndefinedInstn THEN
  174. Val("Instruction", exc.instn)
  175. ELSIF exc.halt = MemoryError THEN
  176. Val("Location", exc.pf);
  177. IF exc.status # - 1 THEN
  178. Val("Status", exc.status)
  179. END
  180. END;
  181. w.Ln;
  182. w.String("Process:"); Reflection.WriteProcess(w, p); w.Ln;
  183. w.String("Stack Traceback:"); w.Ln;
  184. Reflection.StackTraceBack(w, int.PC, int.BP, int.SP, Objects.GetStackBottom(p), long, overflow);
  185. END;
  186. w.String("---------------------------------"); w.Ln;
  187. w.Char(02X); (* "end of trap" *)
  188. w.Update;
  189. TrapWriters.Trapped();
  190. trapState[id] := 0
  191. END Show;
  192. PROCEDURE SetLastExceptionState(ex: Machine.ExceptionState);
  193. VAR id: LONGINT;
  194. BEGIN
  195. id := Machine.AcquirePreemption();
  196. Objects.running[id].exp := ex;
  197. Machine.ReleasePreemption;
  198. END SetLastExceptionState;
  199. PROCEDURE GetLastExceptionState*(): Machine.ExceptionState;
  200. VAR
  201. id: LONGINT;
  202. ex: Machine.ExceptionState;
  203. BEGIN
  204. id := Machine.AcquirePreemption();
  205. ex := Objects.running[id].exp;
  206. Machine.ReleasePreemption;
  207. RETURN ex;
  208. END GetLastExceptionState;
  209. (** Handles an exception. Interrupts are on during this procedure. *)
  210. PROCEDURE HandleException(VAR int: Machine.State; VAR exc: Machine.ExceptionState; VAR handled: BOOLEAN);
  211. VAR
  212. bp, sp, pc, handler: ADDRESS;
  213. BEGIN
  214. bp := int.BP; sp := int.SP; pc := int.PC;
  215. handler := Modules.GetExceptionHandler(pc);
  216. IF handler # -1 THEN (* Handler in the current PAF *)
  217. int.PC := handler; handled := TRUE;
  218. SetTrapVariable(pc, bp); SetLastExceptionState(exc)
  219. ELSE
  220. WHILE (bp # 0) & (handler = -1) DO
  221. SYSTEM.GET(bp + 4, pc);
  222. pc := pc - 1; (* CALL instruction, machine dependant!!! *)
  223. handler := Modules.GetExceptionHandler(pc);
  224. sp := bp; (* Save the old basepointer into the stack pointer *)
  225. SYSTEM.GET(bp, bp) (* Unwind PAF *)
  226. END;
  227. IF handler = -1 THEN
  228. handled := FALSE;
  229. ELSE
  230. int.PC := handler; int.BP := bp; int.SP := sp;
  231. SetTrapVariable(pc, bp); SetLastExceptionState(exc);
  232. handled := TRUE
  233. END
  234. END
  235. END HandleException;
  236. PROCEDURE SetTrapVariable(pc, fp: ADDRESS);
  237. VAR
  238. varadr: ADDRESS;
  239. BEGIN
  240. varadr := Reflection.GetVariableAdr(pc, fp, "trap");
  241. IF varadr # -1 THEN
  242. SYSTEM.PUT8(varadr, 1)
  243. END
  244. END SetTrapVariable;
  245. (* Unbreakable stack trace back with regard to every FINALLY on the way *)
  246. PROCEDURE Unbreakable(p: Objects.Process; VAR int: Machine.State; VAR exc: Machine.ExceptionState; VAR handled: BOOLEAN);
  247. VAR
  248. bp, bpSave, pc, handler, bpBottom:ADDRESS;
  249. hasFinally : BOOLEAN;
  250. BEGIN
  251. bp := int.BP;
  252. pc := int.PC;
  253. hasFinally := FALSE;
  254. handler := Modules.GetExceptionHandler(pc);
  255. (* Handler in the current PAF *)
  256. IF handler # -1 THEN
  257. int.PC := handler;
  258. hasFinally := TRUE;
  259. SetTrapVariable(pc, bp);
  260. END;
  261. (* The first waypoint is the bp of the top PAF *)
  262. bpSave := bp;
  263. WHILE (bp # 0) DO
  264. (* Did we reach the last PAF? *)
  265. SYSTEM.GET(bp, pc);
  266. IF (pc = 0) THEN
  267. bpBottom := bp; (* Save the FP of the last PAF *)
  268. END;
  269. (* Get the return pc *)
  270. SYSTEM.GET(bp + SIZEOF(ADDRESS), pc);
  271. handler := Modules.GetExceptionHandler(pc);
  272. (* Save the last framepointer as stackpointer *)
  273. IF ~hasFinally THEN
  274. int.SP := bp;
  275. END;
  276. SYSTEM.GET(bp, bp);
  277. (* Here bp may be 0. *)
  278. IF (handler # -1) & (bp # 0) THEN (* If Objects.Terminate has a FINALLY this doesn't work !!! *)
  279. IF hasFinally THEN
  280. (* Connect Finally to Finally *)
  281. SYSTEM.PUT(bpSave + SIZEOF(ADDRESS), handler); (* Adapt the return pc *)
  282. SYSTEM.PUT(bpSave, bp); (* Adapt the dynamic link *)
  283. bpSave := bp;
  284. ELSE
  285. int.PC := handler;
  286. int.BP := bp;
  287. bpSave := bp;
  288. hasFinally := TRUE;
  289. END;
  290. SetTrapVariable(pc, bp)
  291. END
  292. END;
  293. (* Now bp = 0, bottom of the stack, so link the last known return PC to the Termination *)
  294. IF ~hasFinally THEN
  295. SYSTEM.GET(bpBottom + SIZEOF(ADDRESS), pc); (* PC of the Terminate *)
  296. int.PC := pc;
  297. int.BP := bpBottom;
  298. ELSIF bpSave # bpBottom THEN
  299. SYSTEM.GET(bpBottom + SIZEOF(ADDRESS), pc); (* PC of the Terminate *)
  300. SYSTEM.PUT(bpSave + SIZEOF(ADDRESS), pc);
  301. SetLastExceptionState(exc)
  302. END;
  303. handled := TRUE; (* If FALSE the process could be restarted, may be this is the meaning? *)
  304. END Unbreakable;
  305. (* General exception handler. *)
  306. PROCEDURE Exception(VAR int: Machine.State);
  307. VAR t: Objects.Process; exc: Machine.ExceptionState; user, traceTrap, handled: BOOLEAN;
  308. BEGIN (* interrupts off *)
  309. t := Objects.running[Machine.ID()]; (* t is running process *)
  310. handled := FALSE;
  311. Machine.GetExceptionState(int, exc);
  312. user := TRUE;
  313. traceTrap := (exc.locks = {}) & (exc.halt >= MAX(INTEGER)) & (exc.halt <= MAX(INTEGER)+1);
  314. Show(t, int, exc, (exc.halt # MAX(INTEGER)+1) & (trapState[Machine.ID()] = 0)); (* Always show the trap info!*)
  315. IF exc.halt = haltUnbreakable THEN
  316. Unbreakable(t, int, exc, handled)
  317. ELSIF ~ traceTrap THEN
  318. HandleException( int, exc, handled)
  319. END;
  320. IF ~handled THEN
  321. (* Taken from Machine to allow the FINALLY in the kernel *)
  322. exc.locks := Machine.BreakAll();
  323. IF ~traceTrap THEN (* trap *)
  324. IF user THEN (* return to outer level *)
  325. IF TraceVerbose THEN
  326. KernelLog.Enter;
  327. KernelLog.String("Jump"); KernelLog.Hex(t.restartPC, 9);
  328. KernelLog.Hex(t.restartSP, 9); KernelLog.Hex(t.stack.high, 9);
  329. KernelLog.Exit
  330. END;
  331. int.BP := t.restartSP; int.SP := t.restartSP; (* reset stack *)
  332. int.PC := t.restartPC; (* restart object body or terminate *)
  333. ELSE (* trap was in kernel (interrupt handler) *) (* fixme: recover from trap in stack traceback *)
  334. Machine.EnableInterrupts();
  335. KernelLog.Enter; KernelLog.String("Kernel halt"); KernelLog.Exit;
  336. Machine.Shutdown(FALSE)
  337. END
  338. END
  339. END;
  340. IF Objects.PleaseHalt IN t.flags THEN
  341. EXCL(t.flags, Objects.PleaseHalt);
  342. IF Objects.Unbreakable IN t.flags THEN EXCL(t.flags, Objects.Unbreakable) END;
  343. IF Objects.SelfTermination IN t.flags THEN EXCL(t.flags, Objects.SelfTermination) END
  344. END
  345. END Exception;
  346. (* Page fault handler. *)
  347. PROCEDURE PageFault(VAR state: Machine.State);
  348. VAR
  349. t: Objects.Process;
  350. adr: ADDRESS;
  351. ignored: LONGINT;
  352. BEGIN
  353. t := Objects.running[Machine.ID()];
  354. Machine.GetPageFault(adr, ignored);
  355. (*IF Machine.IFBit IN state.FLAGS THEN (* enable interrupts again if they were enabled *)
  356. Machine.Sti() (* avoid Processors.StopAll deadlock when waiting for locks below (fixme: remove) *)
  357. END;*)
  358. IF adr > 4096 THEN
  359. (* Not a NIL pointer, maybe stack overflow? *)
  360. IF (t = NIL) OR ~Machine.ExtendStack(t.stack, adr) THEN
  361. IF TraceVerbose THEN
  362. IF t = NIL THEN
  363. KernelLog.Enter; KernelLog.String("GrowStack running=NIL");
  364. KernelLog.Hex(state.PC, 9); KernelLog.Exit
  365. ELSE
  366. KernelLog.Enter;
  367. KernelLog.String("GrowStack failed, pf="); KernelLog.Hex(adr, 8);
  368. KernelLog.String(" adr="); KernelLog.Hex(t.stack.adr, 8);
  369. KernelLog.String(" high="); KernelLog.Hex(t.stack.high, 8);
  370. KernelLog.Exit
  371. END
  372. END;
  373. Exception(state)
  374. ELSE
  375. IF TraceVerbose THEN
  376. KernelLog.Enter; KernelLog.String("GrowStack");
  377. KernelLog.Hex(t.stack.adr, 9); KernelLog.Hex(t.stack.high, 9); KernelLog.Exit
  378. END
  379. END;
  380. ELSE
  381. Exception(state)
  382. END
  383. END PageFault;
  384. PROCEDURE Init;
  385. VAR i: LONGINT; s: ARRAY 8 OF CHAR;
  386. BEGIN
  387. IF TestTrap THEN
  388. Machine.GetConfig("TestTrap", s);
  389. IF s[0] = "1" THEN HALT(98) END
  390. END;
  391. FOR i := 0 TO Machine.MaxCPU-1 DO trapState[i] := 0 END;
  392. Machine.InstallExceptionHandler(PageFault, Machine.Data);
  393. Machine.InstallExceptionHandler(PageFault, Machine.Prefetch);
  394. Machine.InstallExceptionHandler(Exception, Machine.Undef);
  395. Machine.InstallExceptionHandler(Exception, Machine.Swi);
  396. Machine.InstallExceptionHandler(Exception, Machine.Fiq);
  397. IF TestTrap & (s[0] = "2") THEN HALT(99) END
  398. END Init;
  399. BEGIN
  400. modes := " rdy run awl awc awe rip"; (* 4 characters per mode from Objects.Ready to Objects.Terminated *)
  401. flags := "c!p!a!zstido"; (* bottom flags, !=reserved *)
  402. Init
  403. END Traps.
  404. (*
  405. 12.03.1998 pjm Started
  406. 06.08.1998 pjm Exported Show and removed AosException upcall installation & Modules lock
  407. 10.12.1998 pjm New refblk
  408. 23.06.1999 pjm State added
  409. *)
  410. (*
  411. to do:
  412. o stack overflow message is not correctly displayed in case of dynamic arrays (EDI = CR2, ESP # CR2)
  413. o fix KernelLog.Memory calls removed when switching to Streams
  414. o fix use of KernelLog lock in Show
  415. o if allowing modification of variables using their descriptors, it should also have reference to module to avoid gc after free.
  416. *)