summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWu Zhou <woodzltc@cn.ibm.com>2006-02-08 05:41:06 +0000
committerWu Zhou <woodzltc@cn.ibm.com>2006-02-08 05:41:06 +0000
commit15cc036c56823cdd63b75dcf212854277bafb679 (patch)
treef44c1fa11063ab79775f8ebb2f3106cd0425b792
parentba68fc5127ea450fe7f1debd646368e13d41dfe7 (diff)
downloadgdb-15cc036c56823cdd63b75dcf212854277bafb679.tar.gz
* ppc-linux-nat.c (PTRACE_GET_DEBUGREG, PTRACE_SET_DEBUGREG,
PTRACE_GETSIGINFO): Define. (last_stopped_data_address): New. (ppc_linux_check_watch_resources): New function. (ppc_linux_region_ok_for_hw_watchpoint): New function. (ppc_linux_insert_watchpoint): New function. (ppc_linux_remove_watchpoint): New function. (ppc_linux_stopped_data_address): New function. (ppc_linux_stopped_by_watchpoint): New function. (_initialize_ppc_linux_nat): Set the above hardware watchpoint related target vectors. * rs6000-tdep.c (rs6000_gdbarch_init): Set PPC architectures to have nonsteppable watchpoint. * target.c (default_region_ok_for_hw_watchpoint, debug_to_region_ok_for_hw_watchpoint): New prototypes. (update_current_target): Inherit to_region_ok_for_hw_watchpoint and set default to_region_ok_for_hw_watchpoint. (default_region_ok_for_hw_watchpoint): New function. (debug_to_region_ok_for_hw_watchpoint): New function. (setup_target_debug): Set to_region_ok_for_hw_watchpoint of debug_target. * target.h (struct target_ops): Add a new target vector to_region_ok_for_hw_watchpoint. (TARGET_REGION_OK_FOR_HW_WATCHPOINT): Define this if it is not defined anyplace else.
-rw-r--r--gdb/ChangeLog30
-rw-r--r--gdb/ppc-linux-nat.c138
-rw-r--r--gdb/rs6000-tdep.c2
-rw-r--r--gdb/target.c29
-rw-r--r--gdb/target.h6
5 files changed, 203 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2a51386ae95..679131a9dce 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,33 @@
-2005-02-07 Joel Brobecker <brobecker@adacore.com>
+2006-02-08 Ben Elliston <bje@au1.ibm.com>
+ Wu Zhou <woodzltc@cn.ibm.com>
+
+ * ppc-linux-nat.c (PTRACE_GET_DEBUGREG, PTRACE_SET_DEBUGREG,
+ PTRACE_GETSIGINFO): Define.
+ (last_stopped_data_address): New.
+ (ppc_linux_check_watch_resources): New function.
+ (ppc_linux_region_ok_for_hw_watchpoint): New function.
+ (ppc_linux_insert_watchpoint): New function.
+ (ppc_linux_remove_watchpoint): New function.
+ (ppc_linux_stopped_data_address): New function.
+ (ppc_linux_stopped_by_watchpoint): New function.
+ (_initialize_ppc_linux_nat): Set the above hardware watchpoint
+ related target vectors.
+ * rs6000-tdep.c (rs6000_gdbarch_init): Set PPC architectures
+ to have nonsteppable watchpoint.
+ * target.c (default_region_ok_for_hw_watchpoint,
+ debug_to_region_ok_for_hw_watchpoint): New prototypes.
+ (update_current_target): Inherit to_region_ok_for_hw_watchpoint
+ and set default to_region_ok_for_hw_watchpoint.
+ (default_region_ok_for_hw_watchpoint): New function.
+ (debug_to_region_ok_for_hw_watchpoint): New function.
+ (setup_target_debug): Set to_region_ok_for_hw_watchpoint of
+ debug_target.
+ * target.h (struct target_ops): Add a new target vector
+ to_region_ok_for_hw_watchpoint.
+ (TARGET_REGION_OK_FOR_HW_WATCHPOINT): Define this if it is not
+ defined anyplace else.
+2005-02-07 Joel Brobecker <brobecker@adacore.com>
* symfile.c (add_symbol_file_command): Abort if the user forgot
to provide the address when the file has been loaded.
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index c8c9376310c..b52eca2969c 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -81,6 +81,16 @@
#define PTRACE_SETEVRREGS 21
#endif
+/* Similarly for the hardware watchpoint support. */
+#ifndef PTRACE_GET_DEBUGREG
+#define PTRACE_GET_DEBUGREG 25
+#endif
+#ifndef PTRACE_SET_DEBUGREG
+#define PTRACE_SET_DEBUGREG 26
+#endif
+#ifndef PTRACE_GETSIGINFO
+#define PTRACE_GETSIGINFO 0x4202
+#endif
/* This oddity is because the Linux kernel defines elf_vrregset_t as
an array of 33 16 bytes long elements. I.e. it leaves out vrsave.
@@ -146,6 +156,7 @@ struct gdb_evrregset_t
error. */
int have_ptrace_getvrregs = 1;
+static CORE_ADDR last_stopped_data_address = 0;
/* Non-zero if our kernel may support the PTRACE_GETEVRREGS and
PTRACE_SETEVRREGS requests, for reading and writing the SPE
@@ -153,7 +164,6 @@ int have_ptrace_getvrregs = 1;
error. */
int have_ptrace_getsetevrregs = 1;
-
int
kernel_u_size (void)
{
@@ -777,6 +787,124 @@ store_ppc_registers (int tid)
store_spe_register (tid, -1);
}
+static int
+ppc_linux_check_watch_resources (int type, int cnt, int ot)
+{
+ int tid;
+ ptid_t ptid = inferior_ptid;
+
+ /* DABR (data address breakpoint register) is optional for PPC variants.
+ Some variants have one DABR, others have none. So CNT can't be larger
+ than 1. */
+ if (cnt > 1)
+ return 0;
+
+ /* We need to know whether ptrace supports PTRACE_SET_DEBUGREG and whether
+ the target has DABR. If either answer is no, the ptrace call will
+ return -1. Fail in that case. */
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
+ return 0;
+ return 1;
+}
+
+static int
+ppc_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ /* Handle sub-8-byte quantities. */
+ if (len <= 0)
+ return 0;
+
+ /* addr+len must fall in the 8 byte watchable region. */
+ if ((addr + len) > (addr & ~7) + 8)
+ return 0;
+
+ return 1;
+}
+
+/* Set a watchpoint of type TYPE at address ADDR. */
+static long
+ppc_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+{
+ int tid;
+ long dabr_value;
+ ptid_t ptid = inferior_ptid;
+
+ dabr_value = addr & ~7;
+ switch (rw)
+ {
+ case hw_read:
+ /* Set read and translate bits. */
+ dabr_value |= 5;
+ break;
+ case hw_write:
+ /* Set write and translate bits. */
+ dabr_value |= 6;
+ break;
+ case hw_access:
+ /* Set read, write and translate bits. */
+ dabr_value |= 7;
+ break;
+ }
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value);
+}
+
+static long
+ppc_linux_remove_watchpoint (CORE_ADDR addr, int len)
+{
+ int tid;
+ ptid_t ptid = inferior_ptid;
+
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ return ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0);
+}
+
+static int
+ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
+{
+ if (last_stopped_data_address)
+ {
+ *addr_p = last_stopped_data_address;
+ last_stopped_data_address = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc_linux_stopped_by_watchpoint (void)
+{
+ int tid;
+ struct siginfo siginfo;
+ ptid_t ptid = inferior_ptid;
+ CORE_ADDR *addr_p;
+
+ tid = TIDGET(ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
+
+ errno = 0;
+ ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+
+ if (errno != 0 || siginfo.si_signo != SIGTRAP ||
+ (siginfo.si_code & 0xffff) != 0x0004)
+ return 0;
+
+ last_stopped_data_address = (CORE_ADDR) siginfo.si_addr;
+ return 1;
+}
+
static void
ppc_linux_store_inferior_registers (int regno)
{
@@ -900,6 +1028,14 @@ _initialize_ppc_linux_nat (void)
t->to_fetch_registers = ppc_linux_fetch_inferior_registers;
t->to_store_registers = ppc_linux_store_inferior_registers;
+ /* Add our watchpoint methods. */
+ t->to_can_use_hw_breakpoint = ppc_linux_check_watch_resources;
+ t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
+ t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
+ t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+ t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
+ t->to_stopped_data_address = ppc_linux_stopped_data_address;
+
/* Register the target. */
add_target (t);
}
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index 1d4a437ac59..19a4bc9d0d0 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -3387,6 +3387,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
_("rs6000_gdbarch_init: "
"received unexpected BFD 'arch' value"));
+ set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1);
+
/* Sanity check on registers. */
gdb_assert (strcmp (tdep->regs[tdep->ppc_gp0_regnum].name, "r0") == 0);
diff --git a/gdb/target.c b/gdb/target.c
index 81f8716d353..d542bbf1c10 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -48,6 +48,8 @@ static void kill_or_be_killed (int);
static void default_terminal_info (char *, int);
+static int default_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+
static int default_region_size_ok_for_hw_watchpoint (int);
static int nosymbol (char *, CORE_ADDR *);
@@ -129,6 +131,8 @@ static int debug_to_stopped_by_watchpoint (void);
static int debug_to_stopped_data_address (struct target_ops *, CORE_ADDR *);
+static int debug_to_region_ok_for_hw_watchpoint (CORE_ADDR, int);
+
static int debug_to_region_size_ok_for_hw_watchpoint (int);
static void debug_to_terminal_init (void);
@@ -406,6 +410,7 @@ update_current_target (void)
INHERIT (to_stopped_data_address, t);
INHERIT (to_stopped_by_watchpoint, t);
INHERIT (to_have_continuable_watchpoint, t);
+ INHERIT (to_region_ok_for_hw_watchpoint, t);
INHERIT (to_region_size_ok_for_hw_watchpoint, t);
INHERIT (to_terminal_init, t);
INHERIT (to_terminal_inferior, t);
@@ -532,6 +537,8 @@ update_current_target (void)
de_fault (to_stopped_data_address,
(int (*) (struct target_ops *, CORE_ADDR *))
return_zero);
+ de_fault (to_region_ok_for_hw_watchpoint,
+ default_region_ok_for_hw_watchpoint);
de_fault (to_region_size_ok_for_hw_watchpoint,
default_region_size_ok_for_hw_watchpoint);
de_fault (to_terminal_init,
@@ -1579,6 +1586,12 @@ find_default_create_inferior (char *exec_file, char *allargs, char **env,
}
static int
+default_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ return TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT (len);
+}
+
+static int
default_region_size_ok_for_hw_watchpoint (int byte_count)
{
return (byte_count <= TYPE_LENGTH (builtin_type_void_data_ptr));
@@ -2119,6 +2132,21 @@ debug_to_can_use_hw_breakpoint (int type, int cnt, int from_tty)
}
static int
+debug_to_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
+{
+ CORE_ADDR retval;
+
+ retval = debug_target.to_region_ok_for_hw_watchpoint (addr, len);
+
+ fprintf_unfiltered (gdb_stdlog,
+ "TARGET_REGION_OK_FOR_HW_WATCHPOINT (%ld, %ld) = 0x%lx\n",
+ (unsigned long) addr,
+ (unsigned long) len,
+ (unsigned long) retval);
+ return retval;
+}
+
+static int
debug_to_region_size_ok_for_hw_watchpoint (int byte_count)
{
CORE_ADDR retval;
@@ -2537,6 +2565,7 @@ setup_target_debug (void)
current_target.to_remove_watchpoint = debug_to_remove_watchpoint;
current_target.to_stopped_by_watchpoint = debug_to_stopped_by_watchpoint;
current_target.to_stopped_data_address = debug_to_stopped_data_address;
+ current_target.to_region_ok_for_hw_watchpoint = debug_to_region_ok_for_hw_watchpoint;
current_target.to_region_size_ok_for_hw_watchpoint = debug_to_region_size_ok_for_hw_watchpoint;
current_target.to_terminal_init = debug_to_terminal_init;
current_target.to_terminal_inferior = debug_to_terminal_inferior;
diff --git a/gdb/target.h b/gdb/target.h
index 9bb31f984ab..7a72c366809 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -346,6 +346,7 @@ struct target_ops
int (*to_stopped_by_watchpoint) (void);
int to_have_continuable_watchpoint;
int (*to_stopped_data_address) (struct target_ops *, CORE_ADDR *);
+ int (*to_region_ok_for_hw_watchpoint) (CORE_ADDR, int);
int (*to_region_size_ok_for_hw_watchpoint) (int);
void (*to_terminal_init) (void);
void (*to_terminal_inferior) (void);
@@ -1031,6 +1032,11 @@ extern void (*deprecated_target_new_objfile_hook) (struct objfile *);
(*current_target.to_can_use_hw_breakpoint) (TYPE, CNT, OTHERTYPE);
#endif
+#ifndef TARGET_REGION_OK_FOR_HW_WATCHPOINT
+#define TARGET_REGION_OK_FOR_HW_WATCHPOINT(addr, len) \
+ (*current_target.to_region_ok_for_hw_watchpoint) (addr, len)
+#endif
+
#if !defined(TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT)
#define TARGET_REGION_SIZE_OK_FOR_HW_WATCHPOINT(byte_count) \
(*current_target.to_region_size_ok_for_hw_watchpoint) (byte_count)