/* Target-dependent code for AMD64.
- Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
+
Contributed by Jiri Smid, SuSE Labs.
This file is part of GDB.
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. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "arch-utils.h"
/* Register information. */
-struct amd64_register_info
-{
- char *name;
- struct type **type;
-};
-
-static struct amd64_register_info amd64_register_info[] =
+static const char *amd64_register_names[] =
{
- { "rax", &builtin_type_int64 },
- { "rbx", &builtin_type_int64 },
- { "rcx", &builtin_type_int64 },
- { "rdx", &builtin_type_int64 },
- { "rsi", &builtin_type_int64 },
- { "rdi", &builtin_type_int64 },
- { "rbp", &builtin_type_void_data_ptr },
- { "rsp", &builtin_type_void_data_ptr },
+ "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp",
/* %r8 is indeed register number 8. */
- { "r8", &builtin_type_int64 },
- { "r9", &builtin_type_int64 },
- { "r10", &builtin_type_int64 },
- { "r11", &builtin_type_int64 },
- { "r12", &builtin_type_int64 },
- { "r13", &builtin_type_int64 },
- { "r14", &builtin_type_int64 },
- { "r15", &builtin_type_int64 },
- { "rip", &builtin_type_void_func_ptr },
- { "eflags", &builtin_type_int32 },
- { "cs", &builtin_type_int32 },
- { "ss", &builtin_type_int32 },
- { "ds", &builtin_type_int32 },
- { "es", &builtin_type_int32 },
- { "fs", &builtin_type_int32 },
- { "gs", &builtin_type_int32 },
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "rip", "eflags", "cs", "ss", "ds", "es", "fs", "gs",
/* %st0 is register number 24. */
- { "st0", &builtin_type_i387_ext },
- { "st1", &builtin_type_i387_ext },
- { "st2", &builtin_type_i387_ext },
- { "st3", &builtin_type_i387_ext },
- { "st4", &builtin_type_i387_ext },
- { "st5", &builtin_type_i387_ext },
- { "st6", &builtin_type_i387_ext },
- { "st7", &builtin_type_i387_ext },
- { "fctrl", &builtin_type_int32 },
- { "fstat", &builtin_type_int32 },
- { "ftag", &builtin_type_int32 },
- { "fiseg", &builtin_type_int32 },
- { "fioff", &builtin_type_int32 },
- { "foseg", &builtin_type_int32 },
- { "fooff", &builtin_type_int32 },
- { "fop", &builtin_type_int32 },
+ "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7",
+ "fctrl", "fstat", "ftag", "fiseg", "fioff", "foseg", "fooff", "fop",
/* %xmm0 is register number 40. */
- { "xmm0", &builtin_type_v4sf },
- { "xmm1", &builtin_type_v4sf },
- { "xmm2", &builtin_type_v4sf },
- { "xmm3", &builtin_type_v4sf },
- { "xmm4", &builtin_type_v4sf },
- { "xmm5", &builtin_type_v4sf },
- { "xmm6", &builtin_type_v4sf },
- { "xmm7", &builtin_type_v4sf },
- { "xmm8", &builtin_type_v4sf },
- { "xmm9", &builtin_type_v4sf },
- { "xmm10", &builtin_type_v4sf },
- { "xmm11", &builtin_type_v4sf },
- { "xmm12", &builtin_type_v4sf },
- { "xmm13", &builtin_type_v4sf },
- { "xmm14", &builtin_type_v4sf },
- { "xmm15", &builtin_type_v4sf },
- { "mxcsr", &builtin_type_int32 }
+ "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
+ "mxcsr",
};
/* Total number of registers. */
-#define AMD64_NUM_REGS \
- (sizeof (amd64_register_info) / sizeof (amd64_register_info[0]))
+#define AMD64_NUM_REGS ARRAY_SIZE (amd64_register_names)
/* Return the name of register REGNUM. */
-static const char *
+const char *
amd64_register_name (int regnum)
{
if (regnum >= 0 && regnum < AMD64_NUM_REGS)
- return amd64_register_info[regnum].name;
+ return amd64_register_names[regnum];
return NULL;
}
/* Return the GDB type object for the "standard" data type of data in
register REGNUM. */
-static struct type *
+struct type *
amd64_register_type (struct gdbarch *gdbarch, int regnum)
{
- gdb_assert (regnum >= 0 && regnum < AMD64_NUM_REGS);
-
- return *amd64_register_info[regnum].type;
+ if (regnum >= AMD64_RAX_REGNUM && regnum <= AMD64_RDI_REGNUM)
+ return builtin_type_int64;
+ if (regnum == AMD64_RBP_REGNUM || regnum == AMD64_RSP_REGNUM)
+ return builtin_type_void_data_ptr;
+ if (regnum >= AMD64_R8_REGNUM && regnum <= AMD64_R15_REGNUM)
+ return builtin_type_int64;
+ if (regnum == AMD64_RIP_REGNUM)
+ return builtin_type_void_func_ptr;
+ if (regnum == AMD64_EFLAGS_REGNUM)
+ return i386_eflags_type;
+ if (regnum >= AMD64_CS_REGNUM && regnum <= AMD64_GS_REGNUM)
+ return builtin_type_int32;
+ if (regnum >= AMD64_ST0_REGNUM && regnum <= AMD64_ST0_REGNUM + 7)
+ return builtin_type_i387_ext;
+ if (regnum >= AMD64_FCTRL_REGNUM && regnum <= AMD64_FCTRL_REGNUM + 7)
+ return builtin_type_int32;
+ if (regnum >= AMD64_XMM0_REGNUM && regnum <= AMD64_XMM0_REGNUM + 15)
+ return i386_sse_type (gdbarch);
+ if (regnum == AMD64_MXCSR_REGNUM)
+ return i386_mxcsr_type;
+
+ internal_error (__FILE__, __LINE__, _("invalid regnum"));
}
/* DWARF Register Number Mapping as defined in the System V psABI,
AMD64_ST0_REGNUM + 0, AMD64_ST0_REGNUM + 1,
AMD64_ST0_REGNUM + 2, AMD64_ST0_REGNUM + 3,
AMD64_ST0_REGNUM + 4, AMD64_ST0_REGNUM + 5,
- AMD64_ST0_REGNUM + 6, AMD64_ST0_REGNUM + 7
+ AMD64_ST0_REGNUM + 6, AMD64_ST0_REGNUM + 7,
+
+ /* Control and Status Flags Register. */
+ AMD64_EFLAGS_REGNUM,
+
+ /* Selector Registers. */
+ AMD64_ES_REGNUM,
+ AMD64_CS_REGNUM,
+ AMD64_SS_REGNUM,
+ AMD64_DS_REGNUM,
+ AMD64_FS_REGNUM,
+ AMD64_GS_REGNUM,
+ -1,
+ -1,
+
+ /* Segment Base Address Registers. */
+ -1,
+ -1,
+ -1,
+ -1,
+
+ /* Special Selector Registers. */
+ -1,
+ -1,
+
+ /* Floating Point Control Registers. */
+ AMD64_MXCSR_REGNUM,
+ AMD64_FCTRL_REGNUM,
+ AMD64_FSTAT_REGNUM
};
static const int amd64_dwarf_regmap_len =
{
int regnum = -1;
- if (reg >= 0 || reg < amd64_dwarf_regmap_len)
+ if (reg >= 0 && reg < amd64_dwarf_regmap_len)
regnum = amd64_dwarf_regmap[reg];
if (regnum == -1)
- warning ("Unmapped DWARF Register #%d encountered\n", reg);
+ warning (_("Unmapped DWARF Register #%d encountered."), reg);
return regnum;
}
class[0] = class[1] = AMD64_NO_CLASS;
/* Arguments of types (signed and unsigned) _Bool, char, short, int,
- long, long long, and pointers are in the INTEGER class. */
+ long, long long, and pointers are in the INTEGER class. Similarly,
+ range types, used by languages such as Ada, are also in the INTEGER
+ class. */
if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
+ || code == TYPE_CODE_BOOL || code == TYPE_CODE_RANGE
|| code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
&& (len == 1 || len == 2 || len == 4 || len == 8))
class[0] = AMD64_INTEGER;
static enum return_value_convention
amd64_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache,
- void *readbuf, const void *writebuf)
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
enum amd64_reg_class class[2];
int len = TYPE_LENGTH (type);
amd64_classify (type, class);
/* 2. If the type has class MEMORY, then the caller provides space
- for the return value and passes the address of this storage in
- %rdi as if it were the first argument to the function. In
- effect, this address becomes a hidden first argument. */
+ for the return value and passes the address of this storage in
+ %rdi as if it were the first argument to the function. In effect,
+ this address becomes a hidden first argument.
+
+ On return %rax will contain the address that has been passed in
+ by the caller in %rdi. */
if (class[0] == AMD64_MEMORY)
- return RETURN_VALUE_STRUCT_CONVENTION;
+ {
+ /* As indicated by the comment above, the ABI guarantees that we
+ can always find the return value just after the function has
+ returned. */
+
+ if (readbuf)
+ {
+ ULONGEST addr;
+
+ regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr);
+ read_memory (addr, readbuf, TYPE_LENGTH (type));
+ }
+
+ return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+ }
gdb_assert (class[1] != AMD64_MEMORY);
gdb_assert (len <= 16);
if (readbuf)
regcache_raw_read_part (regcache, regnum, offset, min (len, 8),
- (char *) readbuf + i * 8);
+ readbuf + i * 8);
if (writebuf)
regcache_raw_write_part (regcache, regnum, offset, min (len, 8),
- (const char *) writebuf + i * 8);
+ writebuf + i * 8);
}
return RETURN_VALUE_REGISTER_CONVENTION;
for (i = 0; i < nargs; i++)
{
- struct type *type = VALUE_TYPE (args[i]);
+ struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
enum amd64_reg_class class[2];
int needed_integer_regs = 0;
else
{
/* The argument will be passed in registers. */
- char *valbuf = VALUE_CONTENTS (args[i]);
- char buf[8];
+ const gdb_byte *valbuf = value_contents (args[i]);
+ gdb_byte buf[8];
gdb_assert (len <= 16);
/* Write out the arguments to the stack. */
for (i = 0; i < num_stack_args; i++)
{
- struct type *type = VALUE_TYPE (stack_args[i]);
- char *valbuf = VALUE_CONTENTS (stack_args[i]);
+ struct type *type = value_type (stack_args[i]);
+ const gdb_byte *valbuf = value_contents (stack_args[i]);
int len = TYPE_LENGTH (type);
write_memory (sp + element * 8, valbuf, len);
}
static CORE_ADDR
-amd64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
- char buf[8];
+ gdb_byte buf[8];
/* Pass arguments. */
sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);
int frameless_p;
};
-/* Allocate and initialize a frame cache. */
+/* Initialize a frame cache. */
-static struct amd64_frame_cache *
-amd64_alloc_frame_cache (void)
+static void
+amd64_init_frame_cache (struct amd64_frame_cache *cache)
{
- struct amd64_frame_cache *cache;
int i;
- cache = FRAME_OBSTACK_ZALLOC (struct amd64_frame_cache);
-
/* Base address. */
cache->base = 0;
cache->sp_offset = -8;
/* Frameless until proven otherwise. */
cache->frameless_p = 1;
+}
+
+/* Allocate and initialize a frame cache. */
+
+static struct amd64_frame_cache *
+amd64_alloc_frame_cache (void)
+{
+ struct amd64_frame_cache *cache;
+ cache = FRAME_OBSTACK_ZALLOC (struct amd64_frame_cache);
+ amd64_init_frame_cache (cache);
return cache;
}
amd64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
struct amd64_frame_cache *cache)
{
- static unsigned char proto[3] = { 0x48, 0x89, 0xe5 };
- unsigned char buf[3];
- unsigned char op;
+ static gdb_byte proto[3] = { 0x48, 0x89, 0xe5 }; /* movq %rsp, %rbp */
+ gdb_byte buf[3];
+ gdb_byte op;
if (current_pc <= pc)
return current_pc;
struct amd64_frame_cache cache;
CORE_ADDR pc;
- pc = amd64_analyze_prologue (start_pc, 0xffffffffffffffff, &cache);
+ amd64_init_frame_cache (&cache);
+ pc = amd64_analyze_prologue (start_pc, 0xffffffffffffffffLL, &cache);
if (cache.frameless_p)
return start_pc;
amd64_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct amd64_frame_cache *cache;
- char buf[8];
+ gdb_byte buf[8];
int i;
if (*this_cache)
cache = amd64_alloc_frame_cache ();
*this_cache = cache;
- cache->pc = frame_func_unwind (next_frame);
+ cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
if (cache->pc != 0)
amd64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
if (cache->frameless_p)
{
- /* We didn't find a valid frame, which means that CACHE->base
- currently holds the frame pointer for our calling frame. If
- we're at the start of a function, or somewhere half-way its
- prologue, the function's frame probably hasn't been fully
- setup yet. Try to reconstruct the base address for the stack
- frame by looking at the stack pointer. For truly "frameless"
- functions this might work too. */
+ /* We didn't find a valid frame. If we're at the start of a
+ function, or somewhere half-way its prologue, the function's
+ frame probably hasn't been fully setup yet. Try to
+ reconstruct the base address for the stack frame by looking
+ at the stack pointer. For truly "frameless" functions this
+ might work too. */
frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset;
amd64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
struct amd64_frame_cache *cache =
amd64_frame_cache (next_frame, this_cache);
return;
}
- frame_register_unwind (next_frame, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ *optimizedp = 0;
+ *lvalp = lval_register;
+ *addrp = 0;
+ *realnump = regnum;
+ if (valuep)
+ frame_unwind_register (next_frame, (*realnump), valuep);
}
static const struct frame_unwind amd64_frame_unwind =
struct amd64_frame_cache *cache;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
CORE_ADDR addr;
- char buf[8];
+ gdb_byte buf[8];
int i;
if (*this_cache)
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
/* Make sure we've initialized the cache. */
amd64_sigtramp_frame_cache (next_frame, this_cache);
static const struct frame_unwind *
amd64_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
- char *name;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+
+ /* We shouldn't even bother if we don't have a sigcontext_addr
+ handler. */
+ if (tdep->sigcontext_addr == NULL)
+ return NULL;
- find_pc_partial_function (pc, &name, NULL, NULL);
- if (PC_IN_SIGTRAMP (pc, name))
+ if (tdep->sigtramp_p != NULL)
{
- gdb_assert (gdbarch_tdep (current_gdbarch)->sigcontext_addr);
+ if (tdep->sigtramp_p (next_frame))
+ return &amd64_sigtramp_frame_unwind;
+ }
- return &amd64_sigtramp_frame_unwind;
+ if (tdep->sigtramp_start != 0)
+ {
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+
+ gdb_assert (tdep->sigtramp_end != 0);
+ if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
+ return &amd64_sigtramp_frame_unwind;
}
return NULL;
static struct frame_id
amd64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
- char buf[8];
+ gdb_byte buf[8];
CORE_ADDR fp;
frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
}
\f
-/* Supply register REGNUM from the floating-point register set REGSET
- to register cache REGCACHE. If REGNUM is -1, do this for all
- registers in REGSET. */
+/* Supply register REGNUM from the buffer specified by FPREGS and LEN
+ in the floating-point register set REGSET to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
static void
amd64_supply_fpregset (const struct regset *regset, struct regcache *regcache,
int regnum, const void *fpregs, size_t len)
{
- const struct gdbarch_tdep *tdep = regset->descr;
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
gdb_assert (len == tdep->sizeof_fpregset);
amd64_supply_fxsave (regcache, regnum, fpregs);
}
+/* Collect register REGNUM from the register cache REGCACHE and store
+ it in the buffer specified by FPREGS and LEN as described by the
+ floating-point register set REGSET. If REGNUM is -1, do this for
+ all registers in REGSET. */
+
+static void
+amd64_collect_fpregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *fpregs, size_t len)
+{
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
+
+ gdb_assert (len == tdep->sizeof_fpregset);
+ amd64_collect_fxsave (regcache, regnum, fpregs);
+}
+
/* Return the appropriate register set for the core section identified
by SECT_NAME and SECT_SIZE. */
if (strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
{
if (tdep->fpregset == NULL)
- {
- tdep->fpregset = XMALLOC (struct regset);
- tdep->fpregset->descr = tdep;
- tdep->fpregset->supply_regset = amd64_supply_fpregset;
- }
+ tdep->fpregset = regset_alloc (gdbarch, amd64_supply_fpregset,
+ amd64_collect_fpregset);
return tdep->fpregset;
}
set_gdbarch_unwind_dummy_id (gdbarch, amd64_unwind_dummy_id);
- /* FIXME: kettenis/20021026: This is ELF-specific. Fine for now,
- since all supported AMD64 targets are ELF, but that might change
- in the future. */
- set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
-
frame_unwind_append_sniffer (gdbarch, amd64_sigtramp_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, amd64_frame_sniffer);
frame_base_set_default (gdbarch, &amd64_frame_base);
{
i387_supply_fxsave (regcache, regnum, fxsave);
- if (fxsave)
+ if (fxsave && gdbarch_ptr_bit (get_regcache_arch (regcache)) == 64)
{
- const char *regs = fxsave;
+ const gdb_byte *regs = fxsave;
if (regnum == -1 || regnum == I387_FISEG_REGNUM)
regcache_raw_supply (regcache, I387_FISEG_REGNUM, regs + 12);
}
/* Fill register REGNUM (if it is a floating-point or SSE register) in
- *FXSAVE with the value in GDB's register cache. If REGNUM is -1, do
- this for all registers. This function doesn't touch any of the
- reserved bits in *FXSAVE. */
+ *FXSAVE with the value from REGCACHE. If REGNUM is -1, do this for
+ all registers. This function doesn't touch any of the reserved
+ bits in *FXSAVE. */
void
-amd64_fill_fxsave (char *fxsave, int regnum)
+amd64_collect_fxsave (const struct regcache *regcache, int regnum,
+ void *fxsave)
{
- i387_fill_fxsave (fxsave, regnum);
+ gdb_byte *regs = fxsave;
+
+ i387_collect_fxsave (regcache, regnum, fxsave);
- if (regnum == -1 || regnum == I387_FISEG_REGNUM)
- regcache_collect (I387_FISEG_REGNUM, fxsave + 12);
- if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
- regcache_collect (I387_FOSEG_REGNUM, fxsave + 20);
+ if (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 64)
+ {
+ if (regnum == -1 || regnum == I387_FISEG_REGNUM)
+ regcache_raw_collect (regcache, I387_FISEG_REGNUM, regs + 12);
+ if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
+ regcache_raw_collect (regcache, I387_FOSEG_REGNUM, regs + 20);
+ }
}