ntdll: Improved implementation of the segv_handler

André Hentschel nerv at dawncrow.de
Mon Jun 20 12:52:51 CDT 2011


---
 dlls/ntdll/signal_arm.c |  157 +++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 132 insertions(+), 25 deletions(-)

diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index ce65688..5bf6669 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -66,6 +66,8 @@ static pthread_key_t teb_key;
  */
 #ifdef linux
 
+typedef ucontext_t SIGCONTEXT;
+
 /* All Registers access - only for local access */
 # define REG_sig(reg_name, context) ((context)->uc_mcontext.reg_name)
 # define REGn_sig(reg_num, context) ((context)->uc_mcontext.arm_r##reg_num)
@@ -75,11 +77,25 @@ static pthread_key_t teb_key;
 # define LR_sig(context)            REG_sig(arm_lr, context)    /* Link register */
 # define PC_sig(context)            REG_sig(arm_pc, context)    /* Program counter */
 # define CPSR_sig(context)          REG_sig(arm_cpsr, context)  /* Current State Register */
-# define IP_sig(context)            REG_sig(arm_ip, context)    /* Program counter (2?) */
+# define IP_sig(context)            REG_sig(arm_ip, context)    /* Intra-Procedure-call scratch register */
 # define FP_sig(context)            REG_sig(arm_fp, context)    /* Frame pointer */
 
+/* Exceptions */
+# define ERROR_sig(context)			REG_sig(error_code, context)
+# define FAULT_sig(context)			REG_sig(fault_address, context)
+# define TRAP_sig(context)			REG_sig(trap_no, context)
+
 #endif /* linux */
 
+enum arm_trap_code
+{
+    TRAP_ARM_UNKNOWN    = -1,  /* Unknown fault (TRAP_sig not defined) */
+    TRAP_ARM_PRIVINFLT  =  6,   /* Invalid opcode exception */
+    TRAP_ARM_PAGEFLT    = 14,  /* Page fault */
+    TRAP_ARM_ALIGNFLT   = 17,  /* Alignment check exception */
+};
+
+typedef void (WINAPI *raise_func)( EXCEPTION_RECORD *rec, CONTEXT *context );
 typedef int (*wine_signal_handler)(unsigned int sig);
 
 static wine_signal_handler handlers[256];
@@ -206,11 +222,25 @@ __ASM_STDCALL_FUNC( RtlCaptureContext, 4,
  *
  * Set the new CPU context.
  */
-void set_cpu_context( const CONTEXT *context )
-{
-    FIXME("not implemented\n");
-    return;
-}
+/* FIXME: What about the CPSR? */
+__ASM_GLOBAL_FUNC( set_cpu_context,
+                   "mov IP, r0\n\t"
+                   "ldr r0,  [IP, #0x4]\n\t"  /* context->R0 */
+                   "ldr r1,  [IP, #0x8]\n\t"  /* context->R1 */
+                   "ldr r2,  [IP, #0xc]\n\t"  /* context->R2 */
+                   "ldr r3,  [IP, #0x10]\n\t" /* context->R3 */
+                   "ldr r4,  [IP, #0x14]\n\t" /* context->R4 */
+                   "ldr r5,  [IP, #0x18]\n\t" /* context->R5 */
+                   "ldr r6,  [IP, #0x1c]\n\t" /* context->R6 */
+                   "ldr r7,  [IP, #0x20]\n\t" /* context->R7 */
+                   "ldr r8,  [IP, #0x24]\n\t" /* context->R8 */
+                   "ldr r9,  [IP, #0x28]\n\t" /* context->R9 */
+                   "ldr r10, [IP, #0x2c]\n\t" /* context->R10 */
+                   "ldr r11, [IP, #0x30]\n\t" /* context->Fp */
+                   "ldr SP,  [IP, #0x38]\n\t" /* context->Sp */
+                   "ldr LR,  [IP, #0x3c]\n\t" /* context->Lr */
+                   "ldr PC,  [IP, #0x40]\n\t" /* context->Pc */
+                   )
 
 
 /***********************************************************************
@@ -326,6 +356,63 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
     return STATUS_SUCCESS;
 }
 
+/***********************************************************************
+ *           setup_exception_record
+ *
+ * Setup the exception record and context on the thread stack.
+ */
+static EXCEPTION_RECORD *setup_exception_record( SIGCONTEXT *sigcontext, void *stack_ptr, raise_func func )
+{
+    struct stack_layout
+    {
+        CONTEXT           context;
+        EXCEPTION_RECORD  rec;
+    } *stack = stack_ptr;
+    DWORD exception_code = 0;
+
+    stack--;  /* push the stack_layout structure */
+
+    stack->rec.ExceptionRecord  = NULL;
+    stack->rec.ExceptionCode    = exception_code;
+    stack->rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
+    stack->rec.ExceptionAddress = (LPVOID)PC_sig(sigcontext);
+    stack->rec.NumberParameters = 0;
+
+    save_context( &stack->context, sigcontext );
+
+    /* now modify the sigcontext to return to the raise function */
+    SP_sig(sigcontext) = (DWORD)stack;
+    PC_sig(sigcontext) = (DWORD)func;
+    REGn_sig(0, sigcontext) = (DWORD)&stack->rec;  /* first arg for raise_func */
+    REGn_sig(1, sigcontext) = (DWORD)&stack->context; /* second arg for raise_func */
+
+
+    return &stack->rec;
+}
+
+/**********************************************************************
+ *		raise_segv_exception
+ */
+static void WINAPI raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    NTSTATUS status;
+
+    switch(rec->ExceptionCode)
+    {
+    case EXCEPTION_ACCESS_VIOLATION:
+        if (rec->NumberParameters == 2)
+        {
+            if (!(rec->ExceptionCode = virtual_handle_fault( (void *)rec->ExceptionInformation[1],
+                                                             rec->ExceptionInformation[0] )))
+                goto done;
+        }
+        break;
+    }
+    status = NtRaiseException( rec, context, TRUE );
+    if (status) raise_status( status, rec );
+done:
+    set_cpu_context( context );
+}
 
 /**********************************************************************
  *           call_stack_handlers
@@ -453,27 +540,47 @@ static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL f
  */
 static void segv_handler( int signal, siginfo_t *info, void *ucontext )
 {
-    EXCEPTION_RECORD rec;
-    CONTEXT context;
-    NTSTATUS status;
+    EXCEPTION_RECORD *rec;
+    SIGCONTEXT *context = ucontext;
+    void *stack = (void *) (SP_sig(context) & ~3);
 
-    rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
+    /* check for page fault inside the thread stack */
+    if (TRAP_sig(context) == TRAP_ARM_PAGEFLT &&
+        (char *)info->si_addr >= (char *)NtCurrentTeb()->DeallocationStack &&
+        (char *)info->si_addr < (char *)NtCurrentTeb()->Tib.StackBase &&
+        virtual_handle_stack_fault( info->si_addr ))
+    {
+        /* check if this was the last guard page */
+        if ((char *)info->si_addr < (char *)NtCurrentTeb()->DeallocationStack + 2*4096)
+        {
+            rec = setup_exception_record( context, stack, raise_segv_exception );
+            rec->ExceptionCode = EXCEPTION_STACK_OVERFLOW;
+        }
+        return;
+    }
 
-    /* we want the page-fault case to be fast */
-    if ( info->si_code == SEGV_ACCERR )
-        if (!(rec.ExceptionCode = virtual_handle_fault( info->si_addr, 0 ))) return;
+    rec = setup_exception_record( context, stack, raise_segv_exception );
+    if (rec->ExceptionCode == EXCEPTION_STACK_OVERFLOW) return;
 
-    save_context( &context, ucontext );
-    rec.ExceptionRecord  = NULL;
-    rec.ExceptionFlags   = EXCEPTION_CONTINUABLE;
-    rec.ExceptionAddress = (LPVOID)context.Pc;
-    rec.NumberParameters = 2;
-    rec.ExceptionInformation[0] = 0;  /* FIXME: read/write access ? */
-    rec.ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
-
-    status = raise_exception( &rec, &context, TRUE );
-    if (status) raise_status( status, &rec );
-    restore_context( &context, ucontext );
+    switch(TRAP_sig(context))
+    {
+    case TRAP_ARM_PRIVINFLT:   /* Invalid opcode exception */
+        rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+        break;
+    case TRAP_ARM_PAGEFLT:  /* Page fault */
+        rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
+        rec->NumberParameters = 2;
+        rec->ExceptionInformation[0] = (ERROR_sig(context) & 0x800) != 0;
+        rec->ExceptionInformation[1] = (ULONG_PTR)info->si_addr;
+        break;
+    case TRAP_ARM_ALIGNFLT:  /* Alignment check exception */
+        rec->ExceptionCode = EXCEPTION_DATATYPE_MISALIGNMENT;
+        break;
+    default:
+        WINE_ERR( "Got unexpected trap %ld\n", TRAP_sig(context) );
+        rec->ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+        break;
+    }
 }
 
 /**********************************************************************
-- 

Best Regards, André Hentschel



More information about the wine-patches mailing list