/* Target-dependent code for AMD64.
- Copyright (C) 2001-2015 Free Software Foundation, Inc.
+ Copyright (C) 2001-2018 Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
#include "amd64-tdep.h"
#include "i387-tdep.h"
#include "x86-xstate.h"
-
-#include "features/i386/amd64.c"
-#include "features/i386/amd64-avx.c"
-#include "features/i386/amd64-mpx.c"
-#include "features/i386/amd64-avx512.c"
-
-#include "features/i386/x32.c"
-#include "features/i386/x32-avx.c"
-#include "features/i386/x32-avx512.c"
-
+#include <algorithm>
+#include "target-descriptions.h"
+#include "arch/amd64.h"
+#include "producer.h"
#include "ax.h"
#include "ax-gdb.h"
+#include "common/byte-vector.h"
+#include "osabi.h"
+#include "x86-tdep.h"
/* Note that the AMD64 architecture was previously known as x86-64.
The latter is (forever) engraved into the canonical system name as
"xmm28", "xmm29", "xmm30", "xmm31"
};
+static const char *amd64_pkeys_names[] = {
+ "pkru"
+};
+
/* DWARF Register Number Mapping as defined in the System V psABI,
section 3.6. */
if (reg >= 0 && reg < amd64_dwarf_regmap_len)
regnum = amd64_dwarf_regmap[reg];
- if (regnum == -1)
- warning (_("Unmapped DWARF Register #%d encountered."), reg);
- else if (ymm0_regnum >= 0
+ if (ymm0_regnum >= 0
&& i386_xmm_regnum_p (gdbarch, regnum))
regnum += ymm0_regnum - I387_XMM0_REGNUM (tdep);
static struct value *
amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
- struct regcache *regcache,
+ readable_regcache *regcache,
int regnum)
{
- gdb_byte raw_buf[MAX_REGISTER_SIZE];
+ gdb_byte *raw_buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum register_status status;
struct value *result_value;
if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
{
/* Special handling for AH, BH, CH, DH. */
- status = regcache_raw_read (regcache,
- gpnum - AMD64_NUM_LOWER_BYTE_REGS,
- raw_buf);
+ status = regcache->raw_read (gpnum - AMD64_NUM_LOWER_BYTE_REGS,
+ raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf + 1, 1);
else
}
else
{
- status = regcache_raw_read (regcache, gpnum, raw_buf);
+ status = regcache->raw_read (gpnum, raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf, 1);
else
{
int gpnum = regnum - tdep->eax_regnum;
/* Extract (always little endian). */
- status = regcache_raw_read (regcache, gpnum, raw_buf);
+ status = regcache->raw_read (gpnum, raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf, 4);
else
struct regcache *regcache,
int regnum, const gdb_byte *buf)
{
- gdb_byte raw_buf[MAX_REGISTER_SIZE];
+ gdb_byte *raw_buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (i386_byte_regnum_p (gdbarch, regnum))
i386_pseudo_register_write (gdbarch, regcache, regnum, buf);
}
+/* Implement the 'ax_pseudo_register_collect' gdbarch method. */
+
+static int
+amd64_ax_pseudo_register_collect (struct gdbarch *gdbarch,
+ struct agent_expr *ax, int regnum)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (i386_byte_regnum_p (gdbarch, regnum))
+ {
+ int gpnum = regnum - tdep->al_regnum;
+
+ if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
+ ax_reg_mask (ax, gpnum - AMD64_NUM_LOWER_BYTE_REGS);
+ else
+ ax_reg_mask (ax, gpnum);
+ return 0;
+ }
+ else if (i386_dword_regnum_p (gdbarch, regnum))
+ {
+ int gpnum = regnum - tdep->eax_regnum;
+
+ ax_reg_mask (ax, gpnum);
+ return 0;
+ }
+ else
+ return i386_ax_pseudo_register_collect (gdbarch, ax, regnum);
+}
+
\f
/* Register classes as defined in the psABI. */
bitsize = TYPE_LENGTH (subtype) * 8;
endpos = (TYPE_FIELD_BITPOS (type, i) + bitsize - 1) / 64;
- /* Ignore static fields. */
- if (field_is_static (&TYPE_FIELD (type, i)))
+ /* Ignore static fields, or empty fields, for example nested
+ empty structures.*/
+ if (field_is_static (&TYPE_FIELD (type, i)) || bitsize == 0)
continue;
gdb_assert (pos == 0 || pos == 1);
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)
+ || code == TYPE_CODE_PTR || TYPE_IS_REFERENCE (type))
&& (len == 1 || len == 2 || len == 4 || len == 8))
theclass[0] = AMD64_INTEGER;
gdb_assert (regnum != -1);
if (readbuf)
- regcache_raw_read_part (regcache, regnum, offset, min (len, 8),
+ regcache_raw_read_part (regcache, regnum, offset, std::min (len, 8),
readbuf + i * 8);
if (writebuf)
- regcache_raw_write_part (regcache, regnum, offset, min (len, 8),
+ regcache_raw_write_part (regcache, regnum, offset, std::min (len, 8),
writebuf + i * 8);
}
AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5,
AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
};
- struct value **stack_args = alloca (nargs * sizeof (struct value *));
+ struct value **stack_args = XALLOCAVEC (struct value *, nargs);
int num_stack_args = 0;
int num_elements = 0;
int element = 0;
gdb_assert (regnum != -1);
memset (buf, 0, sizeof buf);
- memcpy (buf, valbuf + j * 8, min (len, 8));
+ memcpy (buf, valbuf + j * 8, std::min (len, 8));
regcache_raw_write_part (regcache, regnum, offset, 8, buf);
}
}
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
gdb_byte buf[8];
+ /* BND registers can be in arbitrary values at the moment of the
+ inferior call. This can cause boundary violations that are not
+ due to a real bug or even desired by the user. The best to be done
+ is set the BND registers to allow access to the whole memory, INIT
+ state, before pushing the inferior call. */
+ i387_reset_bnd_regs (gdbarch, regcache);
+
/* Pass arguments. */
sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);
{
/* The number of opcode bytes. */
int opcode_len;
- /* The offset of the rex prefix or -1 if not present. */
- int rex_offset;
+ /* The offset of the REX/VEX instruction encoding prefix or -1 if
+ not present. */
+ int enc_prefix_offset;
/* The offset to the first opcode byte. */
int opcode_offset;
/* The offset to the modrm byte or -1 if not present. */
gdb_byte *raw_insn;
};
-struct displaced_step_closure
+struct amd64_displaced_step_closure : public displaced_step_closure
{
+ amd64_displaced_step_closure (int insn_buf_len)
+ : insn_buf (insn_buf_len, 0)
+ {}
+
/* For rip-relative insns, saved copy of the reg we use instead of %rip. */
- int tmp_used;
+ int tmp_used = 0;
int tmp_regno;
ULONGEST tmp_save;
/* Details of the instruction. */
struct amd64_insn insn_details;
- /* Amount of space allocated to insn_buf. */
- int max_len;
-
- /* The possibly modified insn.
- This is a variable-length field. */
- gdb_byte insn_buf[1];
+ /* The possibly modified insn. */
+ gdb::byte_vector insn_buf;
};
/* WARNING: Keep onebyte_has_modrm, twobyte_has_modrm in sync with
return REX_PREFIX_P (pfx);
}
+/* True if PFX is the start of the 2-byte VEX prefix. */
+
+static bool
+vex2_prefix_p (gdb_byte pfx)
+{
+ return pfx == 0xc5;
+}
+
+/* True if PFX is the start of the 3-byte VEX prefix. */
+
+static bool
+vex3_prefix_p (gdb_byte pfx)
+{
+ return pfx == 0xc4;
+}
+
/* Skip the legacy instruction prefixes in INSN.
We assume INSN is properly sentineled so we don't have to worry
about falling off the end of the buffer. */
details->raw_insn = insn;
details->opcode_len = -1;
- details->rex_offset = -1;
+ details->enc_prefix_offset = -1;
details->opcode_offset = -1;
details->modrm_offset = -1;
/* Skip legacy instruction prefixes. */
insn = amd64_skip_prefixes (insn);
- /* Skip REX instruction prefix. */
+ /* Skip REX/VEX instruction encoding prefixes. */
if (rex_prefix_p (*insn))
{
- details->rex_offset = insn - start;
+ details->enc_prefix_offset = insn - start;
++insn;
}
+ else if (vex2_prefix_p (*insn))
+ {
+ /* Don't record the offset in this case because this prefix has
+ no REX.B equivalent. */
+ insn += 2;
+ }
+ else if (vex3_prefix_p (*insn))
+ {
+ details->enc_prefix_offset = insn - start;
+ insn += 3;
+ }
details->opcode_offset = insn - start;
We set base = pc + insn_length so we can leave disp unchanged. */
static void
-fixup_riprel (struct gdbarch *gdbarch, struct displaced_step_closure *dsc,
+fixup_riprel (struct gdbarch *gdbarch, amd64_displaced_step_closure *dsc,
CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
{
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
const struct amd64_insn *insn_details = &dsc->insn_details;
int modrm_offset = insn_details->modrm_offset;
gdb_byte *insn = insn_details->raw_insn + modrm_offset;
CORE_ADDR rip_base;
- int32_t disp;
int insn_length;
int arch_tmp_regno, tmp_regno;
ULONGEST orig_value;
++insn;
/* Compute the rip-relative address. */
- disp = extract_signed_integer (insn, sizeof (int32_t), byte_order);
- insn_length = gdb_buffered_insn_length (gdbarch, dsc->insn_buf,
- dsc->max_len, from);
+ insn_length = gdb_buffered_insn_length (gdbarch, dsc->insn_buf.data (),
+ dsc->insn_buf.size (), from);
rip_base = from + insn_length;
/* We need a register to hold the address.
arch_tmp_regno = amd64_get_unused_input_int_reg (insn_details);
tmp_regno = amd64_arch_reg_to_regnum (arch_tmp_regno);
- /* REX.B should be unset as we were using rip-relative addressing,
- but ensure it's unset anyway, tmp_regno is not r8-r15. */
- if (insn_details->rex_offset != -1)
- dsc->insn_buf[insn_details->rex_offset] &= ~REX_B;
+ /* Position of the not-B bit in the 3-byte VEX prefix (in byte 1). */
+ static constexpr gdb_byte VEX3_NOT_B = 0x20;
+
+ /* REX.B should be unset (VEX.!B set) as we were using rip-relative
+ addressing, but ensure it's unset (set for VEX) anyway, tmp_regno
+ is not r8-r15. */
+ if (insn_details->enc_prefix_offset != -1)
+ {
+ gdb_byte *pfx = &dsc->insn_buf[insn_details->enc_prefix_offset];
+ if (rex_prefix_p (pfx[0]))
+ pfx[0] &= ~REX_B;
+ else if (vex3_prefix_p (pfx[0]))
+ pfx[1] |= VEX3_NOT_B;
+ else
+ gdb_assert_not_reached ("unhandled prefix");
+ }
regcache_cooked_read_unsigned (regs, tmp_regno, &orig_value);
dsc->tmp_regno = tmp_regno;
static void
fixup_displaced_copy (struct gdbarch *gdbarch,
- struct displaced_step_closure *dsc,
+ amd64_displaced_step_closure *dsc,
CORE_ADDR from, CORE_ADDR to, struct regcache *regs)
{
const struct amd64_insn *details = &dsc->insn_details;
/* Extra space for sentinels so fixup_{riprel,displaced_copy} don't have to
continually watch for running off the end of the buffer. */
int fixup_sentinel_space = len;
- struct displaced_step_closure *dsc =
- xmalloc (sizeof (*dsc) + len + fixup_sentinel_space);
+ amd64_displaced_step_closure *dsc
+ = new amd64_displaced_step_closure (len + fixup_sentinel_space);
gdb_byte *buf = &dsc->insn_buf[0];
struct amd64_insn *details = &dsc->insn_details;
- dsc->tmp_used = 0;
- dsc->max_len = len + fixup_sentinel_space;
-
read_memory (from, buf, len);
/* Set up the sentinel space so we don't have to worry about running
int len, classification;
len = gdbarch_max_insn_length (gdbarch);
- buf = alloca (len);
+ buf = (gdb_byte *) alloca (len);
read_code (addr, buf, len);
amd64_get_insn_details (buf, &details);
void
amd64_displaced_step_fixup (struct gdbarch *gdbarch,
- struct displaced_step_closure *dsc,
+ struct displaced_step_closure *dsc_,
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
+ amd64_displaced_step_closure *dsc = (amd64_displaced_step_closure *) dsc_;
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* The offset we applied to the instruction's address. */
ULONGEST insn_offset = to - from;
- gdb_byte *insn = dsc->insn_buf;
+ gdb_byte *insn = dsc->insn_buf.data ();
const struct amd64_insn *insn_details = &dsc->insn_details;
if (debug_displaced)
regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
- retaddr = (retaddr - insn_offset) & 0xffffffffUL;
+ retaddr = (retaddr - insn_offset) & 0xffffffffffffffffULL;
write_memory_unsigned_integer (rsp, retaddr_len, byte_order, retaddr);
if (debug_displaced)
int len = gdbarch_max_insn_length (gdbarch);
/* Extra space for sentinels. */
int fixup_sentinel_space = len;
- gdb_byte *buf = xmalloc (len + fixup_sentinel_space);
+ gdb_byte *buf = (gdb_byte *) xmalloc (len + fixup_sentinel_space);
struct amd64_insn insn_details;
int offset = 0;
LONGEST rel32, newrel;
the user program would return to. */
if (insn[0] == 0xe8)
{
- gdb_byte push_buf[16];
- unsigned int ret_addr;
+ gdb_byte push_buf[32];
+ CORE_ADDR ret_addr;
+ int i = 0;
/* Where "ret" in the original code will return to. */
ret_addr = oldloc + insn_length;
- push_buf[0] = 0x68; /* pushq $... */
- store_unsigned_integer (&push_buf[1], 4, byte_order, ret_addr);
+
+ /* If pushing an address higher than or equal to 0x80000000,
+ avoid 'pushq', as that sign extends its 32-bit operand, which
+ would be incorrect. */
+ if (ret_addr <= 0x7fffffff)
+ {
+ push_buf[0] = 0x68; /* pushq $... */
+ store_unsigned_integer (&push_buf[1], 4, byte_order, ret_addr);
+ i = 5;
+ }
+ else
+ {
+ push_buf[i++] = 0x48; /* sub $0x8,%rsp */
+ push_buf[i++] = 0x83;
+ push_buf[i++] = 0xec;
+ push_buf[i++] = 0x08;
+
+ push_buf[i++] = 0xc7; /* movl $imm,(%rsp) */
+ push_buf[i++] = 0x04;
+ push_buf[i++] = 0x24;
+ store_unsigned_integer (&push_buf[i], 4, byte_order,
+ ret_addr & 0xffffffff);
+ i += 4;
+
+ push_buf[i++] = 0xc7; /* movl $imm,4(%rsp) */
+ push_buf[i++] = 0x44;
+ push_buf[i++] = 0x24;
+ push_buf[i++] = 0x04;
+ store_unsigned_integer (&push_buf[i], 4, byte_order,
+ ret_addr >> 32);
+ i += 4;
+ }
+ gdb_assert (i <= sizeof (push_buf));
/* Push the push. */
- append_insns (to, 5, push_buf);
+ append_insns (to, i, push_buf);
/* Convert the relative call to a relative jump. */
insn[0] = 0xe9;
if (current_pc > pc + offset_and)
cache->saved_sp_reg = amd64_arch_reg_to_regnum (reg);
- return min (pc + offset + 2, current_pc);
+ return std::min (pc + offset + 2, current_pc);
}
/* Similar to amd64_analyze_stack_align for x32. */
if (current_pc > pc + offset_and)
cache->saved_sp_reg = amd64_arch_reg_to_regnum (reg);
- return min (pc + offset + 2, current_pc);
+ return std::min (pc + offset + 2, current_pc);
}
/* Do a limited analysis of the prologue at PC and update CACHE
&& (cust != NULL
&& COMPUNIT_PRODUCER (cust) != NULL
&& startswith (COMPUNIT_PRODUCER (cust), "clang ")))
- return max (start_pc, post_prologue_pc);
+ return std::max (start_pc, post_prologue_pc);
}
amd64_init_frame_cache (&cache);
struct amd64_frame_cache *cache;
if (*this_cache)
- return *this_cache;
+ return (struct amd64_frame_cache *) *this_cache;
cache = amd64_alloc_frame_cache ();
*this_cache = cache;
int i;
if (*this_cache)
- return *this_cache;
+ return (struct amd64_frame_cache *) *this_cache;
cache = amd64_alloc_frame_cache ();
/* Normal frames, but in a function epilogue. */
-/* The epilogue is defined here as the 'ret' instruction, which will
+/* Implement the stack_frame_destroyed_p gdbarch method.
+
+ The epilogue is defined here as the 'ret' instruction, which will
follow any instruction such as 'leave' or 'pop %ebp' that destroys
the function's stack frame. */
static int
-amd64_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+amd64_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
gdb_byte insn;
struct compunit_symtab *cust;
void **this_prologue_cache)
{
if (frame_relative_level (this_frame) == 0)
- return amd64_in_function_epilogue_p (get_frame_arch (this_frame),
- get_frame_pc (this_frame));
+ return amd64_stack_frame_destroyed_p (get_frame_arch (this_frame),
+ get_frame_pc (this_frame));
else
return 0;
}
gdb_byte buf[8];
if (*this_cache)
- return *this_cache;
+ return (struct amd64_frame_cache *) *this_cache;
cache = amd64_alloc_frame_cache ();
*this_cache = cache;
amd64_supply_fpregset (const struct regset *regset, struct regcache *regcache,
int regnum, const void *fpregs, size_t len)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_assert (len >= tdep->sizeof_fpregset);
const struct regcache *regcache,
int regnum, void *fpregs, size_t len)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
const struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
gdb_assert (len >= tdep->sizeof_fpregset);
AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM
};
+/* Implement the "in_indirect_branch_thunk" gdbarch function. */
+
+static bool
+amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ return x86_in_indirect_branch_thunk (pc, amd64_register_names,
+ AMD64_RAX_REGNUM,
+ AMD64_RIP_REGNUM);
+}
+
void
-amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
+ const target_desc *default_tdesc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
const struct target_desc *tdesc = info.target_desc;
tdep->fpregset = &amd64_fpregset;
if (! tdesc_has_registers (tdesc))
- tdesc = tdesc_amd64;
+ tdesc = default_tdesc;
tdep->tdesc = tdesc;
tdep->num_core_regs = AMD64_NUM_GREGS + I387_NUM_REGS;
tdep->bnd0r_regnum = AMD64_BND0R_REGNUM;
}
+ if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments") != NULL)
+ {
+ const struct tdesc_feature *feature =
+ tdesc_find_feature (tdesc, "org.gnu.gdb.i386.segments");
+ struct tdesc_arch_data *tdesc_data_segments =
+ (struct tdesc_arch_data *) info.tdep_info;
+
+ tdesc_numbered_register (feature, tdesc_data_segments,
+ AMD64_FSBASE_REGNUM, "fs_base");
+ tdesc_numbered_register (feature, tdesc_data_segments,
+ AMD64_GSBASE_REGNUM, "gs_base");
+ }
+
+ if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys") != NULL)
+ {
+ tdep->pkeys_register_names = amd64_pkeys_names;
+ tdep->pkru_regnum = AMD64_PKRU_REGNUM;
+ tdep->num_pkeys_regs = 1;
+ }
+
tdep->num_byte_regs = 20;
tdep->num_word_regs = 16;
tdep->num_dword_regs = 16;
amd64_pseudo_register_read_value);
set_gdbarch_pseudo_register_write (gdbarch,
amd64_pseudo_register_write);
+ set_gdbarch_ax_pseudo_register_collect (gdbarch,
+ amd64_ax_pseudo_register_collect);
set_tdesc_pseudo_register_name (gdbarch, amd64_pseudo_register_name);
set_gdbarch_insn_is_call (gdbarch, amd64_insn_is_call);
set_gdbarch_insn_is_ret (gdbarch, amd64_insn_is_ret);
set_gdbarch_insn_is_jump (gdbarch, amd64_insn_is_jump);
+
+ set_gdbarch_in_indirect_branch_thunk (gdbarch,
+ amd64_in_indirect_branch_thunk);
+}
+
+/* Initialize ARCH for x86-64, no osabi. */
+
+static void
+amd64_none_init_abi (gdbarch_info info, gdbarch *arch)
+{
+ amd64_init_abi (info, arch, amd64_target_description (X86_XSTATE_SSE_MASK));
}
-\f
static struct type *
amd64_x32_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
}
void
-amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+amd64_x32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
+ const target_desc *default_tdesc)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- const struct target_desc *tdesc = info.target_desc;
-
- amd64_init_abi (info, gdbarch);
- if (! tdesc_has_registers (tdesc))
- tdesc = tdesc_x32;
- tdep->tdesc = tdesc;
+ amd64_init_abi (info, gdbarch, default_tdesc);
tdep->num_dword_regs = 17;
set_tdesc_pseudo_register_type (gdbarch, amd64_x32_pseudo_register_type);
set_gdbarch_ptr_bit (gdbarch, 32);
}
+/* Initialize ARCH for x64-32, no osabi. */
+
+static void
+amd64_x32_none_init_abi (gdbarch_info info, gdbarch *arch)
+{
+ amd64_x32_init_abi (info, arch,
+ amd64_target_description (X86_XSTATE_SSE_MASK));
+}
+
/* Return the target description for a specified XSAVE feature mask. */
const struct target_desc *
amd64_target_description (uint64_t xcr0)
{
- switch (xcr0 & X86_XSTATE_ALL_MASK)
- {
- case X86_XSTATE_MPX_AVX512_MASK:
- case X86_XSTATE_AVX512_MASK:
- return tdesc_amd64_avx512;
- case X86_XSTATE_MPX_MASK:
- return tdesc_amd64_mpx;
- case X86_XSTATE_AVX_MASK:
- return tdesc_amd64_avx;
- default:
- return tdesc_amd64;
- }
-}
+ static target_desc *amd64_tdescs \
+ [2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {};
+ target_desc **tdesc;
+
+ tdesc = &amd64_tdescs[(xcr0 & X86_XSTATE_AVX) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_MPX) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_AVX512) ? 1 : 0]
+ [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0];
-/* Provide a prototype to silence -Wmissing-prototypes. */
-void _initialize_amd64_tdep (void);
+ if (*tdesc == NULL)
+ *tdesc = amd64_create_target_description (xcr0, false, false);
+
+ return *tdesc;
+}
void
_initialize_amd64_tdep (void)
{
- initialize_tdesc_amd64 ();
- initialize_tdesc_amd64_avx ();
- initialize_tdesc_amd64_mpx ();
- initialize_tdesc_amd64_avx512 ();
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_NONE,
+ amd64_none_init_abi);
+ gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x64_32, GDB_OSABI_NONE,
+ amd64_x32_none_init_abi);
- initialize_tdesc_x32 ();
- initialize_tdesc_x32_avx ();
- initialize_tdesc_x32_avx512 ();
+#if GDB_SELF_TEST
+ struct
+ {
+ const char *xml;
+ uint64_t mask;
+ } xml_masks[] = {
+ { "i386/amd64.xml", X86_XSTATE_SSE_MASK },
+ { "i386/amd64-avx.xml", X86_XSTATE_AVX_MASK },
+ { "i386/amd64-mpx.xml", X86_XSTATE_MPX_MASK },
+ { "i386/amd64-avx-mpx.xml", X86_XSTATE_AVX_MPX_MASK },
+ { "i386/amd64-avx-avx512.xml", X86_XSTATE_AVX_AVX512_MASK },
+ { "i386/amd64-avx-mpx-avx512-pku.xml",
+ X86_XSTATE_AVX_MPX_AVX512_PKU_MASK },
+ };
+
+ for (auto &a : xml_masks)
+ {
+ auto tdesc = amd64_target_description (a.mask);
+
+ selftests::record_xml_tdesc (a.xml, tdesc);
+ }
+#endif /* GDB_SELF_TEST */
}
\f
amd64_supply_fxsave (struct regcache *regcache, int regnum,
const void *fxsave)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
i387_supply_fxsave (regcache, regnum, fxsave);
if (fxsave
&& gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64)
{
- const gdb_byte *regs = fxsave;
+ const gdb_byte *regs = (const gdb_byte *) fxsave;
if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
regcache_raw_supply (regcache, I387_FISEG_REGNUM (tdep), regs + 12);
amd64_supply_xsave (struct regcache *regcache, int regnum,
const void *xsave)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
i387_supply_xsave (regcache, regnum, xsave);
if (xsave
&& gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64)
{
- const gdb_byte *regs = xsave;
+ const gdb_byte *regs = (const gdb_byte *) xsave;
if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
regcache_raw_supply (regcache, I387_FISEG_REGNUM (tdep),
amd64_collect_fxsave (const struct regcache *regcache, int regnum,
void *fxsave)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- gdb_byte *regs = fxsave;
+ gdb_byte *regs = (gdb_byte *) fxsave;
i387_collect_fxsave (regcache, regnum, fxsave);
amd64_collect_xsave (const struct regcache *regcache, int regnum,
void *xsave, int gcore)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- gdb_byte *regs = xsave;
+ gdb_byte *regs = (gdb_byte *) xsave;
i387_collect_xsave (regcache, regnum, xsave, gcore);