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:
parent
2fd481e1ea
commit
aa5ca48fad
13 changed files with 558 additions and 36 deletions
|
@ -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>
|
||||
|
||||
* server.c (process_serial_event): Re-return unsupported, not
|
||||
|
|
|
@ -104,7 +104,7 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c \
|
|||
$(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 \
|
||||
|
@ -287,6 +287,10 @@ signals.o: ../common/signals.c $(server_h)
|
|||
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)
|
||||
|
@ -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-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
|
||||
|
@ -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-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)
|
||||
|
||||
|
|
|
@ -53,10 +53,10 @@ case "${target}" in
|
|||
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
|
||||
|
@ -71,7 +71,7 @@ case "${target}" in
|
|||
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
|
||||
|
@ -170,7 +170,7 @@ case "${target}" in
|
|||
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
|
||||
|
|
|
@ -224,6 +224,7 @@ delete_lwp (struct lwp_info *lwp)
|
|||
{
|
||||
remove_thread (get_lwp_thread (lwp));
|
||||
remove_inferior (&all_lwps, &lwp->head);
|
||||
free (lwp->arch_private);
|
||||
free (lwp);
|
||||
}
|
||||
|
||||
|
@ -242,6 +243,9 @@ linux_add_process (int pid, int attached)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -251,6 +255,7 @@ linux_add_process (int pid, int attached)
|
|||
static void
|
||||
linux_remove_process (struct process_info *process)
|
||||
{
|
||||
free (process->private->arch_private);
|
||||
free (process->private);
|
||||
remove_process (process);
|
||||
}
|
||||
|
@ -376,6 +381,9 @@ add_lwp (ptid_t 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);
|
||||
|
||||
return lwp;
|
||||
|
@ -466,7 +474,6 @@ linux_attach_lwp_1 (unsigned long lwpid, int initial)
|
|||
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;
|
||||
|
@ -1740,6 +1747,9 @@ linux_resume_one_lwp (struct lwp_info *lwp,
|
|||
*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;
|
||||
|
|
|
@ -56,8 +56,13 @@ struct process_info_private
|
|||
|
||||
/* 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. */
|
||||
|
@ -97,10 +102,24 @@ struct linux_target_ops
|
|||
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)
|
||||
|
||||
|
@ -173,6 +192,9 @@ struct lwp_info
|
|||
THREAD_KNOWN is set. */
|
||||
td_thrhandle_t th;
|
||||
#endif
|
||||
|
||||
/* Arch-specific additions. */
|
||||
struct arch_lwp_info *arch_private;
|
||||
};
|
||||
|
||||
extern struct inferior_list all_lwps;
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
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"
|
||||
|
||||
|
@ -56,6 +58,21 @@ void init_registers_x86_64_linux (void);
|
|||
#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'
|
||||
|
@ -317,6 +334,198 @@ x86_breakpoint_at (CORE_ADDR pc)
|
|||
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
|
||||
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
|
||||
|
@ -630,10 +839,10 @@ struct linux_target_ops the_low_target =
|
|||
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). */
|
||||
|
@ -641,4 +850,7 @@ struct linux_target_ops the_low_target =
|
|||
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
|
||||
};
|
||||
|
|
|
@ -51,6 +51,9 @@ static char **program_argv, **wrapper_argv;
|
|||
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;
|
||||
|
@ -495,6 +498,8 @@ monitor_show_help (void)
|
|||
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");
|
||||
|
@ -1216,6 +1221,16 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
|||
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;
|
||||
|
|
|
@ -271,6 +271,7 @@ extern ptid_t step_thread;
|
|||
|
||||
extern int server_waiting;
|
||||
extern int debug_threads;
|
||||
extern int debug_hw_points;
|
||||
extern int pass_signals[];
|
||||
|
||||
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 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). */
|
||||
|
|
|
@ -170,3 +170,46 @@ warning (const char *string,...)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -122,4 +122,9 @@ struct win32_target_ops the_low_target = {
|
|||
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 */
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "server.h"
|
||||
#include "win32-low.h"
|
||||
#include "i386-low.h"
|
||||
|
||||
#define FCS_REGNUM 27
|
||||
#define FOP_REGNUM 31
|
||||
|
@ -26,15 +27,101 @@
|
|||
/* 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;
|
||||
}
|
||||
|
@ -55,12 +142,13 @@ i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,13 +157,14 @@ i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
|
|||
{
|
||||
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);
|
||||
|
@ -87,16 +176,17 @@ i386_thread_added (win32_thread_info *th)
|
|||
/* 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;
|
||||
|
@ -205,4 +295,8 @@ struct win32_target_ops the_low_target = {
|
|||
i386_single_step,
|
||||
NULL, /* breakpoint */
|
||||
0, /* breakpoint_len */
|
||||
i386_insert_point,
|
||||
i386_remove_point,
|
||||
i386_stopped_by_watchpoint,
|
||||
i386_stopped_data_address
|
||||
};
|
||||
|
|
|
@ -228,6 +228,48 @@ child_delete_thread (DWORD pid, DWORD tid)
|
|||
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,
|
||||
|
@ -1697,10 +1739,10 @@ static struct target_ops win32_target_ops = {
|
|||
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,
|
||||
|
|
|
@ -70,6 +70,12 @@ struct win32_target_ops
|
|||
|
||||
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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue