Allow for the possibility that the local labels won't be in the objdump output.
[deliverable/binutils-gdb.git] / gdb / ia64-linux-nat.c
index 485fa4a0d729ee71f16052585807d3856dd51467..50217f125826f9c26d66b66bb61b90cab55aa650 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions specific to running gdb native on IA-64 running Linux.
-   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -22,6 +22,7 @@
 #include "inferior.h"
 #include "target.h"
 #include "gdbcore.h"
+#include "regcache.h"
 
 #include <signal.h>
 #include <sys/ptrace.h>
@@ -34,6 +35,9 @@
 #include <asm/ptrace_offsets.h>
 #include <sys/procfs.h>
 
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
 /* These must match the order of the register names.
 
    Some sort of lookup table is needed because the offsets associated
@@ -233,7 +237,7 @@ static int u_offsets[] =
     PT_PR,
     PT_CR_IIP, /* ip */
     PT_CR_IPSR, /* psr */
-    PT_CR_IFS, /* cfm */
+    PT_CFM,    /* cfm */
     /* kernel registers not visible via ptrace interface (?) */
     -1, -1, -1, -1, -1, -1, -1, -1,
     /* hole */
@@ -293,9 +297,7 @@ static int u_offsets[] =
   };
 
 CORE_ADDR
-register_addr (regno, blockend)
-     int regno;
-     CORE_ADDR blockend;
+register_addr (int regno, CORE_ADDR blockend)
 {
   CORE_ADDR addr;
 
@@ -353,8 +355,7 @@ int ia64_cannot_store_register (regno)
 }
 
 void
-supply_gregset (gregsetp)
-     gregset_t *gregsetp;
+supply_gregset (gregset_t *gregsetp)
 {
   int regi;
   greg_t *regp = (greg_t *) gregsetp;
@@ -390,9 +391,7 @@ supply_gregset (gregsetp)
 }
 
 void
-fill_gregset (gregsetp, regno)
-     gregset_t *gregsetp;
-     int regno;
+fill_gregset (gregset_t *gregsetp, int regno)
 {
   int regi;
   greg_t *regp = (greg_t *) gregsetp;
@@ -436,8 +435,7 @@ fill_gregset (gregsetp, regno)
    idea of the current floating point register values. */
 
 void
-supply_fpregset (fpregsetp)
-     fpregset_t *fpregsetp;
+supply_fpregset (fpregset_t *fpregsetp)
 {
   register int regi;
   char *from;
@@ -455,9 +453,7 @@ supply_fpregset (fpregsetp)
    them all. */
 
 void
-fill_fpregset (fpregsetp, regno)
-     fpregset_t *fpregsetp;
-     int regno;
+fill_fpregset (fpregset_t *fpregsetp, int regno)
 {
   int regi;
   char *to;
@@ -473,3 +469,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;
+}
This page took 0.02572 seconds and 4 git commands to generate.