Generic.Unix.Traps.Mod 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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, Unix, Objects, Machine, Streams, Modules, Reflection,
  7. TrapWriters, Commands, StdIO;
  8. CONST
  9. AddrSize = SIZEOF( ADDRESS );
  10. MaxRecursion = 2;
  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 LockTrap;
  19. BEGIN
  20. Unix.MtxLock( trapMutex );
  21. END LockTrap;
  22. PROCEDURE UnlockTrap;
  23. BEGIN
  24. trapHandlingLevel := 0;
  25. Unix.MtxUnlock( trapMutex )
  26. END UnlockTrap;
  27. PROCEDURE Append( VAR ar: ARRAY OF CHAR; CONST this: ARRAY OF CHAR );
  28. VAR i, j: LONGINT;
  29. BEGIN
  30. i := 0; j := 0;
  31. WHILE ar[i] # 0X DO INC( i ) END;
  32. WHILE (i < LEN( ar ) - 1) & (this[j] # 0X) DO ar[i] := this[j]; INC( i ); INC( j ) END;
  33. ar[i] := 0X
  34. END Append;
  35. PROCEDURE TimeTag( w: Streams.Writer );
  36. VAR
  37. tv: Unix.Timeval; tz: Unix.Timezone; t: Unix.TmPtr; ret: LONGINT;
  38. PROCEDURE Int( i: LONGINT );
  39. BEGIN
  40. IF i < 10 THEN w.Char( '0' ) END;
  41. w.Int( i, 0 )
  42. END Int;
  43. BEGIN
  44. ret := Unix.gettimeofday( tv, tz );
  45. t := Unix.localtime( tv );
  46. w.Int( 1900 + t.year, 4 ); w.Char( '/' ); Int( t.mon + 1 ); w.Char( '/' ); Int( t.mday );
  47. w.String( " " ); Int( t.hour ); w.Char( ':' ); Int( t.min ); w.Ln;
  48. END TimeTag;
  49. PROCEDURE FinishTrap( w: Streams.Writer; p: Objects.Process );
  50. VAR tag: ADDRESS; td: Modules.TypeDesc; name: ARRAY 72 OF CHAR;
  51. BEGIN
  52. w.Char( 2X ); (* end of trap text *)
  53. w.Update;
  54. TrapWriters.Trapped;
  55. IF p.obj = NIL THEN (* the main thread is not associated with any object *)
  56. Unix.exit( -1 )
  57. ELSE
  58. S.GET( S.VAL( ADDRESS, p.obj ) - AddrSize, tag );
  59. S.GET( tag - AddrSize, td );
  60. IF td.mod # NIL THEN
  61. COPY( td.mod.name, name ); Append( name, "." ); Append( name, td.name );
  62. IF name = "Oberon-System.OberonRunner" THEN UnlockOberon END
  63. END
  64. END;
  65. END FinishTrap;
  66. PROCEDURE Registers( CONST mc: Unix.Mcontext; w: Streams.Writer );
  67. BEGIN
  68. w.String( "SP = " ); w.Address( mc.r_sp );
  69. w.String( " FP = " ); w.Address( mc.r_bp );
  70. w.String( " PC = " ); w.Address( mc.r_pc ); w.Ln;
  71. w.String( "EAX = "); w.Address( mc.r_ax );
  72. w.String(" EBX = "); w.Address( mc.r_bx );
  73. w.String(" ECX = "); w.Address( mc.r_cx );
  74. w.String(" EDX = "); w.Address( mc.r_dx );
  75. w.String(" ESI = "); w.Address( mc.r_si );
  76. w.String(" EDI = "); w.Address( mc.r_di ); w.Ln;
  77. END Registers;
  78. PROCEDURE Trap( sig: LONGINT; mc: Unix.Mcontext);
  79. VAR
  80. pc, sp, bp: ADDRESS;
  81. trapno: LONGINT;
  82. process: Objects.Process;
  83. handler: ExceptionHandler;
  84. w: Streams.Writer;
  85. BEGIN
  86. IF sig IN {1, 2, 14, 15} (* SIGHUP, SIGINT, SIGALRM, SIGTERM *) THEN
  87. (* ignore *) RETURN
  88. END;
  89. IF ~Objects.SystemA2Up THEN Machine.VerboseLog( ) END;
  90. LockTrap;
  91. INC( trapHandlingLevel );
  92. IF trapHandlingLevel > MaxRecursion THEN
  93. UnlockTrap;
  94. Objects.Terminate
  95. END;
  96. w := TrapWriters.GetWriter();
  97. w.Char( 1X ); (* begin of trap text *)
  98. w.Ln;
  99. w.String( Machine.version ); w.String( " " ); TimeTag( w ); w.Ln;
  100. IF trapHandlingLevel = 1 THEN
  101. w.String( "Trap " );
  102. ELSE
  103. w.String( "[Recursive Trap] " );
  104. END;
  105. CASE sig OF
  106. | 1: w.String( "1 (Hangup signal)" );
  107. | 2: w.String( "2 (User interrupt)" );
  108. | 3: w.String( "3 (Quit signal)" );
  109. | 4: w.String( "4 (Illegal instruction)" );
  110. | 5: w.String( "5." );
  111. S.GET( mc.r_sp, trapno ); w.Int( trapno, 0 );
  112. CASE trapno OF
  113. | 1: w.String( " (WITH guard failed)" )
  114. | 2: w.String( " (CASE invalid)" )
  115. | 3: w.String( " (RETURN missing)" )
  116. | 5: w.String( " (implicit type guard failed)" )
  117. | 6: w.String( " (type guard failed)" )
  118. | 7: w.String( " (index out of range)" )
  119. | 8: w.String( " (ASSERT failed)" )
  120. | 9: w.String( " (array dimension error)" )
  121. |12: w.String( " (division error)" )
  122. ELSE
  123. IF trapno >= 30 THEN w.String( " (programmed HALT)" )
  124. ELSE w.String( " (unknown exception)" )
  125. END
  126. END;
  127. | Unix.SIGBUS: w.Int( sig, 0 ); w.String( " (Bus Error)" )
  128. | Unix.SIGFPE: w.Int( sig, 0 ); w.String( " (Arithmetic exception)" );
  129. | 11: w.String( "11 (Segmentation violation)" )
  130. | 13: w.String( "13 (Broken pipe)" )
  131. | 14: w.String( "14 (Alarm signal)" )
  132. ELSE
  133. w.String( "(Signal " ); w.Int( sig, 0 ); w.Char( ')' );
  134. END;
  135. w.Ln; w.Ln;
  136. Registers( mc, w );
  137. w.Ln;
  138. process := Objects.CurrentProcess( );
  139. sp := mc.r_sp; pc := mc.r_pc; bp := mc.r_bp;
  140. IF pc = 0 THEN
  141. (* assume call of procedure variable with value NIL *)
  142. S.GET( sp, pc ); (* get return address on top of stack *)
  143. END;
  144. IF process # NIL THEN
  145. Reflection.StackTraceBack( w, pc, bp, sp, Objects.GetStackBottom( process ), TRUE, FALSE );
  146. SearchExceptionHandler( process, mc, handler );
  147. ELSE
  148. (* avoid recusive trap in case of faulty module Objects *)
  149. Reflection.StackTraceBack( w, pc, bp, sp, sp+512, TRUE, FALSE );
  150. END;
  151. w.Ln; w.Ln;
  152. w.String("----------------------------------------------------"); w.Ln;
  153. FinishTrap( w, process);
  154. UnlockTrap;
  155. IF handler.pc # 0 THEN
  156. w.Ln;
  157. w.String( "### program continues with exception handler ###" ); w.Ln;
  158. Unix.ModifyContext( mc, handler.pc, handler.fp, handler.sp );
  159. RETURN (*! to exception handler !! *)
  160. END;
  161. IF Objects.SystemA2Up THEN Objects.ExitTrap( )
  162. ELSE Machine.Shutdown( FALSE )
  163. END
  164. END Trap;
  165. PROCEDURE UnlockOberon;
  166. CONST OberonKernel = "Oberon-Kernel";
  167. VAR c: PROCEDURE;
  168. BEGIN
  169. IF Modules.ModuleByName( OberonKernel ) # NIL THEN
  170. GETPROCEDURE( OberonKernel, "UnlockOberon", c );
  171. IF c # NIL THEN c END
  172. END;
  173. END UnlockOberon;
  174. PROCEDURE CheckBP( fp: ADDRESS ): ADDRESS;
  175. VAR n: ADDRESS;
  176. BEGIN
  177. IF (fp # NIL) THEN
  178. S.GET(fp, n);
  179. IF ODD(n) THEN RETURN fp + SIZEOF(ADDRESS) END;
  180. END;
  181. RETURN fp;
  182. END CheckBP;
  183. PROCEDURE SearchExceptionHandler( process: Objects.Process; mc: Unix.Mcontext; VAR handler: ExceptionHandler );
  184. VAR entry, fp, sp, pc: ADDRESS;
  185. BEGIN
  186. handler.pc := 0; (* no handler *)
  187. pc := mc.r_pc; fp := mc.r_bp; sp := mc.r_sp;
  188. IF pc = 0 THEN
  189. (* assume call of procedure variable with value NIL *)
  190. S.GET( sp, pc ); (* get return address on top of stack *)
  191. END;
  192. entry := Modules.GetExceptionHandler( pc );
  193. WHILE (entry = -1) & (fp <= process.stackBottom) & (fp#0) & (fp MOD SIZEOF(ADDRESS)=0) DO
  194. fp := CheckBP(fp);
  195. S.GET( fp + AddrSize, pc );
  196. pc := pc - 1; (* CALL instruction, machine dependent!!! *)
  197. entry := Modules.GetExceptionHandler( pc );
  198. sp := fp; (* Save the old framepointer into the stack pointer *)
  199. S.GET( fp, fp ) (* Unwind PAF *)
  200. END;
  201. IF entry # -1 THEN
  202. handler.pc := entry; handler.fp := fp; handler.sp := sp
  203. END
  204. END SearchExceptionHandler;
  205. BEGIN
  206. trapMutex := Unix.NewRecursiveMtx( );
  207. trace := FALSE;
  208. Unix.InstallTrap( Trap );
  209. Unix.HandleSignal( Unix.SIGILL ); (* illegal instruction *)
  210. Unix.HandleSignal( Unix.SIGTRAP ); (* exception *)
  211. Unix.HandleSignal( Unix.SIGBUS ); (* bus error *)
  212. Unix.HandleSignal( Unix.SIGFPE ); (* erroneous arithmetics *)
  213. Unix.HandleSignal( Unix.SIGSEGV ); (* segmentation fault *)
  214. unix := StdIO.env
  215. END Traps.