/* Motorola m68k native support for GNU/Linux.
- Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
- Free Software Foundation, Inc.
+ Copyright (C) 1996-2014 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "language.h"
#include "gdbcore.h"
-#include "gdb_string.h"
+#include <string.h>
#include "regcache.h"
#include "target.h"
#include "linux-nat.h"
#include "m68k-tdep.h"
-#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ptrace.h>
#endif
#include <sys/file.h>
-#include "gdb_stat.h"
+#include <sys/stat.h>
#include "floatformat.h"
-#include "target.h"
-
-/* Prototypes for supply_gregset etc. */
+/* Prototypes for supply_gregset etc. */
#include "gregset.h"
+
+/* Defines ps_err_e, struct ps_prochandle. */
+#include "gdb_proc_service.h"
+
+#ifndef PTRACE_GET_THREAD_AREA
+#define PTRACE_GET_THREAD_AREA 25
+#endif
\f
-/* This table must line up with REGISTER_NAME in "m68k-tdep.c". */
+/* This table must line up with gdbarch_register_name in "m68k-tdep.c". */
static const int regmap[] =
{
PT_D0, PT_D1, PT_D2, PT_D3, PT_D4, PT_D5, PT_D6, PT_D7,
#define NUM_GREGS (18)
#define MAX_NUM_REGS (NUM_GREGS + 11)
-int
+static int
getregs_supplies (int regno)
{
return 0 <= regno && regno < NUM_GREGS;
}
-int
+static int
getfpregs_supplies (int regno)
{
- return FP0_REGNUM <= regno && regno <= M68K_FPI_REGNUM;
+ return M68K_FP0_REGNUM <= regno && regno <= M68K_FPI_REGNUM;
}
/* Does the current host support the GETREGS request? */
-int have_ptrace_getregs =
+static int have_ptrace_getregs =
#ifdef HAVE_PTRACE_GETREGS
1
#else
/* Fetching registers directly from the U area, one at a time. */
-/* FIXME: This duplicates code from `inptrace.c'. The problem is that we
- define FETCH_INFERIOR_REGISTERS since we want to use our own versions
- of {fetch,store}_inferior_registers that use the GETREGS request. This
- means that the code in `infptrace.c' is #ifdef'd out. But we need to
- fall back on that code when GDB is running on top of a kernel that
- doesn't support the GETREGS request. */
-
-#ifndef PT_READ_U
-#define PT_READ_U PTRACE_PEEKUSR
-#endif
-#ifndef PT_WRITE_U
-#define PT_WRITE_U PTRACE_POKEUSR
-#endif
-
/* Fetch one register. */
static void
fetch_register (struct regcache *regcache, int regno)
{
- /* This isn't really an address. But ptrace thinks of it as one. */
- CORE_ADDR regaddr;
- char mess[128]; /* For messages */
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ long regaddr, val;
int i;
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
int tid;
- if (gdbarch_cannot_fetch_register (current_gdbarch, regno))
- {
- memset (buf, '\0', register_size (current_gdbarch, regno)); /* Supply zeroes */
- regcache_raw_supply (regcache, regno, buf);
- return;
- }
-
- /* Overload thread id onto process id */
- tid = TIDGET (inferior_ptid);
+ /* Overload thread id onto process id. */
+ tid = ptid_get_lwp (inferior_ptid);
if (tid == 0)
- tid = PIDGET (inferior_ptid); /* no thread id, just use process id */
+ tid = ptid_get_pid (inferior_ptid); /* no thread id, just use
+ process id. */
regaddr = 4 * regmap[regno];
- for (i = 0; i < register_size (current_gdbarch, regno);
- i += sizeof (PTRACE_TYPE_RET))
+ for (i = 0; i < register_size (gdbarch, regno); i += sizeof (long))
{
errno = 0;
- *(PTRACE_TYPE_RET *) &buf[i] = ptrace (PT_READ_U, tid,
- (PTRACE_TYPE_ARG3) regaddr, 0);
- regaddr += sizeof (PTRACE_TYPE_RET);
+ val = ptrace (PTRACE_PEEKUSER, tid, regaddr, 0);
+ memcpy (&buf[i], &val, sizeof (long));
+ regaddr += sizeof (long);
if (errno != 0)
- {
- sprintf (mess, "reading register %s (#%d)",
- REGISTER_NAME (regno), regno);
- perror_with_name (mess);
- }
+ error (_("Couldn't read register %s (#%d): %s."),
+ gdbarch_register_name (gdbarch, regno),
+ regno, safe_strerror (errno));
}
regcache_raw_supply (regcache, regno, buf);
}
/* Fetch register values from the inferior.
If REGNO is negative, do this for all registers.
- Otherwise, REGNO specifies which register (so we can save time). */
+ Otherwise, REGNO specifies which register (so we can save time). */
static void
old_fetch_inferior_registers (struct regcache *regcache, int regno)
}
else
{
- for (regno = 0; regno < gdbarch_num_regs (current_gdbarch); regno++)
+ for (regno = 0;
+ regno < gdbarch_num_regs (get_regcache_arch (regcache));
+ regno++)
{
fetch_register (regcache, regno);
}
}
}
-/* Store one register. */
+/* Store one register. */
static void
store_register (const struct regcache *regcache, int regno)
{
- /* This isn't really an address. But ptrace thinks of it as one. */
- CORE_ADDR regaddr;
- char mess[128]; /* For messages */
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ long regaddr, val;
int i;
int tid;
- char buf[MAX_REGISTER_SIZE];
+ gdb_byte buf[MAX_REGISTER_SIZE];
- if (gdbarch_cannot_store_register (current_gdbarch, regno))
- return;
-
- /* Overload thread id onto process id */
- tid = TIDGET (inferior_ptid);
+ /* Overload thread id onto process id. */
+ tid = ptid_get_lwp (inferior_ptid);
if (tid == 0)
- tid = PIDGET (inferior_ptid); /* no thread id, just use process id */
+ tid = ptid_get_pid (inferior_ptid); /* no thread id, just use
+ process id. */
regaddr = 4 * regmap[regno];
- /* Put the contents of regno into a local buffer */
+ /* Put the contents of regno into a local buffer. */
regcache_raw_collect (regcache, regno, buf);
- /* Store the local buffer into the inferior a chunk at the time. */
- for (i = 0; i < register_size (current_gdbarch, regno);
- i += sizeof (PTRACE_TYPE_RET))
+ /* Store the local buffer into the inferior a chunk at the time. */
+ for (i = 0; i < register_size (gdbarch, regno); i += sizeof (long))
{
errno = 0;
- ptrace (PT_WRITE_U, tid, (PTRACE_TYPE_ARG3) regaddr,
- *(PTRACE_TYPE_RET *) (buf + i));
- regaddr += sizeof (PTRACE_TYPE_RET);
+ memcpy (&val, &buf[i], sizeof (long));
+ ptrace (PTRACE_POKEUSER, tid, regaddr, val);
+ regaddr += sizeof (long);
if (errno != 0)
- {
- sprintf (mess, "writing register %s (#%d)",
- REGISTER_NAME (regno), regno);
- perror_with_name (mess);
- }
+ error (_("Couldn't write register %s (#%d): %s."),
+ gdbarch_register_name (gdbarch, regno),
+ regno, safe_strerror (errno));
}
}
}
else
{
- for (regno = 0; regno < gdbarch_num_regs (current_gdbarch); regno++)
+ for (regno = 0;
+ regno < gdbarch_num_regs (get_regcache_arch (regcache));
+ regno++)
{
store_register (regcache, regno);
}
\f
/* Given a pointer to a general register set in /proc format
(elf_gregset_t *), unpack the register contents and supply
- them as gdb's idea of the current register values. */
+ them as gdb's idea of the current register values. */
void
supply_gregset (struct regcache *regcache, const elf_gregset_t *gregsetp)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
const elf_greg_t *regp = (const elf_greg_t *) gregsetp;
int regi;
- for (regi = M68K_D0_REGNUM; regi <= SP_REGNUM; regi++)
+ for (regi = M68K_D0_REGNUM;
+ regi <= gdbarch_sp_regnum (gdbarch);
+ regi++)
regcache_raw_supply (regcache, regi, ®p[regmap[regi]]);
- regcache_raw_supply (regcache, PS_REGNUM, ®p[PT_SR]);
- regcache_raw_supply (regcache, PC_REGNUM, ®p[PT_PC]);
+ regcache_raw_supply (regcache, gdbarch_ps_regnum (gdbarch),
+ ®p[PT_SR]);
+ regcache_raw_supply (regcache,
+ gdbarch_pc_regnum (gdbarch), ®p[PT_PC]);
}
/* Fill register REGNO (if it is a general-purpose register) in
#else
-static void fetch_regs (struct regcache *regcache, int tid) {}
-static void store_regs (const struct regcache *regcache, int tid, int regno) {}
+static void fetch_regs (struct regcache *regcache, int tid)
+{
+}
+
+static void store_regs (const struct regcache *regcache, int tid, int regno)
+{
+}
#endif
void
supply_fpregset (struct regcache *regcache, const elf_fpregset_t *fpregsetp)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
int regi;
- for (regi = FP0_REGNUM; regi < FP0_REGNUM + 8; regi++)
+ for (regi = gdbarch_fp0_regnum (gdbarch);
+ regi < gdbarch_fp0_regnum (gdbarch) + 8; regi++)
regcache_raw_supply (regcache, regi,
- FPREG_ADDR (fpregsetp, regi - FP0_REGNUM));
+ FPREG_ADDR (fpregsetp,
+ regi - gdbarch_fp0_regnum (gdbarch)));
regcache_raw_supply (regcache, M68K_FPC_REGNUM, &fpregsetp->fpcntl[0]);
regcache_raw_supply (regcache, M68K_FPS_REGNUM, &fpregsetp->fpcntl[1]);
regcache_raw_supply (regcache, M68K_FPI_REGNUM, &fpregsetp->fpcntl[2]);
fill_fpregset (const struct regcache *regcache,
elf_fpregset_t *fpregsetp, int regno)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
int i;
/* Fill in the floating-point registers. */
- for (i = FP0_REGNUM; i < FP0_REGNUM + 8; i++)
+ for (i = gdbarch_fp0_regnum (gdbarch);
+ i < gdbarch_fp0_regnum (gdbarch) + 8; i++)
if (regno == -1 || regno == i)
regcache_raw_collect (regcache, i,
- FPREG_ADDR (fpregsetp, i - FP0_REGNUM));
+ FPREG_ADDR (fpregsetp,
+ i - gdbarch_fp0_regnum (gdbarch)));
/* Fill in the floating-point control registers. */
for (i = M68K_FPC_REGNUM; i <= M68K_FPI_REGNUM; i++)
#else
-static void fetch_fpregs (struct regcache *regcache, int tid) {}
-static void store_fpregs (const struct regcache *regcache, int tid, int regno) {}
+static void fetch_fpregs (struct regcache *regcache, int tid)
+{
+}
+
+static void store_fpregs (const struct regcache *regcache, int tid, int regno)
+{
+}
#endif
\f
registers). */
static void
-m68k_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
+m68k_linux_fetch_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
{
int tid;
}
/* GNU/Linux LWP ID's are process ID's. */
- tid = TIDGET (inferior_ptid);
+ tid = ptid_get_lwp (inferior_ptid);
if (tid == 0)
- tid = PIDGET (inferior_ptid); /* Not a threaded program. */
+ tid = ptid_get_pid (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
do this for all registers (including the floating point and SSE
registers). */
static void
-m68k_linux_store_inferior_registers (struct regcache *regcache, int regno)
+m68k_linux_store_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
{
int tid;
}
/* GNU/Linux LWP ID's are process ID's. */
- tid = TIDGET (inferior_ptid);
+ tid = ptid_get_lwp (inferior_ptid);
if (tid == 0)
- tid = PIDGET (inferior_ptid); /* Not a threaded program. */
+ tid = ptid_get_pid (inferior_ptid); /* Not a threaded program. */
/* Use the PTRACE_SETFPREGS requests whenever possible, since it
transfers more registers in one system call. But remember that
}
\f
+/* Fetch the thread-local storage pointer for libthread_db. */
+
+ps_err_e
+ps_get_thread_area (const struct ps_prochandle *ph,
+ lwpid_t lwpid, int idx, void **base)
+{
+ if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) < 0)
+ return PS_ERR;
+
+ /* IDX is the bias from the thread pointer to the beginning of the
+ thread descriptor. It has to be subtracted due to implementation
+ quirks in libthread_db. */
+ *base = (char *) *base - idx;
+
+ return PS_OK;
+}
+\f
+
/* Register that we are able to handle GNU/Linux ELF core file
formats. */