This is the mail archive of the gdb-patches@sourceware.cygnus.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[PATCH] IA-64 hardware watchpoint support


I've just committed the following changes for hardware watchpoint support
on IA-64 GNU Linux.  (There are some corresponding kernel changes that
you'll need as well if you wish to actually use these changes.)

	* ia64-linux-nat.c (IA64_PSR_DB, IA64_PSR_DD): Define.
	(fetch_debug_register, fetch_debug_register_pair,
	store_debug_register, store_debug_register_pair, is_power_of_2,
	enable_watchpoints_in_psr, ia64_linux_insert_watchpoint,
	ia64_linux_remove_watchpoint, ia64_linux_stopped_by_watchpoint):
	New functions.
	* config/ia64/nm-linux.h (TARGET_HAS_HARDWARE_WATCHPOINTS,
	TARGET_CAN_USE_HARDWARE_WATCHPOINT, HAVE_STEPPABLE_WATCHPOINT,
	STOPPED_BY_WATCHPOINT, target_insert_watchpoint,
	target_remove_watchpoint): Define.
	(ia64_linux_stopped_by_watchpoint, ia64_linux_insert_watchpoint,
	ia64_linux_remove_watchpoint): Declare.

Index: ia64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v
retrieving revision 1.3
diff -u -p -r1.3 ia64-linux-nat.c
--- ia64-linux-nat.c	2000/04/03 18:58:48	1.3
+++ ia64-linux-nat.c	2000/04/13 02:01:51
@@ -473,3 +473,174 @@ fill_fpregset (fpregsetp, regno)
 	}
     }
 }
+
+#define IA64_PSR_DB (1UL << 24)
+#define IA64_PSR_DD (1UL << 39)
+
+static void
+enable_watchpoints_in_psr (int pid)
+{
+  CORE_ADDR psr;
+
+  psr = read_register_pid (IA64_PSR_REGNUM, pid);
+  if (!(psr & IA64_PSR_DB))
+    {
+      psr |= IA64_PSR_DB;	/* Set the db bit - this enables hardware
+			           watchpoints and breakpoints. */
+      write_register_pid (IA64_PSR_REGNUM, psr, pid);
+    }
+}
+
+static long
+fetch_debug_register (int pid, int idx)
+{
+  long val;
+  int tid;
+
+  tid = TIDGET(pid);
+  if (tid == 0)
+    tid = pid;
+
+  val = ptrace (PT_READ_U, tid, (PTRACE_ARG3_TYPE) (PT_DBR + 8 * idx), 0);
+
+  return val;
+}
+
+static void
+store_debug_register (int pid, int idx, long val)
+{
+  int tid;
+
+  tid = TIDGET(pid);
+  if (tid == 0)
+    tid = pid;
+
+  (void) ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) (PT_DBR + 8 * idx), val);
+}
+
+static void
+fetch_debug_register_pair (int pid, int idx, long *dbr_addr, long *dbr_mask)
+{
+  if (dbr_addr)
+    *dbr_addr = fetch_debug_register (pid, 2 * idx);
+  if (dbr_mask)
+    *dbr_mask = fetch_debug_register (pid, 2 * idx + 1);
+}
+
+static void
+store_debug_register_pair (int pid, int idx, long *dbr_addr, long *dbr_mask)
+{
+  if (dbr_addr)
+    store_debug_register (pid, 2 * idx, *dbr_addr);
+  if (dbr_mask)
+    store_debug_register (pid, 2 * idx + 1, *dbr_mask);
+}
+
+static int
+is_power_of_2 (int val)
+{
+  int i, onecount;
+
+  onecount = 0;
+  for (i = 0; i < 8 * sizeof (val); i++)
+    if (val & (1 << i))
+      onecount++;
+
+  return onecount <= 1;
+}
+
+int
+ia64_linux_insert_watchpoint (int pid, CORE_ADDR addr, int len, int rw)
+{
+  int idx;
+  long dbr_addr, dbr_mask;
+  int max_watchpoints = 4;
+
+  if (len <= 0 || !is_power_of_2 (len))
+    return -1;
+
+  for (idx = 0; idx < max_watchpoints; idx++)
+    {
+      fetch_debug_register_pair (pid, idx, NULL, &dbr_mask);
+      if ((dbr_mask & (0x3UL << 62)) == 0)
+	{
+	  /* Exit loop if both r and w bits clear */
+	  break;
+	}
+    }
+
+  if (idx == max_watchpoints)
+    return -1;
+
+  dbr_addr = (long) addr;
+  dbr_mask = (~(len - 1) & 0x00ffffffffffffffL);  /* construct mask to match */
+  dbr_mask |= 0x0800000000000000L;           /* Only match privilege level 3 */
+  switch (rw)
+    {
+    case hw_write:
+      dbr_mask |= (1L << 62);			/* Set w bit */
+      break;
+    case hw_read:
+      dbr_mask |= (1L << 63);			/* Set r bit */
+      break;
+    case hw_access:
+      dbr_mask |= (3L << 62);			/* Set both r and w bits */
+      break;
+    default:
+      return -1;
+    }
+
+  store_debug_register_pair (pid, idx, &dbr_addr, &dbr_mask);
+  enable_watchpoints_in_psr (pid);
+
+  return 0;
+}
+
+int
+ia64_linux_remove_watchpoint (int pid, CORE_ADDR addr, int len)
+{
+  int idx;
+  long dbr_addr, dbr_mask;
+  int max_watchpoints = 4;
+
+  if (len <= 0 || !is_power_of_2 (len))
+    return -1;
+
+  for (idx = 0; idx < max_watchpoints; idx++)
+    {
+      fetch_debug_register_pair (pid, idx, &dbr_addr, &dbr_mask);
+      if ((dbr_mask & (0x3UL << 62)) && addr == (CORE_ADDR) dbr_addr)
+	{
+	  dbr_addr = 0;
+	  dbr_mask = 0;
+	  store_debug_register_pair (pid, idx, &dbr_addr, &dbr_mask);
+	  return 0;
+	}
+    }
+  return -1;
+}
+
+CORE_ADDR
+ia64_linux_stopped_by_watchpoint (int pid)
+{
+  CORE_ADDR psr;
+  int tid;
+  struct siginfo siginfo;
+
+  tid = TIDGET(pid);
+  if (tid == 0)
+    tid = pid;
+  
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_ARG3_TYPE) 0, &siginfo);
+
+  if (errno != 0 || siginfo.si_code != 4 /* TRAP_HWBKPT */)
+    return 0;
+
+  psr = read_register_pid (IA64_PSR_REGNUM, pid);
+  psr |= IA64_PSR_DD;	/* Set the dd bit - this will disable the watchpoint
+                           for the next instruction */
+  write_register_pid (IA64_PSR_REGNUM, psr, pid);
+
+  return (CORE_ADDR) siginfo.si_addr;
+}
Index: config/ia64/nm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/ia64/nm-linux.h,v
retrieving revision 1.2
diff -u -p -r1.2 nm-linux.h
--- nm-linux.h	2000/04/03 19:10:50	1.2
+++ nm-linux.h	2000/04/13 02:01:51
@@ -44,4 +44,33 @@ extern int ia64_register_u_addr(int, int
 #define PTRACE_ARG3_TYPE long
 #define PTRACE_XFER_TYPE long
 
+/* Hardware watchpoints */
+
+#define TARGET_HAS_HARDWARE_WATCHPOINTS
+
+#define TARGET_CAN_USE_HARDWARE_WATCHPOINT(type, cnt, ot) 1
+
+/* The IA-64 architecture can step over a watch point (without triggering
+   it again) if the "dd" (data debug fault disable) bit in the processor
+   status word is set.
+   
+   This PSR bit is set in ia64_linux_stopped_by_watchpoint when the
+   code there has determined that a hardware watchpoint has indeed
+   been hit.  The CPU will then be able to execute one instruction 
+   without triggering a watchpoint. */
+#define HAVE_STEPPABLE_WATCHPOINT 1
+
+#define STOPPED_BY_WATCHPOINT(W) \
+  ia64_linux_stopped_by_watchpoint (inferior_pid)
+extern CORE_ADDR ia64_linux_stopped_by_watchpoint (int);
+
+#define target_insert_watchpoint(addr, len, type) \
+  ia64_linux_insert_watchpoint (inferior_pid, addr, len, type)
+extern int ia64_linux_insert_watchpoint (int pid, CORE_ADDR addr,
+                                         int len, int rw);
+
+#define target_remove_watchpoint(addr, len, type) \
+  ia64_linux_remove_watchpoint (inferior_pid, addr, len)
+extern int ia64_linux_remove_watchpoint (int pid, CORE_ADDR addr, int len);
+
 #endif /* #ifndef NM_LINUX_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]