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.
This commit is contained in:
parent
29de418dee
commit
8d30e39577
@ -1,3 +1,20 @@
|
||||
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.
|
||||
|
||||
2020-04-08 Tom Tromey <tromey@adacore.com>
|
||||
|
||||
* windows-nat.c (exception_count, event_count): Remove.
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
DWORD named_thread_id;
|
||||
windows_thread_info *named_thread;
|
||||
CORE_ADDR thread_name_target;
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
named_thread = thread_rec (ptid_t (current_event.dwProcessId,
|
||||
named_thread_id, 0),
|
||||
DONT_INVALIDATE_CONTEXT);
|
||||
if (named_thread != NULL)
|
||||
{
|
||||
/* 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;
|
||||
int thread_name_len;
|
||||
gdb::unique_xmalloc_ptr<char> thread_name;
|
||||
|
||||
DEBUG_EXCEPTION_SIMPLE ("MS_VC_EXCEPTION");
|
||||
|
||||
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;
|
||||
|
||||
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<char> 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:
|
||||
|
@ -1,3 +1,11 @@
|
||||
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.
|
||||
|
||||
2020-04-08 Tom Tromey <tromey@adacore.com>
|
||||
|
||||
* win32-low.c (windows_nat::handle_load_dll): Rename from
|
||||
|
@ -1154,117 +1154,6 @@ windows_nat::handle_unload_dll ()
|
||||
unloaded_dll (NULL, load_addr);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user