/* Native-dependent code for GNU/Linux i386.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
- Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009 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 "inferior.h"
;
\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
-
/* Accessing registers through the U area, one at a time. */
/* Fetch one register. */
static void
-fetch_register (int regno)
+fetch_register (struct regcache *regcache, int regno)
{
int tid;
int val;
gdb_assert (!have_ptrace_getregs);
- if (cannot_fetch_register (regno))
+ if (regmap[regno] == -1)
{
- regcache_raw_supply (current_regcache, regno, NULL);
+ regcache_raw_supply (regcache, regno, NULL);
return;
}
tid = PIDGET (inferior_ptid); /* Not a threaded program. */
errno = 0;
- val = ptrace (PTRACE_PEEKUSER, tid, register_addr (regno, 0), 0);
+ val = ptrace (PTRACE_PEEKUSER, tid, 4 * regmap[regno], 0);
if (errno != 0)
- error (_("Couldn't read register %s (#%d): %s."), REGISTER_NAME (regno),
+ error (_("Couldn't read register %s (#%d): %s."),
+ gdbarch_register_name (get_regcache_arch (regcache), regno),
regno, safe_strerror (errno));
- regcache_raw_supply (current_regcache, regno, &val);
+ regcache_raw_supply (regcache, regno, &val);
}
/* Store one register. */
static void
-store_register (int regno)
+store_register (const struct regcache *regcache, int regno)
{
int tid;
int val;
gdb_assert (!have_ptrace_getregs);
- if (cannot_store_register (regno))
+ if (regmap[regno] == -1)
return;
/* GNU/Linux LWP ID's are process ID's. */
tid = PIDGET (inferior_ptid); /* Not a threaded program. */
errno = 0;
- regcache_raw_collect (current_regcache, regno, &val);
- ptrace (PTRACE_POKEUSER, tid, register_addr (regno, 0), val);
+ regcache_raw_collect (regcache, regno, &val);
+ ptrace (PTRACE_POKEUSER, tid, 4 * regmap[regno], val);
if (errno != 0)
- error (_("Couldn't write register %s (#%d): %s."), REGISTER_NAME (regno),
+ error (_("Couldn't write register %s (#%d): %s."),
+ gdbarch_register_name (get_regcache_arch (regcache), regno),
regno, safe_strerror (errno));
}
\f
in *GREGSETP. */
void
-supply_gregset (elf_gregset_t *gregsetp)
+supply_gregset (struct regcache *regcache, const elf_gregset_t *gregsetp)
{
- elf_greg_t *regp = (elf_greg_t *) gregsetp;
+ const elf_greg_t *regp = (const elf_greg_t *) gregsetp;
int i;
for (i = 0; i < I386_NUM_GREGS; i++)
- regcache_raw_supply (current_regcache, i, regp + regmap[i]);
+ regcache_raw_supply (regcache, i, regp + regmap[i]);
- if (I386_LINUX_ORIG_EAX_REGNUM < NUM_REGS)
- regcache_raw_supply (current_regcache, I386_LINUX_ORIG_EAX_REGNUM,
+ if (I386_LINUX_ORIG_EAX_REGNUM
+ < gdbarch_num_regs (get_regcache_arch (regcache)))
+ regcache_raw_supply (regcache, I386_LINUX_ORIG_EAX_REGNUM,
regp + ORIG_EAX);
}
do this for all registers. */
void
-fill_gregset (elf_gregset_t *gregsetp, int regno)
+fill_gregset (const struct regcache *regcache,
+ elf_gregset_t *gregsetp, int regno)
{
elf_greg_t *regp = (elf_greg_t *) gregsetp;
int i;
for (i = 0; i < I386_NUM_GREGS; i++)
if (regno == -1 || regno == i)
- regcache_raw_collect (current_regcache, i, regp + regmap[i]);
+ regcache_raw_collect (regcache, i, regp + regmap[i]);
if ((regno == -1 || regno == I386_LINUX_ORIG_EAX_REGNUM)
- && I386_LINUX_ORIG_EAX_REGNUM < NUM_REGS)
- regcache_raw_collect (current_regcache, I386_LINUX_ORIG_EAX_REGNUM,
+ && I386_LINUX_ORIG_EAX_REGNUM
+ < gdbarch_num_regs (get_regcache_arch (regcache)))
+ regcache_raw_collect (regcache, I386_LINUX_ORIG_EAX_REGNUM,
regp + ORIG_EAX);
}
store their values in GDB's register array. */
static void
-fetch_regs (int tid)
+fetch_regs (struct regcache *regcache, int tid)
{
elf_gregset_t regs;
+ elf_gregset_t *regs_p = ®s;
if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0)
{
perror_with_name (_("Couldn't get registers"));
}
- supply_gregset (®s);
+ supply_gregset (regcache, (const elf_gregset_t *) regs_p);
}
/* Store all valid general-purpose registers in GDB's register array
into the process/thread specified by TID. */
static void
-store_regs (int tid, int regno)
+store_regs (const struct regcache *regcache, int tid, int regno)
{
elf_gregset_t regs;
if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0)
perror_with_name (_("Couldn't get registers"));
- fill_gregset (®s, regno);
+ fill_gregset (regcache, ®s, regno);
if (ptrace (PTRACE_SETREGS, tid, 0, (int) ®s) < 0)
perror_with_name (_("Couldn't write registers"));
#else
-static void fetch_regs (int tid) {}
-static void store_regs (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
\f
*FPREGSETP. */
void
-supply_fpregset (elf_fpregset_t *fpregsetp)
+supply_fpregset (struct regcache *regcache, const elf_fpregset_t *fpregsetp)
{
- i387_supply_fsave (current_regcache, -1, fpregsetp);
+ i387_supply_fsave (regcache, -1, fpregsetp);
}
/* Fill register REGNO (if it is a floating-point register) in
do this for all registers. */
void
-fill_fpregset (elf_fpregset_t *fpregsetp, int regno)
+fill_fpregset (const struct regcache *regcache,
+ elf_fpregset_t *fpregsetp, int regno)
{
- i387_fill_fsave ((char *) fpregsetp, regno);
+ i387_collect_fsave (regcache, regno, fpregsetp);
}
#ifdef HAVE_PTRACE_GETREGS
thier values in GDB's register array. */
static void
-fetch_fpregs (int tid)
+fetch_fpregs (struct regcache *regcache, int tid)
{
elf_fpregset_t fpregs;
if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
perror_with_name (_("Couldn't get floating point status"));
- supply_fpregset (&fpregs);
+ supply_fpregset (regcache, (const elf_fpregset_t *) &fpregs);
}
/* Store all valid floating-point registers in GDB's register array
into the process/thread specified by TID. */
static void
-store_fpregs (int tid, int regno)
+store_fpregs (const struct regcache *regcache, int tid, int regno)
{
elf_fpregset_t fpregs;
if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
perror_with_name (_("Couldn't get floating point status"));
- fill_fpregset (&fpregs, regno);
+ fill_fpregset (regcache, &fpregs, regno);
if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0)
perror_with_name (_("Couldn't write floating point status"));
#else
-static void fetch_fpregs (int tid) {}
-static void store_fpregs (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
values in *FPXREGSETP. */
void
-supply_fpxregset (elf_fpxregset_t *fpxregsetp)
+supply_fpxregset (struct regcache *regcache,
+ const elf_fpxregset_t *fpxregsetp)
{
- i387_supply_fxsave (current_regcache, -1, fpxregsetp);
+ i387_supply_fxsave (regcache, -1, fpxregsetp);
}
/* Fill register REGNO (if it is a floating-point or SSE register) in
-1, do this for all registers. */
void
-fill_fpxregset (elf_fpxregset_t *fpxregsetp, int regno)
+fill_fpxregset (const struct regcache *regcache,
+ elf_fpxregset_t *fpxregsetp, int regno)
{
- i387_fill_fxsave ((char *) fpxregsetp, regno);
+ i387_collect_fxsave (regcache, regno, fpxregsetp);
}
/* Fetch all registers covered by the PTRACE_GETFPXREGS request from
Return non-zero if successful, zero otherwise. */
static int
-fetch_fpxregs (int tid)
+fetch_fpxregs (struct regcache *regcache, int tid)
{
elf_fpxregset_t fpxregs;
perror_with_name (_("Couldn't read floating-point and SSE registers"));
}
- supply_fpxregset (&fpxregs);
+ supply_fpxregset (regcache, (const elf_fpxregset_t *) &fpxregs);
return 1;
}
Return non-zero if successful, zero otherwise. */
static int
-store_fpxregs (int tid, int regno)
+store_fpxregs (const struct regcache *regcache, int tid, int regno)
{
elf_fpxregset_t fpxregs;
perror_with_name (_("Couldn't read floating-point and SSE registers"));
}
- fill_fpxregset (&fpxregs, regno);
+ fill_fpxregset (regcache, &fpxregs, regno);
if (ptrace (PTRACE_SETFPXREGS, tid, 0, &fpxregs) == -1)
perror_with_name (_("Couldn't write floating-point and SSE registers"));
#else
-static int fetch_fpxregs (int tid) { return 0; }
-static int store_fpxregs (int tid, int regno) { return 0; }
+static int fetch_fpxregs (struct regcache *regcache, int tid) { return 0; }
+static int store_fpxregs (const struct regcache *regcache, int tid, int regno) { return 0; }
#endif /* HAVE_PTRACE_GETFPXREGS */
\f
/* 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)
-{
- gdb_assert (regno >= 0 && regno < NUM_REGS);
- return (!have_ptrace_getregs && regmap[regno] == -1);
-}
-
-int
-cannot_store_register (int regno)
-{
- gdb_assert (regno >= 0 && regno < NUM_REGS);
- return (!have_ptrace_getregs && regmap[regno] == -1);
-}
-
/* Fetch register REGNO from the child process. If REGNO is -1, do
this for all registers (including the floating point and SSE
registers). */
static void
-i386_linux_fetch_inferior_registers (int regno)
+i386_linux_fetch_inferior_registers (struct regcache *regcache, int regno)
{
int tid;
{
int i;
- for (i = 0; i < NUM_REGS; i++)
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
if (regno == -1 || regno == i)
- fetch_register (i);
+ fetch_register (regcache, i);
return;
}
zero. */
if (regno == -1)
{
- fetch_regs (tid);
+ fetch_regs (regcache, tid);
/* The call above might reset `have_ptrace_getregs'. */
if (!have_ptrace_getregs)
{
- i386_linux_fetch_inferior_registers (regno);
+ i386_linux_fetch_inferior_registers (regcache, regno);
return;
}
- if (fetch_fpxregs (tid))
+ if (fetch_fpxregs (regcache, tid))
return;
- fetch_fpregs (tid);
+ fetch_fpregs (regcache, tid);
return;
}
if (GETREGS_SUPPLIES (regno))
{
- fetch_regs (tid);
+ fetch_regs (regcache, tid);
return;
}
if (GETFPXREGS_SUPPLIES (regno))
{
- if (fetch_fpxregs (tid))
+ if (fetch_fpxregs (regcache, tid))
return;
/* Either our processor or our kernel doesn't support the SSE
more graceful to handle differences in the register set using
gdbarch. Until then, this will at least make things work
plausibly. */
- fetch_fpregs (tid);
+ fetch_fpregs (regcache, tid);
return;
}
do this for all registers (including the floating point and SSE
registers). */
static void
-i386_linux_store_inferior_registers (int regno)
+i386_linux_store_inferior_registers (struct regcache *regcache, int regno)
{
int tid;
{
int i;
- for (i = 0; i < NUM_REGS; i++)
+ for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
if (regno == -1 || regno == i)
- store_register (i);
+ store_register (regcache, i);
return;
}
store_fpxregs can fail, and return zero. */
if (regno == -1)
{
- store_regs (tid, regno);
- if (store_fpxregs (tid, regno))
+ store_regs (regcache, tid, regno);
+ if (store_fpxregs (regcache, tid, regno))
return;
- store_fpregs (tid, regno);
+ store_fpregs (regcache, tid, regno);
return;
}
if (GETREGS_SUPPLIES (regno))
{
- store_regs (tid, regno);
+ store_regs (regcache, tid, regno);
return;
}
if (GETFPXREGS_SUPPLIES (regno))
{
- if (store_fpxregs (tid, regno))
+ if (store_fpxregs (regcache, tid, regno))
return;
/* Either our processor or our kernel doesn't support the SSE
registers, so just write the FP registers in the traditional
way. */
- store_fpregs (tid, regno);
+ store_fpregs (regcache, tid, regno);
return;
}
/* Support for debug registers. */
+static unsigned long i386_linux_dr[DR_CONTROL + 1];
+
static unsigned long
-i386_linux_dr_get (int regnum)
+i386_linux_dr_get (ptid_t ptid, 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);
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
/* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
ptrace call fails breaks debugging remote targets. The correct
}
static void
-i386_linux_dr_set (int regnum, unsigned long value)
+i386_linux_dr_set (ptid_t ptid, 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);
+ tid = TIDGET (ptid);
+ if (tid == 0)
+ tid = PIDGET (ptid);
errno = 0;
ptrace (PTRACE_POKEUSER, tid,
void
i386_linux_dr_set_control (unsigned long control)
{
- i386_linux_dr_set (DR_CONTROL, control);
+ struct lwp_info *lp;
+ ptid_t ptid;
+
+ i386_linux_dr[DR_CONTROL] = control;
+ ALL_LWPS (lp, ptid)
+ i386_linux_dr_set (ptid, DR_CONTROL, control);
}
void
i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
{
+ struct lwp_info *lp;
+ ptid_t ptid;
+
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
- i386_linux_dr_set (DR_FIRSTADDR + regnum, addr);
+ i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
+ ALL_LWPS (lp, ptid)
+ i386_linux_dr_set (ptid, 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);
+ i386_linux_dr_set_addr (regnum, 0);
}
unsigned long
i386_linux_dr_get_status (void)
{
- return i386_linux_dr_get (DR_STATUS);
+ return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+}
+
+static void
+i386_linux_new_thread (ptid_t ptid)
+{
+ int i;
+
+ for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+ i386_linux_dr_set (ptid, i, i386_linux_dr[i]);
+
+ i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
}
\f
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_ptid" are the same. */
- pid = PIDGET (inferior_ptid);
-
if (step)
{
- CORE_ADDR pc = read_pc_pid (pid_to_ptid (pid));
+ struct regcache *regcache = get_thread_regcache (pid_to_ptid (pid));
+ ULONGEST pc;
gdb_byte buf[LINUX_SYSCALL_LEN];
request = PTRACE_SINGLESTEP;
+ regcache_cooked_read_unsigned
+ (regcache, gdbarch_pc_regnum (get_regcache_arch (regcache)), &pc);
+
/* Returning from a signal trampoline is done by calling a
special system call (sigreturn or rt_sigreturn, see
i386-linux-tdep.c for more information). This system call
that's about to be restored, and set the trace flag there. */
/* First check if PC is at a system call. */
- if (deprecated_read_memory_nobpt (pc, buf, LINUX_SYSCALL_LEN) == 0
+ if (target_read_memory (pc, buf, LINUX_SYSCALL_LEN) == 0
&& memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
{
- int syscall = read_register_pid (LINUX_SYSCALL_REGNUM,
- pid_to_ptid (pid));
+ ULONGEST syscall;
+ regcache_cooked_read_unsigned (regcache,
+ LINUX_SYSCALL_REGNUM, &syscall);
/* Then check the system call number. */
if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn)
{
- CORE_ADDR sp = read_register (I386_ESP_REGNUM);
- CORE_ADDR addr = sp;
+ ULONGEST sp, addr;
unsigned long int eflags;
+ regcache_cooked_read_unsigned (regcache, I386_ESP_REGNUM, &sp);
if (syscall == SYS_rt_sigreturn)
addr = read_memory_integer (sp + 8, 4) + 20;
+ else
+ addr = sp;
/* Set the trace flag in the context that's about to be
restored. */
/* Fill in the generic GNU/Linux methods. */
t = linux_target ();
+ i386_use_watchpoints (t);
+
/* Override the default ptrace resume method. */
t->to_resume = i386_linux_resume;
/* Register the target. */
linux_nat_add_target (t);
+ linux_nat_set_new_thread (t, i386_linux_new_thread);
}