From 8d30e395779603a8d36fa8bdfddba88a312552f4 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Wed, 8 Apr 2020 14:33:35 -0600 Subject: Share handle_exception Both gdb and gdbserver have a "handle_exception" function, the bulk of which is shared between the two implementations. This patch arranges for the entire thing to be moved into nat/windows-nat.c, with the differences handled by callbacks. This patch introduces one more callback to make this possible. gdb/ChangeLog 2020-04-08 Tom Tromey * windows-nat.c (MS_VC_EXCEPTION): Move to nat/windows-nat.c. (handle_exception_result): Move to nat/windows-nat.h. (DEBUG_EXCEPTION_SIMPLE): Remove. (windows_nat::handle_ms_vc_exception): New function. (handle_exception): Move to nat/windows-nat.c. (get_windows_debug_event): Update. (STATUS_WX86_BREAKPOINT, STATUS_WX86_SINGLE_STEP): Move to nat/windows-nat.c. * nat/windows-nat.h (handle_ms_vc_exception): Declare. (handle_exception_result): Move from windows-nat.c. (handle_exception): Declare. * nat/windows-nat.c (MS_VC_EXCEPTION, handle_exception) (STATUS_WX86_SINGLE_STEP, STATUS_WX86_BREAKPOINT): Move from windows-nat.c. gdbserver/ChangeLog 2020-04-08 Tom Tromey * win32-low.c (handle_exception): Remove. (windows_nat::handle_ms_vc_exception): New function. (get_child_debug_event): Add "continue_status" parameter. Update. (win32_wait): Update. --- gdb/ChangeLog | 17 ++++ gdb/nat/windows-nat.c | 175 +++++++++++++++++++++++++++++++++++++++ gdb/nat/windows-nat.h | 20 +++++ gdb/windows-nat.c | 218 +++++++------------------------------------------ gdbserver/ChangeLog | 8 ++ gdbserver/win32-low.cc | 132 ++++-------------------------- 6 files changed, 266 insertions(+), 304 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d8d5540..663e2af 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,22 @@ 2020-04-08 Tom Tromey + * windows-nat.c (MS_VC_EXCEPTION): Move to nat/windows-nat.c. + (handle_exception_result): Move to nat/windows-nat.h. + (DEBUG_EXCEPTION_SIMPLE): Remove. + (windows_nat::handle_ms_vc_exception): New function. + (handle_exception): Move to nat/windows-nat.c. + (get_windows_debug_event): Update. + (STATUS_WX86_BREAKPOINT, STATUS_WX86_SINGLE_STEP): Move to + nat/windows-nat.c. + * nat/windows-nat.h (handle_ms_vc_exception): Declare. + (handle_exception_result): Move from windows-nat.c. + (handle_exception): Declare. + * nat/windows-nat.c (MS_VC_EXCEPTION, handle_exception) + (STATUS_WX86_SINGLE_STEP, STATUS_WX86_BREAKPOINT): Move from + windows-nat.c. + +2020-04-08 Tom Tromey + * windows-nat.c (exception_count, event_count): Remove. (handle_exception, get_windows_debug_event) (do_initial_windows_stuff): Update. diff --git a/gdb/nat/windows-nat.c b/gdb/nat/windows-nat.c index 80a1583..6bbf41c 100644 --- a/gdb/nat/windows-nat.c +++ b/gdb/nat/windows-nat.c @@ -18,6 +18,10 @@ #include "gdbsupport/common-defs.h" #include "nat/windows-nat.h" +#include "gdbsupport/common-debug.h" + +#define STATUS_WX86_BREAKPOINT 0x4000001F +#define STATUS_WX86_SINGLE_STEP 0x4000001E namespace windows_nat { @@ -137,4 +141,175 @@ get_image_name (HANDLE h, void *address, int unicode) return buf; } +/* The exception thrown by a program to tell the debugger the name of + a thread. The exception record contains an ID of a thread and a + name to give it. This exception has no documented name, but MSDN + dubs it "MS_VC_EXCEPTION" in one code example. */ +#define MS_VC_EXCEPTION 0x406d1388 + +handle_exception_result +handle_exception (struct target_waitstatus *ourstatus, bool debug_exceptions) +{ +#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ + debug_printf ("gdb: Target exception %s at %s\n", x, \ + host_address_to_string (\ + current_event.u.Exception.ExceptionRecord.ExceptionAddress)) + + EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord; + DWORD code = rec->ExceptionCode; + handle_exception_result result = HANDLE_EXCEPTION_HANDLED; + + memcpy (&siginfo_er, rec, sizeof siginfo_er); + + ourstatus->kind = TARGET_WAITKIND_STOPPED; + + /* Record the context of the current thread. */ + thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0), + DONT_SUSPEND); + + switch (code) + { + case EXCEPTION_ACCESS_VIOLATION: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION"); + ourstatus->value.sig = GDB_SIGNAL_SEGV; +#ifdef __CYGWIN__ + { + /* See if the access violation happened within the cygwin DLL + itself. Cygwin uses a kind of exception handling to deal + with passed-in invalid addresses. gdb should not treat + these as real SEGVs since they will be silently handled by + cygwin. A real SEGV will (theoretically) be caught by + cygwin later in the process and will be sent as a + cygwin-specific-signal. So, ignore SEGVs if they show up + within the text segment of the DLL itself. */ + const char *fn; + CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress; + + if ((!cygwin_exceptions && (addr >= cygwin_load_start + && addr < cygwin_load_end)) + || (find_pc_partial_function (addr, &fn, NULL, NULL) + && startswith (fn, "KERNEL32!IsBad"))) + return HANDLE_EXCEPTION_UNHANDLED; + } +#endif + break; + case STATUS_STACK_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW"); + ourstatus->value.sig = GDB_SIGNAL_SEGV; + break; + case STATUS_FLOAT_DENORMAL_OPERAND: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_INEXACT_RESULT: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_INVALID_OPERATION: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_STACK_CHECK: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_UNDERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_FLOAT_DIVIDE_BY_ZERO: + DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_INTEGER_DIVIDE_BY_ZERO: + DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case STATUS_INTEGER_OVERFLOW: + DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW"); + ourstatus->value.sig = GDB_SIGNAL_FPE; + break; + case EXCEPTION_BREAKPOINT: +#ifdef __x86_64__ + if (ignore_first_breakpoint) + { + /* For WOW64 processes, there are always 2 breakpoint exceptions + on startup, first a BREAKPOINT for the 64bit ntdll.dll, + then a WX86_BREAKPOINT for the 32bit ntdll.dll. + Here we only care about the WX86_BREAKPOINT's. */ + ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + ignore_first_breakpoint = false; + } +#endif + /* FALLTHROUGH */ + case STATUS_WX86_BREAKPOINT: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT"); + ourstatus->value.sig = GDB_SIGNAL_TRAP; +#ifdef _WIN32_WCE + /* Remove the initial breakpoint. */ + check_breakpoints ((CORE_ADDR) (long) current_event + .u.Exception.ExceptionRecord.ExceptionAddress); +#endif + break; + case DBG_CONTROL_C: + DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C"); + ourstatus->value.sig = GDB_SIGNAL_INT; + break; + case DBG_CONTROL_BREAK: + DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK"); + ourstatus->value.sig = GDB_SIGNAL_INT; + break; + case EXCEPTION_SINGLE_STEP: + case STATUS_WX86_SINGLE_STEP: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP"); + ourstatus->value.sig = GDB_SIGNAL_TRAP; + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION"); + ourstatus->value.sig = GDB_SIGNAL_ILL; + break; + case EXCEPTION_PRIV_INSTRUCTION: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION"); + ourstatus->value.sig = GDB_SIGNAL_ILL; + break; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); + ourstatus->value.sig = GDB_SIGNAL_ILL; + break; + case MS_VC_EXCEPTION: + DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION"); + if (handle_ms_vc_exception (rec)) + { + ourstatus->value.sig = GDB_SIGNAL_TRAP; + result = HANDLE_EXCEPTION_IGNORED; + break; + } + /* treat improperly formed exception as unknown */ + /* FALLTHROUGH */ + default: + /* Treat unhandled first chance exceptions specially. */ + if (current_event.u.Exception.dwFirstChance) + return HANDLE_EXCEPTION_UNHANDLED; + debug_printf ("gdb: unknown target exception 0x%08x at %s\n", + (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, + host_address_to_string ( + current_event.u.Exception.ExceptionRecord.ExceptionAddress)); + ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; + break; + } + + last_sig = ourstatus->value.sig; + return result; + +#undef DEBUG_EXCEPTION_SIMPLE +} + } diff --git a/gdb/nat/windows-nat.h b/gdb/nat/windows-nat.h index 2b2fd11..a4e0b39 100644 --- a/gdb/nat/windows-nat.h +++ b/gdb/nat/windows-nat.h @@ -143,6 +143,16 @@ extern void handle_load_dll (); extern void handle_unload_dll (); +/* Handle MS_VC_EXCEPTION when processing a stop. MS_VC_EXCEPTION is + somewhat undocumented but is used to tell the debugger the name of + a thread. + + Return true if the exception was handled; return false otherwise. + + This function must be supplied by the embedding application. */ + +extern bool handle_ms_vc_exception (const EXCEPTION_RECORD *rec); + /* Currently executing process */ extern HANDLE current_process_handle; @@ -205,6 +215,16 @@ extern EXCEPTION_RECORD siginfo_er; get_image_name. */ extern const char *get_image_name (HANDLE h, void *address, int unicode); +typedef enum +{ + HANDLE_EXCEPTION_UNHANDLED = 0, + HANDLE_EXCEPTION_HANDLED, + HANDLE_EXCEPTION_IGNORED +} handle_exception_result; + +extern handle_exception_result handle_exception + (struct target_waitstatus *ourstatus, bool debug_exceptions); + } #endif diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c index eb55025..d48f90a 100644 --- a/gdb/windows-nat.c +++ b/gdb/windows-nat.c @@ -72,9 +72,6 @@ #include "gdbsupport/gdb_wait.h" #include "nat/windows-nat.h" -#define STATUS_WX86_BREAKPOINT 0x4000001F -#define STATUS_WX86_SINGLE_STEP 0x4000001E - using namespace windows_nat; #define AdjustTokenPrivileges dyn_AdjustTokenPrivileges @@ -213,19 +210,6 @@ static int debug_registers_used; static int windows_initialization_done; #define DR6_CLEAR_VALUE 0xffff0ff0 -/* The exception thrown by a program to tell the debugger the name of - a thread. The exception record contains an ID of a thread and a - name to give it. This exception has no documented name, but MSDN - dubs it "MS_VC_EXCEPTION" in one code example. */ -#define MS_VC_EXCEPTION 0x406d1388 - -typedef enum -{ - HANDLE_EXCEPTION_UNHANDLED = 0, - HANDLE_EXCEPTION_HANDLED, - HANDLE_EXCEPTION_IGNORED -} handle_exception_result; - /* The string sent by cygwin when it processes a signal. FIXME: This should be in a cygwin include file. */ #ifndef _CYGWIN_SIGNAL_STRING @@ -1203,189 +1187,45 @@ display_selectors (const char * args, int from_tty) } } -#define DEBUG_EXCEPTION_SIMPLE(x) if (debug_exceptions) \ - printf_unfiltered ("gdb: Target exception %s at %s\n", x, \ - host_address_to_string (\ - current_event.u.Exception.ExceptionRecord.ExceptionAddress)) +/* See nat/windows-nat.h. */ -static handle_exception_result -handle_exception (struct target_waitstatus *ourstatus) +bool +windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec) { - EXCEPTION_RECORD *rec = ¤t_event.u.Exception.ExceptionRecord; - DWORD code = rec->ExceptionCode; - handle_exception_result result = HANDLE_EXCEPTION_HANDLED; - - memcpy (&siginfo_er, rec, sizeof siginfo_er); - - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - /* Record the context of the current thread. */ - thread_rec (ptid_t (current_event.dwProcessId, current_event.dwThreadId, 0), - DONT_SUSPEND); - - switch (code) + if (rec->NumberParameters >= 3 + && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) { - case EXCEPTION_ACCESS_VIOLATION: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ACCESS_VIOLATION"); - ourstatus->value.sig = GDB_SIGNAL_SEGV; -#ifdef __CYGWIN__ - { - /* See if the access violation happened within the cygwin DLL - itself. Cygwin uses a kind of exception handling to deal - with passed-in invalid addresses. gdb should not treat - these as real SEGVs since they will be silently handled by - cygwin. A real SEGV will (theoretically) be caught by - cygwin later in the process and will be sent as a - cygwin-specific-signal. So, ignore SEGVs if they show up - within the text segment of the DLL itself. */ - const char *fn; - CORE_ADDR addr = (CORE_ADDR) (uintptr_t) rec->ExceptionAddress; - - if ((!cygwin_exceptions && (addr >= cygwin_load_start - && addr < cygwin_load_end)) - || (find_pc_partial_function (addr, &fn, NULL, NULL) - && startswith (fn, "KERNEL32!IsBad"))) - return HANDLE_EXCEPTION_UNHANDLED; - } -#endif - break; - case STATUS_STACK_OVERFLOW: - DEBUG_EXCEPTION_SIMPLE ("STATUS_STACK_OVERFLOW"); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_FLOAT_DENORMAL_OPERAND: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DENORMAL_OPERAND"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INEXACT_RESULT: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INEXACT_RESULT"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INVALID_OPERATION: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_INVALID_OPERATION"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_OVERFLOW: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_OVERFLOW"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_STACK_CHECK: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_STACK_CHECK"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_UNDERFLOW: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_UNDERFLOW"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_DIVIDE_BY_ZERO: - DEBUG_EXCEPTION_SIMPLE ("STATUS_FLOAT_DIVIDE_BY_ZERO"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_DIVIDE_BY_ZERO: - DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_DIVIDE_BY_ZERO"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_OVERFLOW: - DEBUG_EXCEPTION_SIMPLE ("STATUS_INTEGER_OVERFLOW"); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_BREAKPOINT: -#ifdef __x86_64__ - if (ignore_first_breakpoint) - { - /* For WOW64 processes, there are always 2 breakpoint exceptions - on startup, first a BREAKPOINT for the 64bit ntdll.dll, - then a WX86_BREAKPOINT for the 32bit ntdll.dll. - Here we only care about the WX86_BREAKPOINT's. */ - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - ignore_first_breakpoint = false; - } -#endif - /* FALLTHROUGH */ - case STATUS_WX86_BREAKPOINT: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_BREAKPOINT"); - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - case DBG_CONTROL_C: - DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_C"); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case DBG_CONTROL_BREAK: - DEBUG_EXCEPTION_SIMPLE ("DBG_CONTROL_BREAK"); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case EXCEPTION_SINGLE_STEP: - case STATUS_WX86_SINGLE_STEP: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_SINGLE_STEP"); - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_ILLEGAL_INSTRUCTION"); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_PRIV_INSTRUCTION: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_PRIV_INSTRUCTION"); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - DEBUG_EXCEPTION_SIMPLE ("EXCEPTION_NONCONTINUABLE_EXCEPTION"); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case MS_VC_EXCEPTION: - if (rec->NumberParameters >= 3 - && (rec->ExceptionInformation[0] & 0xffffffff) == 0x1000) - { - DWORD named_thread_id; - windows_thread_info *named_thread; - CORE_ADDR thread_name_target; + DWORD named_thread_id; + windows_thread_info *named_thread; + CORE_ADDR thread_name_target; - DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION"); + thread_name_target = rec->ExceptionInformation[1]; + named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]); - thread_name_target = rec->ExceptionInformation[1]; - named_thread_id = (DWORD) (0xffffffff & rec->ExceptionInformation[2]); + if (named_thread_id == (DWORD) -1) + named_thread_id = current_event.dwThreadId; - if (named_thread_id == (DWORD) -1) - named_thread_id = current_event.dwThreadId; + named_thread = thread_rec (ptid_t (current_event.dwProcessId, + named_thread_id, 0), + DONT_INVALIDATE_CONTEXT); + if (named_thread != NULL) + { + int thread_name_len; + gdb::unique_xmalloc_ptr thread_name; - named_thread = thread_rec (ptid_t (current_event.dwProcessId, - named_thread_id, 0), - DONT_INVALIDATE_CONTEXT); - if (named_thread != NULL) + thread_name_len = target_read_string (thread_name_target, + &thread_name, 1025, NULL); + if (thread_name_len > 0) { - int thread_name_len; - gdb::unique_xmalloc_ptr thread_name; - - thread_name_len = target_read_string (thread_name_target, - &thread_name, 1025, NULL); - if (thread_name_len > 0) - { - thread_name.get ()[thread_name_len - 1] = '\0'; - named_thread->name = std::move (thread_name); - } + thread_name.get ()[thread_name_len - 1] = '\0'; + named_thread->name = std::move (thread_name); } - ourstatus->value.sig = GDB_SIGNAL_TRAP; - result = HANDLE_EXCEPTION_IGNORED; - break; } - /* treat improperly formed exception as unknown */ - /* FALLTHROUGH */ - default: - /* Treat unhandled first chance exceptions specially. */ - if (current_event.u.Exception.dwFirstChance) - return HANDLE_EXCEPTION_UNHANDLED; - printf_unfiltered ("gdb: unknown target exception 0x%08x at %s\n", - (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, - host_address_to_string ( - current_event.u.Exception.ExceptionRecord.ExceptionAddress)); - ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; - break; + + return true; } - last_sig = ourstatus->value.sig; - return result; + + return false; } /* Resume thread specified by ID, or all artificially suspended @@ -1876,7 +1716,7 @@ windows_nat_target::get_windows_debug_event (int pid, "EXCEPTION_DEBUG_EVENT")); if (saw_create != 1) break; - switch (handle_exception (ourstatus)) + switch (handle_exception (ourstatus, debug_exceptions)) { case HANDLE_EXCEPTION_UNHANDLED: default: diff --git a/gdbserver/ChangeLog b/gdbserver/ChangeLog index e6213ad..a00176a 100644 --- a/gdbserver/ChangeLog +++ b/gdbserver/ChangeLog @@ -1,5 +1,13 @@ 2020-04-08 Tom Tromey + * win32-low.c (handle_exception): Remove. + (windows_nat::handle_ms_vc_exception): New function. + (get_child_debug_event): Add "continue_status" parameter. + Update. + (win32_wait): Update. + +2020-04-08 Tom Tromey + * win32-low.c (windows_nat::handle_load_dll): Rename from handle_load_dll. No longer static. (windows_nat::handle_unload_dll): Rename from handle_unload_dll. diff --git a/gdbserver/win32-low.cc b/gdbserver/win32-low.cc index 73d4a6a..7018083 100644 --- a/gdbserver/win32-low.cc +++ b/gdbserver/win32-low.cc @@ -1155,117 +1155,6 @@ windows_nat::handle_unload_dll () } static void -handle_exception (struct target_waitstatus *ourstatus) -{ - DWORD code = current_event.u.Exception.ExceptionRecord.ExceptionCode; - - memcpy (&siginfo_er, ¤t_event.u.Exception.ExceptionRecord, - sizeof siginfo_er); - - ourstatus->kind = TARGET_WAITKIND_STOPPED; - - switch (code) - { - case EXCEPTION_ACCESS_VIOLATION: - OUTMSG2 (("EXCEPTION_ACCESS_VIOLATION")); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_STACK_OVERFLOW: - OUTMSG2 (("STATUS_STACK_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_SEGV; - break; - case STATUS_FLOAT_DENORMAL_OPERAND: - OUTMSG2 (("STATUS_FLOAT_DENORMAL_OPERAND")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - OUTMSG2 (("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INEXACT_RESULT: - OUTMSG2 (("STATUS_FLOAT_INEXACT_RESULT")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_INVALID_OPERATION: - OUTMSG2 (("STATUS_FLOAT_INVALID_OPERATION")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_OVERFLOW: - OUTMSG2 (("STATUS_FLOAT_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_STACK_CHECK: - OUTMSG2 (("STATUS_FLOAT_STACK_CHECK")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_UNDERFLOW: - OUTMSG2 (("STATUS_FLOAT_UNDERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_FLOAT_DIVIDE_BY_ZERO: - OUTMSG2 (("STATUS_FLOAT_DIVIDE_BY_ZERO")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_DIVIDE_BY_ZERO: - OUTMSG2 (("STATUS_INTEGER_DIVIDE_BY_ZERO")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case STATUS_INTEGER_OVERFLOW: - OUTMSG2 (("STATUS_INTEGER_OVERFLOW")); - ourstatus->value.sig = GDB_SIGNAL_FPE; - break; - case EXCEPTION_BREAKPOINT: - OUTMSG2 (("EXCEPTION_BREAKPOINT")); - ourstatus->value.sig = GDB_SIGNAL_TRAP; -#ifdef _WIN32_WCE - /* Remove the initial breakpoint. */ - check_breakpoints ((CORE_ADDR) (long) current_event - .u.Exception.ExceptionRecord.ExceptionAddress); -#endif - break; - case DBG_CONTROL_C: - OUTMSG2 (("DBG_CONTROL_C")); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case DBG_CONTROL_BREAK: - OUTMSG2 (("DBG_CONTROL_BREAK")); - ourstatus->value.sig = GDB_SIGNAL_INT; - break; - case EXCEPTION_SINGLE_STEP: - OUTMSG2 (("EXCEPTION_SINGLE_STEP")); - ourstatus->value.sig = GDB_SIGNAL_TRAP; - break; - case EXCEPTION_ILLEGAL_INSTRUCTION: - OUTMSG2 (("EXCEPTION_ILLEGAL_INSTRUCTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_PRIV_INSTRUCTION: - OUTMSG2 (("EXCEPTION_PRIV_INSTRUCTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - OUTMSG2 (("EXCEPTION_NONCONTINUABLE_EXCEPTION")); - ourstatus->value.sig = GDB_SIGNAL_ILL; - break; - default: - if (current_event.u.Exception.dwFirstChance) - { - ourstatus->kind = TARGET_WAITKIND_SPURIOUS; - return; - } - OUTMSG2 (("gdbserver: unknown target exception 0x%08x at 0x%s", - (unsigned) current_event.u.Exception.ExceptionRecord.ExceptionCode, - phex_nz ((uintptr_t) current_event.u.Exception.ExceptionRecord. - ExceptionAddress, sizeof (uintptr_t)))); - ourstatus->value.sig = GDB_SIGNAL_UNKNOWN; - break; - } - OUTMSG2 (("\n")); - last_sig = ourstatus->value.sig; -} - - -static void suspend_one_thread (thread_info *thread) { windows_thread_info *th = (windows_thread_info *) thread_target_data (thread); @@ -1297,15 +1186,25 @@ auto_delete_breakpoint (CORE_ADDR stop_pc) } #endif +/* See nat/windows-nat.h. */ + +bool +windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec) +{ + return false; +} + /* Get the next event from the child. */ static int -get_child_debug_event (struct target_waitstatus *ourstatus) +get_child_debug_event (DWORD *continue_status, + struct target_waitstatus *ourstatus) { ptid_t ptid; last_sig = GDB_SIGNAL_0; ourstatus->kind = TARGET_WAITKIND_SPURIOUS; + *continue_status = DBG_CONTINUE; /* Check if GDB sent us an interrupt request. */ check_remote_input_interrupt_request (); @@ -1488,7 +1387,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus) "for pid=%u tid=%x\n", (unsigned) current_event.dwProcessId, (unsigned) current_event.dwThreadId)); - handle_exception (ourstatus); + if (handle_exception (ourstatus, debug_threads) + == HANDLE_EXCEPTION_UNHANDLED) + *continue_status = DBG_EXCEPTION_NOT_HANDLED; break; case OUTPUT_DEBUG_STRING_EVENT: @@ -1536,7 +1437,8 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus, while (1) { - if (!get_child_debug_event (ourstatus)) + DWORD continue_status; + if (!get_child_debug_event (&continue_status, ourstatus)) continue; switch (ourstatus->kind) @@ -1560,7 +1462,7 @@ win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus, /* fall-through */ case TARGET_WAITKIND_SPURIOUS: /* do nothing, just continue */ - child_continue (DBG_CONTINUE, -1); + child_continue (continue_status, -1); break; } } -- cgit v1.1