/* Target-dependent code for AMD64.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
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 "arch-utils.h"
/* Return the name of register REGNUM. */
const char *
-amd64_register_name (int regnum)
+amd64_register_name (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= 0 && regnum < AMD64_NUM_REGS)
return amd64_register_names[regnum];
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;
+ return i386_sse_type (gdbarch);
if (regnum == AMD64_MXCSR_REGNUM)
return i386_mxcsr_type;
number used by GDB. */
static int
-amd64_dwarf_reg_to_regnum (int reg)
+amd64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
int regnum = -1;
return regnum;
}
-/* Return nonzero if a value of type TYPE stored in register REGNUM
- needs any special handling. */
-
-static int
-amd64_convert_register_p (int regnum, struct type *type)
-{
- return i386_fp_regnum_p (regnum);
-}
\f
/* Register classes as defined in the psABI. */
class. */
if ((code == TYPE_CODE_INT || code == TYPE_CODE_ENUM
|| code == TYPE_CODE_BOOL || code == TYPE_CODE_RANGE
+ || code == TYPE_CODE_CHAR
|| code == TYPE_CODE_PTR || code == TYPE_CODE_REF)
&& (len == 1 || len == 2 || len == 4 || len == 8))
class[0] = AMD64_INTEGER;
- /* Arguments of types float, double and __m64 are in class SSE. */
- else if (code == TYPE_CODE_FLT && (len == 4 || len == 8))
+ /* Arguments of types float, double, _Decimal32, _Decimal64 and __m64
+ are in class SSE. */
+ else if ((code == TYPE_CODE_FLT || code == TYPE_CODE_DECFLOAT)
+ && (len == 4 || len == 8))
/* FIXME: __m64 . */
class[0] = AMD64_SSE;
- /* Arguments of types __float128 and __m128 are split into two
- halves. The least significant ones belong to class SSE, the most
+ /* Arguments of types __float128, _Decimal128 and __m128 are split into
+ two halves. The least significant ones belong to class SSE, the most
significant one to class SSEUP. */
- /* FIXME: __float128, __m128. */
+ else if (code == TYPE_CODE_DECFLOAT && len == 16)
+ /* FIXME: __float128, __m128. */
+ class[0] = AMD64_SSE, class[1] = AMD64_SSEUP;
/* The 64-bit mantissa of arguments of type long double belongs to
class X87, the 16-bit exponent plus 6 bytes of padding belongs to
}
static enum return_value_convention
-amd64_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache,
+amd64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
enum amd64_reg_class class[2];
/* Return PC of first real instruction. */
static CORE_ADDR
-amd64_skip_prologue (CORE_ADDR start_pc)
+amd64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
struct amd64_frame_cache cache;
CORE_ADDR pc;
/* Normal frames. */
static struct amd64_frame_cache *
-amd64_frame_cache (struct frame_info *next_frame, void **this_cache)
+amd64_frame_cache (struct frame_info *this_frame, void **this_cache)
{
struct amd64_frame_cache *cache;
gdb_byte buf[8];
cache = amd64_alloc_frame_cache ();
*this_cache = cache;
- cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
+ cache->pc = get_frame_func (this_frame);
if (cache->pc != 0)
- amd64_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+ amd64_analyze_prologue (cache->pc, get_frame_pc (this_frame), cache);
if (cache->frameless_p)
{
at the stack pointer. For truly "frameless" functions this
might work too. */
- frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
+ get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset;
}
else
{
- frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
+ get_frame_register (this_frame, AMD64_RBP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8);
}
}
static void
-amd64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+amd64_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
{
struct amd64_frame_cache *cache =
- amd64_frame_cache (next_frame, this_cache);
+ amd64_frame_cache (this_frame, this_cache);
/* This marks the outermost frame. */
if (cache->base == 0)
(*this_id) = frame_id_build (cache->base + 16, cache->pc);
}
-static void
-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, gdb_byte *valuep)
+static struct value *
+amd64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
+ int regnum)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct amd64_frame_cache *cache =
- amd64_frame_cache (next_frame, this_cache);
+ amd64_frame_cache (this_frame, this_cache);
gdb_assert (regnum >= 0);
- if (regnum == SP_REGNUM && cache->saved_sp)
- {
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (valuep)
- {
- /* Store the value. */
- store_unsigned_integer (valuep, 8, cache->saved_sp);
- }
- return;
- }
+ if (regnum == gdbarch_sp_regnum (gdbarch) && cache->saved_sp)
+ return frame_unwind_got_constant (this_frame, regnum, cache->saved_sp);
if (regnum < AMD64_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
- {
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = cache->saved_regs[regnum];
- *realnump = -1;
- if (valuep)
- {
- /* Read the value in from memory. */
- read_memory (*addrp, valuep,
- register_size (current_gdbarch, regnum));
- }
- return;
- }
+ return frame_unwind_got_memory (this_frame, regnum,
+ cache->saved_regs[regnum]);
- *optimizedp = 0;
- *lvalp = lval_register;
- *addrp = 0;
- *realnump = regnum;
- if (valuep)
- frame_unwind_register (next_frame, (*realnump), valuep);
+ return frame_unwind_got_register (this_frame, regnum, regnum);
}
static const struct frame_unwind amd64_frame_unwind =
{
NORMAL_FRAME,
amd64_frame_this_id,
- amd64_frame_prev_register
+ amd64_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-
-static const struct frame_unwind *
-amd64_frame_sniffer (struct frame_info *next_frame)
-{
- return &amd64_frame_unwind;
-}
\f
/* Signal trampolines. */
on both platforms. */
static struct amd64_frame_cache *
-amd64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
+amd64_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
{
struct amd64_frame_cache *cache;
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
CORE_ADDR addr;
gdb_byte buf[8];
int i;
cache = amd64_alloc_frame_cache ();
- frame_unwind_register (next_frame, AMD64_RSP_REGNUM, buf);
+ get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8) - 8;
- addr = tdep->sigcontext_addr (next_frame);
+ addr = tdep->sigcontext_addr (this_frame);
gdb_assert (tdep->sc_reg_offset);
gdb_assert (tdep->sc_num_regs <= AMD64_NUM_SAVED_REGS);
for (i = 0; i < tdep->sc_num_regs; i++)
}
static void
-amd64_sigtramp_frame_this_id (struct frame_info *next_frame,
+amd64_sigtramp_frame_this_id (struct frame_info *this_frame,
void **this_cache, struct frame_id *this_id)
{
struct amd64_frame_cache *cache =
- amd64_sigtramp_frame_cache (next_frame, this_cache);
+ amd64_sigtramp_frame_cache (this_frame, this_cache);
- (*this_id) = frame_id_build (cache->base + 16, frame_pc_unwind (next_frame));
+ (*this_id) = frame_id_build (cache->base + 16, get_frame_pc (this_frame));
}
-static void
-amd64_sigtramp_frame_prev_register (struct frame_info *next_frame,
- void **this_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, gdb_byte *valuep)
+static struct value *
+amd64_sigtramp_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
{
/* Make sure we've initialized the cache. */
- amd64_sigtramp_frame_cache (next_frame, this_cache);
+ amd64_sigtramp_frame_cache (this_frame, this_cache);
- amd64_frame_prev_register (next_frame, this_cache, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ return amd64_frame_prev_register (this_frame, this_cache, regnum);
}
-static const struct frame_unwind amd64_sigtramp_frame_unwind =
-{
- SIGTRAMP_FRAME,
- amd64_sigtramp_frame_this_id,
- amd64_sigtramp_frame_prev_register
-};
-
-static const struct frame_unwind *
-amd64_sigtramp_frame_sniffer (struct frame_info *next_frame)
+static int
+amd64_sigtramp_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ void **this_cache)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
/* We shouldn't even bother if we don't have a sigcontext_addr
handler. */
if (tdep->sigcontext_addr == NULL)
- return NULL;
+ return 0;
if (tdep->sigtramp_p != NULL)
{
- if (tdep->sigtramp_p (next_frame))
- return &amd64_sigtramp_frame_unwind;
+ if (tdep->sigtramp_p (this_frame))
+ return 1;
}
if (tdep->sigtramp_start != 0)
{
- CORE_ADDR pc = frame_pc_unwind (next_frame);
+ CORE_ADDR pc = get_frame_pc (this_frame);
gdb_assert (tdep->sigtramp_end != 0);
if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
- return &amd64_sigtramp_frame_unwind;
+ return 1;
}
- return NULL;
+ return 0;
}
+
+static const struct frame_unwind amd64_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ amd64_sigtramp_frame_this_id,
+ amd64_sigtramp_frame_prev_register,
+ NULL,
+ amd64_sigtramp_frame_sniffer
+};
\f
static CORE_ADDR
-amd64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+amd64_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
struct amd64_frame_cache *cache =
- amd64_frame_cache (next_frame, this_cache);
+ amd64_frame_cache (this_frame, this_cache);
return cache->base;
}
};
static struct frame_id
-amd64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+amd64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
- gdb_byte buf[8];
CORE_ADDR fp;
- frame_unwind_register (next_frame, AMD64_RBP_REGNUM, buf);
- fp = extract_unsigned_integer (buf, 8);
+ fp = get_frame_register_unsigned (this_frame, AMD64_RBP_REGNUM);
- return frame_id_build (fp + 16, frame_pc_unwind (next_frame));
+ return frame_id_build (fp + 16, get_frame_pc (this_frame));
}
/* 16 byte align the SP per frame requirements. */
}
\f
+/* Figure out where the longjmp will land. Slurp the jmp_buf out of
+ %rdi. We expect its value to be a pointer to the jmp_buf structure
+ from which we extract the address that we will land at. This
+ address is copied into PC. This routine returns non-zero on
+ success. */
+
+static int
+amd64_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
+{
+ gdb_byte buf[8];
+ CORE_ADDR jb_addr;
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ int jb_pc_offset = gdbarch_tdep (gdbarch)->jb_pc_offset;
+ int len = TYPE_LENGTH (builtin_type_void_func_ptr);
+
+ /* If JB_PC_OFFSET is -1, we have no way to find out where the
+ longjmp will land. */
+ if (jb_pc_offset == -1)
+ return 0;
+
+ get_frame_register (frame, AMD64_RDI_REGNUM, buf);
+ jb_addr = extract_typed_address (buf, builtin_type_void_data_ptr);
+ if (target_read_memory (jb_addr + jb_pc_offset, buf, len))
+ return 0;
+
+ *pc = extract_typed_address (buf, builtin_type_void_func_ptr);
+
+ return 1;
+}
+
void
amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_frame_align (gdbarch, amd64_frame_align);
set_gdbarch_frame_red_zone_size (gdbarch, 128);
- set_gdbarch_convert_register_p (gdbarch, amd64_convert_register_p);
+ set_gdbarch_convert_register_p (gdbarch, i387_convert_register_p);
set_gdbarch_register_to_value (gdbarch, i387_register_to_value);
set_gdbarch_value_to_register (gdbarch, i387_value_to_register);
set_gdbarch_num_pseudo_regs (gdbarch, 0);
tdep->mm0_regnum = -1;
- set_gdbarch_unwind_dummy_id (gdbarch, amd64_unwind_dummy_id);
+ set_gdbarch_dummy_id (gdbarch, amd64_dummy_id);
- frame_unwind_append_sniffer (gdbarch, amd64_sigtramp_frame_sniffer);
- frame_unwind_append_sniffer (gdbarch, amd64_frame_sniffer);
+ frame_unwind_append_unwinder (gdbarch, &amd64_sigtramp_frame_unwind);
+ frame_unwind_append_unwinder (gdbarch, &amd64_frame_unwind);
frame_base_set_default (gdbarch, &amd64_frame_base);
/* If we have a register mapping, enable the generic core file support. */
if (tdep->gregset_reg_offset)
set_gdbarch_regset_from_core_section (gdbarch,
amd64_regset_from_core_section);
+
+ set_gdbarch_get_longjmp_target (gdbarch, amd64_get_longjmp_target);
}
\f
-#define I387_ST0_REGNUM AMD64_ST0_REGNUM
-
/* The 64-bit FXSAVE format differs from the 32-bit format in the
sense that the instruction pointer and data pointer are simply
64-bit offsets into the code segment and the data segment instead
void
amd64_supply_fxsave (struct regcache *regcache, int regnum,
- const void *fxsave)
+ const void *fxsave)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
i387_supply_fxsave (regcache, regnum, fxsave);
- if (fxsave && gdbarch_ptr_bit (get_regcache_arch (regcache)) == 64)
+ if (fxsave && gdbarch_ptr_bit (gdbarch) == 64)
{
const gdb_byte *regs = fxsave;
- if (regnum == -1 || regnum == I387_FISEG_REGNUM)
- regcache_raw_supply (regcache, I387_FISEG_REGNUM, regs + 12);
- if (regnum == -1 || regnum == I387_FOSEG_REGNUM)
- regcache_raw_supply (regcache, I387_FOSEG_REGNUM, regs + 20);
+ if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
+ regcache_raw_supply (regcache, I387_FISEG_REGNUM (tdep), regs + 12);
+ if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep))
+ regcache_raw_supply (regcache, I387_FOSEG_REGNUM (tdep), regs + 20);
}
}
amd64_collect_fxsave (const struct regcache *regcache, int regnum,
void *fxsave)
{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_byte *regs = fxsave;
i387_collect_fxsave (regcache, regnum, fxsave);
- if (gdbarch_ptr_bit (get_regcache_arch (regcache)) == 64)
+ if (gdbarch_ptr_bit (gdbarch) == 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);
+ if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
+ regcache_raw_collect (regcache, I387_FISEG_REGNUM (tdep), regs + 12);
+ if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep))
+ regcache_raw_collect (regcache, I387_FOSEG_REGNUM (tdep), regs + 20);
}
}