gdb/
[deliverable/binutils-gdb.git] / gdb / i386gnu-nat.c
index 6834ea011b0a1b864b390614dcf34fbde924f6f5..b31378390f28562c1384a390614a3b2b71204fae 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
+   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,237 @@ 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.  */
+void
+gnu_fetch_registers (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 (current_inferior);
 
-  state = proc_get_state (thread, 1);
+  thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
+  if (!thread)
+    error (_("Can't fetch registers from thread %d: No such thread"),
+          PIDGET (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);
        }
     }
-}
-\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;
-{
-  int i;
-  int bothstatus;
-  int top;
-  int fpreg;
-  unsigned char *p;
 
-  bothstatus = ((status != 0) && (ep->status != 0));
-  if (status != 0)
+  if (regno >= I386_NUM_GREGS || regno == -1)
     {
-      if (bothstatus)
-       printf_unfiltered ("u: ");
-      print_387_status_word (status);
-    }
+      proc_debug (thread, "fetching floating-point registers");
 
-  if (ep->status != 0)
-    {
-      if (bothstatus)
-       printf_unfiltered ("e: ");
-      print_387_status_word (ep->status);
+      fetch_fpregs (regcache, thread);
     }
+}
+\f
 
-  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));
-
-  top = (ep->status >> 11) & 7;
+/* 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)
+{
+  mach_msg_type_number_t count = i386_FLOAT_STATE_COUNT;
+  struct i386_float_state state;
+  error_t err;
 
-  printf_unfiltered ("regno  tag  msb              lsb  value\n");
-  for (fpreg = 7; fpreg >= 0; fpreg--)
+  err = thread_get_state (thread->port, i386_FLOAT_STATE,
+                         (thread_state_t) &state, &count);
+  if (err)
     {
-      double val;
-
-      printf_unfiltered ("%s %d: ", fpreg == top ? "=>" : "  ", fpreg);
+      warning (_("Couldn't fetch floating-point state from %s"),
+              proc_string (thread));
+      return;
+    }
 
-      switch ((ep->tag >> (fpreg * 2)) & 3)
-       {
-       case 0:
-         printf_unfiltered ("valid ");
-         break;
-       case 1:
-         printf_unfiltered ("zero  ");
-         break;
-       case 2:
-         printf_unfiltered ("trap  ");
-         break;
-       case 3:
-         printf_unfiltered ("empty ");
-         break;
-       }
-      for (i = 9; i >= 0; i--)
-       printf_unfiltered ("%02x", ep->regs[fpreg][i]);
+  /* 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);
 
-      floatformat_to_double (&floatformat_i387_ext, (char *) ep->regs[fpreg],
-                            &val);
-      printf_unfiltered ("  %g\n", val);
+  err = thread_set_state (thread->port, i386_FLOAT_STATE,
+                         (thread_state_t) &state, i386_FLOAT_STATE_COUNT);
+  if (err)
+    {
+      warning (_("Couldn't store floating-point state into %s"),
+              proc_string (thread));
+      return;
     }
-  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));
 }
 
-/*
- * 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                           */
-
-typedef struct fpstate
+/* Store at least register REGNO, or all regs if REGNO == -1.  */
+void
+gnu_store_registers (struct regcache *regcache, int regno)
 {
-#if 1
-  unsigned char state[FP_STATE_BYTES]; /* "hardware" state */
-#else
-  struct env387 state;         /* Actually this */
-#endif
-  int status;                  /* Duplicate status */
-}
- *fpstate_t;
+  struct proc *thread;
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
 
-/* 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);
+  /* Make sure we know about new threads.  */
+  inf_update_procs (current_inferior);
 
+  thread = inf_tid_to_thread (current_inferior, PIDGET (inferior_ptid));
   if (!thread)
-    error ("get_i387_state: Invalid thread");
-
-  proc_abort (thread, 0);      /* Make sure THREAD's in a reasonable state. */
+    error (_("Couldn't store registers into thread %d: No such thread"),
+          PIDGET (inferior_ptid));
 
-  err = thread_get_state (thread->port, i386_FLOAT_STATE, state, &fsCnt);
-  if (err)
+  if (regno < I386_NUM_GREGS || regno == -1)
     {
-      warning ("Can not get live floating point state: %s",
-              mach_error_string (err));
-      return 0;
-    }
+      thread_state_t state;
+      thread_state_data_t old_state;
+      int was_aborted = thread->aborted;
+      int was_valid = thread->state_valid;
+      int 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;
+      if (!was_aborted && was_valid)
+       memcpy (&old_state, &thread->state, sizeof (old_state));
 
-  /* 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));
+      state = proc_get_state (thread, 1);
+      if (!state)
+       {
+         warning (_("Couldn't store registers into %s"), proc_string (thread));
+         return;
+       }
 
-  fstate->status = fsp->exc_status;
+      /* 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;
 
-  memcpy (fstate->state, (char *) &fsp->hw_state, FP_STATE_BYTES);
+      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..."));
+             }
+       }
 
-  return 1;
-}
+      if (regno == -1)
+       {
+         int i;
 
-/*
- * This is called by "info float" command
- */
-void
-i386_mach3_float_info ()
-{
-  char buf[sizeof (struct fpstate) + 2 * sizeof (int)];
-  int valid = 0;
-  fpstate_t fps;
+         proc_debug (thread, "storing all registers");
 
-  if (target_has_execution)
-    valid = get_i387_state (buf);
+         for (i = 0; i < I386_NUM_GREGS; i++)
+           if (regcache_valid_p (regcache, i))
+             regcache_raw_collect (regcache, i, REG_ADDR (state, i));
+       }
+      else
+       {
+         proc_debug (thread, "storing register %s",
+                     gdbarch_register_name (gdbarch, regno));
 
-  if (!valid)
-    {
-      warning ("no floating point status saved");
-      return;
+         gdb_assert (regcache_valid_p (regcache, regno));
+         regcache_raw_collect (regcache, regno, REG_ADDR (state, regno));
+       }
+
+      /* Restore the T bit.  */
+      ((struct i386_thread_state *)state)->efl &= ~0x100;
+      ((struct i386_thread_state *)state)->efl |= trace;
     }
 
-  fps = (fpstate_t) buf;
+  if (regno >= I386_NUM_GREGS || regno == -1)
+    {
+      proc_debug (thread, "storing floating-point registers");
 
-  print_387_status (fps->status, (struct env387 *) fps->state);
+      store_fpregs (regcache, thread, regno);
+    }
 }
This page took 0.029562 seconds and 4 git commands to generate.