Generic.Unix.Traps.Mod 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. (* ETH Oberon, Copyright 2000 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich.
  2. Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *)
  3. MODULE Traps; (** AUTHOR "G.F."; PURPOSE "Exception Trap and symbolic debugging"; *)
  4. (* 2000.02.06 g.f. UnixOberon release 2.3.6d *)
  5. (* 2006.07.09 g.f. UnixAos version *)
  6. IMPORT S := SYSTEM, Trace, Glue, Unix, Objects, Machine, Heaps, Streams, Modules, Reflection,
  7. TrapWriters, Commands, StdIO;
  8. CONST
  9. AddrSize = SIZEOF( ADDRESS );
  10. MaxRecursion = 4;
  11. TYPE
  12. ExceptionHandler = RECORD pc, fp, sp: ADDRESS END;
  13. VAR
  14. TrapHandlingLevel: LONGINT;
  15. trace: BOOLEAN;
  16. unix: Commands.Context;
  17. trapMutex: Unix.Mutex_t;
  18. PROCEDURE Append( VAR ar: ARRAY OF CHAR; CONST this: ARRAY OF CHAR );
  19. VAR i, j: LONGINT;
  20. BEGIN
  21. i := 0; j := 0;
  22. WHILE ar[i] # 0X DO INC( i ) END;
  23. WHILE (i < LEN( ar ) - 1) & (this[j] # 0X) DO ar[i] := this[j]; INC( i ); INC( j ) END;
  24. ar[i] := 0X
  25. END Append;
  26. PROCEDURE TimeTag( w: Streams.Writer );
  27. VAR
  28. tv: Unix.Timeval; tz: Unix.Timezone; t: Unix.TmPtr; ret: LONGINT;
  29. PROCEDURE Int( i: LONGINT );
  30. BEGIN
  31. IF i < 10 THEN w.Char( '0' ) END;
  32. w.Int( i, 0 )
  33. END Int;
  34. BEGIN
  35. ret := Unix.gettimeofday( tv, tz );
  36. t := Unix.localtime( tv );
  37. w.Int( 1900 + t.year, 4 ); w.Char( '/' ); Int( t.mon + 1 ); w.Char( '/' ); Int( t.mday );
  38. w.String( " " ); Int( t.hour ); w.Char( ':' ); Int( t.min ); w.Ln;
  39. END TimeTag;
  40. PROCEDURE FinishTrap( w: Streams.Writer; p: Objects.Process );
  41. VAR tag: ADDRESS; td: Modules.TypeDesc; name: ARRAY 72 OF CHAR;
  42. BEGIN
  43. w.Char( 2X ); (* end of trap text *)
  44. w.Update;
  45. TrapWriters.Trapped;
  46. IF p.obj = NIL THEN (* the main thread is not associated with any object *)
  47. Unix.exit( -1 )
  48. ELSE
  49. S.GET( S.VAL( ADDRESS, p.obj ) - AddrSize, tag );
  50. S.GET( tag - AddrSize, td );
  51. IF td.mod # NIL THEN
  52. COPY( td.mod.name, name ); Append( name, "." ); Append( name, td.name );
  53. IF name = "Oberon.System.OberonRunner" THEN UnlockOberon END
  54. END
  55. END;
  56. END FinishTrap;
  57. PROCEDURE Registers(CONST c:Unix.McontextDesc; w: Streams.Writer);
  58. BEGIN
  59. w.String("EAX= "); w.Address(c.r_ax);
  60. w.String(" EBX= "); w.Address(c.r_bx);
  61. w.String(" ECX= "); w.Address(c.r_cx);
  62. w.String(" EDX= "); w.Address(c.r_dx);
  63. w.String(" ESI= "); w.Address(c.r_si);
  64. w.String(" EDI= "); w.Address(c.r_di);
  65. w.Ln;
  66. END Registers;
  67. PROCEDURE Trap( sig: LONGINT; ucp: Unix.Ucontext);
  68. VAR
  69. pc, sp, bp: ADDRESS;
  70. trapno: LONGINT;
  71. process: Objects.Process;
  72. handler: ExceptionHandler;
  73. w: Streams.Writer;
  74. BEGIN
  75. Trace.Char("Z");
  76. IF trace THEN
  77. Trace.String( "Aos Trap: signal = " ); Trace.Int( sig, 0 );
  78. Trace.String( ", ucp = " ); Trace.Address( S.VAL( ADDRESS, ucp ) );
  79. Trace.String( ", traphandling level = " ); Trace.Int( TrapHandlingLevel, 1 );
  80. Trace.Ln;
  81. END;
  82. Unix.MtxLock(trapMutex);
  83. INC( TrapHandlingLevel );
  84. w := TrapWriters.GetWriter();
  85. w.Char( 1X ); (* begin of trap text *)
  86. Trace.Char("Y");
  87. w.Ln;
  88. w.String( Machine.version ); w.String( " " ); TimeTag( w ); w.Ln;
  89. IF TrapHandlingLevel <= MaxRecursion THEN
  90. w.String( "Trap " );
  91. ELSE
  92. w.String( "[recursive Trap] " );
  93. END;
  94. sp := ucp.mc.r_sp;
  95. CASE sig OF
  96. | 1: w.String( "1 (Hangup signal)" );
  97. | 2: w.String( "2 (User interrupt)" );
  98. | 3: w.String( "3 (Quit signal)" );
  99. | 4: w.String( "4 (Illegal instruction)" );
  100. | 5: w.String( "5." );
  101. S.GET( sp, trapno ); w.Int( trapno, 0 );
  102. CASE trapno OF
  103. | 1: w.String( " (WITH guard failed)" )
  104. | 2: w.String( " (CASE invalid)" )
  105. | 3: w.String( " (RETURN missing)" )
  106. | 5: w.String( " (implicit type guard failed)" )
  107. | 6: w.String( " (type guard failed)" )
  108. | 7: w.String( " (index out of range)" )
  109. | 8: w.String( " (ASSERT failed)" )
  110. | 9: w.String( " (array dimension error)" )
  111. |12: w.String( " (division error)" )
  112. ELSE
  113. IF trapno >= 30 THEN w.String( " (programmed HALT)" )
  114. ELSE w.String( " (unknown exception)" )
  115. END
  116. END;
  117. | 8: w.String( "8 (Arithmetic exception)" );
  118. |10: w.String( "10 (Bus Error)" )
  119. |11: w.String( "11 (Segmentation violation)" )
  120. |13: w.String( "13 (Broken pipe)" )
  121. |14: w.String( "14 (Alarm signal)" )
  122. ELSE
  123. w.String( "(Signal " ); w.Int( sig, 0 ); w.Char( ')' );
  124. END;
  125. w.Ln;
  126. IF TrapHandlingLevel <= MaxRecursion THEN
  127. process := Objects.CurrentProcess( );
  128. pc := ucp.mc.r_pc; bp := ucp.mc.r_bp;
  129. IF pc = 0 THEN
  130. (* assume call of procedure variable with value NIL *)
  131. S.GET( sp, pc ); (* get return address on top of stack *)
  132. END;
  133. w.Ln;
  134. w.String( " sp = " ); w.Address( sp ); w.String( ", fp = " ); w.Address( bp );
  135. w.String( ", pc = " ); w.Address( pc ); w.Ln;
  136. w.Ln;
  137. Registers(ucp.mc,w);
  138. Reflection.StackTraceBack( w, pc, bp, sp, Objects.GetStackBottom( process ), TRUE, FALSE );
  139. SearchExceptionHandler( process, ucp, handler );
  140. END;
  141. w.Ln; w.Ln;
  142. w.String("----------------------------------------------------"); w.Ln;
  143. IF (TrapHandlingLevel > MaxRecursion) THEN Machine.Shutdown( FALSE ) END;
  144. FinishTrap( w, process);
  145. TrapHandlingLevel := 0;
  146. Unix.MtxUnlock(trapMutex);
  147. IF handler.pc # 0 THEN
  148. IF Unix.Version # "Darwin" THEN
  149. (* in the Darwin port Unix.ModifyContext fails with bus error. Stack alignment problem? *)
  150. w.Ln;
  151. w.String( "### program continues with exception handler ###" ); w.Ln;
  152. Unix.ModifyContext( ucp, handler.pc, handler.fp, handler.sp );
  153. RETURN (*! to exception handler !! *)
  154. END
  155. END;
  156. IF Machine.standaloneAppl THEN
  157. unix.error.Ln; unix.error.Ln;
  158. unix.error.String( "### Program aborted. Stack traceback in logfile" ); unix.error.Ln;
  159. unix.error.Update;
  160. Machine.Shutdown( FALSE )
  161. ELSIF TrapHandlingLevel > MaxRecursion THEN
  162. Objects.Terminate
  163. ELSE
  164. Objects.ExitTrap()
  165. END
  166. END Trap;
  167. PROCEDURE UnlockOberon;
  168. CONST OberonKernel = "Oberon.Kernel";
  169. VAR c: PROCEDURE;
  170. BEGIN
  171. IF Modules.ModuleByName( OberonKernel ) # NIL THEN
  172. GETPROCEDURE( OberonKernel, "UnlockOberon", c );
  173. IF c # NIL THEN c END
  174. END;
  175. END UnlockOberon;
  176. PROCEDURE CheckBP(fp: ADDRESS): ADDRESS;
  177. VAR n: ADDRESS;
  178. BEGIN
  179. IF (fp # NIL) THEN
  180. S.GET(fp, n);
  181. IF ODD(n) THEN RETURN fp + SIZEOF(ADDRESS) END;
  182. END;
  183. RETURN fp;
  184. END CheckBP;
  185. PROCEDURE SearchExceptionHandler( process: Objects.Process; cont: Unix.Ucontext; VAR handler: ExceptionHandler );
  186. VAR entry, fp, sp, pc: ADDRESS;
  187. BEGIN
  188. handler.pc := 0; (* no handler *)
  189. pc := cont.mc.r_pc; fp := cont.mc.r_bp; sp := cont.mc.r_sp;
  190. IF pc = 0 THEN
  191. (* assume call of procedure variable with value NIL *)
  192. S.GET( sp, pc ); (* get return address on top of stack *)
  193. END;
  194. entry := Modules.GetExceptionHandler( pc );
  195. WHILE (entry = -1) & (fp <= process.stackBottom) & (fp#0) DO
  196. fp := CheckBP(fp);
  197. S.GET( fp + AddrSize, pc );
  198. pc := pc - 1; (* CALL instruction, machine dependent!!! *)
  199. entry := Modules.GetExceptionHandler( pc );
  200. sp := fp; (* Save the old framepointer into the stack pointer *)
  201. S.GET( fp, fp ) (* Unwind PAF *)
  202. END;
  203. IF entry # -1 THEN
  204. handler.pc := entry; handler.fp := fp; handler.sp := sp
  205. END
  206. END SearchExceptionHandler;
  207. PROCEDURE SignalHandler( signal: LONGINT; scp, ucp, dummy: ADDRESS );
  208. (* 'dummy' for 16 byte stack alignment, MacOS! *)
  209. BEGIN
  210. IF ~(signal IN {1, 2, 14, 15}) (* SIGHUP, SIGINT, SIGALRM, SIGTERM *) THEN
  211. IF trace THEN
  212. Trace.String( "Traps.SignalHander: received signal " );
  213. Trace.Int( signal, 1 ); Trace.Ln
  214. END;
  215. (*IF Heaps.collecting THEN
  216. Trace.Ln; Trace.String( "PANIC: Trap " ); Trace.Int( signal, 0 );
  217. Trace.String( " in garbage collector" ); Trace.Ln; Trace.Ln;
  218. Machine.Release( Machine.Heaps );
  219. Trap( signal, S.VAL( Unix.Ucontext, ucp ), TRUE )
  220. ELSE
  221. *)
  222. Trap( signal, S.VAL( Unix.Ucontext, ucp ))
  223. (* END *)
  224. END
  225. END SignalHandler;
  226. BEGIN
  227. trapMutex := Unix.RecursiveMtxInit(0);
  228. trace := 3 IN Glue.debug;
  229. Unix.InstallSignalHandler( SignalHandler );
  230. unix := StdIO.env
  231. END Traps.