ntdll: Avoid reading DR6 if possible

Petr Tesarik hat at tesarici.cz
Mon Mar 27 07:49:13 CST 2006


Hi,

in reaction to Juliard's comments, I've sent this patch which avoids
the need to read DR6 for each SIGTRAP on some platforms.

The major change is that we use the siginfo structure to distinguish
between kill() and a hardware interrupt.  A fallback is still provided
if si_code is not available, but that might require a wineserver
request, or may generate a SIGSEGV.

Since the improvement requires to use the new-style signal handlers
and these are supported by newer Linux kernels, I've changed the
default on Linux to SA_SIGINFO handlers.

(Apply this patch after the previous one on the same issue, or ask me
to send a patch against the current CVS, but that one might be pretty
large.)

ChangeLog:

* Use si_code from siginfo to decide on the reason of a SIGTRAP
* Use SA_SIGINFO on Linux if available
-------------- next part --------------
--- signal_i386.c	2006-03-27 14:46:21.000000000 +0200
+++ signal_i386.c.siginfo	2006-03-27 14:56:02.000000000 +0200
@@ -65,6 +65,65 @@
  */
 
 #ifdef linux
+#ifdef HAVE_UCONTEXT_H
+#include <ucontext.h>
+typedef ucontext_t SIGCONTEXT;
+
+#define HANDLER_DEF(name) void name( int __signal, siginfo_t *__siginfo, SIGCONTEXT *__context )
+#define HANDLER_CONTEXT __context
+
+#ifndef REG_EAX
+# define REG_GS		0
+# define REG_FS		1
+# define REG_ES		2
+# define REG_DS		3
+# define REG_EDI	4
+# define REG_ESI	5
+# define REG_EBP	6
+# define REG_ESP	7
+# define REG_EBX	8
+# define REG_EDX	9
+# define REG_ECX	10
+# define REG_EAX	11
+# define REG_TRAPNO	12
+# define REG_ERR	13
+# define REG_EIP	14
+# define REG_CS		15
+# define REG_EFL	16
+# define REG_UESP	17
+# define REG_SS		18
+#endif /* REG_EAX */
+
+#define EAX_sig(context)     ((context)->uc_mcontext.gregs[REG_EAX])
+#define EBX_sig(context)     ((context)->uc_mcontext.gregs[REG_EBX])
+#define ECX_sig(context)     ((context)->uc_mcontext.gregs[REG_ECX])
+#define EDX_sig(context)     ((context)->uc_mcontext.gregs[REG_EDX])
+#define ESI_sig(context)     ((context)->uc_mcontext.gregs[REG_ESI])
+#define EDI_sig(context)     ((context)->uc_mcontext.gregs[REG_EDI])
+#define EBP_sig(context)     ((context)->uc_mcontext.gregs[REG_EBP])
+
+#define CS_sig(context)      ((context)->uc_mcontext.gregs[REG_CS])
+#define DS_sig(context)      ((context)->uc_mcontext.gregs[REG_DS])
+#define ES_sig(context)      ((context)->uc_mcontext.gregs[REG_ES])
+#define FS_sig(context)      ((context)->uc_mcontext.gregs[REG_FS])
+#define GS_sig(context)      ((context)->uc_mcontext.gregs[REG_GS])
+#define SS_sig(context)      ((context)->uc_mcontext.gregs[REG_SS])
+
+#define EFL_sig(context)     ((context)->uc_mcontext.gregs[REG_EFL])
+
+#define EIP_sig(context)     ((context)->uc_mcontext.gregs[REG_EIP])
+#define ESP_sig(context)     ((context)->uc_mcontext.gregs[REG_ESP])
+
+#define TRAP_sig(context)    ((context)->uc_mcontext.gregs[REG_TRAPNO])
+
+#define FPU_sig(context)     ((FLOATING_SAVE_AREA*)((context)->uc_mcontext.fpregs))
+#define ERROR_sig(context)   ((context)->uc_mcontext.gregs[REG_ERR])
+
+#define CODE_sig(context)    (__siginfo->si_code)
+#define FAULT_ADDRESS        (__siginfo->si_addr)
+
+#else  /* HAVE_UCONTEXT_H */
+
 typedef struct
 {
     unsigned short sc_gs, __gsh;
@@ -91,9 +150,37 @@
     unsigned long cr2;
 } volatile SIGCONTEXT;
 
+#define EAX_sig(context)     ((context)->sc_eax)
+#define EBX_sig(context)     ((context)->sc_ebx)
+#define ECX_sig(context)     ((context)->sc_ecx)
+#define EDX_sig(context)     ((context)->sc_edx)
+#define ESI_sig(context)     ((context)->sc_esi)
+#define EDI_sig(context)     ((context)->sc_edi)
+#define EBP_sig(context)     ((context)->sc_ebp)
+
+#define CS_sig(context)      ((context)->sc_cs)
+#define DS_sig(context)      ((context)->sc_ds)
+#define ES_sig(context)      ((context)->sc_es)
+#define FS_sig(context)      ((context)->sc_fs)
+#define GS_sig(context)      ((context)->sc_gs)
+#define SS_sig(context)      ((context)->sc_ss)
+
+#define TRAP_sig(context)    ((context)->sc_trapno)
+
+#define ERROR_sig(context)   ((context)->sc_err)
+#define FPU_sig(context)     ((FLOATING_SAVE_AREA*)((context)->i387))
+#define FAULT_ADDRESS        ((void *)HANDLER_CONTEXT->cr2)
+
+#define EFL_sig(context)     ((context)->sc_eflags)
+
+#define EIP_sig(context)     (*((unsigned long*)&(context)->sc_eip))
+#define ESP_sig(context)     (*((unsigned long*)&(context)->sc_esp))
+
 #define HANDLER_DEF(name) void name( int __signal, SIGCONTEXT __context )
 #define HANDLER_CONTEXT (&__context)
 
+#endif /* HAVE_UCONTEXT */
+
 /* this is the sigaction structure from the Linux 2.1.20 kernel.  */
 struct kernel_sigaction
 {
@@ -336,10 +423,11 @@
 #define ERROR_sig(context)   ((context)->uc_mcontext->es.err)
 
 #define FAULT_ADDRESS        (__siginfo->si_addr)
+#define CODE_sig(context)    (__siginfo->si_code)
 
 #endif /* __APPLE__ */
 
-#if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ||\
+#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) ||\
     defined(__OpenBSD__) || defined(__EMX__) || defined(__CYGWIN__)
 
 #define EAX_sig(context)     ((context)->sc_eax)
@@ -363,12 +451,6 @@
 #define ERROR_sig(context)   ((context)->sc_err)
 #endif
 
-#ifdef linux
-#define ERROR_sig(context)   ((context)->sc_err)
-#define FPU_sig(context)     ((FLOATING_SAVE_AREA*)((context)->i387))
-#define FAULT_ADDRESS        ((void *)HANDLER_CONTEXT->cr2)
-#endif
-
 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #define EFL_sig(context)     ((context)->sc_efl)
 /* FreeBSD, see i386/i386/traps.c::trap_pfault va->err kludge  */
@@ -380,7 +462,7 @@
 #define EIP_sig(context)     (*((unsigned long*)&(context)->sc_eip))
 #define ESP_sig(context)     (*((unsigned long*)&(context)->sc_esp))
 
-#endif  /* linux || __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
+#endif  /* __NetBSD__ || __FreeBSD__ || __OpenBSD__ */
 
 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
 
@@ -419,6 +501,7 @@
 #endif
 
 #define FAULT_ADDRESS         (__siginfo->si_addr)
+#define CODE_sig(context)     (__siginfo->si_code)
 
 #endif  /* svr4 || SCO_DS */
 
@@ -471,6 +554,29 @@
 }
 
 
+/**********************************************************************
+ *		get_signal_origin
+ *
+ * Can be used from within signal handlers to determine the
+ * origin of the signal.  Return values:
+ *
+ *   1 signal originated from user-space, i.e. by kill(),
+ *     sigsend(), raise(), tkill(), etc.
+ *
+ *   0 kernel-generated signal
+ *
+ *  -1 unknown (not available on this platform)
+ *
+ * This cannot be an inline function, since the information is
+ * actually in __siginfo, not in context. :((
+ *
+ */
+#ifdef CODE_sig
+#define get_signal_origin(context)	(CODE_sig(context) <= 0 ? 1 : 0)
+#else
+#define get_signal_origin(context)	-1
+#endif
+
 /***********************************************************************
  *           get_trap_code
  *
@@ -1354,22 +1460,55 @@
 {
     EXCEPTION_RECORD *rec;
 
-    switch(get_trap_code(HANDLER_CONTEXT))
+    if (get_signal_origin(HANDLER_CONTEXT) == 1)
     {
-    case TRAP_x86_UNKNOWN:  /* TRAP_code not available */
-        rec = setup_exception( HANDLER_CONTEXT, raise_trap_exception );
-        break;
-    case TRAP_x86_TRCTRAP:  /* Single-step exception */
-        rec = setup_exception( HANDLER_CONTEXT, raise_singlestep_exception );
-        break;
-    case TRAP_x86_BPTFLT:   /* Breakpoint exception */
-        rec = setup_exception( HANDLER_CONTEXT, raise_breakpoint_exception );
-        break;
-    default:
-        /* unexpected, so it will have been a user-generated signal */
+        /* user-generated: breakpoint with no backing up */
         rec = setup_exception( HANDLER_CONTEXT, raise_exception );
         rec->ExceptionCode = EXCEPTION_BREAKPOINT;
-        break;
+    }
+    else if (get_signal_origin(HANDLER_CONTEXT) == 0 &&
+             get_trap_code(HANDLER_CONTEXT) != TRAP_x86_UNKNOWN)
+    {
+        /* TRAP_code() is reliable for kernel-generated signals */
+        rec = setup_exception( HANDLER_CONTEXT, raise_exception);
+
+        switch(get_trap_code(HANDLER_CONTEXT))
+        {
+        case TRAP_x86_TRCTRAP:
+            rec->ExceptionCode = EXCEPTION_SINGLE_STEP;
+            break;
+        case TRAP_x86_BPTFLT:
+            /* back up over the int3 instruction */
+            rec->ExceptionAddress = (char *)rec->ExceptionAddress - 1;
+            rec->ExceptionCode = EXCEPTION_BREAKPOINT;
+            break;
+        default:
+            ERR( "Got unexpected trap %d\n", get_trap_code(HANDLER_CONTEXT) );
+            /* fall through */
+            rec->ExceptionCode = EXCEPTION_BREAKPOINT;
+            break;
+        }
+    }
+    else
+    {
+        /* signal origin is unknown, TRAP_code() is semi-reliable */
+        switch(get_trap_code(HANDLER_CONTEXT))
+        {
+        case TRAP_x86_UNKNOWN:  /* TRAP_code not available */
+            rec = setup_exception( HANDLER_CONTEXT, raise_trap_exception );
+            break;
+        case TRAP_x86_TRCTRAP:  /* Single-step exception */
+            rec = setup_exception( HANDLER_CONTEXT, raise_singlestep_exception );
+            break;
+        case TRAP_x86_BPTFLT:   /* Breakpoint exception */
+            rec = setup_exception( HANDLER_CONTEXT, raise_breakpoint_exception );
+            break;
+        default:
+            /* unexpected, so it will have been a user-generated signal */
+            rec = setup_exception( HANDLER_CONTEXT, raise_exception );
+            rec->ExceptionCode = EXCEPTION_BREAKPOINT;
+            break;
+        }
     }
 }
 
@@ -1505,6 +1644,9 @@
         struct kernel_sigaction sig_act;
         sig_act.ksa_handler = func;
         sig_act.ksa_flags   = SA_RESTART;
+#ifdef HAVE_UCONTEXT_H
+	sig_act.ksa_flags  |= SA_SIGINFO;
+#endif
         sig_act.ksa_mask    = (1 << (SIGINT-1)) |
                               (1 << (SIGUSR1-1)) |
                               (1 << (SIGUSR2-1));
@@ -1519,7 +1661,9 @@
     sigaddset( &sig_act.sa_mask, SIGUSR1 );
     sigaddset( &sig_act.sa_mask, SIGUSR2 );
 
-#if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
+#if defined(linux) && defined(HAVE_UCONTEXT_H)
+    sig_act.sa_flags = SA_SIGINFO | SA_RESTART;
+#elif defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
     sig_act.sa_flags = SA_RESTART;
 #elif defined (__svr4__) || defined(_SCO_DS) || defined(__APPLE__)
     sig_act.sa_flags = SA_SIGINFO | SA_RESTART;


More information about the wine-patches mailing list