/* 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
/* 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;
}
-/* Return PC of first real instruction. */
+/* 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_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
+amd64_skip_xmm_prologue (CORE_ADDR pc, CORE_ADDR start_pc)
{
- struct amd64_frame_cache cache;
- CORE_ADDR pc;
struct symtab_and_line start_pc_sal, next_sal;
gdb_byte buf[4 + 8 * 7];
int offset, xmmreg;
- amd64_init_frame_cache (&cache);
- pc = amd64_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffLL,
- &cache);
- if (cache.frameless_p)
- return start_pc;
-
- /* GCC PR debug/48827 produced false prologue end:
- 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: */
-
if (pc == start_pc)
return pc;
start_pc_sal = find_pc_sect_line (start_pc, NULL, 0);
if (start_pc_sal.symtab == NULL
- || !start_pc_sal.symtab->amd64_prologue_line_bug
+ || producer_is_gcc_ge_4 (start_pc_sal.symtab->producer) < 6
|| start_pc_sal.pc != start_pc || pc >= start_pc_sal.end)
return pc;
offset = 4;
for (xmmreg = 0; xmmreg < 8; xmmreg++)
{
- /* movaps %xmmreg?,-0x??(%rbp) */
+ /* 0x0f 0x29 0b??000101 movaps %xmmreg?,-0x??(%rbp) */
if (buf[offset] != 0x0f || buf[offset + 1] != 0x29
- || (buf[offset + 2] & 0b00111111) != (xmmreg << 3 | 0b101))
+ || (buf[offset + 2] & 0x3f) != (xmmreg << 3 | 0x5))
return pc;
- if ((buf[offset + 2] & 0b11000000) == 0b01000000)
+ /* 0b01?????? */
+ if ((buf[offset + 2] & 0xc0) == 0x40)
{
/* 8-bit displacement. */
offset += 4;
}
- else if ((buf[offset + 2] & 0b11000000) == 0b10000000)
+ /* 0b10?????? */
+ else if ((buf[offset + 2] & 0xc0) == 0x80)
{
/* 32-bit displacement. */
offset += 7;
return next_sal.end;
}
+
+/* Return PC of first real instruction. */
+
+static CORE_ADDR
+amd64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
+{
+ struct amd64_frame_cache cache;
+ CORE_ADDR pc;
+
+ amd64_init_frame_cache (&cache);
+ pc = amd64_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffLL,
+ &cache);
+ if (cache.frameless_p)
+ return start_pc;
+
+ return amd64_skip_xmm_prologue (pc, start_pc);
+}
\f
/* Normal frames. */
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. */
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. */