/* Target-dependent code for AMD64.
- Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
Contributed by Jiri Smid, SuSE Labs.
amd64_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum >= AMD64_RAX_REGNUM && regnum <= AMD64_RDI_REGNUM)
- return builtin_type_int64;
+ return builtin_type (gdbarch)->builtin_int64;
if (regnum == AMD64_RBP_REGNUM || regnum == AMD64_RSP_REGNUM)
return builtin_type (gdbarch)->builtin_data_ptr;
if (regnum >= AMD64_R8_REGNUM && regnum <= AMD64_R15_REGNUM)
- return builtin_type_int64;
+ return builtin_type (gdbarch)->builtin_int64;
if (regnum == AMD64_RIP_REGNUM)
return builtin_type (gdbarch)->builtin_func_ptr;
if (regnum == AMD64_EFLAGS_REGNUM)
- return i386_eflags_type;
+ return i386_eflags_type (gdbarch);
if (regnum >= AMD64_CS_REGNUM && regnum <= AMD64_GS_REGNUM)
- return builtin_type_int32;
+ return builtin_type (gdbarch)->builtin_int32;
if (regnum >= AMD64_ST0_REGNUM && regnum <= AMD64_ST0_REGNUM + 7)
- return builtin_type_i387_ext;
+ return i387_ext_type (gdbarch);
if (regnum >= AMD64_FCTRL_REGNUM && regnum <= AMD64_FCTRL_REGNUM + 7)
- return builtin_type_int32;
+ return builtin_type (gdbarch)->builtin_int32;
if (regnum >= AMD64_XMM0_REGNUM && regnum <= AMD64_XMM0_REGNUM + 15)
return i386_sse_type (gdbarch);
if (regnum == AMD64_MXCSR_REGNUM)
- return i386_mxcsr_type;
+ return i386_mxcsr_type (gdbarch);
internal_error (__FILE__, __LINE__, _("invalid regnum"));
}
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
gdb_byte buf[8];
/* Pass arguments. */
/* Pass "hidden" argument". */
if (struct_return)
{
- store_unsigned_integer (buf, 8, struct_addr);
+ store_unsigned_integer (buf, 8, byte_order, struct_addr);
regcache_cooked_write (regcache, AMD64_RDI_REGNUM, buf);
}
/* Store return address. */
sp -= 8;
- store_unsigned_integer (buf, 8, bp_addr);
+ store_unsigned_integer (buf, 8, byte_order, bp_addr);
write_memory (sp, buf, 8);
/* Finally, update the stack pointer... */
- store_unsigned_integer (buf, 8, sp);
+ store_unsigned_integer (buf, 8, byte_order, sp);
regcache_cooked_write (regcache, AMD64_RSP_REGNUM, buf);
/* ...and fake a frame pointer. */
about falling off the end of the buffer. */
static gdb_byte *
-skip_prefixes (gdb_byte *insn)
+amd64_skip_prefixes (gdb_byte *insn)
{
while (1)
{
details->modrm_offset = -1;
/* Skip legacy instruction prefixes. */
- insn = skip_prefixes (insn);
+ insn = amd64_skip_prefixes (insn);
/* Skip REX instruction prefix. */
if (rex_prefix_p (*insn))
need_modrm = twobyte_has_modrm[*insn];
/* Check for three-byte opcode. */
- if (*insn == 0x38 || *insn == 0x3a)
+ switch (*insn)
{
+ case 0x24:
+ case 0x25:
+ case 0x38:
+ case 0x3a:
+ case 0x7a:
+ case 0x7b:
++insn;
details->opcode_len = 3;
+ break;
+ default:
+ details->opcode_len = 2;
+ break;
}
- else
- details->opcode_len = 2;
}
else
{
fixup_riprel (struct gdbarch *gdbarch, struct 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;
++insn;
/* Compute the rip-relative address. */
- disp = extract_signed_integer (insn, sizeof (int32_t));
+ disp = extract_signed_integer (insn, sizeof (int32_t), byte_order);
insn_length = amd64_insn_length (gdbarch, dsc->insn_buf, dsc->max_len, from);
rip_base = from + insn_length;
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog, "displaced: %%rip-relative addressing used.\n"
- "displaced: using temp reg %d, old value 0x%s, new value 0x%s\n",
- dsc->tmp_regno, paddr_nz (dsc->tmp_save),
- paddr_nz (rip_base));
+ "displaced: using temp reg %d, old value %s, new value %s\n",
+ dsc->tmp_regno, paddress (gdbarch, dsc->tmp_save),
+ paddress (gdbarch, rip_base));
}
static void
if (debug_displaced)
{
- fprintf_unfiltered (gdb_stdlog, "displaced: copy 0x%s->0x%s: ",
- paddr_nz (from), paddr_nz (to));
+ fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ",
+ paddress (gdbarch, from), paddress (gdbarch, to));
displaced_step_dump_bytes (gdb_stdlog, buf, len);
}
return 0;
}
-static int
-amd64_breakpoint_p (const struct amd64_insn *details)
-{
- const gdb_byte *insn = &details->raw_insn[details->opcode_offset];
-
- return insn[0] == 0xcc; /* int 3 */
-}
-
/* Return non-zero if INSN is a system call, and set *LENGTHP to its
length in bytes. Otherwise, return zero. */
CORE_ADDR from, CORE_ADDR to,
struct regcache *regs)
{
+ 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;
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
- "displaced: fixup (0x%s, 0x%s), "
+ "displaced: fixup (%s, %s), "
"insn = 0x%02x 0x%02x ...\n",
- paddr_nz (from), paddr_nz (to), insn[0], insn[1]);
+ paddress (gdbarch, from), paddress (gdbarch, to),
+ insn[0], insn[1]);
/* If we used a tmp reg, restore it. */
if (dsc->tmp_used)
{
if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog, "displaced: restoring reg %d to 0x%s\n",
- dsc->tmp_regno, paddr_nz (dsc->tmp_save));
+ fprintf_unfiltered (gdb_stdlog, "displaced: restoring reg %d to %s\n",
+ dsc->tmp_regno, paddress (gdbarch, dsc->tmp_save));
regcache_cooked_write_unsigned (regs, dsc->tmp_regno, dsc->tmp_save);
}
{
ULONGEST rip = orig_rip - insn_offset;
- /* If we have stepped over a breakpoint, set %rip to
- point at the breakpoint instruction itself.
-
- (gdbarch_decr_pc_after_break was never something the core
- of GDB should have been concerned with; arch-specific
- code should be making PC values consistent before
- presenting them to GDB.) */
- if (amd64_breakpoint_p (insn_details))
- {
- if (debug_displaced)
- fprintf_unfiltered (gdb_stdlog,
- "displaced: stepped breakpoint\n");
- rip--;
- }
+ /* If we just stepped over a breakpoint insn, we don't backup
+ the pc on purpose; this is to match behaviour without
+ stepping. */
regcache_cooked_write_unsigned (regs, AMD64_RIP_REGNUM, rip);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
"displaced: "
- "relocated %%rip from 0x%s to 0x%s\n",
- paddr_nz (orig_rip), paddr_nz (rip));
+ "relocated %%rip from %s to %s\n",
+ paddress (gdbarch, orig_rip),
+ paddress (gdbarch, rip));
}
}
const ULONGEST retaddr_len = 8;
regcache_cooked_read_unsigned (regs, AMD64_RSP_REGNUM, &rsp);
- retaddr = read_memory_unsigned_integer (rsp, retaddr_len);
+ retaddr = read_memory_unsigned_integer (rsp, retaddr_len, byte_order);
retaddr = (retaddr - insn_offset) & 0xffffffffUL;
- write_memory_unsigned_integer (rsp, retaddr_len, retaddr);
+ write_memory_unsigned_integer (rsp, retaddr_len, byte_order, retaddr);
if (debug_displaced)
fprintf_unfiltered (gdb_stdlog,
- "displaced: relocated return addr at 0x%s "
- "to 0x%s\n",
- paddr_nz (rsp),
- paddr_nz (retaddr));
+ "displaced: relocated return addr at %s "
+ "to %s\n",
+ paddress (gdbarch, rsp),
+ paddress (gdbarch, retaddr));
}
}
\f
cache->pc = 0;
/* Saved registers. We initialize these to -1 since zero is a valid
- offset (that's where %rbp is supposed to be stored). */
+ offset (that's where %rbp is supposed to be stored).
+ The values start out as being offsets, and are later converted to
+ addresses (at which point -1 is interpreted as an address, still meaning
+ "invalid"). */
for (i = 0; i < AMD64_NUM_SAVED_REGS; i++)
cache->saved_regs[i] = -1;
cache->saved_sp = 0;
to have no prologue and thus no valid frame pointer in %rbp. */
static CORE_ADDR
-amd64_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+amd64_analyze_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR pc, CORE_ADDR current_pc,
struct amd64_frame_cache *cache)
{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
static gdb_byte proto[3] = { 0x48, 0x89, 0xe5 }; /* movq %rsp, %rbp */
gdb_byte buf[3];
gdb_byte op;
pc = amd64_analyze_stack_align (pc, current_pc, cache);
- op = read_memory_unsigned_integer (pc, 1);
+ op = read_memory_unsigned_integer (pc, 1, byte_order);
if (op == 0x55) /* pushq %rbp */
{
CORE_ADDR pc;
amd64_init_frame_cache (&cache);
- pc = amd64_analyze_prologue (start_pc, 0xffffffffffffffffLL, &cache);
+ pc = amd64_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffLL,
+ &cache);
if (cache.frameless_p)
return start_pc;
static struct amd64_frame_cache *
amd64_frame_cache (struct frame_info *this_frame, void **this_cache)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct amd64_frame_cache *cache;
gdb_byte buf[8];
int i;
cache->pc = get_frame_func (this_frame);
if (cache->pc != 0)
- amd64_analyze_prologue (cache->pc, get_frame_pc (this_frame), cache);
+ amd64_analyze_prologue (gdbarch, cache->pc, get_frame_pc (this_frame),
+ cache);
if (cache->saved_sp_reg != -1)
{
/* Stack pointer has been saved. */
get_frame_register (this_frame, cache->saved_sp_reg, buf);
- cache->saved_sp = extract_unsigned_integer(buf, 8);
+ cache->saved_sp = extract_unsigned_integer(buf, 8, byte_order);
}
if (cache->frameless_p)
else
{
get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
- cache->base = extract_unsigned_integer (buf, 8) + cache->sp_offset;
+ cache->base = extract_unsigned_integer (buf, 8, byte_order)
+ + cache->sp_offset;
}
}
else
{
get_frame_register (this_frame, AMD64_RBP_REGNUM, buf);
- cache->base = extract_unsigned_integer (buf, 8);
+ cache->base = extract_unsigned_integer (buf, 8, byte_order);
}
/* Now that we have the base address for the stack frame we can
static struct amd64_frame_cache *
amd64_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct amd64_frame_cache *cache;
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
CORE_ADDR addr;
gdb_byte buf[8];
int i;
cache = amd64_alloc_frame_cache ();
get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
- cache->base = extract_unsigned_integer (buf, 8) - 8;
+ cache->base = extract_unsigned_integer (buf, 8, byte_order) - 8;
addr = tdep->sigcontext_addr (this_frame);
gdb_assert (tdep->sc_reg_offset);
amd64_frame_base_address
};
+/* Normal frames, but in a function epilogue. */
+
+/* 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)
+{
+ gdb_byte insn;
+
+ if (target_read_memory (pc, &insn, 1))
+ return 0; /* Can't read memory at pc. */
+
+ if (insn != 0xc3) /* 'ret' instruction. */
+ return 0;
+
+ return 1;
+}
+
+static int
+amd64_epilogue_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame,
+ 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));
+ else
+ return 0;
+}
+
+static struct amd64_frame_cache *
+amd64_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct amd64_frame_cache *cache;
+ gdb_byte buf[8];
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = amd64_alloc_frame_cache ();
+ *this_cache = cache;
+
+ /* Cache base will be %esp plus cache->sp_offset (-8). */
+ get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 8,
+ byte_order) + cache->sp_offset;
+
+ /* Cache pc will be the frame func. */
+ cache->pc = get_frame_pc (this_frame);
+
+ /* The saved %esp will be at cache->base plus 16. */
+ cache->saved_sp = cache->base + 16;
+
+ /* The saved %eip will be at cache->base plus 8. */
+ cache->saved_regs[AMD64_RIP_REGNUM] = cache->base + 8;
+
+ return cache;
+}
+
+static void
+amd64_epilogue_frame_this_id (struct frame_info *this_frame,
+ void **this_cache,
+ struct frame_id *this_id)
+{
+ struct amd64_frame_cache *cache = amd64_epilogue_frame_cache (this_frame,
+ this_cache);
+
+ (*this_id) = frame_id_build (cache->base + 8, cache->pc);
+}
+
+static const struct frame_unwind amd64_epilogue_frame_unwind =
+{
+ NORMAL_FRAME,
+ amd64_epilogue_frame_this_id,
+ amd64_frame_prev_register,
+ NULL,
+ amd64_epilogue_frame_sniffer
+};
+
static struct frame_id
amd64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
return 1;
}
+static const int amd64_record_regmap[] =
+{
+ AMD64_RAX_REGNUM, AMD64_RCX_REGNUM, AMD64_RDX_REGNUM, AMD64_RBX_REGNUM,
+ AMD64_RSP_REGNUM, AMD64_RBP_REGNUM, AMD64_RSI_REGNUM, AMD64_RDI_REGNUM,
+ AMD64_R8_REGNUM, AMD64_R9_REGNUM, AMD64_R10_REGNUM, AMD64_R11_REGNUM,
+ AMD64_R12_REGNUM, AMD64_R13_REGNUM, AMD64_R14_REGNUM, AMD64_R15_REGNUM,
+ AMD64_RIP_REGNUM, AMD64_EFLAGS_REGNUM, AMD64_CS_REGNUM, AMD64_SS_REGNUM,
+ AMD64_DS_REGNUM, AMD64_ES_REGNUM, AMD64_FS_REGNUM, AMD64_GS_REGNUM
+};
+
void
amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_num_pseudo_regs (gdbarch, 0);
tdep->mm0_regnum = -1;
+ tdep->record_regmap = amd64_record_regmap;
+
set_gdbarch_dummy_id (gdbarch, amd64_dummy_id);
+ /* Hook the function epilogue frame unwinder. This unwinder is
+ appended to the list first, so that it supercedes the other
+ unwinders in function epilogues. */
+ frame_unwind_prepend_unwinder (gdbarch, &amd64_epilogue_frame_unwind);
+
+ /* Hook the prologue-based frame unwinders. */
frame_unwind_append_unwinder (gdbarch, &amd64_sigtramp_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &amd64_frame_unwind);
frame_base_set_default (gdbarch, &amd64_frame_base);