*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / i386-linux-nat.c
index 49149830e8495b56b01ac77a43d397699e874bf2..94d9ab393bd16a0967e6924f14d821188d8131dc 100644 (file)
@@ -1,5 +1,5 @@
 /* Native-dependent code for Linux/x86.
-   Copyright 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "defs.h"
 #include "inferior.h"
 #include "gdbcore.h"
+#include "regcache.h"
 
-/* For i386_linux_skip_solib_resolver.  */
-#include "symtab.h"
-#include "symfile.h"
-#include "objfiles.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
@@ -114,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'.
@@ -138,9 +164,7 @@ int have_ptrace_getfpxregs =
 #endif
 
 /* Registers we shouldn't try to fetch.  */
-#if !defined (CANNOT_FETCH_REGISTER)
-#define CANNOT_FETCH_REGISTER(regno) 0
-#endif
+#define OLD_CANNOT_FETCH_REGISTER(regno) ((regno) >= NUM_GREGS)
 
 /* Fetch one register.  */
 
@@ -155,7 +179,7 @@ fetch_register (int regno)
   char buf[MAX_REGISTER_RAW_SIZE];
   int tid;
 
-  if (CANNOT_FETCH_REGISTER (regno))
+  if (OLD_CANNOT_FETCH_REGISTER (regno))
     {
       memset (buf, '\0', REGISTER_RAW_SIZE (regno));   /* Supply zeroes */
       supply_register (regno, buf);
@@ -163,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;
 
@@ -198,7 +222,7 @@ old_fetch_inferior_registers (int regno)
     }
   else
     {
-      for (regno = 0; regno < ARCH_NUM_REGS; regno++)
+      for (regno = 0; regno < NUM_REGS; regno++)
        {
          fetch_register (regno);
        }
@@ -206,9 +230,7 @@ old_fetch_inferior_registers (int regno)
 }
 
 /* Registers we shouldn't try to store.  */
-#if !defined (CANNOT_STORE_REGISTER)
-#define CANNOT_STORE_REGISTER(regno) 0
-#endif
+#define OLD_CANNOT_STORE_REGISTER(regno) ((regno) >= NUM_GREGS)
 
 /* Store one register. */
 
@@ -222,14 +244,14 @@ store_register (int regno)
   unsigned int offset;         /* Offset of registers within the u area.  */
   int tid;
 
-  if (CANNOT_STORE_REGISTER (regno))
+  if (OLD_CANNOT_STORE_REGISTER (regno))
     {
       return;
     }
 
   /* 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;
 
@@ -262,7 +284,7 @@ old_store_inferior_registers (int regno)
     }
   else
     {
-      for (regno = 0; regno < ARCH_NUM_REGS; regno++)
+      for (regno = 0; regno < NUM_REGS; regno++)
        {
          store_register (regno);
        }
@@ -273,7 +295,7 @@ old_store_inferior_registers (int regno)
 /* Transfering the general-purpose registers between GDB, inferiors
    and core files.  */
 
-/* Fill GDB's register array with the genereal-purpose register values
+/* Fill GDB's register array with the general-purpose register values
    in *GREGSETP.  */
 
 void
@@ -478,7 +500,15 @@ store_fpxregs (int tid, int regno)
     return 0;
   
   if (ptrace (PTRACE_GETFPXREGS, tid, 0, &fpxregs) == -1)
-    perror_with_name ("Couldn't read floating-point and SSE registers");
+    {
+      if (errno == EIO)
+       {
+         have_ptrace_getfpxregs = 0;
+         return 0;
+       }
+
+      perror_with_name ("Couldn't read floating-point and SSE registers");
+    }
 
   fill_fpxregset (&fpxregs, regno);
 
@@ -518,6 +548,26 @@ static void dummy_sse_values (void) {}
 
 /* Transferring arbitrary registers between GDB and inferior.  */
 
+/* Check if register REGNO in the child process is accessible.
+   If we are accessing registers directly via the U area, only the
+   general-purpose registers are available.
+   All registers should be accessible if we have GETREGS support.  */
+   
+int
+cannot_fetch_register (int regno)
+{
+  if (! have_ptrace_getregs)
+    return OLD_CANNOT_FETCH_REGISTER (regno);
+  return 0;
+}
+int
+cannot_store_register (int regno)
+{
+  if (! have_ptrace_getregs)
+    return OLD_CANNOT_STORE_REGISTER (regno);
+  return 0;
+}
+
 /* Fetch register REGNO from the child process.  If REGNO is -1, do
    this for all registers (including the floating point and SSE
    registers).  */
@@ -536,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
@@ -581,7 +631,8 @@ fetch_inferior_registers (int regno)
       return;
     }
 
-  internal_error ("Got request for bad register number %d.", regno);
+  internal_error (__FILE__, __LINE__,
+                 "Got request for bad register number %d.", regno);
 }
 
 /* Store register REGNO back into the child process.  If REGNO is -1,
@@ -601,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
@@ -634,7 +685,83 @@ store_inferior_registers (int regno)
       return;
     }
 
-  internal_error ("Got request to store bad register number %d.", regno);
+  internal_error (__FILE__, __LINE__,
+                 "Got request to store bad register number %d.", 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
 
@@ -741,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;
@@ -770,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)
@@ -778,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;
 
@@ -797,98 +927,6 @@ child_resume (int pid, int step, enum target_signal signal)
 }
 \f
 
-/* Calling functions in shared libraries.  */
-/* FIXME: kettenis/2000-03-05: Doesn't this belong in a
-   target-dependent file?  The function
-   `i386_linux_skip_solib_resolver' is mentioned in
-   `config/i386/tm-linux.h'.  */
-
-/* Find the minimal symbol named NAME, and return both the minsym
-   struct and its objfile.  This probably ought to be in minsym.c, but
-   everything there is trying to deal with things like C++ and
-   SOFUN_ADDRESS_MAYBE_TURQUOISE, ...  Since this is so simple, it may
-   be considered too special-purpose for general consumption.  */
-
-static struct minimal_symbol *
-find_minsym_and_objfile (char *name, struct objfile **objfile_p)
-{
-  struct objfile *objfile;
-
-  ALL_OBJFILES (objfile)
-    {
-      struct minimal_symbol *msym;
-
-      ALL_OBJFILE_MSYMBOLS (objfile, msym)
-       {
-         if (SYMBOL_NAME (msym)
-             && STREQ (SYMBOL_NAME (msym), name))
-           {
-             *objfile_p = objfile;
-             return msym;
-           }
-       }
-    }
-
-  return 0;
-}
-
-static CORE_ADDR
-skip_hurd_resolver (CORE_ADDR pc)
-{
-  /* The HURD dynamic linker is part of the GNU C library, so many
-     GNU/Linux distributions use it.  (All ELF versions, as far as I
-     know.)  An unresolved PLT entry points to "_dl_runtime_resolve",
-     which calls "fixup" to patch the PLT, and then passes control to
-     the function.
-
-     We look for the symbol `_dl_runtime_resolve', and find `fixup' in
-     the same objfile.  If we are at the entry point of `fixup', then
-     we set a breakpoint at the return address (at the top of the
-     stack), and continue.
-  
-     It's kind of gross to do all these checks every time we're
-     called, since they don't change once the executable has gotten
-     started.  But this is only a temporary hack --- upcoming versions
-     of Linux will provide a portable, efficient interface for
-     debugging programs that use shared libraries.  */
-
-  struct objfile *objfile;
-  struct minimal_symbol *resolver 
-    = find_minsym_and_objfile ("_dl_runtime_resolve", &objfile);
-
-  if (resolver)
-    {
-      struct minimal_symbol *fixup
-       = lookup_minimal_symbol ("fixup", 0, objfile);
-
-      if (fixup && SYMBOL_VALUE_ADDRESS (fixup) == pc)
-       return (SAVED_PC_AFTER_CALL (get_current_frame ()));
-    }
-
-  return 0;
-}      
-
-/* See the comments for SKIP_SOLIB_RESOLVER at the top of infrun.c.
-   This function:
-   1) decides whether a PLT has sent us into the linker to resolve
-      a function reference, and 
-   2) if so, tells us where to set a temporary breakpoint that will
-      trigger when the dynamic linker is done.  */
-
-CORE_ADDR
-i386_linux_skip_solib_resolver (CORE_ADDR pc)
-{
-  CORE_ADDR result;
-
-  /* Plug in functions for other kinds of resolvers here.  */
-  result = skip_hurd_resolver (pc);
-  if (result)
-    return result;
-
-  return 0;
-}
-\f
-
 /* Register that we are able to handle Linux ELF core file formats.  */
 
 static struct core_fns linux_elf_core_fns =
This page took 0.028776 seconds and 4 git commands to generate.