diff options
author | Tom Tromey <tromey@adacore.com> | 2020-04-08 14:33:35 -0600 |
---|---|---|
committer | Tom Tromey <tromey@adacore.com> | 2020-04-08 14:47:59 -0600 |
commit | 8d30e395779603a8d36fa8bdfddba88a312552f4 (patch) | |
tree | 469d9065623bf700d4a4fa02988fc58f415f9195 /gdb/nat | |
parent | 29de418deeac717886df20ef0419240aa0dfc32a (diff) | |
download | gdb-8d30e395779603a8d36fa8bdfddba88a312552f4.zip gdb-8d30e395779603a8d36fa8bdfddba88a312552f4.tar.gz gdb-8d30e395779603a8d36fa8bdfddba88a312552f4.tar.bz2 |
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 <tromey@adacore.com>
* 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 <tromey@adacore.com>
* 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.
Diffstat (limited to 'gdb/nat')
-rw-r--r-- | gdb/nat/windows-nat.c | 175 | ||||
-rw-r--r-- | gdb/nat/windows-nat.h | 20 |
2 files changed, 195 insertions, 0 deletions
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 |