Module: wine Branch: stable Commit: a10117349d13926a82e1b3f1bf8135559612b1ed URL: http://source.winehq.org/git/wine.git/?a=commit;h=a10117349d13926a82e1b3f1bf...
Author: Henri Verbeet hverbeet@codeweavers.com Date: Mon Feb 15 18:18:05 2016 +0100
ntdll: Add special handling for int $0x2d exceptions.
Signed-off-by: Henri Verbeet hverbeet@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org (cherry picked from commit e65c89f1c52c8aa4bbc375751138d0aec6bd237a) Signed-off-by: Michael Stefaniuc mstefani@winehq.org
---
dlls/ntdll/signal_i386.c | 29 ++++++++++++++++++++++++++++- dlls/ntdll/tests/exception.c | 38 +++++++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 16 deletions(-)
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index a3abbff..10235fe 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -1553,6 +1553,31 @@ static inline DWORD is_privileged_instr( CONTEXT *context ) } }
+ +/*********************************************************************** + * handle_interrupt + * + * Handle an interrupt. + */ +static inline BOOL handle_interrupt( unsigned int interrupt, EXCEPTION_RECORD *rec, CONTEXT *context ) +{ + switch(interrupt) + { + case 0x2d: + context->Eip += 3; + rec->ExceptionCode = EXCEPTION_BREAKPOINT; + rec->ExceptionAddress = (void *)context->Eip; + rec->NumberParameters = is_wow64 ? 1 : 3; + rec->ExceptionInformation[0] = context->Eax; + rec->ExceptionInformation[1] = context->Ecx; + rec->ExceptionInformation[2] = context->Edx; + return TRUE; + default: + return FALSE; + } +} + + /*********************************************************************** * check_invalid_gs * @@ -2072,8 +2097,10 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) case TRAP_x86_PROTFLT: /* General protection fault */ case TRAP_x86_UNKNOWN: /* Unknown fault code */ { + CONTEXT *win_context = get_exception_context( rec ); WORD err = get_error_code(context); - if (!err && (rec->ExceptionCode = is_privileged_instr( get_exception_context(rec) ))) break; + if (!err && (rec->ExceptionCode = is_privileged_instr( win_context ))) break; + if ((err & 7) == 2 && handle_interrupt( err >> 3, rec, win_context )) break; rec->ExceptionCode = EXCEPTION_ACCESS_VIOLATION; rec->NumberParameters = 2; rec->ExceptionInformation[0] = 0; diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index a368997..93e5ae5 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -219,6 +219,11 @@ static const struct exception
{ { 0xf1, 0x90, 0xc3 }, /* icebp; nop; ret */ 1, 1, FALSE, STATUS_SINGLE_STEP, 0 }, + { { 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, /* mov $0xb8b8b8b8, %eax */ + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, /* mov $0xb9b9b9b9, %ecx */ + 0xba, 0xba, 0xba, 0xba, 0xba, /* mov $0xbabababa, %edx */ + 0xcd, 0x2d, 0xc3 }, /* int $0x2d; ret */ + 17, 0, FALSE, STATUS_BREAKPOINT, 3, { 0xb8b8b8b8, 0xb9b9b9b9, 0xbabababa } }, };
static int got_exception; @@ -473,7 +478,7 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { const struct exception *except = *(const struct exception **)(frame + 1); - unsigned int i, entry = except - exceptions; + unsigned int i, parameter_count, entry = except - exceptions;
got_exception++; trace( "exception %u: %x flags:%x addr:%p\n", @@ -482,20 +487,23 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram ok( rec->ExceptionCode == except->status || (except->alt_status != 0 && rec->ExceptionCode == except->alt_status), "%u: Wrong exception code %x/%x\n", entry, rec->ExceptionCode, except->status ); - ok( rec->ExceptionAddress == (char*)code_mem + except->offset, - "%u: Wrong exception address %p/%p\n", entry, - rec->ExceptionAddress, (char*)code_mem + except->offset ); - - if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status) - { - ok( rec->NumberParameters == except->nb_params, - "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); - } + ok( context->Eip == (DWORD_PTR)code_mem + except->offset, + "%u: Unexpected eip %#x/%#lx\n", entry, + context->Eip, (DWORD_PTR)code_mem + except->offset ); + ok( rec->ExceptionAddress == (char*)context->Eip || + (rec->ExceptionCode == STATUS_BREAKPOINT && rec->ExceptionAddress == (char*)context->Eip + 1), + "%u: Unexpected exception address %p/%p\n", entry, + rec->ExceptionAddress, (char*)context->Eip ); + + if (except->status == STATUS_BREAKPOINT && is_wow64) + parameter_count = 1; + else if (except->alt_status == 0 || rec->ExceptionCode != except->alt_status) + parameter_count = except->nb_params; else - { - ok( rec->NumberParameters == except->alt_nb_params, - "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); - } + parameter_count = except->alt_nb_params; + + ok( rec->NumberParameters == parameter_count, + "%u: Unexpected parameter count %u/%u\n", entry, rec->NumberParameters, parameter_count );
/* Most CPUs (except Intel Core apparently) report a segment limit violation */ /* instead of page faults for accesses beyond 0xffffffff */ @@ -530,7 +538,7 @@ static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *fram
skip_params: /* don't handle exception if it's not the address we expected */ - if (rec->ExceptionAddress != (char*)code_mem + except->offset) return ExceptionContinueSearch; + if (context->Eip != (DWORD_PTR)code_mem + except->offset) return ExceptionContinueSearch;
context->Eip += except->length; return ExceptionContinueExecution;