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.
This commit is contained in:
Doug Evans
2009-06-30 16:35:25 +00:00
parent 2fd481e1ea
commit aa5ca48fad
13 changed files with 558 additions and 36 deletions

View File

@ -1,3 +1,70 @@
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> 2009-06-25 Pedro Alves <pedro@codesourcery.com>
* server.c (process_serial_event): Re-return unsupported, not * server.c (process_serial_event): Re-return unsupported, not

View File

@ -104,7 +104,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c \
$(srcdir)/thread-db.c $(srcdir)/utils.c \ $(srcdir)/thread-db.c $(srcdir)/utils.c \
$(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \ $(srcdir)/linux-arm-low.c $(srcdir)/linux-cris-low.c \
$(srcdir)/linux-crisv32-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-ia64-low.c $(srcdir)/linux-low.c \
$(srcdir)/linux-m32r-low.c \ $(srcdir)/linux-m32r-low.c \
$(srcdir)/linux-m68k-low.c $(srcdir)/linux-mips-low.c \ $(srcdir)/linux-m68k-low.c $(srcdir)/linux-mips-low.c \
@ -287,6 +287,10 @@ signals.o: ../common/signals.c $(server_h)
memmem.o: ../gnulib/memmem.c memmem.o: ../gnulib/memmem.c
$(CC) -o memmem.o -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< $(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) i387-fp.o: i387-fp.c $(server_h)
linux-low.o: linux-low.c $(linux_low_h) $(server_h) linux-low.o: linux-low.c $(linux_low_h) $(server_h)
@ -304,7 +308,7 @@ linux-ppc-low.o: linux-ppc-low.c $(linux_low_h) $(server_h)
linux-s390-low.o: linux-s390-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-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) \ 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) 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_h = $(srcdir)/win32-low.h
@ -312,7 +316,7 @@ win32_low_h = $(srcdir)/win32-low.h
win32-low.o: win32-low.c $(win32_low_h) $(server_h) $(regdef_h) $(regcache_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-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) spu-low.o: spu-low.c $(server_h)

View File

@ -53,10 +53,10 @@ case "${target}" in
srv_linux_thread_db=yes srv_linux_thread_db=yes
;; ;;
i[34567]86-*-cygwin*) srv_regobj=reg-i386.o 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 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_usrregs=yes
srv_linux_regsets=yes srv_linux_regsets=yes
srv_linux_thread_db=yes srv_linux_thread_db=yes
@ -71,7 +71,7 @@ case "${target}" in
srv_mingwce=yes srv_mingwce=yes
;; ;;
i[34567]86-*-mingw*) srv_regobj=reg-i386.o 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 srv_mingw=yes
;; ;;
ia64-*-linux*) srv_regobj=reg-ia64.o ia64-*-linux*) srv_regobj=reg-ia64.o
@ -170,7 +170,7 @@ case "${target}" in
srv_tgtobj="spu-low.o" srv_tgtobj="spu-low.o"
;; ;;
x86_64-*-linux*) srv_regobj="reg-x86-64-linux.o reg-i386-linux.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_usrregs=yes # This is for i386 progs.
srv_linux_regsets=yes srv_linux_regsets=yes
srv_linux_thread_db=yes srv_linux_thread_db=yes

View File

@ -224,6 +224,7 @@ delete_lwp (struct lwp_info *lwp)
{ {
remove_thread (get_lwp_thread (lwp)); remove_thread (get_lwp_thread (lwp));
remove_inferior (&all_lwps, &lwp->head); remove_inferior (&all_lwps, &lwp->head);
free (lwp->arch_private);
free (lwp); free (lwp);
} }
@ -242,6 +243,9 @@ linux_add_process (int pid, int attached)
proc = add_process (pid, attached); proc = add_process (pid, attached);
proc->private = xcalloc (1, sizeof (*proc->private)); 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; return proc;
} }
@ -251,6 +255,7 @@ linux_add_process (int pid, int attached)
static void static void
linux_remove_process (struct process_info *process) linux_remove_process (struct process_info *process)
{ {
free (process->private->arch_private);
free (process->private); free (process->private);
remove_process (process); remove_process (process);
} }
@ -376,6 +381,9 @@ add_lwp (ptid_t ptid)
lwp->head.id = ptid; 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); add_inferior_to_list (&all_lwps, &lwp->head);
return lwp; return lwp;
@ -466,7 +474,6 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
new_lwp = (struct lwp_info *) add_lwp (ptid); new_lwp = (struct lwp_info *) add_lwp (ptid);
add_thread (ptid, new_lwp); add_thread (ptid, new_lwp);
/* We need to wait for SIGSTOP before being able to make the next /* We need to wait for SIGSTOP before being able to make the next
ptrace call on this LWP. */ ptrace call on this LWP. */
new_lwp->must_set_ptrace_flags = 1; new_lwp->must_set_ptrace_flags = 1;
@ -1740,6 +1747,9 @@ linux_resume_one_lwp (struct lwp_info *lwp,
*p_sig = NULL; *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 *) regcache_invalidate_one ((struct inferior_list_entry *)
get_lwp_thread (lwp)); get_lwp_thread (lwp));
errno = 0; errno = 0;

View File

@ -56,8 +56,13 @@ struct process_info_private
/* Connection to the libthread_db library. */ /* Connection to the libthread_db library. */
td_thragent_t *thread_agent; td_thragent_t *thread_agent;
/* Arch-specific additions. */
struct arch_process_info *arch_private;
}; };
struct lwp_info;
struct linux_target_ops struct linux_target_ops
{ {
/* Architecture-specific setup. */ /* Architecture-specific setup. */
@ -97,10 +102,24 @@ struct linux_target_ops
If DIRECTION is 1, then copy from INF to NATIVE. If DIRECTION is 1, then copy from INF to NATIVE.
If DIRECTION is 0, copy from NATIVE to INF. */ If DIRECTION is 0, copy from NATIVE to INF. */
int (*siginfo_fixup) (struct siginfo *native, void *inf, int direction); 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; 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 pid_of(proc) ptid_get_pid ((proc)->head.id)
#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id) #define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
@ -173,6 +192,9 @@ struct lwp_info
THREAD_KNOWN is set. */ THREAD_KNOWN is set. */
td_thrhandle_t th; td_thrhandle_t th;
#endif #endif
/* Arch-specific additions. */
struct arch_lwp_info *arch_private;
}; };
extern struct inferior_list all_lwps; extern struct inferior_list all_lwps;

View File

@ -18,10 +18,12 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <stddef.h>
#include <signal.h> #include <signal.h>
#include "server.h" #include "server.h"
#include "linux-low.h" #include "linux-low.h"
#include "i387-fp.h" #include "i387-fp.h"
#include "i386-low.h"
#include "gdb_proc_service.h" #include "gdb_proc_service.h"
@ -56,6 +58,21 @@ void init_registers_x86_64_linux (void);
#define ARCH_GET_GS 0x1004 #define ARCH_GET_GS 0x1004
#endif #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__ #ifdef __x86_64__
/* Mapping between the general-purpose registers in `struct user' /* Mapping between the general-purpose registers in `struct user'
@ -317,6 +334,198 @@ x86_breakpoint_at (CORE_ADDR pc)
return 0; return 0;
} }
/* 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);
}
/* 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;
}
/* 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;
}
}
/* When GDBSERVER is built as a 64-bit application on linux, the /* When GDBSERVER is built as a 64-bit application on linux, the
PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since 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 debugging a 32-bit inferior with a 64-bit GDBSERVER should look the same
@ -630,10 +839,10 @@ struct linux_target_ops the_low_target =
NULL, NULL,
1, 1,
x86_breakpoint_at, x86_breakpoint_at,
NULL, x86_insert_point,
NULL, x86_remove_point,
NULL, x86_stopped_by_watchpoint,
NULL, x86_stopped_data_address,
/* collect_ptrace_register/supply_ptrace_register are not needed in the /* collect_ptrace_register/supply_ptrace_register are not needed in the
native i386 case (no registers smaller than an xfer unit), and are not native i386 case (no registers smaller than an xfer unit), and are not
used in the biarch case (HAVE_LINUX_USRREGS is not defined). */ used in the biarch case (HAVE_LINUX_USRREGS is not defined). */
@ -641,4 +850,7 @@ struct linux_target_ops the_low_target =
NULL, NULL,
/* need to fix up i386 siginfo if host is amd64 */ /* need to fix up i386 siginfo if host is amd64 */
x86_siginfo_fixup, x86_siginfo_fixup,
x86_linux_new_process,
x86_linux_new_thread,
x86_linux_prepare_to_resume
}; };

View File

@ -51,6 +51,9 @@ static char **program_argv, **wrapper_argv;
was originally used to debug LinuxThreads support. */ was originally used to debug LinuxThreads support. */
int debug_threads; int debug_threads;
/* Enable debugging of h/w breakpoint/watchpoint support. */
int debug_hw_points;
int pass_signals[TARGET_SIGNAL_LAST]; int pass_signals[TARGET_SIGNAL_LAST];
jmp_buf toplevel; jmp_buf toplevel;
@ -495,6 +498,8 @@ monitor_show_help (void)
monitor_output ("The following monitor commands are supported:\n"); monitor_output ("The following monitor commands are supported:\n");
monitor_output (" set debug <0|1>\n"); monitor_output (" set debug <0|1>\n");
monitor_output (" Enable general debugging messages\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 (" set remote-debug <0|1>\n");
monitor_output (" Enable remote protocol debugging messages\n"); monitor_output (" Enable remote protocol debugging messages\n");
monitor_output (" exit\n"); monitor_output (" exit\n");
@ -1216,6 +1221,16 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
debug_threads = 0; debug_threads = 0;
monitor_output ("Debug output disabled.\n"); 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) else if (strcmp (mon, "set remote-debug 1") == 0)
{ {
remote_debug = 1; remote_debug = 1;

View File

@ -271,6 +271,7 @@ extern ptid_t step_thread;
extern int server_waiting; extern int server_waiting;
extern int debug_threads; extern int debug_threads;
extern int debug_hw_points;
extern int pass_signals[]; extern int pass_signals[];
extern jmp_buf toplevel; extern jmp_buf toplevel;
@ -407,6 +408,7 @@ void perror_with_name (const char *string);
void error (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2); 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 fatal (const char *string,...) ATTR_NORETURN ATTR_FORMAT (printf, 1, 2);
void warning (const char *string,...) 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 /* 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). */ is chosen to fill up a packet (the headers account for the 32). */

View File

@ -170,3 +170,46 @@ warning (const char *string,...)
fprintf (stderr, "\n"); fprintf (stderr, "\n");
va_end (args); 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;
}

View File

@ -122,4 +122,9 @@ struct win32_target_ops the_low_target = {
NULL, /* single_step */ NULL, /* single_step */
(const unsigned char *) &arm_wince_breakpoint, (const unsigned char *) &arm_wince_breakpoint,
arm_wince_breakpoint_len, 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 */
}; };

View File

@ -17,6 +17,7 @@
#include "server.h" #include "server.h"
#include "win32-low.h" #include "win32-low.h"
#include "i386-low.h"
#define FCS_REGNUM 27 #define FCS_REGNUM 27
#define FOP_REGNUM 31 #define FOP_REGNUM 31
@ -26,15 +27,101 @@
/* Defined in auto-generated file reg-i386.c. */ /* Defined in auto-generated file reg-i386.c. */
void init_registers_i386 (void); 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_changed = 0;
static int debug_registers_used = 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 static void
i386_initial_stuff (void) i386_initial_stuff (void)
{ {
memset (&dr, 0, sizeof (dr)); i386_low_init_dregs (&debug_reg_state);
debug_registers_changed = 0; debug_registers_changed = 0;
debug_registers_used = 0; debug_registers_used = 0;
} }
@ -55,12 +142,13 @@ i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
if (th->tid == current_event->dwThreadId) if (th->tid == current_event->dwThreadId)
{ {
/* Copy dr values from the current thread. */ /* Copy dr values from the current thread. */
dr[0] = th->context.Dr0; struct i386_debug_reg_state *dr = &debug_reg_state;
dr[1] = th->context.Dr1; dr->dr_mirror[0] = th->context.Dr0;
dr[2] = th->context.Dr2; dr->dr_mirror[1] = th->context.Dr1;
dr[3] = th->context.Dr3; dr->dr_mirror[2] = th->context.Dr2;
dr[6] = th->context.Dr6; dr->dr_mirror[3] = th->context.Dr3;
dr[7] = th->context.Dr7; dr->dr_status_mirror = th->context.Dr6;
dr->dr_control_mirror = th->context.Dr7;
} }
} }
@ -69,13 +157,14 @@ i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
{ {
if (debug_registers_changed) if (debug_registers_changed)
{ {
th->context.Dr0 = dr[0]; struct i386_debug_reg_state *dr = &debug_reg_state;
th->context.Dr1 = dr[1]; th->context.Dr0 = dr->dr_mirror[0];
th->context.Dr2 = dr[2]; th->context.Dr1 = dr->dr_mirror[1];
th->context.Dr3 = dr[3]; th->context.Dr2 = dr->dr_mirror[2];
/* th->context.Dr6 = dr[6]; th->context.Dr3 = dr->dr_mirror[3];
/* th->context.Dr6 = dr->dr_status_mirror;
FIXME: should we set dr6 also ?? */ FIXME: should we set dr6 also ?? */
th->context.Dr7 = dr[7]; th->context.Dr7 = dr->dr_control_mirror;
} }
SetThreadContext (th->h, &th->context); SetThreadContext (th->h, &th->context);
@ -87,16 +176,17 @@ i386_thread_added (win32_thread_info *th)
/* Set the debug registers for the new thread if they are used. */ /* Set the debug registers for the new thread if they are used. */
if (debug_registers_used) if (debug_registers_used)
{ {
struct i386_debug_reg_state *dr = &debug_reg_state;
th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS; th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
GetThreadContext (th->h, &th->context); GetThreadContext (th->h, &th->context);
th->context.Dr0 = dr[0]; th->context.Dr0 = dr->dr_mirror[0];
th->context.Dr1 = dr[1]; th->context.Dr1 = dr->dr_mirror[1];
th->context.Dr2 = dr[2]; th->context.Dr2 = dr->dr_mirror[2];
th->context.Dr3 = dr[3]; th->context.Dr3 = dr->dr_mirror[3];
/* th->context.Dr6 = dr[6]; /* th->context.Dr6 = dr->dr_status_mirror;
FIXME: should we set dr6 also ?? */ FIXME: should we set dr6 also ?? */
th->context.Dr7 = dr[7]; th->context.Dr7 = dr->dr_control_mirror;
SetThreadContext (th->h, &th->context); SetThreadContext (th->h, &th->context);
th->context.ContextFlags = 0; th->context.ContextFlags = 0;
@ -205,4 +295,8 @@ struct win32_target_ops the_low_target = {
i386_single_step, i386_single_step,
NULL, /* breakpoint */ NULL, /* breakpoint */
0, /* breakpoint_len */ 0, /* breakpoint_len */
i386_insert_point,
i386_remove_point,
i386_stopped_by_watchpoint,
i386_stopped_data_address
}; };

View File

@ -228,6 +228,48 @@ child_delete_thread (DWORD pid, DWORD tid)
delete_thread_info (thread); 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. */ /* Transfer memory from/to the debugged process. */
static int static int
child_xfer_memory (CORE_ADDR memaddr, char *our, int len, child_xfer_memory (CORE_ADDR memaddr, char *our, int len,
@ -1697,10 +1739,10 @@ static struct target_ops win32_target_ops = {
NULL, NULL,
win32_request_interrupt, win32_request_interrupt,
NULL, NULL,
NULL, win32_insert_point,
NULL, win32_remove_point,
NULL, win32_stopped_by_watchpoint,
NULL, win32_stopped_data_address,
NULL, NULL,
NULL, NULL,
NULL, NULL,

View File

@ -70,6 +70,12 @@ struct win32_target_ops
const unsigned char *breakpoint; const unsigned char *breakpoint;
int breakpoint_len; 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; extern struct win32_target_ops the_low_target;