*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / i386-linux-nat.c
index 62fe3d4191b1aa4b98c5e7ff9414b614d3c712df..94d9ab393bd16a0967e6924f14d821188d8131dc 100644 (file)
@@ -23,6 +23,7 @@
 #include "gdbcore.h"
 #include "regcache.h"
 
+#include "gdb_assert.h"
 #include <sys/ptrace.h>
 #include <sys/user.h>
 #include <sys/procfs.h>
 #include <sys/reg.h>
 #endif
 
+#ifdef HAVE_SYS_DEBUGREG_H
+#include <sys/debugreg.h>
+#endif
+
+#ifndef DR_FIRSTADDR
+#define DR_FIRSTADDR 0
+#endif
+
+#ifndef DR_LASTADDR
+#define DR_LASTADDR 3
+#endif
+
+#ifndef DR_STATUS
+#define DR_STATUS 6
+#endif
+
+#ifndef DR_CONTROL
+#define DR_CONTROL 7
+#endif
+
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
 /* Prototypes for local functions.  */
 static void dummy_sse_values (void);
 
-/* On Linux, threads are implemented as pseudo-processes, in which
-   case we may be tracing more than one process at a time.  In that
-   case, inferior_pid will contain the main process ID and the
-   individual thread (process) ID mashed together.  These macros are
-   used to separate them out.  These definitions should be overridden
-   if thread support is included.  */
-
-#if !defined (PIDGET)  /* Default definition for PIDGET/TIDGET.  */
-#define PIDGET(PID)    PID
-#define TIDGET(PID)    0
-#endif
 \f
 
 /* The register sets used in Linux ELF core-dumps are identical to the
@@ -110,6 +120,26 @@ int have_ptrace_getfpxregs =
 ;
 \f
 
+/* Support for the user struct.  */
+
+/* Return the address of register REGNUM.  BLOCKEND is the value of
+   u.u_ar0, which should point to the registers.  */
+
+CORE_ADDR
+register_u_addr (CORE_ADDR blockend, int regnum)
+{
+  return (blockend + 4 * regmap[regnum]);
+}
+
+/* Return the size of the user struct.  */
+
+int
+kernel_u_size (void)
+{
+  return (sizeof (struct user));
+}
+\f
+
 /* Fetching registers directly from the U area, one at a time.  */
 
 /* FIXME: kettenis/2000-03-05: This duplicates code from `inptrace.c'.
@@ -157,8 +187,8 @@ fetch_register (int regno)
     }
 
   /* Overload thread id onto process id */
-  if ((tid = TIDGET (inferior_pid)) == 0)
-    tid = inferior_pid;                /* no thread id, just use process id */
+  if ((tid = TIDGET (inferior_ptid)) == 0)
+    tid = PIDGET (inferior_ptid);      /* no thread id, just use process id */
 
   offset = U_REGS_OFFSET;
 
@@ -220,8 +250,8 @@ store_register (int regno)
     }
 
   /* Overload thread id onto process id */
-  if ((tid = TIDGET (inferior_pid)) == 0)
-    tid = inferior_pid;                /* no thread id, just use process id */
+  if ((tid = TIDGET (inferior_ptid)) == 0)
+    tid = PIDGET (inferior_ptid);      /* no thread id, just use process id */
 
   offset = U_REGS_OFFSET;
 
@@ -556,8 +586,8 @@ fetch_inferior_registers (int regno)
     }
 
   /* Linux LWP ID's are process ID's.  */
-  if ((tid = TIDGET (inferior_pid)) == 0)
-    tid = inferior_pid;                /* Not a threaded program.  */
+  if ((tid = TIDGET (inferior_ptid)) == 0)
+    tid = PIDGET (inferior_ptid);              /* Not a threaded program.  */
 
   /* Use the PTRACE_GETFPXREGS request whenever possible, since it
      transfers more registers in one system call, and we'll cache the
@@ -622,8 +652,8 @@ store_inferior_registers (int regno)
     }
 
   /* Linux LWP ID's are process ID's.  */
-  if ((tid = TIDGET (inferior_pid)) == 0)
-    tid = inferior_pid;                /* Not a threaded program.  */
+  if ((tid = TIDGET (inferior_ptid)) == 0)
+    tid = PIDGET (inferior_ptid);      /* Not a threaded program.  */
 
   /* Use the PTRACE_SETFPXREGS requests whenever possible, since it
      transfers more registers in one system call.  But remember that
@@ -660,6 +690,81 @@ store_inferior_registers (int regno)
 }
 \f
 
+static unsigned long
+i386_linux_dr_get (int regnum)
+{
+  int tid;
+  unsigned long value;
+
+  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
+     multi-threaded processes here.  For now, pretend there is just
+     one thread.  */
+  tid = PIDGET (inferior_ptid);
+
+  /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
+     ptrace call fails breaks debugging remote targets.  The correct
+     way to fix this is to add the hardware breakpoint and watchpoint
+     stuff to the target vectore.  For now, just return zero if the
+     ptrace call fails.  */
+  errno = 0;
+  value = ptrace (PT_READ_U, tid,
+                 offsetof (struct user, u_debugreg[regnum]), 0);
+  if (errno != 0)
+#if 0
+    perror_with_name ("Couldn't read debug register");
+#else
+    return 0;
+#endif
+
+  return value;
+}
+
+static void
+i386_linux_dr_set (int regnum, unsigned long value)
+{
+  int tid;
+
+  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
+     multi-threaded processes here.  For now, pretend there is just
+     one thread.  */
+  tid = PIDGET (inferior_ptid);
+
+  errno = 0;
+  ptrace (PT_WRITE_U, tid,
+         offsetof (struct user, u_debugreg[regnum]), value);
+  if (errno != 0)
+    perror_with_name ("Couldn't write debug register");
+}
+
+void
+i386_linux_dr_set_control (unsigned long control)
+{
+  i386_linux_dr_set (DR_CONTROL, control);
+}
+
+void
+i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+{
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  i386_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+}
+
+void
+i386_linux_dr_reset_addr (int regnum)
+{
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  i386_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
+}
+
+unsigned long
+i386_linux_dr_get_status (void)
+{
+  return i386_linux_dr_get (DR_STATUS);
+}
+\f
+
 /* Interpreting register set info found in core files.  */
 
 /* Provide registers to GDB from a core file.
@@ -763,19 +868,21 @@ static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
    If SIGNAL is nonzero, give it that signal.  */
 
 void
-child_resume (int pid, int step, enum target_signal signal)
+child_resume (ptid_t ptid, int step, enum target_signal signal)
 {
+  int pid = PIDGET (ptid);
+
   int request = PTRACE_CONT;
 
   if (pid == -1)
     /* Resume all threads.  */
     /* I think this only gets used in the non-threaded case, where "resume
-       all threads" and "resume inferior_pid" are the same.  */
-    pid = inferior_pid;
+       all threads" and "resume inferior_ptid" are the same.  */
+    pid = PIDGET (inferior_ptid);
 
   if (step)
     {
-      CORE_ADDR pc = read_pc_pid (pid);
+      CORE_ADDR pc = read_pc_pid (pid_to_ptid (pid));
       unsigned char buf[LINUX_SYSCALL_LEN];
 
       request = PTRACE_SINGLESTEP;
@@ -792,7 +899,8 @@ child_resume (int pid, int step, enum target_signal signal)
       if (read_memory_nobpt (pc, (char *) buf, LINUX_SYSCALL_LEN) == 0
          && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
        {
-         int syscall = read_register_pid (LINUX_SYSCALL_REGNUM, pid);
+         int syscall = read_register_pid (LINUX_SYSCALL_REGNUM,
+                                          pid_to_ptid (pid));
 
          /* Then check the system call number.  */
          if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn)
@@ -800,7 +908,7 @@ child_resume (int pid, int step, enum target_signal signal)
              CORE_ADDR sp = read_register (SP_REGNUM);
              CORE_ADDR addr = sp;
              unsigned long int eflags;
-             
+
              if (syscall == SYS_rt_sigreturn)
                addr = read_memory_integer (sp + 8, 4) + 20;
 
This page took 0.028192 seconds and 4 git commands to generate.