mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 18:08:24 +08:00
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:
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
|
@ -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). */
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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 */
|
||||||
};
|
};
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
Reference in New Issue
Block a user