bool
win32_process_target::supports_z_point_type (char z_type)
{
- return (the_low_target.supports_z_point_type != NULL
- && the_low_target.supports_z_point_type (z_type));
+ return (z_type == Z_PACKET_SW_BP
+ || (the_low_target.supports_z_point_type != NULL
+ && the_low_target.supports_z_point_type (z_type)));
}
int
win32_process_target::insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
int size, raw_breakpoint *bp)
{
- if (the_low_target.insert_point != NULL)
+ if (type == raw_bkpt_type_sw)
+ return insert_memory_breakpoint (bp);
+ else if (the_low_target.insert_point != NULL)
return the_low_target.insert_point (type, addr, size, bp);
else
/* Unsupported (see target.h). */
win32_process_target::remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
int size, raw_breakpoint *bp)
{
- if (the_low_target.remove_point != NULL)
+ if (type == raw_bkpt_type_sw)
+ return remove_memory_breakpoint (bp);
+ else if (the_low_target.remove_point != NULL)
return the_low_target.remove_point (type, addr, size, bp);
else
/* Unsupported (see target.h). */
});
faked_breakpoint = 0;
- if (!ContinueDebugEvent (current_event.dwProcessId,
- current_event.dwThreadId,
- continue_status))
- return FALSE;
-
- return TRUE;
+ return continue_last_debug_event (continue_status, debug_threads);
}
/* Fetch register(s) from the current thread context. */
{
if (!child_continue (DBG_CONTINUE, -1))
break;
- if (!WaitForDebugEvent (¤t_event, INFINITE))
+ if (!wait_for_debug_event (¤t_event, INFINITE))
break;
if (current_event.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
break;
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)
{
}
#endif
+/* See nat/windows-nat.h. */
+
+bool
+windows_nat::handle_ms_vc_exception (const EXCEPTION_RECORD *rec)
+{
+ return false;
+}
+
+/* A helper function that will, if needed, set
+ 'stopped_at_software_breakpoint' on the thread and adjust the
+ PC. */
+
+static void
+maybe_adjust_pc ()
+{
+ struct regcache *regcache = get_thread_regcache (current_thread, 1);
+ child_fetch_inferior_registers (regcache, -1);
+
+ windows_thread_info *th = thread_rec (current_thread_ptid (),
+ DONT_INVALIDATE_CONTEXT);
+ th->stopped_at_software_breakpoint = false;
+
+ if (current_event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT
+ && (current_event.u.Exception.ExceptionRecord.ExceptionCode
+ == EXCEPTION_BREAKPOINT)
+ && child_initialization_done)
+ {
+ th->stopped_at_software_breakpoint = true;
+ CORE_ADDR pc = regcache_read_pc (regcache);
+ CORE_ADDR sw_breakpoint_pc = pc - the_low_target.decr_pc_after_break;
+ regcache_write_pc (regcache, sw_breakpoint_pc);
+ }
+}
+
/* 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 ();
happen is the user will see a spurious breakpoint. */
current_event.dwDebugEventCode = 0;
- if (!WaitForDebugEvent (¤t_event, 0))
+ if (!wait_for_debug_event (¤t_event, 0))
{
OUTMSG2(("no attach events left\n"));
fake_breakpoint_event ();
/* Keep the wait time low enough for comfortable remote
interruption, but high enough so gdbserver doesn't become a
bottleneck. */
- if (!WaitForDebugEvent (¤t_event, 250))
+ if (!wait_for_debug_event (¤t_event, 250))
{
DWORD e = GetLastError();
"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:
win32_process_target::wait (ptid_t ptid, target_waitstatus *ourstatus,
int options)
{
- struct regcache *regcache;
-
if (cached_status.kind != TARGET_WAITKIND_IGNORE)
{
/* The core always does a wait after creating the inferior, and
while (1)
{
- if (!get_child_debug_event (ourstatus))
+ DWORD continue_status;
+ if (!get_child_debug_event (&continue_status, ourstatus))
continue;
switch (ourstatus->kind)
case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_SIGNALLED:
case TARGET_WAITKIND_LOADED:
- OUTMSG2 (("Child Stopped with signal = %d \n",
- ourstatus->value.sig));
-
- regcache = get_thread_regcache (current_thread, 1);
- child_fetch_inferior_registers (regcache, -1);
- return debug_event_ptid (¤t_event);
+ {
+ OUTMSG2 (("Child Stopped with signal = %d \n",
+ ourstatus->value.sig));
+ maybe_adjust_pc ();
+ return debug_event_ptid (¤t_event);
+ }
default:
OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
/* fall-through */
case TARGET_WAITKIND_SPURIOUS:
/* do nothing, just continue */
- child_continue (DBG_CONTINUE, -1);
+ child_continue (continue_status, -1);
break;
}
}
return the_low_target.breakpoint;
}
+bool
+win32_process_target::stopped_by_sw_breakpoint ()
+{
+ windows_thread_info *th = thread_rec (current_thread_ptid (),
+ DONT_INVALIDATE_CONTEXT);
+ return th == nullptr ? false : th->stopped_at_software_breakpoint;
+}
+
+bool
+win32_process_target::supports_stopped_by_sw_breakpoint ()
+{
+ return true;
+}
+
+CORE_ADDR
+win32_process_target::read_pc (struct regcache *regcache)
+{
+ return (*the_low_target.get_pc) (regcache);
+}
+
+void
+win32_process_target::write_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+ return (*the_low_target.set_pc) (regcache, pc);
+}
+
/* The win32 target ops object. */
static win32_process_target the_win32_target;