amd64-linux-tdep.c [plain text]
#include "defs.h"
#include "inferior.h"
#include "gdbcore.h"
#include "regcache.h"
#include "osabi.h"
#include "gdb_string.h"
#include "amd64-tdep.h"
#include "amd64-linux-tdep.h"
#define USER_R15 0
#define USER_R14 1
#define USER_R13 2
#define USER_R12 3
#define USER_RBP 4
#define USER_RBX 5
#define USER_R11 6
#define USER_R10 7
#define USER_R9 8
#define USER_R8 9
#define USER_RAX 10
#define USER_RCX 11
#define USER_RDX 12
#define USER_RSI 13
#define USER_RDI 14
#define USER_RIP 16
#define USER_CS 17
#define USER_EFLAGS 18
#define USER_RSP 19
#define USER_SS 20
#define USER_DS 23
#define USER_ES 24
#define USER_FS 25
#define USER_GS 26
static int user_to_gdb_regmap[] =
{
USER_RAX, USER_RBX, USER_RCX, USER_RDX,
USER_RSI, USER_RDI, USER_RBP, USER_RSP,
USER_R8, USER_R9, USER_R10, USER_R11,
USER_R12, USER_R13, USER_R14, USER_R15,
USER_RIP, USER_EFLAGS,
USER_CS, USER_SS,
USER_DS, USER_ES, USER_FS, USER_GS
};
void
amd64_linux_supply_gregset (char *regp)
{
int i;
for (i = 0; i < AMD64_NUM_GREGS; i++)
supply_register (i, regp + (user_to_gdb_regmap[i] * 8));
}
void
amd64_linux_fill_gregset (char *regp, int regno)
{
int i;
for (i = 0; i < AMD64_NUM_GREGS; i++)
if (regno == -1 || regno == i)
regcache_collect (i, regp + (user_to_gdb_regmap[i] * 8));
}
static void
fetch_core_registers (char *core_reg_sect, unsigned core_reg_size,
int which, CORE_ADDR ignore)
{
switch (which)
{
case 0:
if (core_reg_size != 216)
warning ("Wrong size register set in core file.");
else
amd64_linux_supply_gregset (core_reg_sect);
break;
case 2:
case 3:
if (core_reg_size != 512)
warning ("Wrong size XMM register set in core file.");
else
amd64_supply_fxsave (current_regcache, -1, core_reg_sect);
break;
default:
break;
}
}
static struct core_fns amd64_core_fns =
{
bfd_target_elf_flavour,
default_check_format,
default_core_sniffer,
fetch_core_registers,
NULL
};
#define LINUX_SIGTRAMP_INSN0 0x48
#define LINUX_SIGTRAMP_OFFSET0 0
#define LINUX_SIGTRAMP_INSN1 0x0f
#define LINUX_SIGTRAMP_OFFSET1 7
static const unsigned char linux_sigtramp_code[] =
{
LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
LINUX_SIGTRAMP_INSN1, 0x05
};
#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
static CORE_ADDR
amd64_linux_sigtramp_start (CORE_ADDR pc)
{
unsigned char buf[LINUX_SIGTRAMP_LEN];
if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
return 0;
if (buf[0] != LINUX_SIGTRAMP_INSN0)
{
if (buf[0] != LINUX_SIGTRAMP_INSN1)
return 0;
pc -= LINUX_SIGTRAMP_OFFSET1;
if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
return 0;
}
if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
return 0;
return pc;
}
static int
amd64_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
{
if (name == NULL || strstr (name, "sigaction") != NULL)
return (amd64_linux_sigtramp_start (pc) != 0);
return (strcmp ("__restore_rt", name) == 0);
}
#define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
static CORE_ADDR
amd64_linux_sigcontext_addr (struct frame_info *next_frame)
{
CORE_ADDR sp;
char buf[8];
frame_unwind_register (next_frame, SP_REGNUM, buf);
sp = extract_unsigned_integer (buf, 8);
return sp + AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
}
static int amd64_linux_sc_reg_offset[] =
{
13 * 8,
11 * 8,
14 * 8,
12 * 8,
9 * 8,
8 * 8,
10 * 8,
15 * 8,
0 * 8,
1 * 8,
2 * 8,
3 * 8,
4 * 8,
5 * 8,
6 * 8,
7 * 8,
16 * 8,
17 * 8,
-1,
-1,
-1,
-1,
-1,
-1
};
static void
amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
amd64_init_abi (info, gdbarch);
set_gdbarch_pc_in_sigtramp (gdbarch, amd64_linux_pc_in_sigtramp);
tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
}
extern void _initialize_amd64_linux_tdep (void);
void
_initialize_amd64_linux_tdep (void)
{
add_core_fns (&amd64_core_fns);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
GDB_OSABI_LINUX, amd64_linux_init_abi);
}