/* Target-dependent code for AMD64.
- Copyright (C) 2001-2018 Free Software Foundation, Inc.
+ Copyright (C) 2001-2020 Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
#include "disasm.h"
#include "amd64-tdep.h"
#include "i387-tdep.h"
-#include "x86-xstate.h"
+#include "gdbsupport/x86-xstate.h"
#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 "gdbsupport/byte-vector.h"
#include "osabi.h"
#include "x86-tdep.h"
readable_regcache *regcache,
int regnum)
{
- 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;
- gdb_byte *buf;
- result_value = allocate_value (register_type (gdbarch, regnum));
+ value *result_value = allocate_value (register_type (gdbarch, regnum));
VALUE_LVAL (result_value) = lval_register;
VALUE_REGNUM (result_value) = regnum;
- buf = value_contents_raw (result_value);
+ gdb_byte *buf = value_contents_raw (result_value);
if (i386_byte_regnum_p (gdbarch, regnum))
{
/* Extract (always little endian). */
if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
{
+ gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
+ gdb_byte raw_buf[register_size (gdbarch, gpnum)];
+
/* Special handling for AH, BH, CH, DH. */
- status = regcache->raw_read (gpnum - AMD64_NUM_LOWER_BYTE_REGS,
- raw_buf);
+ register_status status = regcache->raw_read (gpnum, raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf + 1, 1);
else
}
else
{
- status = regcache->raw_read (gpnum, raw_buf);
+ gdb_byte raw_buf[register_size (gdbarch, gpnum)];
+ register_status status = regcache->raw_read (gpnum, raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf, 1);
else
else if (i386_dword_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->eax_regnum;
+ gdb_byte raw_buf[register_size (gdbarch, gpnum)];
/* Extract (always little endian). */
- status = regcache->raw_read (gpnum, raw_buf);
+ register_status 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 = (gdb_byte *) alloca (register_size (gdbarch, regnum));
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (i386_byte_regnum_p (gdbarch, regnum))
if (gpnum >= AMD64_NUM_LOWER_BYTE_REGS)
{
+ gpnum -= AMD64_NUM_LOWER_BYTE_REGS;
+ gdb_byte raw_buf[register_size (gdbarch, gpnum)];
+
/* Read ... AH, BH, CH, DH. */
- regcache->raw_read (gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf);
+ regcache->raw_read (gpnum, raw_buf);
/* ... Modify ... (always little endian). */
memcpy (raw_buf + 1, buf, 1);
/* ... Write. */
- regcache->raw_write (gpnum - AMD64_NUM_LOWER_BYTE_REGS, raw_buf);
+ regcache->raw_write (gpnum, raw_buf);
}
else
{
+ gdb_byte raw_buf[register_size (gdbarch, gpnum)];
+
/* Read ... */
regcache->raw_read (gpnum, raw_buf);
/* ... Modify ... (always little endian). */
else if (i386_dword_regnum_p (gdbarch, regnum))
{
int gpnum = regnum - tdep->eax_regnum;
+ gdb_byte raw_buf[register_size (gdbarch, gpnum)];
/* Read ... */
regcache->raw_read (gpnum, raw_buf);
static void amd64_classify (struct type *type, enum amd64_reg_class theclass[2]);
-/* Return non-zero if TYPE is a non-POD structure or union type. */
+/* Return true if TYPE is a structure or union with unaligned fields. */
-static int
-amd64_non_pod_p (struct type *type)
+static bool
+amd64_has_unaligned_fields (struct type *type)
{
- /* ??? A class with a base class certainly isn't POD, but does this
- catch all non-POD structure types? */
- if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_N_BASECLASSES (type) > 0)
- return 1;
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ for (int i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int bitpos = TYPE_FIELD_BITPOS (type, i);
+ int align = type_align(subtype);
+
+ /* Ignore static fields, empty fields (for example nested
+ empty structures), and bitfields (these are handled by
+ the caller). */
+ if (field_is_static (&TYPE_FIELD (type, i))
+ || (TYPE_FIELD_BITSIZE (type, i) == 0
+ && TYPE_LENGTH (subtype) == 0)
+ || TYPE_FIELD_PACKED (type, i))
+ continue;
- return 0;
+ if (bitpos % 8 != 0)
+ return true;
+
+ int bytepos = bitpos / 8;
+ if (bytepos % align != 0)
+ return true;
+
+ if (amd64_has_unaligned_fields (subtype))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Classify field I of TYPE starting at BITOFFSET according to the rules for
+ structures and union types, and store the result in THECLASS. */
+
+static void
+amd64_classify_aggregate_field (struct type *type, int i,
+ enum amd64_reg_class theclass[2],
+ unsigned int bitoffset)
+{
+ struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
+ int bitpos = bitoffset + TYPE_FIELD_BITPOS (type, i);
+ int pos = bitpos / 64;
+ enum amd64_reg_class subclass[2];
+ int bitsize = TYPE_FIELD_BITSIZE (type, i);
+ int endpos;
+
+ if (bitsize == 0)
+ bitsize = TYPE_LENGTH (subtype) * 8;
+ endpos = (bitpos + bitsize - 1) / 64;
+
+ /* Ignore static fields, or empty fields, for example nested
+ empty structures.*/
+ if (field_is_static (&TYPE_FIELD (type, i)) || bitsize == 0)
+ return;
+
+ if (TYPE_CODE (subtype) == TYPE_CODE_STRUCT
+ || TYPE_CODE (subtype) == TYPE_CODE_UNION)
+ {
+ /* Each field of an object is classified recursively. */
+ int j;
+ for (j = 0; j < TYPE_NFIELDS (subtype); j++)
+ amd64_classify_aggregate_field (subtype, j, theclass, bitpos);
+ return;
+ }
+
+ gdb_assert (pos == 0 || pos == 1);
+
+ amd64_classify (subtype, subclass);
+ theclass[pos] = amd64_merge_classes (theclass[pos], subclass[0]);
+ if (bitsize <= 64 && pos == 0 && endpos == 1)
+ /* This is a bit of an odd case: We have a field that would
+ normally fit in one of the two eightbytes, except that
+ it is placed in a way that this field straddles them.
+ This has been seen with a structure containing an array.
+
+ The ABI is a bit unclear in this case, but we assume that
+ this field's class (stored in subclass[0]) must also be merged
+ into class[1]. In other words, our field has a piece stored
+ in the second eight-byte, and thus its class applies to
+ the second eight-byte as well.
+
+ In the case where the field length exceeds 8 bytes,
+ it should not be necessary to merge the field class
+ into class[1]. As LEN > 8, subclass[1] is necessarily
+ different from AMD64_NO_CLASS. If subclass[1] is equal
+ to subclass[0], then the normal class[1]/subclass[1]
+ merging will take care of everything. For subclass[1]
+ to be different from subclass[0], I can only see the case
+ where we have a SSE/SSEUP or X87/X87UP pair, which both
+ use up all 16 bytes of the aggregate, and are already
+ handled just fine (because each portion sits on its own
+ 8-byte). */
+ theclass[1] = amd64_merge_classes (theclass[1], subclass[0]);
+ if (pos == 0)
+ theclass[1] = amd64_merge_classes (theclass[1], subclass[1]);
}
/* Classify TYPE according to the rules for aggregate (structures and
static void
amd64_classify_aggregate (struct type *type, enum amd64_reg_class theclass[2])
{
- /* 1. If the size of an object is larger than two eightbytes, or in
- C++, is a non-POD structure or union type, or contains
+ /* 1. If the size of an object is larger than two eightbytes, or it has
unaligned fields, it has class memory. */
- if (TYPE_LENGTH (type) > 16 || amd64_non_pod_p (type))
+ if (TYPE_LENGTH (type) > 16 || amd64_has_unaligned_fields (type))
{
theclass[0] = theclass[1] = AMD64_MEMORY;
return;
|| TYPE_CODE (type) == TYPE_CODE_UNION);
for (i = 0; i < TYPE_NFIELDS (type); i++)
- {
- struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
- int pos = TYPE_FIELD_BITPOS (type, i) / 64;
- enum amd64_reg_class subclass[2];
- int bitsize = TYPE_FIELD_BITSIZE (type, i);
- int endpos;
-
- if (bitsize == 0)
- bitsize = TYPE_LENGTH (subtype) * 8;
- endpos = (TYPE_FIELD_BITPOS (type, i) + bitsize - 1) / 64;
-
- /* 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);
-
- amd64_classify (subtype, subclass);
- theclass[pos] = amd64_merge_classes (theclass[pos], subclass[0]);
- if (bitsize <= 64 && pos == 0 && endpos == 1)
- /* This is a bit of an odd case: We have a field that would
- normally fit in one of the two eightbytes, except that
- it is placed in a way that this field straddles them.
- This has been seen with a structure containing an array.
-
- The ABI is a bit unclear in this case, but we assume that
- this field's class (stored in subclass[0]) must also be merged
- into class[1]. In other words, our field has a piece stored
- in the second eight-byte, and thus its class applies to
- the second eight-byte as well.
-
- In the case where the field length exceeds 8 bytes,
- it should not be necessary to merge the field class
- into class[1]. As LEN > 8, subclass[1] is necessarily
- different from AMD64_NO_CLASS. If subclass[1] is equal
- to subclass[0], then the normal class[1]/subclass[1]
- merging will take care of everything. For subclass[1]
- to be different from subclass[0], I can only see the case
- where we have a SSE/SSEUP or X87/X87UP pair, which both
- use up all 16 bytes of the aggregate, and are already
- handled just fine (because each portion sits on its own
- 8-byte). */
- theclass[1] = amd64_merge_classes (theclass[1], subclass[0]);
- if (pos == 0)
- theclass[1] = amd64_merge_classes (theclass[1], subclass[1]);
- }
+ amd64_classify_aggregate_field (type, i, theclass, 0);
}
/* 4. Then a post merger cleanup is done: */
\f
static CORE_ADDR
-amd64_push_arguments (struct regcache *regcache, int nargs,
- struct value **args, CORE_ADDR sp, int struct_return)
+amd64_push_arguments (struct regcache *regcache, int nargs, struct value **args,
+ CORE_ADDR sp, function_call_return_method return_method)
{
static int integer_regnum[] =
{
int i;
/* Reserve a register for the "hidden" argument. */
- if (struct_return)
+if (return_method == return_method_struct)
integer_reg++;
for (i = 0; i < nargs; i++)
offset = 8;
break;
+ case AMD64_NO_CLASS:
+ continue;
+
default:
gdb_assert (!"Unexpected register class.");
}
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)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
gdb_byte buf[8];
i387_reset_bnd_regs (gdbarch, regcache);
/* Pass arguments. */
- sp = amd64_push_arguments (regcache, nargs, args, sp, struct_return);
+ sp = amd64_push_arguments (regcache, nargs, args, sp, return_method);
/* Pass "hidden" argument". */
- if (struct_return)
+ if (return_method == return_method_struct)
{
store_unsigned_integer (buf, 8, byte_order, struct_addr);
regcache->cooked_write (AMD64_RDI_REGNUM, buf);
cache = amd64_alloc_frame_cache ();
*this_cache = cache;
- TRY
+ try
{
amd64_frame_cache_1 (this_frame, cache);
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
return cache;
}
cache = amd64_alloc_frame_cache ();
- TRY
+ try
{
get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 8, byte_order) - 8;
cache->base_p = 1;
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
*this_cache = cache;
return cache;
cache = amd64_alloc_frame_cache ();
*this_cache = cache;
- TRY
+ try
{
/* Cache base will be %esp plus cache->sp_offset (-8). */
get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
cache->base_p = 1;
}
- CATCH (ex, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &ex)
{
if (ex.error != NOT_AVAILABLE_ERROR)
- throw_exception (ex);
+ throw;
}
- END_CATCH
return cache;
}
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");
+ tdep->fsbase_regnum = AMD64_FSBASE_REGNUM;
}
if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.pkeys") != NULL)
static void
amd64_none_init_abi (gdbarch_info info, gdbarch *arch)
{
- amd64_init_abi (info, arch, amd64_target_description (X86_XSTATE_SSE_MASK));
+ amd64_init_abi (info, arch, amd64_target_description (X86_XSTATE_SSE_MASK,
+ true));
}
static struct type *
amd64_x32_none_init_abi (gdbarch_info info, gdbarch *arch)
{
amd64_x32_init_abi (info, arch,
- amd64_target_description (X86_XSTATE_SSE_MASK));
+ amd64_target_description (X86_XSTATE_SSE_MASK, true));
}
/* Return the target description for a specified XSAVE feature mask. */
const struct target_desc *
-amd64_target_description (uint64_t xcr0)
+amd64_target_description (uint64_t xcr0, bool segments)
{
static target_desc *amd64_tdescs \
- [2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/] = {};
+ [2/*AVX*/][2/*MPX*/][2/*AVX512*/][2/*PKRU*/][2/*segments*/] = {};
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];
+ [(xcr0 & X86_XSTATE_PKRU) ? 1 : 0]
+ [segments ? 1 : 0];
if (*tdesc == NULL)
- *tdesc = amd64_create_target_description (xcr0, false, false);
+ *tdesc = amd64_create_target_description (xcr0, false, false,
+ segments);
return *tdesc;
}
amd64_none_init_abi);
gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x64_32, GDB_OSABI_NONE,
amd64_x32_none_init_abi);
-
-#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
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);
+ regcache->raw_supply (I387_FISEG_REGNUM (tdep), regs + 12);
if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep))
- regcache_raw_supply (regcache, I387_FOSEG_REGNUM (tdep), regs + 20);
+ regcache->raw_supply (I387_FOSEG_REGNUM (tdep), regs + 20);
}
}
&& gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64)
{
const gdb_byte *regs = (const gdb_byte *) xsave;
- static const gdb_byte zero[I386_MAX_REGISTER_SIZE] = { 0 };
ULONGEST clear_bv;
clear_bv = i387_xsave_get_clear_bv (gdbarch, xsave);
if (!(clear_bv & X86_XSTATE_X87))
{
if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
- regcache_raw_supply (regcache, I387_FISEG_REGNUM (tdep),
- regs + 12);
+ regcache->raw_supply (I387_FISEG_REGNUM (tdep), regs + 12);
if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep))
- regcache_raw_supply (regcache, I387_FOSEG_REGNUM (tdep),
- regs + 20);
+ regcache->raw_supply (I387_FOSEG_REGNUM (tdep), regs + 20);
}
}
}
if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64)
{
if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
- regcache_raw_collect (regcache, I387_FISEG_REGNUM (tdep), regs + 12);
+ regcache->raw_collect (I387_FISEG_REGNUM (tdep), regs + 12);
if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep))
- regcache_raw_collect (regcache, I387_FOSEG_REGNUM (tdep), regs + 20);
+ regcache->raw_collect (I387_FOSEG_REGNUM (tdep), regs + 20);
}
}
if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64)
{
if (regnum == -1 || regnum == I387_FISEG_REGNUM (tdep))
- regcache_raw_collect (regcache, I387_FISEG_REGNUM (tdep),
+ regcache->raw_collect (I387_FISEG_REGNUM (tdep),
regs + 12);
if (regnum == -1 || regnum == I387_FOSEG_REGNUM (tdep))
- regcache_raw_collect (regcache, I387_FOSEG_REGNUM (tdep),
+ regcache->raw_collect (I387_FOSEG_REGNUM (tdep),
regs + 20);
}
}