* doc/binutils.texi: Add --dwarf-check option.
[deliverable/binutils-gdb.git] / gdb / i386gnu-nat.c
index 6834ea011b0a1b864b390614dcf34fbde924f6f5..f15cf0c994d7f2ba4348d73c5e1d3202f40717cd 100644 (file)
@@ -1,11 +1,13 @@
-/* Low level interface to I386 running the GNU Hurd
-   Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc.
+/* Low level interface to i386 running the GNU Hurd.
+
+   Copyright (C) 1992, 1995-1996, 1998, 2000-2001, 2004, 2007-2012 Free
+   Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "inferior.h"
 #include "floatformat.h"
+#include "regcache.h"
 
-#include <stdio.h>
+#include "gdb_assert.h"
 #include <errno.h>
+#include <stdio.h>
+#include "gdb_string.h"
 
 #include <mach.h>
+#include <mach_error.h>
 #include <mach/message.h>
 #include <mach/exception.h>
-#include <mach_error.h>
-
-#include "gnu-nat.h"
 
-/* Hmmm... Should this not be here?
- * Now for i386_float_info() target_has_execution
- */
-#include <target.h>
+#include "i386-tdep.h"
 
-/* @@@ Should move print_387_status() to i387-tdep.c */
-extern void print_387_control_word (); /* i387-tdep.h */
-extern void print_387_status_word ();
-\f
-/* Find offsets to thread states at compile time.
- * If your compiler does not grok this, calculate offsets
- * offsets yourself and use them (or get a compatible compiler :-)
- */
+#include "gnu-nat.h"
+#include "i387-tdep.h"
 
-#define  REG_OFFSET(reg) (int)(&((struct i386_thread_state *)0)->reg)
+#ifdef HAVE_SYS_PROCFS_H
+# include <sys/procfs.h>
+# include "gregset.h"
+#endif
 
-/* at reg_offset[i] is the offset to the i386_thread_state
- * location where the gdb registers[i] is stored.
- */
+/* Offset to the thread_state_t location where REG is stored.  */
+#define REG_OFFSET(reg) offsetof (struct i386_thread_state, reg)
 
+/* At REG_OFFSET[N] is the offset to the thread_state_t location where
+   the GDB register N is stored.  */
 static int reg_offset[] =
 {
   REG_OFFSET (eax), REG_OFFSET (ecx), REG_OFFSET (edx), REG_OFFSET (ebx),
@@ -60,309 +56,261 @@ static int reg_offset[] =
   REG_OFFSET (ds), REG_OFFSET (es), REG_OFFSET (fs), REG_OFFSET (gs)
 };
 
-#define REG_ADDR(state,regnum) ((char *)(state)+reg_offset[regnum])
-
-/* Fetch COUNT contiguous registers from thread STATE starting from REGNUM
- * Caller knows that the regs handled in one transaction are of same size.
- */
-#define FETCH_REGS(state, regnum, count) \
-  memcpy (&registers[REGISTER_BYTE (regnum)], \
-         REG_ADDR (state, regnum), \
-         count * REGISTER_RAW_SIZE (regnum))
-
-/* Store COUNT contiguous registers to thread STATE starting from REGNUM */
-#define STORE_REGS(state, regnum, count) \
-  memcpy (REG_ADDR (state, regnum), \
-         &registers[REGISTER_BYTE (regnum)], \
-         count * REGISTER_RAW_SIZE (regnum))
-\f
-/*
- * Fetch inferiors registers for gdb.
- * REG specifies which (as gdb views it) register, -1 for all.
- */
-void
-gnu_fetch_registers (int reg)
-{
-  struct proc *thread;
-  thread_state_t state;
+#define REG_ADDR(state, regnum) ((char *)(state) + reg_offset[regnum])
+#define CREG_ADDR(state, regnum) ((const char *)(state) + reg_offset[regnum])
 
-  inf_update_procs (current_inferior); /* Make sure we know about new threads.  */
+\f
+/* Get the whole floating-point state of THREAD and record the values
+   of the corresponding (pseudo) registers.  */
 
-  thread = inf_tid_to_thread (current_inferior, inferior_pid);
-  if (!thread)
-    error ("fetch inferior registers: %d: Invalid thread", inferior_pid);
+static void
+fetch_fpregs (struct regcache *regcache, struct proc *thread)
+{
+  mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+  struct i386_float_state state;
+  error_t err;
 
-  state = proc_get_state (thread, 0);
+  err = thread_get_state (thread->port, i386_FLOAT_STATE,
+                         (thread_state_t) &state, &count);
+  if (err)
+    {
+      warning (_("Couldn't fetch floating-point state from %s"),
+              proc_string (thread));
+      return;
+    }
 
-  if (!state)
-    warning ("Couldn't fetch register %s from %s (invalid thread).",
-            REGISTER_NAME (reg), proc_string (thread));
-  else if (reg >= 0)
+  if (!state.initialized)
     {
-      proc_debug (thread, "fetching register: %s", REGISTER_NAME (reg));
-      supply_register (reg, REG_ADDR (state, reg));
-      thread->fetched_regs |= (1 << reg);
+      /* The floating-point state isn't initialized.  */
+      i387_supply_fsave (regcache, -1, NULL);
     }
   else
     {
-      proc_debug (thread, "fetching all registers");
-      for (reg = 0; reg < NUM_REGS; reg++)
-       supply_register (reg, REG_ADDR (state, reg));
-      thread->fetched_regs = ~0;
+      /* Supply the floating-point registers.  */
+      i387_supply_fsave (regcache, -1, state.hw_state);
     }
 }
-\f
-/* Store our register values back into the inferior.
- * If REG is -1, do this for all registers.
- * Otherwise, REG specifies which register
- *
- * On mach3 all registers are always saved in one call.
- */
+
+#ifdef HAVE_SYS_PROCFS_H
+/* These two calls are used by the core-regset.c code for
+   reading ELF core files.  */
 void
-gnu_store_registers (reg)
-     int reg;
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs)
 {
-  struct proc *thread;
-  int was_aborted, was_valid;
-  thread_state_t state;
-  thread_state_data_t old_state;
-
-  inf_update_procs (current_inferior); /* Make sure we know about new threads.  */
+  int i;
+  for (i = 0; i < I386_NUM_GREGS; i++)
+    regcache_raw_supply (regcache, i, CREG_ADDR (gregs, i));
+}
 
-  thread = inf_tid_to_thread (current_inferior, inferior_pid);
-  if (!thread)
-    error ("store inferior registers: %d: Invalid thread", inferior_pid);
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs)
+{
+  i387_supply_fsave (regcache, -1, fpregs);
+}
+#endif
 
-  proc_debug (thread, "storing register %s.", REGISTER_NAME (reg));
+/* Fetch register REGNO, or all regs if REGNO is -1.  */
+static void
+gnu_fetch_registers (struct target_ops *ops,
+                    struct regcache *regcache, int regno)
+{
+  struct proc *thread;
 
-  was_aborted = thread->aborted;
-  was_valid = thread->state_valid;
-  if (!was_aborted && was_valid)
-    bcopy (&thread->state, &old_state, sizeof (old_state));
+  /* Make sure we know about new threads.  */
+  inf_update_procs (gnu_current_inf);
 
-  state = proc_get_state (thread, 1);
+  thread = inf_tid_to_thread (gnu_current_inf,
+                             ptid_get_tid (inferior_ptid));
+  if (!thread)
+    error (_("Can't fetch registers from thread %s: No such thread"),
+          target_pid_to_str (inferior_ptid));
 
-  if (!state)
-    warning ("Couldn't store register %s from %s (invalid thread).",
-            REGISTER_NAME (reg), proc_string (thread));
-  else
+  if (regno < I386_NUM_GREGS || regno == -1)
     {
-      if (!was_aborted && was_valid)
-       /* See which registers have changed after aborting the thread.  */
+      thread_state_t state;
+
+      /* This does the dirty work for us.  */
+      state = proc_get_state (thread, 0);
+      if (!state)
        {
-         int check_reg;
-         for (check_reg = 0; check_reg < NUM_REGS; check_reg++)
-           if ((thread->fetched_regs & (1 << check_reg))
-               && bcmp (REG_ADDR (&old_state, check_reg),
-                        REG_ADDR (state, check_reg),
-                        REGISTER_RAW_SIZE (check_reg)))
-             /* Register CHECK_REG has changed!  Ack!  */
-             {
-               warning ("Register %s changed after thread was aborted.",
-                        REGISTER_NAME (check_reg));
-               if (reg >= 0 && reg != check_reg)
-                 /* Update gdb's copy of the register.  */
-                 supply_register (check_reg, REG_ADDR (state, check_reg));
-               else
-                 warning ("... also writing this register!  Suspicious...");
-             }
+         warning (_("Couldn't fetch registers from %s"),
+                  proc_string (thread));
+         return;
        }
 
-      if (reg >= 0)
+      if (regno == -1)
        {
-         proc_debug (thread, "storing register: %s", REGISTER_NAME (reg));
-         STORE_REGS (state, reg, 1);
+         int i;
+
+         proc_debug (thread, "fetching all register");
+
+         for (i = 0; i < I386_NUM_GREGS; i++)
+           regcache_raw_supply (regcache, i, REG_ADDR (state, i));
+         thread->fetched_regs = ~0;
        }
       else
        {
-         proc_debug (thread, "storing all registers");
-         for (reg = 0; reg < NUM_REGS; reg++)
-           STORE_REGS (state, reg, 1);
+         proc_debug (thread, "fetching register %s",
+                     gdbarch_register_name (get_regcache_arch (regcache),
+                                            regno));
+
+         regcache_raw_supply (regcache, regno,
+                              REG_ADDR (state, regno));
+         thread->fetched_regs |= (1 << regno);
        }
     }
+
+  if (regno >= I386_NUM_GREGS || regno == -1)
+    {
+      proc_debug (thread, "fetching floating-point registers");
+
+      fetch_fpregs (regcache, thread);
+    }
 }
 \f
-/* jtv@hut.fi: I copied and modified this 387 code from
- * gdb/i386-xdep.c. Modifications for Mach 3.0.
- *
- * i387 status dumper. See also i387-tdep.c
- */
-struct env387
-{
-  unsigned short control;
-  unsigned short r0;
-  unsigned short status;
-  unsigned short r1;
-  unsigned short tag;
-  unsigned short r2;
-  unsigned long eip;
-  unsigned short code_seg;
-  unsigned short opcode;
-  unsigned long operand;
-  unsigned short operand_seg;
-  unsigned short r3;
-  unsigned char regs[8][10];
-};
-/* This routine is machine independent?
- * Should move it to i387-tdep.c but you need to export struct env387
- */
-static
-print_387_status (status, ep)
-     unsigned short status;
-     struct env387 *ep;
+
+/* Store the whole floating-point state into THREAD using information
+   from the corresponding (pseudo) registers.  */
+static void
+store_fpregs (const struct regcache *regcache, struct proc *thread, int regno)
 {
-  int i;
-  int bothstatus;
-  int top;
-  int fpreg;
-  unsigned char *p;
+  mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+  struct i386_float_state state;
+  error_t err;
 
-  bothstatus = ((status != 0) && (ep->status != 0));
-  if (status != 0)
+  err = thread_get_state (thread->port, i386_FLOAT_STATE,
+                         (thread_state_t) &state, &count);
+  if (err)
     {
-      if (bothstatus)
-       printf_unfiltered ("u: ");
-      print_387_status_word (status);
+      warning (_("Couldn't fetch floating-point state from %s"),
+              proc_string (thread));
+      return;
     }
 
-  if (ep->status != 0)
+  /* FIXME: kettenis/2001-07-15: Is this right?  Should we somehow
+     take into account DEPRECATED_REGISTER_VALID like the old code did?  */
+  i387_collect_fsave (regcache, regno, state.hw_state);
+
+  err = thread_set_state (thread->port, i386_FLOAT_STATE,
+                         (thread_state_t) &state, i386_FLOAT_STATE_COUNT);
+  if (err)
     {
-      if (bothstatus)
-       printf_unfiltered ("e: ");
-      print_387_status_word (ep->status);
+      warning (_("Couldn't store floating-point state into %s"),
+              proc_string (thread));
+      return;
     }
+}
 
-  print_387_control_word (ep->control);
-  printf_unfiltered ("last exception: ");
-  printf_unfiltered ("opcode %s; ", local_hex_string (ep->opcode));
-  printf_unfiltered ("pc %s:", local_hex_string (ep->code_seg));
-  printf_unfiltered ("%s; ", local_hex_string (ep->eip));
-  printf_unfiltered ("operand %s", local_hex_string (ep->operand_seg));
-  printf_unfiltered (":%s\n", local_hex_string (ep->operand));
+/* Store at least register REGNO, or all regs if REGNO == -1.  */
+static void
+gnu_store_registers (struct target_ops *ops,
+                    struct regcache *regcache, int regno)
+{
+  struct proc *thread;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+  /* Make sure we know about new threads.  */
+  inf_update_procs (gnu_current_inf);
 
-  top = (ep->status >> 11) & 7;
+  thread = inf_tid_to_thread (gnu_current_inf,
+                             ptid_get_tid (inferior_ptid));
+  if (!thread)
+    error (_("Couldn't store registers into thread %s: No such thread"),
+          target_pid_to_str (inferior_ptid));
 
-  printf_unfiltered ("regno  tag  msb              lsb  value\n");
-  for (fpreg = 7; fpreg >= 0; fpreg--)
+  if (regno < I386_NUM_GREGS || regno == -1)
     {
-      double val;
+      thread_state_t state;
+      thread_state_data_t old_state;
+      int was_aborted = thread->aborted;
+      int was_valid = thread->state_valid;
+      int trace;
 
-      printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : "  ", fpreg);
+      if (!was_aborted && was_valid)
+       memcpy (&old_state, &thread->state, sizeof (old_state));
 
-      switch ((ep->tag >> (fpreg * 2)) & 3)
+      state = proc_get_state (thread, 1);
+      if (!state)
        {
-       case 0:
-         printf_unfiltered ("valid ");
-         break;
-       case 1:
-         printf_unfiltered ("zero  ");
-         break;
-       case 2:
-         printf_unfiltered ("trap  ");
-         break;
-       case 3:
-         printf_unfiltered ("empty ");
-         break;
+         warning (_("Couldn't store registers into %s"),
+                  proc_string (thread));
+         return;
        }
-      for (i = 9; i >= 0; i--)
-       printf_unfiltered ("%02x", ep->regs[fpreg][i]);
 
-      floatformat_to_double (&floatformat_i387_ext, (char *) ep->regs[fpreg],
-                            &val);
-      printf_unfiltered ("  %g\n", val);
-    }
-  if (ep->r0)
-    printf_unfiltered ("warning: reserved0 is %s\n", local_hex_string (ep->r0));
-  if (ep->r1)
-    printf_unfiltered ("warning: reserved1 is %s\n", local_hex_string (ep->r1));
-  if (ep->r2)
-    printf_unfiltered ("warning: reserved2 is %s\n", local_hex_string (ep->r2));
-  if (ep->r3)
-    printf_unfiltered ("warning: reserved3 is %s\n", local_hex_string (ep->r3));
-}
+      /* Save the T bit.  We might try to restore the %eflags register
+         below, but changing the T bit would seriously confuse GDB.  */
+      trace = ((struct i386_thread_state *)state)->efl & 0x100;
 
-/*
- * values that go into fp_kind (from <i386/fpreg.h>)
- */
-#define FP_NO   0              /* no fp chip, no emulator (no fp support)      */
-#define FP_SW   1              /* no fp chip, using software emulator          */
-#define FP_HW   2              /* chip present bit                             */
-#define FP_287  2              /* 80287 chip present                           */
-#define FP_387  3              /* 80387 chip present                           */
+      if (!was_aborted && was_valid)
+       /* See which registers have changed after aborting the thread.  */
+       {
+         int check_regno;
+
+         for (check_regno = 0; check_regno < I386_NUM_GREGS; check_regno++)
+           if ((thread->fetched_regs & (1 << check_regno))
+               && memcpy (REG_ADDR (&old_state, check_regno),
+                          REG_ADDR (state, check_regno),
+                          register_size (gdbarch, check_regno)))
+             /* Register CHECK_REGNO has changed!  Ack!  */
+             {
+               warning (_("Register %s changed after the thread was aborted"),
+                        gdbarch_register_name (gdbarch, check_regno));
+               if (regno >= 0 && regno != check_regno)
+                 /* Update GDB's copy of the register.  */
+                 regcache_raw_supply (regcache, check_regno,
+                                      REG_ADDR (state, check_regno));
+               else
+                 warning (_("... also writing this register!  "
+                            "Suspicious..."));
+             }
+       }
 
-typedef struct fpstate
-{
-#if 1
-  unsigned char state[FP_STATE_BYTES]; /* "hardware" state */
-#else
-  struct env387 state;         /* Actually this */
-#endif
-  int status;                  /* Duplicate status */
-}
- *fpstate_t;
+      if (regno == -1)
+       {
+         int i;
 
-/* Mach 3 specific routines.
- */
-static int
-get_i387_state (fstate)
-     struct fpstate *fstate;
-{
-  error_t err;
-  thread_state_data_t state;
-  unsigned int fsCnt = i386_FLOAT_STATE_COUNT;
-  struct i386_float_state *fsp;
-  struct proc *thread = inf_tid_to_thread (current_inferior, inferior_pid);
+         proc_debug (thread, "storing all registers");
 
-  if (!thread)
-    error ("get_i387_state: Invalid thread");
+         for (i = 0; i < I386_NUM_GREGS; i++)
+           if (REG_VALID == regcache_register_status (regcache, i))
+             regcache_raw_collect (regcache, i, REG_ADDR (state, i));
+       }
+      else
+       {
+         proc_debug (thread, "storing register %s",
+                     gdbarch_register_name (gdbarch, regno));
 
-  proc_abort (thread, 0);      /* Make sure THREAD's in a reasonable state. */
+         gdb_assert (REG_VALID == regcache_register_status (regcache, regno));
+         regcache_raw_collect (regcache, regno, REG_ADDR (state, regno));
+       }
 
-  err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt);
-  if (err)
-    {
-      warning ("Can not get live floating point state: %s",
-              mach_error_string (err));
-      return 0;
+      /* Restore the T bit.  */
+      ((struct i386_thread_state *)state)->efl &= ~0x100;
+      ((struct i386_thread_state *)state)->efl |= trace;
     }
 
-  fsp = (struct i386_float_state *) state;
-  /* The 387 chip (also 486 counts) or a software emulator? */
-  if (!fsp->initialized || (fsp->fpkind != FP_387 && fsp->fpkind != FP_SW))
-    return 0;
-
-  /* Clear the target then copy thread's float state there.
-     Make a copy of the status word, for some reason?
-   */
-  memset (fstate, 0, sizeof (struct fpstate));
-
-  fstate->status = fsp->exc_status;
-
-  memcpy (fstate->state, (char *) &fsp->hw_state, FP_STATE_BYTES);
+  if (regno >= I386_NUM_GREGS || regno == -1)
+    {
+      proc_debug (thread, "storing floating-point registers");
 
-  return 1;
+      store_fpregs (regcache, thread, regno);
+    }
 }
 
-/*
- * This is called by "info float" command
- */
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+extern initialize_file_ftype _initialize_i386gnu_nat;
+
 void
-i386_mach3_float_info ()
+_initialize_i386gnu_nat (void)
 {
-  char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
-  int valid = 0;
-  fpstate_t fps;
-
-  if (target_has_execution)
-    valid = get_i387_state (buf);
+  struct target_ops *t;
 
-  if (!valid)
-    {
-      warning ("no floating point status saved");
-      return;
-    }
+  /* Fill in the generic GNU/Hurd methods.  */
+  t = gnu_target ();
 
-  fps = (fpstate_t) buf;
+  t->to_fetch_registers = gnu_fetch_registers;
+  t->to_store_registers = gnu_store_registers;
 
-  print_387_status (fps->status, (struct env387 *) fps->state);
+  /* Register the target.  */
+  add_target (t);
 }
This page took 0.048552 seconds and 4 git commands to generate.