+2009-06-30 Doug Evans <dje@google.com>
+ Pierre Muller <muller@ics.u-strasbg.fr>
+
+ Add h/w watchpoint support to x86-linux, win32-i386.
+ * Makefile.in (SFILES): Add i386-low.c
+ (i386_low_h): Define.
+ (i386-low.o): Add dependencies.
+ (linux-x86-low.o): Add i386-low.h dependency.
+ (win32-i386-low.o): Ditto.
+ * i386-low.c: New file.
+ * i386-low.h: New file.
+ * configure.srv (i[34567]86-*-cygwin*): Add i386-low.o to srv_tgtobj.
+ (i[34567]86-*-linux*, i[34567]86-*-mingw*, x86_64-*-linux*): Ditto.
+ * linux-low.c (linux_add_process): Initialize arch_private.
+ (linux_remove_process): Free arch_private.
+ (add_lwp): Initialize arch_private.
+ (delete_lwp): Free arch_private.
+ (linux_resume_one_lwp): Call the_low_target.prepare_to_resume if
+ provided.
+ * linux-low.h (process_info_private): New member arch_private.
+ (lwp_info): New member arch_private.
+ (linux_target_ops): New members new_process, new_thread,
+ prepare_to_resume.
+ (ptid_of): New macro.
+ * linux-x86-low.c: Include stddef.h, i386-low.h.
+ (arch_process_info): New struct.
+ (arch_lwp_info): New struct.
+ (x86_linux_dr_get, x86_linux_dr_set): New functions.
+ (i386_dr_low_set_addr, i386_dr_low_set_control): New functions.
+ (i386_dr_low_get_status): New function.
+ (x86_insert_point, x86_remove_point): New functions.
+ (x86_stopped_by_watchpoint): New function.
+ (x86_stopped_data_address): New function.
+ (x86_linux_new_process, x86_linux_new_thread): New functions.
+ (x86_linux_prepare_to_resume): New function.
+ (the_low_target): Add entries for insert_point, remove_point,
+ stopped_by_watchpoint, stopped_data_address, new_process, new_thread,
+ prepare_to_resume.
+ * server.c (debug_hw_points): New global.
+ (monitor_show_help): Document set debug-hw-points.
+ (handle_query): Process "set debug-hw-points".
+ * server.h (debug_hw_points): Declare.
+ (paddress): Declare.
+ * utils.c (NUMCELLS, CELLSIZE): New macros.
+ (get_sell, xsnprintf, paddress): New functions.
+ * win32-arm-low.c (the_low_target): Add entries for insert_point,
+ remove_point, stopped_by_watchpoint, stopped_data_address.
+ * win32-i386-low.c: Include i386-low.h.
+ (debug_reg_state): Replaces dr.
+ (i386_dr_low_set_addr, i386_dr_low_set_control): New functions.
+ (i386_dr_low_get_status): New function.
+ (i386_insert_point, i386_remove_point): New functions.
+ (i386_stopped_by_watchpoint): New function.
+ (i386_stopped_data_address): New function.
+ (i386_initial_stuff): Update.
+ (get_thread_context,set_thread_context,i386_thread_added): Update.
+ (the_low_target): Add entries for insert_point,
+ remove_point, stopped_by_watchpoint, stopped_data_address.
+ * win32-low.c (win32_insert_watchpoint): New function.
+ (win32_remove_watchpoint): New function.
+ (win32_stopped_by_watchpoint): New function.
+ (win32_stopped_data_address): New function.
+ (win32_target_ops): Add entries for insert_watchpoint,
+ remove_watchpoint, stopped_by_watchpoint, stopped_data_address.
+ * win32-low.h (win32_target_ops): New members insert_point,
+ remove_point, stopped_by_watchpoint, stopped_data_address.
+
2009-06-25 Pedro Alves <pedro@codesourcery.com>
* server.c (process_serial_event): Re-return unsupported, not
$(srcdir)/thread-db.c $(srcdir)/utils.c \
$(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \
$(srcdir)/linux-crisv32-low.c \
- $(srcdir)/i387-fp.c \
+ ${srcdir}/i386-low.c $(srcdir)/i387-fp.c \
$(srcdir)/linux-ia64-low.c $(srcdir)/linux-low.c \
$(srcdir)/linux-m32r-low.c \
$(srcdir)/linux-m68k-low.c $(srcdir)/linux-mips-low.c \
memmem.o: ../gnulib/memmem.c
$(CC) -o memmem.o -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+i386_low_h = $(srcdir)/i386-low.h
+
+i386-low.o: i386-low.c $(i386_low_h) $(server_h) $(target_h)
+
i387-fp.o: i387-fp.c $(server_h)
linux-low.o: linux-low.c $(linux_low_h) $(server_h)
linux-s390-low.o: linux-s390-low.c $(linux_low_h) $(server_h)
linux-sh-low.o: linux-sh-low.c $(linux_low_h) $(server_h)
linux-x86-low.o: linux-x86-low.c $(linux_low_h) $(server_h) \
- $(gdb_proc_service_h)
+ $(gdb_proc_service_h) $(i386_low_h)
linux-xtensa-low.o: linux-xtensa-low.c xtensa-xtregs.c $(linux_low_h) $(server_h)
win32_low_h = $(srcdir)/win32-low.h
win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_h)
win32-arm-low.o: win32-arm-low.c $(win32_low_h) $(server_h)
-win32-i386-low.o: win32-i386-low.c $(win32_low_h) $(server_h)
+win32-i386-low.o: win32-i386-low.c $(win32_low_h) $(server_h) $(i386_low_h)
spu-low.o: spu-low.c $(server_h)
srv_linux_thread_db=yes
;;
i[34567]86-*-cygwin*) srv_regobj=reg-i386.o
- srv_tgtobj="win32-low.o win32-i386-low.o"
+ srv_tgtobj="i386-low.o win32-low.o win32-i386-low.o"
;;
i[34567]86-*-linux*) srv_regobj=reg-i386-linux.o
- srv_tgtobj="linux-low.o linux-x86-low.o i387-fp.o"
+ srv_tgtobj="linux-low.o linux-x86-low.o i386-low.o i387-fp.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
srv_linux_thread_db=yes
srv_mingwce=yes
;;
i[34567]86-*-mingw*) srv_regobj=reg-i386.o
- srv_tgtobj="win32-low.o win32-i386-low.o"
+ srv_tgtobj="i386-low.o win32-low.o win32-i386-low.o"
srv_mingw=yes
;;
ia64-*-linux*) srv_regobj=reg-ia64.o
srv_tgtobj="spu-low.o"
;;
x86_64-*-linux*) srv_regobj="reg-x86-64-linux.o reg-i386-linux.o"
- srv_tgtobj="linux-low.o linux-x86-low.o i387-fp.o"
+ srv_tgtobj="linux-low.o linux-x86-low.o i386-low.o i387-fp.o"
srv_linux_usrregs=yes # This is for i386 progs.
srv_linux_regsets=yes
srv_linux_thread_db=yes
{
remove_thread (get_lwp_thread (lwp));
remove_inferior (&all_lwps, &lwp->head);
+ free (lwp->arch_private);
free (lwp);
}
proc = add_process (pid, attached);
proc->private = xcalloc (1, sizeof (*proc->private));
+ if (the_low_target.new_process != NULL)
+ proc->private->arch_private = the_low_target.new_process ();
+
return proc;
}
static void
linux_remove_process (struct process_info *process)
{
+ free (process->private->arch_private);
free (process->private);
remove_process (process);
}
lwp->head.id = ptid;
+ if (the_low_target.new_thread != NULL)
+ lwp->arch_private = the_low_target.new_thread ();
+
add_inferior_to_list (&all_lwps, &lwp->head);
return lwp;
new_lwp = (struct lwp_info *) add_lwp (ptid);
add_thread (ptid, new_lwp);
-
/* We need to wait for SIGSTOP before being able to make the next
ptrace call on this LWP. */
new_lwp->must_set_ptrace_flags = 1;
*p_sig = NULL;
}
+ if (the_low_target.prepare_to_resume != NULL)
+ the_low_target.prepare_to_resume (lwp);
+
regcache_invalidate_one ((struct inferior_list_entry *)
get_lwp_thread (lwp));
errno = 0;
/* Connection to the libthread_db library. */
td_thragent_t *thread_agent;
+
+ /* Arch-specific additions. */
+ struct arch_process_info *arch_private;
};
+struct lwp_info;
+
struct linux_target_ops
{
/* Architecture-specific setup. */
If DIRECTION is 1, then copy from INF to NATIVE.
If DIRECTION is 0, copy from NATIVE to INF. */
int (*siginfo_fixup) (struct siginfo *native, void *inf, int direction);
+
+ /* Hook to call when a new process is created or attached to.
+ If extra per-process architecture-specific data is needed,
+ allocate it here. */
+ struct arch_process_info * (*new_process) (void);
+
+ /* Hook to call when a new thread is detected.
+ If extra per-thread architecture-specific data is needed,
+ allocate it here. */
+ struct arch_lwp_info * (*new_thread) (void);
+
+ /* Hook to call prior to resuming a thread. */
+ void (*prepare_to_resume) (struct lwp_info *);
};
extern struct linux_target_ops the_low_target;
+#define ptid_of(proc) ((proc)->head.id)
#define pid_of(proc) ptid_get_pid ((proc)->head.id)
#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
THREAD_KNOWN is set. */
td_thrhandle_t th;
#endif
+
+ /* Arch-specific additions. */
+ struct arch_lwp_info *arch_private;
};
extern struct inferior_list all_lwps;
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#include <stddef.h>
#include <signal.h>
#include "server.h"
#include "linux-low.h"
#include "i387-fp.h"
+#include "i386-low.h"
#include "gdb_proc_service.h"
#define ARCH_GET_GS 0x1004
#endif
+/* Per-process arch-specific data we want to keep. */
+
+struct arch_process_info
+{
+ struct i386_debug_reg_state debug_reg_state;
+};
+
+/* Per-thread arch-specific data we want to keep. */
+
+struct arch_lwp_info
+{
+ /* Non-zero if our copy differs from what's recorded in the thread. */
+ int debug_registers_changed;
+};
+
#ifdef __x86_64__
/* Mapping between the general-purpose registers in `struct user'
return 0;
}
\f
+/* Support for debug registers. */
+
+static unsigned long
+x86_linux_dr_get (ptid_t ptid, int regnum)
+{
+ int tid;
+ unsigned long value;
+
+ tid = ptid_get_lwp (ptid);
+
+ errno = 0;
+ value = ptrace (PTRACE_PEEKUSER, tid,
+ offsetof (struct user, u_debugreg[regnum]), 0);
+ if (errno != 0)
+ error ("Couldn't read debug register");
+
+ return value;
+}
+
+static void
+x86_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
+{
+ int tid;
+
+ tid = ptid_get_lwp (ptid);
+
+ errno = 0;
+ ptrace (PTRACE_POKEUSER, tid,
+ offsetof (struct user, u_debugreg[regnum]), value);
+ if (errno != 0)
+ error ("Couldn't write debug register");
+}
+
+/* Update the inferior's debug register REGNUM from STATE. */
+
+void
+i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum)
+{
+ struct inferior_list_entry *lp;
+ CORE_ADDR addr;
+ /* Only need to update the threads of this process. */
+ int pid = pid_of (get_thread_lwp (current_inferior));
+
+ if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
+ fatal ("Invalid debug register %d", regnum);
+
+ addr = state->dr_mirror[regnum];
+
+ for (lp = all_lwps.head; lp; lp = lp->next)
+ {
+ struct lwp_info *lwp = (struct lwp_info *) lp;
+
+ /* The actual update is done later, we just mark that the register
+ needs updating. */
+ if (pid_of (lwp) == pid)
+ lwp->arch_private->debug_registers_changed = 1;
+ }
+}
+
+/* Update the inferior's DR7 debug control register from STATE. */
+
+void
+i386_dr_low_set_control (const struct i386_debug_reg_state *state)
+{
+ struct inferior_list_entry *lp;
+ /* Only need to update the threads of this process. */
+ int pid = pid_of (get_thread_lwp (current_inferior));
+
+ for (lp = all_lwps.head; lp; lp = lp->next)
+ {
+ struct lwp_info *lwp = (struct lwp_info *) lp;
+
+ /* The actual update is done later, we just mark that the register
+ needs updating. */
+ if (pid_of (lwp) == pid)
+ lwp->arch_private->debug_registers_changed = 1;
+ }
+}
+
+/* Get the value of the DR6 debug status register from the inferior
+ and record it in STATE. */
+
+void
+i386_dr_low_get_status (struct i386_debug_reg_state *state)
+{
+ struct lwp_info *lwp = get_thread_lwp (current_inferior);
+ ptid_t ptid = ptid_of (lwp);
+
+ state->dr_status_mirror = x86_linux_dr_get (ptid, DR_STATUS);
+}
+\f
+/* Watchpoint support. */
+
+static int
+x86_insert_point (char type, CORE_ADDR addr, int len)
+{
+ struct process_info *proc = current_process ();
+ switch (type)
+ {
+ case '2':
+ case '3':
+ case '4':
+ return i386_low_insert_watchpoint (&proc->private->arch_private->debug_reg_state,
+ type, addr, len);
+ default:
+ /* Unsupported. */
+ return 1;
+ }
+}
+
+static int
+x86_remove_point (char type, CORE_ADDR addr, int len)
+{
+ struct process_info *proc = current_process ();
+ switch (type)
+ {
+ case '2':
+ case '3':
+ case '4':
+ return i386_low_remove_watchpoint (&proc->private->arch_private->debug_reg_state,
+ type, addr, len);
+ default:
+ /* Unsupported. */
+ return 1;
+ }
+}
+
+static int
+x86_stopped_by_watchpoint (void)
+{
+ struct process_info *proc = current_process ();
+ return i386_low_stopped_by_watchpoint (&proc->private->arch_private->debug_reg_state);
+}
+
+static CORE_ADDR
+x86_stopped_data_address (void)
+{
+ struct process_info *proc = current_process ();
+ CORE_ADDR addr;
+ if (i386_low_stopped_data_address (&proc->private->arch_private->debug_reg_state,
+ &addr))
+ return addr;
+ return 0;
+}
+\f
+/* Called when a new process is created. */
+
+static struct arch_process_info *
+x86_linux_new_process (void)
+{
+ struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+ i386_low_init_dregs (&info->debug_reg_state);
+
+ return info;
+}
+
+/* Called when a new thread is detected. */
+
+static struct arch_lwp_info *
+x86_linux_new_thread (void)
+{
+ struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+ info->debug_registers_changed = 1;
+
+ return info;
+}
+
+/* Called when resuming a thread.
+ If the debug regs have changed, update the thread's copies. */
+
+static void
+x86_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+ if (lwp->arch_private->debug_registers_changed)
+ {
+ int i;
+ ptid_t ptid = ptid_of (lwp);
+ int pid = ptid_get_pid (ptid);
+ struct process_info *proc = find_process_pid (pid);
+ struct i386_debug_reg_state *state = &proc->private->arch_private->debug_reg_state;
+
+ for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+ x86_linux_dr_set (ptid, i, state->dr_mirror[i]);
+
+ x86_linux_dr_set (ptid, DR_CONTROL, state->dr_control_mirror);
+
+ lwp->arch_private->debug_registers_changed = 0;
+ }
+}
+\f
/* When GDBSERVER is built as a 64-bit application on linux, the
PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since
debugging a 32-bit inferior with a 64-bit GDBSERVER should look the same
NULL,
1,
x86_breakpoint_at,
- NULL,
- NULL,
- NULL,
- NULL,
+ x86_insert_point,
+ x86_remove_point,
+ x86_stopped_by_watchpoint,
+ x86_stopped_data_address,
/* collect_ptrace_register/supply_ptrace_register are not needed in the
native i386 case (no registers smaller than an xfer unit), and are not
used in the biarch case (HAVE_LINUX_USRREGS is not defined). */
NULL,
/* need to fix up i386 siginfo if host is amd64 */
x86_siginfo_fixup,
+ x86_linux_new_process,
+ x86_linux_new_thread,
+ x86_linux_prepare_to_resume
};
was originally used to debug LinuxThreads support. */
int debug_threads;
+/* Enable debugging of h/w breakpoint/watchpoint support. */
+int debug_hw_points;
+
int pass_signals[TARGET_SIGNAL_LAST];
jmp_buf toplevel;
monitor_output ("The following monitor commands are supported:\n");
monitor_output (" set debug <0|1>\n");
monitor_output (" Enable general debugging messages\n");
+ monitor_output (" set debug-hw-points <0|1>\n");
+ monitor_output (" Enable h/w breakpoint/watchpoint debugging messages\n");
monitor_output (" set remote-debug <0|1>\n");
monitor_output (" Enable remote protocol debugging messages\n");
monitor_output (" exit\n");
debug_threads = 0;
monitor_output ("Debug output disabled.\n");
}
+ else if (strcmp (mon, "set debug-hw-points 1") == 0)
+ {
+ debug_hw_points = 1;
+ monitor_output ("H/W point debugging output enabled.\n");
+ }
+ else if (strcmp (mon, "set debug-hw-points 0") == 0)
+ {
+ debug_hw_points = 0;
+ monitor_output ("H/W point debugging output disabled.\n");
+ }
else if (strcmp (mon, "set remote-debug 1") == 0)
{
remote_debug = 1;
extern int server_waiting;
extern int debug_threads;
+extern int debug_hw_points;
extern int pass_signals[];
extern jmp_buf toplevel;
void error (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
void fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
void warning (const char *string,...) ATTR_FORMAT (printf, 1, 2);
+char *paddress (CORE_ADDR addr);
/* Maximum number of bytes to read/write at once. The value here
is chosen to fill up a packet (the headers account for the 32). */
fprintf (stderr, "\n");
va_end (args);
}
+
+/* Temporary storage using circular buffer. */
+#define NUMCELLS 4
+#define CELLSIZE 50
+
+/* Return the next entry in the circular buffer. */
+
+static char *
+get_cell (void)
+{
+ static char buf[NUMCELLS][CELLSIZE];
+ static int cell = 0;
+ if (++cell >= NUMCELLS)
+ cell = 0;
+ return buf[cell];
+}
+
+/* Stdarg wrapper around vsnprintf.
+ SIZE is the size of the buffer pointed to by STR. */
+
+static int
+xsnprintf (char *str, size_t size, const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start (args, format);
+ ret = vsnprintf (str, size, format, args);
+ va_end (args);
+
+ return ret;
+}
+
+/* Convert a CORE_ADDR into a HEX string, like %lx.
+ The result is stored in a circular static buffer, NUMCELLS deep. */
+
+char *
+paddress (CORE_ADDR addr)
+{
+ char *str = get_cell ();
+ xsnprintf (str, CELLSIZE, "%lx", (long) addr);
+ return str;
+}
NULL, /* single_step */
(const unsigned char *) &arm_wince_breakpoint,
arm_wince_breakpoint_len,
+ /* Watchpoint related functions. See target.h for comments. */
+ NULL, /* insert_point */
+ NULL, /* remove_point */
+ NULL, /* stopped_by_watchpoint */
+ NULL /* stopped_data_address */
};
#include "server.h"
#include "win32-low.h"
+#include "i386-low.h"
#define FCS_REGNUM 27
#define FOP_REGNUM 31
/* Defined in auto-generated file reg-i386.c. */
void init_registers_i386 (void);
-static unsigned dr[8];
+static struct i386_debug_reg_state debug_reg_state;
static int debug_registers_changed = 0;
static int debug_registers_used = 0;
+/* Update the inferior's debug register REGNUM from STATE. */
+
+void
+i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum)
+{
+ if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
+ fatal ("Invalid debug register %d", regnum);
+
+ /* debug_reg_state.dr_mirror is already set.
+ Just notify i386_set_thread_context, i386_thread_added
+ that the registers need to be updated. */
+ debug_registers_changed = 1;
+ debug_registers_used = 1;
+}
+
+/* Update the inferior's DR7 debug control register from STATE. */
+
+void
+i386_dr_low_set_control (const struct i386_debug_reg_state *state)
+{
+ /* debug_reg_state.dr_control_mirror is already set.
+ Just notify i386_set_thread_context, i386_thread_added
+ that the registers need to be updated. */
+ debug_registers_changed = 1;
+ debug_registers_used = 1;
+}
+
+/* Get the value of the DR6 debug status register from the inferior
+ and record it in STATE. */
+
+void
+i386_dr_low_get_status (struct i386_debug_reg_state *state)
+{
+ /* We don't need to do anything here, the last call to thread_rec for
+ current_event.dwThreadId id has already set it. */
+}
+
+/* Watchpoint support. */
+
+static int
+i386_insert_point (char type, CORE_ADDR addr, int len)
+{
+ switch (type)
+ {
+ case '2':
+ case '3':
+ case '4':
+ return i386_low_insert_watchpoint (&debug_reg_state,
+ type, addr, len);
+ default:
+ /* Unsupported. */
+ return 1;
+ }
+}
+
+static int
+i386_remove_point (char type, CORE_ADDR addr, int len)
+{
+ switch (type)
+ {
+ case '2':
+ case '3':
+ case '4':
+ return i386_low_remove_watchpoint (&debug_reg_state,
+ type, addr, len);
+ default:
+ /* Unsupported. */
+ return 1;
+ }
+}
+
+static int
+i386_stopped_by_watchpoint (void)
+{
+ return i386_low_stopped_by_watchpoint (&debug_reg_state);
+}
+
+static CORE_ADDR
+i386_stopped_data_address (void)
+{
+ CORE_ADDR addr;
+ if (i386_low_stopped_data_address (&debug_reg_state, &addr))
+ return addr;
+ return 0;
+}
+
static void
i386_initial_stuff (void)
{
- memset (&dr, 0, sizeof (dr));
+ i386_low_init_dregs (&debug_reg_state);
debug_registers_changed = 0;
debug_registers_used = 0;
}
if (th->tid == current_event->dwThreadId)
{
/* Copy dr values from the current thread. */
- dr[0] = th->context.Dr0;
- dr[1] = th->context.Dr1;
- dr[2] = th->context.Dr2;
- dr[3] = th->context.Dr3;
- dr[6] = th->context.Dr6;
- dr[7] = th->context.Dr7;
+ struct i386_debug_reg_state *dr = &debug_reg_state;
+ dr->dr_mirror[0] = th->context.Dr0;
+ dr->dr_mirror[1] = th->context.Dr1;
+ dr->dr_mirror[2] = th->context.Dr2;
+ dr->dr_mirror[3] = th->context.Dr3;
+ dr->dr_status_mirror = th->context.Dr6;
+ dr->dr_control_mirror = th->context.Dr7;
}
}
{
if (debug_registers_changed)
{
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
+ struct i386_debug_reg_state *dr = &debug_reg_state;
+ th->context.Dr0 = dr->dr_mirror[0];
+ th->context.Dr1 = dr->dr_mirror[1];
+ th->context.Dr2 = dr->dr_mirror[2];
+ th->context.Dr3 = dr->dr_mirror[3];
+ /* th->context.Dr6 = dr->dr_status_mirror;
FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
+ th->context.Dr7 = dr->dr_control_mirror;
}
SetThreadContext (th->h, &th->context);
/* Set the debug registers for the new thread if they are used. */
if (debug_registers_used)
{
+ struct i386_debug_reg_state *dr = &debug_reg_state;
th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext (th->h, &th->context);
- th->context.Dr0 = dr[0];
- th->context.Dr1 = dr[1];
- th->context.Dr2 = dr[2];
- th->context.Dr3 = dr[3];
- /* th->context.Dr6 = dr[6];
+ th->context.Dr0 = dr->dr_mirror[0];
+ th->context.Dr1 = dr->dr_mirror[1];
+ th->context.Dr2 = dr->dr_mirror[2];
+ th->context.Dr3 = dr->dr_mirror[3];
+ /* th->context.Dr6 = dr->dr_status_mirror;
FIXME: should we set dr6 also ?? */
- th->context.Dr7 = dr[7];
+ th->context.Dr7 = dr->dr_control_mirror;
SetThreadContext (th->h, &th->context);
th->context.ContextFlags = 0;
i386_single_step,
NULL, /* breakpoint */
0, /* breakpoint_len */
+ i386_insert_point,
+ i386_remove_point,
+ i386_stopped_by_watchpoint,
+ i386_stopped_data_address
};
delete_thread_info (thread);
}
+/* These watchpoint related wrapper functions simply pass on the function call
+ if the low target has registered a corresponding function. */
+
+static int
+win32_insert_point (char type, CORE_ADDR addr, int len)
+{
+ if (the_low_target.insert_point != NULL)
+ return the_low_target.insert_point (type, addr, len);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_remove_point (char type, CORE_ADDR addr, int len)
+{
+ if (the_low_target.remove_point != NULL)
+ return the_low_target.remove_point (type, addr, len);
+ else
+ /* Unsupported (see target.h). */
+ return 1;
+}
+
+static int
+win32_stopped_by_watchpoint (void)
+{
+ if (the_low_target.stopped_by_watchpoint != NULL)
+ return the_low_target.stopped_by_watchpoint ();
+ else
+ return 0;
+}
+
+static CORE_ADDR
+win32_stopped_data_address (void)
+{
+ if (the_low_target.stopped_data_address != NULL)
+ return the_low_target.stopped_data_address ();
+ else
+ return 0;
+}
+
+
/* Transfer memory from/to the debugged process. */
static int
child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
NULL,
win32_request_interrupt,
NULL,
- NULL,
- NULL,
- NULL,
- NULL,
+ win32_insert_point,
+ win32_remove_point,
+ win32_stopped_by_watchpoint,
+ win32_stopped_data_address,
NULL,
NULL,
NULL,
const unsigned char *breakpoint;
int breakpoint_len;
+
+ /* Breakpoint/Watchpoint related functions. See target.h for comments. */
+ int (*insert_point) (char type, CORE_ADDR addr, int len);
+ int (*remove_point) (char type, CORE_ADDR addr, int len);
+ int (*stopped_by_watchpoint) (void);
+ CORE_ADDR (*stopped_data_address) (void);
};
extern struct win32_target_ops the_low_target;