/* Target-dependent code for AMD64.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
- 2011 Free Software Foundation, Inc.
+ Copyright (C) 2001-2012 Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
#include "features/i386/amd64.c"
#include "features/i386/amd64-avx.c"
+#include "ax.h"
+#include "ax-gdb.h"
+
/* Note that the AMD64 architecture was previously known as x86-64.
The latter is (forever) engraved into the canonical system name as
returned by config.guess, and used as the name for the AMD64 port
return i386_pseudo_register_name (gdbarch, regnum);
}
-static enum register_status
-amd64_pseudo_register_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int regnum, gdb_byte *buf)
+static struct value *
+amd64_pseudo_register_read_value (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum)
{
gdb_byte raw_buf[MAX_REGISTER_SIZE];
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_LVAL (result_value) = lval_register;
+ VALUE_REGNUM (result_value) = regnum;
+ buf = value_contents_raw (result_value);
if (i386_byte_regnum_p (gdbarch, regnum))
{
raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf + 1, 1);
+ else
+ mark_value_bytes_unavailable (result_value, 0,
+ TYPE_LENGTH (value_type (result_value)));
}
else
{
status = regcache_raw_read (regcache, gpnum, raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf, 1);
+ else
+ mark_value_bytes_unavailable (result_value, 0,
+ TYPE_LENGTH (value_type (result_value)));
}
-
- return status;
}
else if (i386_dword_regnum_p (gdbarch, regnum))
{
status = regcache_raw_read (regcache, gpnum, raw_buf);
if (status == REG_VALID)
memcpy (buf, raw_buf, 4);
-
- return status;
+ else
+ mark_value_bytes_unavailable (result_value, 0,
+ TYPE_LENGTH (value_type (result_value)));
}
else
- return i386_pseudo_register_read (gdbarch, regcache, regnum, buf);
+ i386_pseudo_register_read_into_value (gdbarch, regcache, regnum,
+ result_value);
+
+ return result_value;
}
static void
if (class[0] == AMD64_MEMORY || class[1] == AMD64_MEMORY)
class[0] = class[1] = AMD64_MEMORY;
- /* Rule (b): If SSEUP is not preceeded by SSE, it is converted to
+ /* Rule (b): If SSEUP is not preceded by SSE, it is converted to
SSE. */
if (class[0] == AMD64_SSEUP)
class[0] = AMD64_SSE;
/* Pass "hidden" argument". */
if (struct_return)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* The "hidden" argument is passed throught the first argument
register. */
const int arg_regnum = tdep->call_dummy_integer_regs[0];
if (have_sib)
{
int base = SIB_BASE_FIELD (details->raw_insn[details->modrm_offset + 1]);
- int index = SIB_INDEX_FIELD (details->raw_insn[details->modrm_offset + 1]);
+ int idx = SIB_INDEX_FIELD (details->raw_insn[details->modrm_offset + 1]);
used_regs_mask |= 1 << base;
- used_regs_mask |= 1 << index;
+ used_regs_mask |= 1 << idx;
}
else
{
*to += len;
}
-void
+static void
amd64_relocate_instruction (struct gdbarch *gdbarch,
CORE_ADDR *to, CORE_ADDR oldloc)
{
return pc;
}
+/* Work around false termination of prologue - GCC PR debug/48827.
+
+ START_PC is the first instruction of a function, PC is its minimal already
+ determined advanced address. Function returns PC if it has nothing to do.
+
+ 84 c0 test %al,%al
+ 74 23 je after
+ <-- here is 0 lines advance - the false prologue end marker.
+ 0f 29 85 70 ff ff ff movaps %xmm0,-0x90(%rbp)
+ 0f 29 4d 80 movaps %xmm1,-0x80(%rbp)
+ 0f 29 55 90 movaps %xmm2,-0x70(%rbp)
+ 0f 29 5d a0 movaps %xmm3,-0x60(%rbp)
+ 0f 29 65 b0 movaps %xmm4,-0x50(%rbp)
+ 0f 29 6d c0 movaps %xmm5,-0x40(%rbp)
+ 0f 29 75 d0 movaps %xmm6,-0x30(%rbp)
+ 0f 29 7d e0 movaps %xmm7,-0x20(%rbp)
+ after: */
+
+static CORE_ADDR
+amd64_skip_xmm_prologue (CORE_ADDR pc, CORE_ADDR start_pc)
+{
+ struct symtab_and_line start_pc_sal, next_sal;
+ gdb_byte buf[4 + 8 * 7];
+ int offset, xmmreg;
+
+ if (pc == start_pc)
+ return pc;
+
+ start_pc_sal = find_pc_sect_line (start_pc, NULL, 0);
+ if (start_pc_sal.symtab == NULL
+ || producer_is_gcc_ge_4 (start_pc_sal.symtab->producer) < 6
+ || start_pc_sal.pc != start_pc || pc >= start_pc_sal.end)
+ return pc;
+
+ next_sal = find_pc_sect_line (start_pc_sal.end, NULL, 0);
+ if (next_sal.line != start_pc_sal.line)
+ return pc;
+
+ /* START_PC can be from overlayed memory, ignored here. */
+ if (target_read_memory (next_sal.pc - 4, buf, sizeof (buf)) != 0)
+ return pc;
+
+ /* test %al,%al */
+ if (buf[0] != 0x84 || buf[1] != 0xc0)
+ return pc;
+ /* je AFTER */
+ if (buf[2] != 0x74)
+ return pc;
+
+ offset = 4;
+ for (xmmreg = 0; xmmreg < 8; xmmreg++)
+ {
+ /* 0x0f 0x29 0b??000101 movaps %xmmreg?,-0x??(%rbp) */
+ if (buf[offset] != 0x0f || buf[offset + 1] != 0x29
+ || (buf[offset + 2] & 0x3f) != (xmmreg << 3 | 0x5))
+ return pc;
+
+ /* 0b01?????? */
+ if ((buf[offset + 2] & 0xc0) == 0x40)
+ {
+ /* 8-bit displacement. */
+ offset += 4;
+ }
+ /* 0b10?????? */
+ else if ((buf[offset + 2] & 0xc0) == 0x80)
+ {
+ /* 32-bit displacement. */
+ offset += 7;
+ }
+ else
+ return pc;
+ }
+
+ /* je AFTER */
+ if (offset - 4 != buf[3])
+ return pc;
+
+ return next_sal.end;
+}
+
/* Return PC of first real instruction. */
static CORE_ADDR
if (cache.frameless_p)
return start_pc;
- return pc;
+ return amd64_skip_xmm_prologue (pc, start_pc);
}
\f
default_frame_sniffer
};
\f
+/* Generate a bytecode expression to get the value of the saved PC. */
+
+static void
+amd64_gen_return_address (struct gdbarch *gdbarch,
+ struct agent_expr *ax, struct axs_value *value,
+ CORE_ADDR scope)
+{
+ /* The following sequence assumes the traditional use of the base
+ register. */
+ ax_reg (ax, AMD64_RBP_REGNUM);
+ ax_const_l (ax, 8);
+ ax_simple (ax, aop_add);
+ value->type = register_type (gdbarch, AMD64_RIP_REGNUM);
+ value->kind = axs_lvalue_memory;
+}
+\f
/* Signal trampolines. */
amd64_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
{
gdb_byte insn;
+ struct symtab *symtab;
+
+ symtab = find_pc_symtab (pc);
+ if (symtab && symtab->epilogue_unwind_valid)
+ return 0;
if (target_read_memory (pc, &insn, 1))
return 0; /* Can't read memory at pc. */
/* Avoid wiring in the MMX registers for now. */
tdep->num_mmx_regs = 0;
- set_gdbarch_pseudo_register_read (gdbarch,
- amd64_pseudo_register_read);
+ set_gdbarch_pseudo_register_read_value (gdbarch,
+ amd64_pseudo_register_read_value);
set_gdbarch_pseudo_register_write (gdbarch,
amd64_pseudo_register_write);
set_gdbarch_get_longjmp_target (gdbarch, amd64_get_longjmp_target);
set_gdbarch_relocate_instruction (gdbarch, amd64_relocate_instruction);
+
+ set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
}
}
-/* Similar to amd64_collect_fxsave, but but use XSAVE extended state. */
+/* Similar to amd64_collect_fxsave, but use XSAVE extended state. */
void
amd64_collect_xsave (const struct regcache *regcache, int regnum,