#include "defs.h"
#include "inferior.h"
#include "gdbcore.h"
#include "regcache.h"
#include "linux-nat.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include <sys/ptrace.h>
#include <sys/debugreg.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <asm/prctl.h>
#include <asm/ptrace.h>
#include <sys/reg.h>
#include "gdb_proc_service.h"
#include "gregset.h"
#include "amd64-tdep.h"
#include "i386-linux-tdep.h"
#include "amd64-nat.h"
static int amd64_linux_gregset64_reg_offset[] =
{
RAX * 8, RBX * 8,
RCX * 8, RDX * 8,
RSI * 8, RDI * 8,
RBP * 8, RSP * 8,
R8 * 8, R9 * 8,
R10 * 8, R11 * 8,
R12 * 8, R13 * 8,
R14 * 8, R15 * 8,
RIP * 8, EFLAGS * 8,
CS * 8, SS * 8,
DS * 8, ES * 8,
FS * 8, GS * 8
};
static int amd64_linux_gregset32_reg_offset[] =
{
RAX * 8, RCX * 8,
RDX * 8, RBX * 8,
RSP * 8, RBP * 8,
RSI * 8, RDI * 8,
RIP * 8, EFLAGS * 8,
CS * 8, SS * 8,
DS * 8, ES * 8,
FS * 8, GS * 8,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1,
ORIG_RAX * 8
};
void
supply_gregset (elf_gregset_t *gregsetp)
{
amd64_supply_native_gregset (current_regcache, gregsetp, -1);
}
void
fill_gregset (elf_gregset_t *gregsetp, int regnum)
{
amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
}
void
supply_fpregset (elf_fpregset_t *fpregsetp)
{
amd64_supply_fxsave (current_regcache, -1, fpregsetp);
}
void
fill_fpregset (elf_fpregset_t *fpregsetp, int regnum)
{
amd64_collect_fxsave (current_regcache, regnum, fpregsetp);
}
void
fetch_inferior_registers (int regnum)
{
int tid;
tid = TIDGET (inferior_ptid);
if (tid == 0)
tid = PIDGET (inferior_ptid);
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
{
elf_gregset_t regs;
if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0)
perror_with_name (_("Couldn't get registers"));
amd64_supply_native_gregset (current_regcache, ®s, -1);
if (regnum != -1)
return;
}
if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
{
elf_fpregset_t fpregs;
if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
perror_with_name (_("Couldn't get floating point status"));
amd64_supply_fxsave (current_regcache, -1, &fpregs);
}
}
void
store_inferior_registers (int regnum)
{
int tid;
tid = TIDGET (inferior_ptid);
if (tid == 0)
tid = PIDGET (inferior_ptid);
if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
{
elf_gregset_t regs;
if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0)
perror_with_name (_("Couldn't get registers"));
amd64_collect_native_gregset (current_regcache, ®s, regnum);
if (ptrace (PTRACE_SETREGS, tid, 0, (long) ®s) < 0)
perror_with_name (_("Couldn't write registers"));
if (regnum != -1)
return;
}
if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
{
elf_fpregset_t fpregs;
if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
perror_with_name (_("Couldn't get floating point status"));
amd64_collect_fxsave (current_regcache, regnum, &fpregs);
if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
perror_with_name (_("Couldn't write floating point status"));
return;
}
}
static unsigned long
amd64_linux_dr_get (int regnum)
{
int tid;
unsigned long value;
tid = PIDGET (inferior_ptid);
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
amd64_linux_dr_set (int regnum, unsigned long value)
{
int tid;
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
amd64_linux_dr_set_control (unsigned long control)
{
amd64_linux_dr_set (DR_CONTROL, control);
}
void
amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
{
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
}
void
amd64_linux_dr_reset_addr (int regnum)
{
gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
}
unsigned long
amd64_linux_dr_get_status (void)
{
return amd64_linux_dr_get (DR_STATUS);
}
ps_err_e
ps_get_thread_area (const struct ps_prochandle *ph,
lwpid_t lwpid, int idx, void **base)
{
if (gdbarch_ptr_bit (current_gdbarch) == 32)
{
unsigned int desc[4];
gdb_assert (sizeof (int) == 4);
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 25
#endif
if (ptrace (PTRACE_GET_THREAD_AREA,
lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
return PS_ERR;
(*base) = (void *) (long) desc[1];
return PS_OK;
}
else
{
#ifndef PTRACE_ARCH_PRCTL
#define PTRACE_ARCH_PRCTL 30
#endif
gdb_assert (FS < ELF_NGREG);
gdb_assert (GS < ELF_NGREG);
switch (idx)
{
case FS:
if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
return PS_OK;
break;
case GS:
if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
return PS_OK;
break;
default:
return PS_BADADDR;
}
}
return PS_ERR;
}
void
child_post_startup_inferior (ptid_t ptid)
{
i386_cleanup_dregs ();
linux_child_post_startup_inferior (ptid);
}
void _initialize_amd64_linux_nat (void);
void
_initialize_amd64_linux_nat (void)
{
amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
amd64_native_gregset64_reg_offset = amd64_linux_gregset64_reg_offset;
gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
== amd64_native_gregset32_num_regs);
gdb_assert (ARRAY_SIZE (amd64_linux_gregset64_reg_offset)
== amd64_native_gregset64_num_regs);
}