diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index be82a84..05dd7cc 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -261,8 +261,8 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) } /* Call handler */ - TRACE( "calling handler at %p code=%x flags=%x\n", - frame->Handler, rec->ExceptionCode, rec->ExceptionFlags ); + TRACE( "calling handler at %p code=%x flags=%x address=%p\n", + frame->Handler, rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress ); res = EXC_CallHandler( rec, frame, context, &dispatch, frame->Handler, EXC_RaiseHandler ); TRACE( "handler at %p returned %x\n", frame->Handler, res ); @@ -302,6 +302,10 @@ static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL f { NTSTATUS status; + if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) +// GET_IP(context) = (char *)GET_IP(context) - 1; + context->Eip = (char *)context->Eip - 1; + if (first_chance) { DWORD c; diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index d18f3d2..c7fd195 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -39,6 +39,9 @@ static struct _TEB * (WINAPI *pNtCurrentTeb)(void); static NTSTATUS (WINAPI *pNtGetContextThread)(HANDLE,CONTEXT*); static NTSTATUS (WINAPI *pNtSetContextThread)(HANDLE,CONTEXT*); +static NTSTATUS (WINAPI *pRtlRaiseException)(EXCEPTION_RECORD *rec); +static NTSTATUS (WINAPI *pNtRaiseException)(EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance); +// static PVOID (WINAPI RtlAddVectoredExceptionHandler)(ULONG first, PVECTORED_EXCEPTION_HANDLER func); static void *code_mem; /* Test various instruction combinations that cause a protection fault on the i386, @@ -162,6 +165,8 @@ static const struct exception 0, 5, STATUS_ACCESS_VIOLATION, 2, { 1, 0xffffffff } }, }; +static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */ + static int got_exception; static void run_exception_test(const void *handler, const void* context, @@ -184,6 +189,120 @@ static void run_exception_test(const void *handler, const void* context, pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; } +static DWORD handler2( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ +// const struct exception *except = *(const struct exception **)(frame + 1); +// unsigned int i, entry = except - exceptions; + CONTEXT ctx; + NTSTATUS ret; + + got_exception++; + trace( "exception2: %08x flags:%x addr:%p context: Eip:%x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, context->Eip ); + + memset(&ctx, 0, sizeof(ctx)); + ctx.ContextFlags = CONTEXT_CONTROL;//CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; + ret = pNtGetContextThread(GetCurrentThread(), &ctx);/* not fully valid as we are currently running */ + ok(!ret, "NtGetContextThread failed\n"); + trace( "NtGetContextThread Eip:%p\n", ctx.Eip); + +// trace( "\n", context->Eip); + +// ok( rec->ExceptionCode == except->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 ); + +// ok( rec->NumberParameters == except->nb_params, +// "%u: Wrong number of parameters %u/%u\n", entry, rec->NumberParameters, except->nb_params ); + + /* Most CPUs (except Intel Core apparently) report a segment limit violation */ + /* instead of page faults for accesses beyond 0xffffffff */ +// if (except->nb_params == 2 && except->params[1] >= 0xfffffffd) +// { +// if (rec->ExceptionInformation[0] == 0 && rec->ExceptionInformation[1] == 0xffffffff) +// goto skip_params; +// } + +// for (i = 0; i < rec->NumberParameters; i++) +// ok( rec->ExceptionInformation[i] == except->params[i], +// "%u: Wrong parameter %d: %lx/%x\n", +// entry, i, rec->ExceptionInformation[i], except->params[i] ); + +// 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(got_exception == 2) + /* Eip in context is decreased by 1 + * Increase it again, else execution will continue in the middle of a instruction */ + if(rec->ExceptionCode == EXCEPTION_BREAKPOINT) + context->Eip += 1; + return ExceptionContinueExecution; +} + +static void run_exception_test2(DWORD exception_code, const void* context//, + /*const void *code, unsigned int code_size*/) +{ + struct { + EXCEPTION_REGISTRATION_RECORD frame; + const void *context; + } exc_frame; + EXCEPTION_RECORD record; + + record.ExceptionCode = exception_code; + record.ExceptionFlags = 0; + record.ExceptionRecord = NULL; + record.ExceptionAddress = NULL;//&int3_code; + record.NumberParameters = 0; + trace("raising exception: %x setting record.ExceptionAddress to %x\n", exception_code, record.ExceptionAddress); + + exc_frame.frame.Handler = handler2; + exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; + exc_frame.context = context; + + pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; + pRtlRaiseException(&record); + pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; +} + +static void run_exception_test3(DWORD exception_code, const void* context//, + /*const void *code, unsigned int code_size*/) +{ + struct { + EXCEPTION_REGISTRATION_RECORD frame; + const void *context; + } exc_frame; + + EXCEPTION_RECORD record; + CONTEXT ctx, ctx2; + NTSTATUS ret; + + ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; + ret = pNtGetContextThread(GetCurrentThread(), &ctx);/* not fully valid as we are currently running */ + ok(!ret, "NtGetContextThread failed\n"); + memcpy(&ctx2, &ctx, sizeof(ctx)); + + record.ExceptionCode = exception_code; + record.ExceptionFlags = 0; + record.ExceptionRecord = NULL; + record.ExceptionAddress = NULL;//&int3_code; + record.NumberParameters = 0; + trace("setting record.ExceptionAddress to %x\n", record.ExceptionAddress); + + exc_frame.frame.Handler = handler2; + exc_frame.frame.Prev = pNtCurrentTeb()->Tib.ExceptionList; + exc_frame.context = context; + + pNtCurrentTeb()->Tib.ExceptionList = &exc_frame.frame; + pNtRaiseException(&record, &ctx, TRUE); + ok(memcmp(&ctx2, &ctx, sizeof(ctx)) == 0, "context should be the same after call\n"); + pNtCurrentTeb()->Tib.ExceptionList = exc_frame.frame.Prev; +} + + static DWORD handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) { @@ -373,15 +492,15 @@ static DWORD int3_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD { ok( rec->ExceptionAddress == code_mem, "exception address not at: %p, but at %p\n", code_mem, rec->ExceptionAddress); - todo_wine { +// todo_wine { ok( context->Eip == (DWORD)code_mem, "eip not at: %p, but at %#x\n", code_mem, context->Eip); - } +// } if(context->Eip == (DWORD)code_mem) context->Eip++; /* skip breakpoint */ return ExceptionContinueExecution; } -static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */ +// static const BYTE int3_code[] = { 0xCC, 0xc3 }; /* int 3, ret */ static void test_exceptions(void) @@ -391,7 +510,11 @@ static void test_exceptions(void) pNtGetContextThread = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtGetContextThread" ); pNtSetContextThread = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtSetContextThread" ); - if (!pNtGetContextThread || !pNtSetContextThread) + pRtlRaiseException = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlRaiseException" ); + pNtRaiseException = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtRaiseException" ); +// pRtlAddVectoredExceptionHandler = (void *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "RtlAddVectoredExceptionHandler" ); + + if (!pNtGetContextThread || !pNtSetContextThread || !pRtlRaiseException || !pNtRaiseException /*|| !pRtlAddVectoredExceptionHandler*/) { trace( "NtGetContextThread/NtSetContextThread not found, skipping tests\n" ); return; @@ -399,6 +522,11 @@ static void test_exceptions(void) /* test handling of debug registers */ run_exception_test(dreg_handler, NULL, &segfault_code, sizeof(segfault_code)); + run_exception_test2(0x12345, NULL); + run_exception_test2(EXCEPTION_BREAKPOINT, NULL); + + run_exception_test3(0x12345, NULL); + run_exception_test3(EXCEPTION_BREAKPOINT, NULL); ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; res = pNtGetContextThread(GetCurrentThread(), &ctx);