| Index: gdb/amd64-tdep.c
|
| diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
|
| index 8ae1142c47e35bde014af73938adc83aa6c12595..19968fc8d18817e83c8d544e2f854d65debfef85 100644
|
| --- a/gdb/amd64-tdep.c
|
| +++ b/gdb/amd64-tdep.c
|
| @@ -1,6 +1,6 @@
|
| /* Target-dependent code for AMD64.
|
|
|
| - Copyright (C) 2001-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2001-2013 Free Software Foundation, Inc.
|
|
|
| Contributed by Jiri Smid, SuSE Labs.
|
|
|
| @@ -43,6 +43,7 @@
|
|
|
| #include "features/i386/amd64.c"
|
| #include "features/i386/amd64-avx.c"
|
| +#include "features/i386/amd64-mpx.c"
|
| #include "features/i386/x32.c"
|
| #include "features/i386/x32-avx.c"
|
|
|
| @@ -92,15 +93,9 @@ static const char *amd64_ymmh_names[] =
|
| "ymm12h", "ymm13h", "ymm14h", "ymm15h"
|
| };
|
|
|
| -/* The registers used to pass integer arguments during a function call. */
|
| -static int amd64_dummy_call_integer_regs[] =
|
| +static const char *amd64_mpx_names[] =
|
| {
|
| - AMD64_RDI_REGNUM, /* %rdi */
|
| - AMD64_RSI_REGNUM, /* %rsi */
|
| - AMD64_RDX_REGNUM, /* %rdx */
|
| - AMD64_RCX_REGNUM, /* %rcx */
|
| - 8, /* %r8 */
|
| - 9 /* %r9 */
|
| + "bnd0raw", "bnd1raw", "bnd2raw", "bnd3raw", "bndcfgu", "bndstatus"
|
| };
|
|
|
| /* DWARF Register Number Mapping as defined in the System V psABI,
|
| @@ -120,7 +115,14 @@ static int amd64_dwarf_regmap[] =
|
| AMD64_RSP_REGNUM,
|
|
|
| /* Extended Integer Registers 8 - 15. */
|
| - 8, 9, 10, 11, 12, 13, 14, 15,
|
| + AMD64_R8_REGNUM, /* %r8 */
|
| + AMD64_R9_REGNUM, /* %r9 */
|
| + AMD64_R10_REGNUM, /* %r10 */
|
| + AMD64_R11_REGNUM, /* %r11 */
|
| + AMD64_R12_REGNUM, /* %r12 */
|
| + AMD64_R13_REGNUM, /* %r13 */
|
| + AMD64_R14_REGNUM, /* %r14 */
|
| + AMD64_R15_REGNUM, /* %r15 */
|
|
|
| /* Return Address RA. Mapped to RIP. */
|
| AMD64_RIP_REGNUM,
|
| @@ -391,6 +393,20 @@ amd64_pseudo_register_write (struct gdbarch *gdbarch,
|
|
|
|
|
|
|
| +/* Register classes as defined in the psABI. */
|
| +
|
| +enum amd64_reg_class
|
| +{
|
| + AMD64_INTEGER,
|
| + AMD64_SSE,
|
| + AMD64_SSEUP,
|
| + AMD64_X87,
|
| + AMD64_X87UP,
|
| + AMD64_COMPLEX_X87,
|
| + AMD64_NO_CLASS,
|
| + AMD64_MEMORY
|
| +};
|
| +
|
| /* Return the union class of CLASS1 and CLASS2. See the psABI for
|
| details. */
|
|
|
| @@ -427,6 +443,8 @@ amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
|
| return AMD64_SSE;
|
| }
|
|
|
| +static void amd64_classify (struct type *type, enum amd64_reg_class class[2]);
|
| +
|
| /* Return non-zero if TYPE is a non-POD structure or union type. */
|
|
|
| static int
|
| @@ -446,12 +464,10 @@ amd64_non_pod_p (struct type *type)
|
| static void
|
| amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
|
| {
|
| - int len = TYPE_LENGTH (type);
|
| -
|
| /* 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
|
| unaligned fields, it has class memory. */
|
| - if (len > 16 || amd64_non_pod_p (type))
|
| + if (TYPE_LENGTH (type) > 16 || amd64_non_pod_p (type))
|
| {
|
| class[0] = class[1] = AMD64_MEMORY;
|
| return;
|
| @@ -471,7 +487,7 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
|
|
|
| /* All fields in an array have the same type. */
|
| amd64_classify (subtype, class);
|
| - if (len > 8 && class[1] == AMD64_NO_CLASS)
|
| + if (TYPE_LENGTH (type) > 8 && class[1] == AMD64_NO_CLASS)
|
| class[1] = class[0];
|
| }
|
| else
|
| @@ -548,7 +564,7 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
|
|
|
| /* Classify TYPE, and store the result in CLASS. */
|
|
|
| -void
|
| +static void
|
| amd64_classify (struct type *type, enum amd64_reg_class class[2])
|
| {
|
| enum type_code code = TYPE_CODE (type);
|
| @@ -588,6 +604,23 @@ amd64_classify (struct type *type, enum amd64_reg_class class[2])
|
| /* Class X87 and X87UP. */
|
| class[0] = AMD64_X87, class[1] = AMD64_X87UP;
|
|
|
| + /* Arguments of complex T where T is one of the types float or
|
| + double get treated as if they are implemented as:
|
| +
|
| + struct complexT {
|
| + T real;
|
| + T imag;
|
| + }; */
|
| + else if (code == TYPE_CODE_COMPLEX && len == 8)
|
| + class[0] = AMD64_SSE;
|
| + else if (code == TYPE_CODE_COMPLEX && len == 16)
|
| + class[0] = class[1] = AMD64_SSE;
|
| +
|
| + /* A variable of type complex long double is classified as type
|
| + COMPLEX_X87. */
|
| + else if (code == TYPE_CODE_COMPLEX && len == 32)
|
| + class[0] = AMD64_COMPLEX_X87;
|
| +
|
| /* Aggregates. */
|
| else if (code == TYPE_CODE_ARRAY || code == TYPE_CODE_STRUCT
|
| || code == TYPE_CODE_UNION)
|
| @@ -599,7 +632,6 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
|
| struct type *type, struct regcache *regcache,
|
| gdb_byte *readbuf, const gdb_byte *writebuf)
|
| {
|
| - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
| enum amd64_reg_class class[2];
|
| int len = TYPE_LENGTH (type);
|
| static int integer_regnum[] = { AMD64_RAX_REGNUM, AMD64_RDX_REGNUM };
|
| @@ -609,10 +641,9 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
|
| int i;
|
|
|
| gdb_assert (!(readbuf && writebuf));
|
| - gdb_assert (tdep->classify);
|
|
|
| /* 1. Classify the return type with the classification algorithm. */
|
| - tdep->classify (type, class);
|
| + 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
|
| @@ -638,6 +669,30 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
|
| return RETURN_VALUE_ABI_RETURNS_ADDRESS;
|
| }
|
|
|
| + /* 8. If the class is COMPLEX_X87, the real part of the value is
|
| + returned in %st0 and the imaginary part in %st1. */
|
| + if (class[0] == AMD64_COMPLEX_X87)
|
| + {
|
| + if (readbuf)
|
| + {
|
| + regcache_raw_read (regcache, AMD64_ST0_REGNUM, readbuf);
|
| + regcache_raw_read (regcache, AMD64_ST1_REGNUM, readbuf + 16);
|
| + }
|
| +
|
| + if (writebuf)
|
| + {
|
| + i387_return_value (gdbarch, regcache);
|
| + regcache_raw_write (regcache, AMD64_ST0_REGNUM, writebuf);
|
| + regcache_raw_write (regcache, AMD64_ST1_REGNUM, writebuf + 16);
|
| +
|
| + /* Fix up the tag word such that both %st(0) and %st(1) are
|
| + marked as valid. */
|
| + regcache_raw_write_unsigned (regcache, AMD64_FTAG_REGNUM, 0xfff);
|
| + }
|
| +
|
| + return RETURN_VALUE_REGISTER_CONVENTION;
|
| + }
|
| +
|
| gdb_assert (class[1] != AMD64_MEMORY);
|
| gdb_assert (len <= 16);
|
|
|
| @@ -710,11 +765,15 @@ static CORE_ADDR
|
| amd64_push_arguments (struct regcache *regcache, int nargs,
|
| struct value **args, CORE_ADDR sp, int struct_return)
|
| {
|
| - struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
| - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
| - int *integer_regs = tdep->call_dummy_integer_regs;
|
| - int num_integer_regs = tdep->call_dummy_num_integer_regs;
|
| -
|
| + static int integer_regnum[] =
|
| + {
|
| + AMD64_RDI_REGNUM, /* %rdi */
|
| + AMD64_RSI_REGNUM, /* %rsi */
|
| + AMD64_RDX_REGNUM, /* %rdx */
|
| + AMD64_RCX_REGNUM, /* %rcx */
|
| + AMD64_R8_REGNUM, /* %r8 */
|
| + AMD64_R9_REGNUM /* %r9 */
|
| + };
|
| static int sse_regnum[] =
|
| {
|
| /* %xmm0 ... %xmm7 */
|
| @@ -724,11 +783,6 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
|
| AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
|
| };
|
| struct value **stack_args = alloca (nargs * sizeof (struct value *));
|
| - /* An array that mirrors the stack_args array. For all arguments
|
| - that are passed by MEMORY, if that argument's address also needs
|
| - to be stored in a register, the ARG_ADDR_REGNO array will contain
|
| - that register number (or a negative value otherwise). */
|
| - int *arg_addr_regno = alloca (nargs * sizeof (int));
|
| int num_stack_args = 0;
|
| int num_elements = 0;
|
| int element = 0;
|
| @@ -736,8 +790,6 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
|
| int sse_reg = 0;
|
| int i;
|
|
|
| - gdb_assert (tdep->classify);
|
| -
|
| /* Reserve a register for the "hidden" argument. */
|
| if (struct_return)
|
| integer_reg++;
|
| @@ -752,7 +804,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
|
| int j;
|
|
|
| /* Classify argument. */
|
| - tdep->classify (type, class);
|
| + amd64_classify (type, class);
|
|
|
| /* Calculate the number of integer and SSE registers needed for
|
| this argument. */
|
| @@ -766,25 +818,13 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
|
|
|
| /* Check whether enough registers are available, and if the
|
| argument should be passed in registers at all. */
|
| - if (integer_reg + needed_integer_regs > num_integer_regs
|
| + if (integer_reg + needed_integer_regs > ARRAY_SIZE (integer_regnum)
|
| || sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum)
|
| || (needed_integer_regs == 0 && needed_sse_regs == 0))
|
| {
|
| /* The argument will be passed on the stack. */
|
| num_elements += ((len + 7) / 8);
|
| - stack_args[num_stack_args] = args[i];
|
| - /* If this is an AMD64_MEMORY argument whose address must also
|
| - be passed in one of the integer registers, reserve that
|
| - register and associate this value to that register so that
|
| - we can store the argument address as soon as we know it. */
|
| - if (class[0] == AMD64_MEMORY
|
| - && tdep->memory_args_by_pointer
|
| - && integer_reg < tdep->call_dummy_num_integer_regs)
|
| - arg_addr_regno[num_stack_args] =
|
| - tdep->call_dummy_integer_regs[integer_reg++];
|
| - else
|
| - arg_addr_regno[num_stack_args] = -1;
|
| - num_stack_args++;
|
| + stack_args[num_stack_args++] = args[i];
|
| }
|
| else
|
| {
|
| @@ -802,7 +842,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
|
| switch (class[j])
|
| {
|
| case AMD64_INTEGER:
|
| - regnum = integer_regs[integer_reg++];
|
| + regnum = integer_regnum[integer_reg++];
|
| break;
|
|
|
| case AMD64_SSE:
|
| @@ -840,19 +880,8 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
|
| struct type *type = value_type (stack_args[i]);
|
| const gdb_byte *valbuf = value_contents (stack_args[i]);
|
| int len = TYPE_LENGTH (type);
|
| - CORE_ADDR arg_addr = sp + element * 8;
|
| -
|
| - write_memory (arg_addr, valbuf, len);
|
| - if (arg_addr_regno[i] >= 0)
|
| - {
|
| - /* We also need to store the address of that argument in
|
| - the given register. */
|
| - gdb_byte buf[8];
|
| - enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
| -
|
| - store_unsigned_integer (buf, 8, byte_order, arg_addr);
|
| - regcache_cooked_write (regcache, arg_addr_regno[i], buf);
|
| - }
|
| +
|
| + write_memory (sp + element * 8, valbuf, len);
|
| element += ((len + 7) / 8);
|
| }
|
|
|
| @@ -871,7 +900,6 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
| int struct_return, CORE_ADDR struct_addr)
|
| {
|
| enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
| - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
| gdb_byte buf[8];
|
|
|
| /* Pass arguments. */
|
| @@ -880,19 +908,10 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
|
| /* Pass "hidden" argument". */
|
| if (struct_return)
|
| {
|
| - /* The "hidden" argument is passed throught the first argument
|
| - register. */
|
| - const int arg_regnum = tdep->call_dummy_integer_regs[0];
|
| -
|
| store_unsigned_integer (buf, 8, byte_order, struct_addr);
|
| - regcache_cooked_write (regcache, arg_regnum, buf);
|
| + regcache_cooked_write (regcache, AMD64_RDI_REGNUM, buf);
|
| }
|
|
|
| - /* Reserve some memory on the stack for the integer-parameter registers,
|
| - if required by the ABI. */
|
| - if (tdep->integer_param_regs_saved_in_caller_frame)
|
| - sp -= tdep->call_dummy_num_integer_regs * 8;
|
| -
|
| /* Store return address. */
|
| sp -= 8;
|
| store_unsigned_integer (buf, 8, byte_order, bp_addr);
|
| @@ -1593,7 +1612,7 @@ amd64_relocate_instruction (struct gdbarch *gdbarch,
|
| /* Where "ret" in the original code will return to. */
|
| ret_addr = oldloc + insn_length;
|
| push_buf[0] = 0x68; /* pushq $... */
|
| - memcpy (&push_buf[1], &ret_addr, 4);
|
| + store_unsigned_integer (&push_buf[1], 4, byte_order, ret_addr);
|
| /* Push the push. */
|
| append_insns (to, 5, push_buf);
|
|
|
| @@ -1742,7 +1761,7 @@ amd64_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
|
| int reg, r;
|
| int offset, offset_and;
|
|
|
| - if (target_read_memory (pc, buf, sizeof buf))
|
| + if (target_read_code (pc, buf, sizeof buf))
|
| return pc;
|
|
|
| /* Check caller-saved saved register. The first instruction has
|
| @@ -2085,7 +2104,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
|
| else
|
| pc = amd64_analyze_stack_align (pc, current_pc, cache);
|
|
|
| - op = read_memory_unsigned_integer (pc, 1, byte_order);
|
| + op = read_code_unsigned_integer (pc, 1, byte_order);
|
|
|
| if (op == 0x55) /* pushq %rbp */
|
| {
|
| @@ -2098,7 +2117,7 @@ amd64_analyze_prologue (struct gdbarch *gdbarch,
|
| if (current_pc <= pc + 1)
|
| return current_pc;
|
|
|
| - read_memory (pc + 1, buf, 3);
|
| + read_code (pc + 1, buf, 3);
|
|
|
| /* Check for `movq %rsp, %rbp'. */
|
| if (memcmp (buf, mov_rsp_rbp_1, 3) == 0
|
| @@ -2166,7 +2185,7 @@ amd64_skip_xmm_prologue (CORE_ADDR pc, CORE_ADDR start_pc)
|
| return pc;
|
|
|
| /* START_PC can be from overlayed memory, ignored here. */
|
| - if (target_read_memory (next_sal.pc - 4, buf, sizeof (buf)) != 0)
|
| + if (target_read_code (next_sal.pc - 4, buf, sizeof (buf)) != 0)
|
| return pc;
|
|
|
| /* test %al,%al */
|
| @@ -2214,6 +2233,22 @@ amd64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
|
| {
|
| struct amd64_frame_cache cache;
|
| CORE_ADDR pc;
|
| + CORE_ADDR func_addr;
|
| +
|
| + if (find_pc_partial_function (start_pc, NULL, &func_addr, NULL))
|
| + {
|
| + CORE_ADDR post_prologue_pc
|
| + = skip_prologue_using_sal (gdbarch, func_addr);
|
| + struct symtab *s = find_pc_symtab (func_addr);
|
| +
|
| + /* Clang always emits a line note before the prologue and another
|
| + one after. We trust clang to emit usable line notes. */
|
| + if (post_prologue_pc
|
| + && (s != NULL
|
| + && s->producer != NULL
|
| + && strncmp (s->producer, "clang ", sizeof ("clang ") - 1) == 0))
|
| + return max (start_pc, post_prologue_pc);
|
| + }
|
|
|
| amd64_init_frame_cache (&cache);
|
| pc = amd64_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffLL,
|
| @@ -2816,6 +2851,13 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
| tdep->ymm0h_regnum = AMD64_YMM0H_REGNUM;
|
| }
|
|
|
| + if (tdesc_find_feature (tdesc, "org.gnu.gdb.i386.mpx") != NULL)
|
| + {
|
| + tdep->mpx_register_names = amd64_mpx_names;
|
| + tdep->bndcfgu_regnum = AMD64_BNDCFGU_REGNUM;
|
| + tdep->bnd0r_regnum = AMD64_BND0R_REGNUM;
|
| + }
|
| +
|
| tdep->num_byte_regs = 20;
|
| tdep->num_word_regs = 16;
|
| tdep->num_dword_regs = 16;
|
| @@ -2867,10 +2909,6 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
| set_gdbarch_push_dummy_call (gdbarch, amd64_push_dummy_call);
|
| set_gdbarch_frame_align (gdbarch, amd64_frame_align);
|
| set_gdbarch_frame_red_zone_size (gdbarch, 128);
|
| - tdep->call_dummy_num_integer_regs =
|
| - ARRAY_SIZE (amd64_dummy_call_integer_regs);
|
| - tdep->call_dummy_integer_regs = amd64_dummy_call_integer_regs;
|
| - tdep->classify = amd64_classify;
|
|
|
| set_gdbarch_convert_register_p (gdbarch, i387_convert_register_p);
|
| set_gdbarch_register_to_value (gdbarch, i387_register_to_value);
|
| @@ -2961,6 +2999,7 @@ _initialize_amd64_tdep (void)
|
| {
|
| initialize_tdesc_amd64 ();
|
| initialize_tdesc_amd64_avx ();
|
| + initialize_tdesc_amd64_mpx ();
|
| initialize_tdesc_x32 ();
|
| initialize_tdesc_x32_avx ();
|
| }
|
|
|