#include <ctype.h>
#include "defs.h"
#include "gdb_assert.h"
#include "dis-asm.h"
#include "gdbcore.h"
#include "gdbarch.h"
#include "ui-out.h"
#include "target.h"
#include "gdbtypes.h"
#include "frame.h"
#include "objfiles.h"
#include "exceptions.h"
#include "inferior.h"
#include "objc-lang.h"
#include "regcache.h"
#include "command.h"
#include "gdbcmd.h"
#include "x86-shared-tdep.h"
#include "i386-tdep.h"
#include "amd64-tdep.h"
int debug_x86bt;
static void
show_debug_x86bt (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("x86 backtracer debugging is %s.\n"), value);
}
#define REX_W_PREFIX_P(op) (((op) & (~0x5)) == 0x48)
#define REX_W_R(op) (((op) & 0x4) >> 2)
#define REX_W_B(op) ((op) & 0x1)
static int
x86_mov_esp_ebp_pattern_p (CORE_ADDR memaddr)
{
gdb_byte op = read_memory_unsigned_integer (memaddr, 1);
if (op == 0x48)
{
memaddr++;
op = read_memory_unsigned_integer (memaddr, 1);
}
if (op == 0x8b)
if (read_memory_unsigned_integer (memaddr + 1, 1) == 0xec)
return 1;
if (op == 0x89)
if (read_memory_unsigned_integer (memaddr + 1, 1) == 0xe5)
return 1;
return 0;
}
static int
x86_push_ebp_pattern_p (CORE_ADDR memaddr)
{
gdb_byte op = read_memory_unsigned_integer (memaddr, 1);
if (op == 0x55)
return 1;
if (op == 0x6a)
if (read_memory_unsigned_integer (memaddr + 1, 1) == 0x00)
return 1;
return 0;
}
static int
x86_ret_pattern_p (CORE_ADDR memaddr)
{
gdb_byte op = read_memory_unsigned_integer (memaddr, 1);
if (op == 0xc3 || op == 0xcb || op == 0xc2 || op == 0xca)
return 1;
if (op == 0xc9)
return 1;
return 0;
}
static int
x86_picbase_setup_pattern_p (CORE_ADDR memaddr, int *regnum)
{
gdb_byte op;
if (length_of_this_instruction (memaddr) != 5
|| read_memory_unsigned_integer (memaddr, 1) != 0xe8
|| read_memory_unsigned_integer (memaddr + 1, 4) != 0)
return 0;
op = read_memory_unsigned_integer (memaddr + 5, 1);
if ((op & 0xf8) != 0x58)
return 0;
if (regnum)
*regnum = (int) op & 0x7;
return 1;
}
int
i386_nonvolatile_regnum_p (int r)
{
if (r == I386_EBX_REGNUM || r == I386_EBP_REGNUM
|| r == I386_ESI_REGNUM || r == I386_EDI_REGNUM
|| r == I386_ESP_REGNUM)
return 1;
else
return 0;
}
int
i386_argument_regnum_p (int r)
{
return 0;
}
int
x86_64_nonvolatile_regnum_p (int r)
{
if (r == AMD64_RBX_REGNUM || r == AMD64_RSP_REGNUM
|| r == AMD64_RBP_REGNUM
|| r == AMD64_R8_REGNUM + 4 || r == AMD64_R8_REGNUM + 5
|| r == AMD64_R8_REGNUM + 6 || r == AMD64_R8_REGNUM + 7)
return 1;
else
return 0;
}
int
x86_64_argument_regnum_p (int r)
{
if (r == AMD64_RDI_REGNUM || r == AMD64_RSI_REGNUM
|| r == AMD64_RDX_REGNUM || r == AMD64_RCX_REGNUM
|| r == AMD64_R8_REGNUM || r == AMD64_R8_REGNUM + 1)
return 1;
else
return 0;
}
int
i386_machine_regno_to_gdb_regno (int r)
{
return r;
}
int
x86_64_machine_regno_to_gdb_regno (int r)
{
switch (r)
{
case 0: return AMD64_RAX_REGNUM;
case 1: return AMD64_RCX_REGNUM;
case 2: return AMD64_RDX_REGNUM;
case 3: return AMD64_RBX_REGNUM;
case 4: return AMD64_RSP_REGNUM;
case 5: return AMD64_RBP_REGNUM;
case 6: return AMD64_RSI_REGNUM;
case 7: return AMD64_RDI_REGNUM;
default: return r;
}
}
static int
x86_push_reg_p (CORE_ADDR memaddr, int *regnum)
{
gdb_byte op;
int prefix_bit = 0;
op = read_memory_unsigned_integer (memaddr, 1);
if (op == 0x41)
{
prefix_bit = 1 << 3;
op = read_memory_unsigned_integer (memaddr + 1, 1);
}
if (op >= 0x50 && op <= 0x57)
{
int r = (op - 0x50) | prefix_bit;
if (regnum != NULL)
*regnum = r;
return 1;
}
return 0;
}
static int
x86_pop_p (CORE_ADDR memaddr)
{
gdb_byte op = read_memory_unsigned_integer (memaddr, 1);
if (op == 0x41)
op = read_memory_unsigned_integer (memaddr + 1, 1);
if ((op & 0xf8) == 0x58)
return 1;
return 0;
}
static int
x86_mov_reg_to_local_stack_frame_p (CORE_ADDR memaddr, int *regnum, int *offset)
{
gdb_byte op;
int source_reg_mod = 0;
int target_reg_mod = 0;
op = read_memory_unsigned_integer (memaddr, 1);
if (REX_W_PREFIX_P (op))
{
source_reg_mod = REX_W_R (op) << 3;
target_reg_mod = REX_W_B (op) << 3;
if (target_reg_mod == 1)
return 0;
op = read_memory_unsigned_integer (++memaddr, 1);
}
if (op == 0x89)
{
op = read_memory_unsigned_integer (memaddr + 1, 1);
int op_sans_dest_reg = op & (~0x38);
if (op_sans_dest_reg != 0x45 && op_sans_dest_reg != 0x85)
return 0;
int saved_reg = ((op >> 3) & 0x7) | source_reg_mod;
int off = 0;
if (op_sans_dest_reg == 0x45)
off = (int8_t) read_memory_unsigned_integer (memaddr + 2, 1);
if (op_sans_dest_reg == 0x85)
off = (uint32_t) read_memory_unsigned_integer (memaddr + 2, 4);
if (off > 0)
return 0;
if (regnum != NULL)
*regnum = saved_reg;
if (offset != NULL)
*offset = abs (off);
return 1;
}
return 0;
}
static int
x86_mov_func_arg_to_reg_p (CORE_ADDR memaddr, int *regnum, int *offset)
{
gdb_byte op;
int source_reg_mod = 0;
int target_reg_mod = 0;
op = read_memory_unsigned_integer (memaddr, 1);
if (REX_W_PREFIX_P (op))
{
source_reg_mod = REX_W_R (op) << 3;
target_reg_mod = REX_W_B (op) << 3;
if (target_reg_mod == 1)
return 0;
op = read_memory_unsigned_integer (++memaddr, 1);
}
if (op == 0x8b)
{
op = read_memory_unsigned_integer (memaddr + 1, 1);
int op_sans_dest_reg = op & (~0x38);
if (op_sans_dest_reg != 0x45 && op_sans_dest_reg != 0x85)
return 0;
int saved_reg = ((op >> 3) & 0x7) | source_reg_mod;
int off = 0;
if (op_sans_dest_reg == 0x45)
off = (int8_t) read_memory_unsigned_integer (memaddr + 2, 1);
if (op_sans_dest_reg == 0x85)
off = (int32_t) read_memory_unsigned_integer (memaddr + 2, 4);
if (offset != NULL)
*offset = off;
if (regnum != NULL)
*regnum = saved_reg;
return 1;
}
return 0;
}
static int
x86_unopt_arg_copy_to_local_stack_p (CORE_ADDR memaddr)
{
int reg1, off1, reg2, off2;
if (x86_mov_func_arg_to_reg_p (memaddr, ®1, &off1) == 0)
return 0;
memaddr += length_of_this_instruction (memaddr);
if (x86_mov_reg_to_local_stack_frame_p (memaddr, ®2, &off2) == 0)
return 0;
if (reg1 != reg2)
return 0;
if (off1 < 0 || off2 > 0)
return 0;
return 1;
}
static int32_t
x86_sub_esp_pattern_p (CORE_ADDR memaddr)
{
gdb_byte op, next_op;
op = read_memory_unsigned_integer (memaddr, 1);
if (op == 0x48)
{
op = read_memory_unsigned_integer (++memaddr, 1);
}
next_op = read_memory_unsigned_integer (memaddr + 1, 1);
if (op == 0x83 && next_op == 0xec)
{
return (int8_t) read_memory_integer (memaddr + 2, 1);
}
if (op == 0x81 && next_op == 0xec)
{
return (int32_t) read_memory_integer (memaddr + 2, 4);
}
return 0;
}
static int
x86_jump_insn_p (CORE_ADDR memaddr)
{
gdb_byte op;
op = read_memory_unsigned_integer (memaddr, 1);
if (op >= 0x70 && op <= 0x7f)
return 1;
if (op == 0xe3)
return 1;
if (op == 0xe9 || op == 0xea || op == 0xeb)
return 1;
if (op == 0x0f)
{
op = read_memory_unsigned_integer (memaddr + 1, 1);
if (op >= 0x80 && op <= 0x8f)
return 1;
}
return 0;
}
static int
x86_blocks_context_var_copy_pattern_p (CORE_ADDR memaddr, int wordsize)
{
int reg1, off1, reg2, reg3, off3;
if (x86_mov_func_arg_to_reg_p (memaddr, ®1, &off1) == 0)
return 0;
memaddr += length_of_this_instruction (memaddr);
gdb_byte op;
int off = 0;
op = read_memory_unsigned_integer (memaddr, 1);
if (REX_W_PREFIX_P (op))
{
int source_reg_mod = REX_W_R (op) << 3;
int target_reg_mod = REX_W_B (op) << 3;
if (source_reg_mod != target_reg_mod)
return 0;
off++;
op = read_memory_unsigned_integer (memaddr + off, 1);
}
if (op != 0x8b)
return 0;
off++;
op = read_memory_unsigned_integer (memaddr + off, 1);
if ((op & ~0x3f) != 0x40)
return 0;
int sreg = (op & 0x38) >> 3;
int treg = (op & 0x7);
if (sreg != treg)
return 0;
reg2 = sreg;
memaddr += length_of_this_instruction (memaddr);
if (x86_mov_reg_to_local_stack_frame_p (memaddr, ®3, &off3) == 0)
return 0;
if (reg1 != reg2 || reg2 != reg3)
return 0;
if (wordsize == 4 && off1 < 0)
return 0;
if (wordsize == 8 && off1 > 0)
return 0;
return 1;
}
static struct type *
init_vector_type (struct type *elt_type, int n)
{
struct type *array_type;
array_type = create_array_type (0, elt_type,
create_range_type (0, builtin_type_int,
0, n-1));
TYPE_FLAGS (array_type) |= TYPE_FLAG_VECTOR;
return array_type;
}
struct type *
build_builtin_type_vec128i_big (void)
{
struct type *t;
struct type *int16_big;
struct type *int32_big;
struct type *int64_big;
struct type *uint128_big;
struct type *v4_float_big;
struct type *v2_double_big;
struct type *v16_int8_big;
struct type *v8_int16_big;
struct type *v4_int32_big;
struct type *v2_int64_big;
int16_big = init_type (TYPE_CODE_INT, 16 / 8, 0, "int16_t", (struct objfile *) NULL);
TYPE_BYTE_ORDER (int16_big) = BFD_ENDIAN_BIG;
int32_big = init_type (TYPE_CODE_INT, 32 / 8, 0, "int32_t", (struct objfile *) NULL);
TYPE_BYTE_ORDER (int32_big) = BFD_ENDIAN_BIG;
int64_big = init_type (TYPE_CODE_INT, 64 / 8, 0, "int64_t", (struct objfile *) NULL);
TYPE_BYTE_ORDER (int64_big) = BFD_ENDIAN_BIG;
uint128_big = init_type (TYPE_CODE_INT, 128 / 8, TYPE_FLAG_UNSIGNED, "uint128_t", (struct objfile *) NULL);
TYPE_BYTE_ORDER (uint128_big) = BFD_ENDIAN_BIG;
v4_float_big = init_vector_type (builtin_type_ieee_single_big, 4);
v2_double_big = init_vector_type (builtin_type_ieee_double_big, 2);
v2_int64_big = init_vector_type (int64_big, 2);
v4_int32_big = init_vector_type (int32_big, 4);
v8_int16_big = init_vector_type (int16_big, 8);
v16_int8_big = init_vector_type (builtin_type_int8, 16);
t = init_composite_type ("__gdb_builtin_type_vec128i_big", TYPE_CODE_UNION);
append_composite_type_field (t, "v4_float", v4_float_big);
append_composite_type_field (t, "v2_double", v2_double_big);
append_composite_type_field (t, "v16_int8", v16_int8_big);
append_composite_type_field (t, "v8_int16", v8_int16_big);
append_composite_type_field (t, "v4_int32", v4_int32_big);
append_composite_type_field (t, "v2_int64", v2_int64_big);
append_composite_type_field (t, "uint128", uint128_big);
TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
TYPE_NAME (t) = "builtin_type_vec128i_big";
return t;
}
void
x86_initialize_frame_cache (struct x86_frame_cache *cache, int wordsize)
{
int i;
if (wordsize == 4)
{
cache->eip_regnum = I386_EIP_REGNUM;
cache->ebp_regnum = I386_EBP_REGNUM;
cache->esp_regnum = I386_ESP_REGNUM;
cache->num_savedregs = I386_NUM_GREGS;
cache->volatile_reg_p = i386_nonvolatile_regnum_p;
cache->argument_reg_p = i386_argument_regnum_p;
cache->machine_regno_to_gdb_regno = i386_machine_regno_to_gdb_regno;
}
else
{
cache->eip_regnum = AMD64_RIP_REGNUM;
cache->ebp_regnum = AMD64_RBP_REGNUM;
cache->esp_regnum = AMD64_RSP_REGNUM;
cache->num_savedregs = AMD64_NUM_GREGS;
cache->volatile_reg_p = x86_64_nonvolatile_regnum_p;
cache->argument_reg_p = x86_64_argument_regnum_p;
cache->machine_regno_to_gdb_regno = x86_64_machine_regno_to_gdb_regno;
}
cache->frame_base = INVALID_ADDRESS;
cache->sp_offset = 0;
cache->func_start_addr = INVALID_ADDRESS;
cache->scanned_limit = INVALID_ADDRESS;
cache->pc = INVALID_ADDRESS;
cache->saved_regs = FRAME_OBSTACK_CALLOC (cache->num_savedregs, CORE_ADDR);
cache->wordsize = wordsize;
for (i = 0; i < cache->num_savedregs; i++)
cache->saved_regs[i] = INVALID_ADDRESS;
cache->saved_sp = INVALID_ADDRESS;
cache->saved_regs_are_absolute = 0;
cache->ebp_is_frame_pointer = 0;
cache->prologue_scan_status = no_scan_done;
cache->saved_regs[cache->eip_regnum] = 0;
}
struct x86_frame_cache *
x86_alloc_frame_cache (int wordsize)
{
struct x86_frame_cache *cache;
cache = FRAME_OBSTACK_ZALLOC (struct x86_frame_cache);
x86_initialize_frame_cache (cache, wordsize);
return cache;
}
CORE_ADDR
x86_analyze_prologue (CORE_ADDR func_start_addr, CORE_ADDR limit,
struct x86_frame_cache *cache)
{
int insn_count = 0;
int saw_push_ebp = 0;
int saw_mov_esp_ebp = 0;
int saw_sub_esp_insn = 0;
int non_prologue_insns = 0;
const int insn_limit = 50;
CORE_ADDR end_of_frame_setup = func_start_addr;
CORE_ADDR pc = func_start_addr;
cache->scanned_limit = limit;
cache->prologue_scan_status = full_scan_succeeded;
if (debug_x86bt > 2)
printf_filtered ("X86BT: Analyzing prologue func start addr 0x%s, "
"pc addr 0x%s\n",
paddr_nz (func_start_addr), paddr_nz (limit));
if (func_start_addr == INVALID_ADDRESS)
{
cache->ebp_is_frame_pointer = 1;
cache->saved_regs[cache->ebp_regnum] = cache->wordsize;
return limit;
}
while (non_prologue_insns < 10 && pc < limit && insn_count++ < insn_limit)
{
int r;
CORE_ADDR next_insn = pc + length_of_this_instruction (pc);
int prologue_insn = 0;
if (x86_ret_pattern_p (pc))
break;
if (x86_push_reg_p (pc, &r))
{
r = cache->machine_regno_to_gdb_regno (r);
cache->sp_offset += cache->wordsize;
if (cache->volatile_reg_p (r) || cache->argument_reg_p (r))
{
if (cache->saved_regs[r] == INVALID_ADDRESS)
{
cache->saved_regs[r] = cache->sp_offset;
if (r == cache->ebp_regnum)
saw_push_ebp = 1;
prologue_insn = 1;
}
}
goto loopend;
}
if (x86_sub_esp_pattern_p (pc))
{
cache->sp_offset += x86_sub_esp_pattern_p (pc);
saw_sub_esp_insn = 1;
prologue_insn = 1;
goto loopend;
}
if (x86_mov_esp_ebp_pattern_p (pc))
{
saw_mov_esp_ebp = 1;
prologue_insn = 1;
goto loopend;
}
if (x86_picbase_setup_pattern_p (pc, NULL))
{
next_insn = next_insn + length_of_this_instruction (next_insn);
prologue_insn = 1;
goto loopend;
}
int off;
if (x86_mov_reg_to_local_stack_frame_p (pc, &r, &off))
{
r = cache->machine_regno_to_gdb_regno (r);
if ((cache->volatile_reg_p (r) || cache->argument_reg_p (r))
&& cache->saved_regs[r] == INVALID_ADDRESS)
{
cache->saved_regs[r] = off + cache->wordsize;
prologue_insn = 1;
}
goto loopend;
}
if (x86_unopt_arg_copy_to_local_stack_p (pc))
{
next_insn = next_insn + length_of_this_instruction (next_insn);
prologue_insn = 1;
goto loopend;
}
if (x86_jump_insn_p (pc))
break;
if (x86_pop_p (pc))
{
cache->sp_offset -= cache->wordsize;
goto loopend;
}
if (x86_blocks_context_var_copy_pattern_p (pc, cache->wordsize))
{
next_insn = next_insn + length_of_this_instruction (next_insn);
next_insn = next_insn + length_of_this_instruction (next_insn);
prologue_insn = 1;
goto loopend;
}
if (x86_push_ebp_pattern_p (pc))
{
if (saw_push_ebp)
break;
saw_push_ebp = 1;
cache->sp_offset += cache->wordsize;
cache->saved_regs[cache->ebp_regnum] = cache->sp_offset;
prologue_insn = 1;
goto loopend;
}
if (read_memory_unsigned_integer (pc, 1) == 0xe8)
break;
loopend:
if (prologue_insn)
end_of_frame_setup = next_insn;
else
non_prologue_insns++;
pc = next_insn;
}
if (saw_push_ebp && saw_mov_esp_ebp)
{
cache->ebp_is_frame_pointer = 1;
cache->saved_regs[cache->ebp_regnum] = cache->wordsize;
return end_of_frame_setup;
}
if (saw_push_ebp == 0 && saw_sub_esp_insn)
{
cache->saved_regs[cache->ebp_regnum] = INVALID_ADDRESS;
cache->ebp_is_frame_pointer = 0;
return end_of_frame_setup;
}
if (saw_push_ebp && saw_mov_esp_ebp == 0)
{
cache->ebp_is_frame_pointer = 0;
return end_of_frame_setup;
}
cache->ebp_is_frame_pointer = 0;
return end_of_frame_setup;
}
void
x86_finalize_saved_reg_locations (struct frame_info *next_frame,
struct x86_frame_cache *cache)
{
gdb_byte buf[8];
if (cache->saved_regs_are_absolute == 1)
return;
if (cache->ebp_is_frame_pointer)
{
frame_unwind_register (next_frame, cache->ebp_regnum, buf);
cache->frame_base = extract_unsigned_integer (buf, cache->wordsize)
+ cache->wordsize;
}
else
{
frame_unwind_register (next_frame, cache->esp_regnum, buf);
cache->frame_base = extract_unsigned_integer (buf, cache->wordsize)
+ cache->sp_offset;
}
int i;
for (i = 0; i < cache->num_savedregs; i++)
if (cache->saved_regs[i] != INVALID_ADDRESS)
cache->saved_regs[i] = cache->frame_base - cache->saved_regs[i];
cache->saved_sp = cache->frame_base + cache->wordsize;
cache->saved_regs_are_absolute = 1;
}
CORE_ADDR
x86_quickie_analyze_prologue (CORE_ADDR func_start_addr, CORE_ADDR limit,
struct x86_frame_cache *cache,
int potentially_frameless)
{
ULONGEST buf;
gdb_byte i386_pat[3] = { 0x55, 0x89, 0xe5 };
gdb_byte x86_64_pat[4] = { 0x55, 0x48, 0x89, 0xe5 };
cache->func_start_addr = func_start_addr;
cache->pc = limit;
if (func_start_addr == INVALID_ADDRESS
&& potentially_frameless == 1
&& limit != INVALID_ADDRESS)
{
if (safe_read_memory_unsigned_integer (limit, 4, &buf))
{
if (memcmp (&buf, i386_pat, sizeof (i386_pat)) == 0
|| memcmp (&buf, x86_64_pat, sizeof (x86_64_pat)) == 0)
{
cache->prologue_scan_status = quick_scan_succeeded;
cache->ebp_is_frame_pointer = 0;
return limit;
}
}
}
if (func_start_addr == INVALID_ADDRESS)
{
cache->prologue_scan_status = quick_scan_succeeded;
cache->saved_regs[cache->ebp_regnum] = cache->wordsize;
cache->ebp_is_frame_pointer = 1;
return limit;
}
read_memory (func_start_addr, &buf, 4);
int i386_matched = memcmp (&buf, i386_pat, sizeof (i386_pat)) == 0;
int x86_64_matched = memcmp (&buf, x86_64_pat, sizeof (x86_64_pat)) == 0;
if (i386_matched || x86_64_matched)
{
if (limit == func_start_addr)
{
cache->prologue_scan_status = quick_scan_succeeded;
cache->ebp_is_frame_pointer = 0;
return func_start_addr;
}
if (limit == func_start_addr + 1)
{
cache->prologue_scan_status = quick_scan_succeeded;
cache->ebp_is_frame_pointer = 0;
cache->sp_offset += cache->wordsize;
return limit;
}
cache->prologue_scan_status = quick_scan_succeeded;
cache->ebp_is_frame_pointer = 1;
cache->sp_offset += cache->wordsize;
cache->saved_regs[cache->ebp_regnum] = cache->wordsize;
if (i386_matched)
return func_start_addr + 3;
else
return func_start_addr + 4;
}
cache->prologue_scan_status = quick_scan_failed;
cache->ebp_is_frame_pointer = 0;
return func_start_addr;
}
struct x86_frame_cache *
x86_frame_cache (struct frame_info *next_frame, void **this_cache, int wordsize)
{
struct x86_frame_cache *cache;
int potentially_frameless;
CORE_ADDR prologue_parsed_to = 0;
CORE_ADDR current_pc;
if (*this_cache)
return *this_cache;
potentially_frameless = frame_relative_level (next_frame) == -1
|| get_frame_type (next_frame) == SIGTRAMP_FRAME
|| get_frame_type (next_frame) == DUMMY_FRAME;
cache = x86_alloc_frame_cache (wordsize);
*this_cache = cache;
current_pc = frame_pc_unwind (next_frame);
pc_set_load_state (current_pc, OBJF_SYM_ALL, 0);
cache->func_start_addr = frame_func_unwind (next_frame);
cache->pc = current_pc;
if (pc_in_objc_trampoline_p (current_pc, NULL))
{
cache->prologue_scan_status = full_scan_succeeded;
cache->ebp_is_frame_pointer = 0;
return cache;
}
if (cache->func_start_addr == 0)
{
cache->func_start_addr = INVALID_ADDRESS;
}
else
{
if (current_pc < cache->func_start_addr
|| (current_pc - cache->func_start_addr) > 65000)
prologue_parsed_to = cache->func_start_addr = INVALID_ADDRESS;
}
if (cache->func_start_addr == INVALID_ADDRESS
&& current_pc == 0 && potentially_frameless)
{
cache->prologue_scan_status = full_scan_succeeded;
cache->ebp_is_frame_pointer = 0;
return cache;
}
prologue_parsed_to = x86_quickie_analyze_prologue (cache->func_start_addr,
current_pc, cache, potentially_frameless);
if (cache->prologue_scan_status == quick_scan_failed)
{
x86_initialize_frame_cache (cache, wordsize);
cache->func_start_addr = frame_func_unwind (next_frame);
cache->pc = frame_pc_unwind (next_frame);
prologue_parsed_to = x86_analyze_prologue (cache->func_start_addr,
current_pc, cache);
}
if (potentially_frameless == 0 && cache->ebp_is_frame_pointer == 0)
{
cache->saved_regs[cache->ebp_regnum] = cache->wordsize;
cache->ebp_is_frame_pointer = 1;
}
return cache;
}
void
x86_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
int wordsize = TARGET_PTR_BIT / 8;
struct x86_frame_cache *cache = x86_frame_cache (next_frame, this_cache,
wordsize);
CORE_ADDR startaddr;
CORE_ADDR prev_frame_pc = INVALID_ADDRESS;
x86_finalize_saved_reg_locations (next_frame, cache);
if (get_frame_type (next_frame) == SENTINEL_FRAME)
{
struct gdb_exception e;
TRY_CATCH (e, RETURN_MASK_ERROR)
{
gdb_byte buf[8];
read_memory (cache->frame_base, buf, wordsize);
}
if (e.reason != NO_ERROR)
{
if (debug_x86bt)
printf_filtered ("X86BT: Terminating backtrace of thread port#: "
"0x%lx with unreadible "
"initial stack address at 0x%s, at frame level %d.\n",
inferior_ptid.tid, paddr_nz (cache->frame_base),
frame_relative_level (next_frame) + 1);
*this_id = null_frame_id;
return;
}
}
if (get_frame_type (next_frame) != SENTINEL_FRAME)
{
if (get_prev_frame (next_frame) != NULL)
{
struct gdb_exception e;
TRY_CATCH (e, RETURN_MASK_ALL)
{
prev_frame_pc = frame_pc_unwind (get_prev_frame (next_frame));
}
if (e.reason != NO_ERROR)
{
if (debug_x86bt)
printf_filtered ("X86BT: Could not retrieve saved pc value at frame "
"level %d in backtrace of thread port# 0x%lx, "
"tried to read it from stack addr 0x%s.\n",
frame_relative_level (next_frame) + 1,
inferior_ptid.tid,
paddr_nz (cache->frame_base));
prev_frame_pc = 0;
}
}
if (prev_frame_pc == 0)
{
struct minimal_symbol *minsym;
minsym = lookup_minimal_symbol_by_pc (frame_pc_unwind (next_frame));
if (!minsym || strcmp (SYMBOL_LINKAGE_NAME (minsym),
"trap_from_kernel") != 0)
{
*this_id = null_frame_id;
return;
}
}
if (cache->frame_base == 0)
{
if (debug_x86bt)
printf_filtered ("X86BT: Frame level %d's frame base is 0, done "
"backtracing thread port# 0x%lx\n",
frame_relative_level (next_frame) + 1,
inferior_ptid.tid);
*this_id = null_frame_id;
return;
}
else
{
ULONGEST prev_frame_addr = 0;
if (safe_read_memory_unsigned_integer
(cache->frame_base - wordsize, wordsize, &prev_frame_addr))
{
if (prev_frame_addr == 0)
{
if (debug_x86bt)
printf_filtered ("X86BT: Frame level %d's frame base is 0, "
"done backtracing thread port# 0x%lx\n",
frame_relative_level (next_frame) + 1,
inferior_ptid.tid);
*this_id = null_frame_id;
return;
}
}
else
{
if (debug_x86bt)
printf_filtered ("X86BT: Could not read frame level %d's frame "
"pointer value in thread port# 0x%lx.\n",
frame_relative_level (next_frame) + 1,
inferior_ptid.tid);
}
}
}
if (cache->func_start_addr == INVALID_ADDRESS)
startaddr = 0;
else
startaddr = cache->func_start_addr;
if (debug_x86bt > 2)
printf_filtered ("X86BT: Creating frame %d id pc 0x%s, "
"func-start-pc 0x%s, frame ptr 0x%s\n",
frame_relative_level (next_frame) + 1,
paddr_nz (cache->pc),
paddr_nz (startaddr),
paddr_nz (cache->frame_base + wordsize));
(*this_id) = frame_id_build (cache->frame_base + wordsize, startaddr);
}
void
x86_frame_prev_register (struct frame_info *next_frame, void **this_cache,
int regnum, enum opt_state *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
int wordsize = TARGET_PTR_BIT / 8;
struct x86_frame_cache *cache = x86_frame_cache (next_frame, this_cache,
wordsize);
if (cache->prologue_scan_status != full_scan_succeeded
&& regnum != cache->eip_regnum
&& regnum != cache->ebp_regnum
&& regnum != cache->esp_regnum
&& cache->func_start_addr != 0
&& cache->func_start_addr != INVALID_ADDRESS)
{
x86_initialize_frame_cache (cache, wordsize);
cache->func_start_addr = frame_func_unwind (next_frame);
cache->pc = frame_pc_unwind (next_frame);
x86_analyze_prologue (cache->func_start_addr, cache->pc, cache);
}
if (cache->saved_regs_are_absolute == 0)
x86_finalize_saved_reg_locations (next_frame, cache);
gdb_assert (regnum >= 0);
if (regnum == cache->esp_regnum && cache->saved_sp != INVALID_ADDRESS)
{
*optimizedp = opt_okay;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
store_unsigned_integer (valuep, wordsize, cache->saved_sp);
}
return;
}
if (regnum < cache->num_savedregs && cache->saved_regs[regnum] != -1)
{
*optimizedp = opt_okay;
*lvalp = lval_memory;
*addrp = cache->saved_regs[regnum];
*realnump = -1;
if (valuep)
{
read_memory (*addrp, valuep,
register_size (current_gdbarch, regnum));
if (debug_x86bt > 8)
printf_filtered ("X86BT: Retrieving reg #%d for frame %d, "
"is saved at 0x%s, value 0x%s\n",
regnum,
frame_relative_level (next_frame) + 2,
paddr_nz (cache->saved_regs[regnum]),
paddr_nz (read_memory_unsigned_integer (cache->saved_regs[regnum], cache->wordsize)));
}
return;
}
*optimizedp = opt_okay;
*lvalp = lval_register;
*addrp = 0;
*realnump = regnum;
if (valuep)
{
if (debug_x86bt > 8)
printf_filtered ("X86BT: Could not find save location for regnum %d in frame %d, going down stack.\n",
regnum, frame_relative_level (next_frame) + 1);
frame_unwind_register (next_frame, (*realnump), valuep);
}
}
CORE_ADDR
x86_cxx_virtual_override_thunk_trampline (CORE_ADDR pc)
{
struct minimal_symbol *msym;
int is_thunk = 0;
msym = lookup_minimal_symbol_by_pc (pc);
if (msym == NULL)
return 0;
if (strncmp (SYMBOL_LINKAGE_NAME (msym), "_ZThn", 5) == 0)
{
if (isdigit ((SYMBOL_LINKAGE_NAME (msym))[5]))
is_thunk = 1;
}
else if (strncmp (SYMBOL_LINKAGE_NAME (msym), "_ZTv", 4) == 0)
{
if (isdigit ((SYMBOL_LINKAGE_NAME (msym))[4]))
is_thunk = 1;
}
if (is_thunk == 0)
return 0;
int insn_count = 0;
while (insn_count++ < 6)
{
if (lookup_minimal_symbol_by_pc (pc) != msym)
return 0;
gdb_byte op;
op = read_memory_unsigned_integer (pc, 1);
if (op == 0xe9)
{
int64_t off = read_memory_integer (pc + 1, 4);
return pc + 5 + off;
}
if (op == 0xeb)
{
int64_t off = read_memory_integer (pc + 1, 1);
return pc + 1 + off;
}
pc += length_of_this_instruction (pc);
}
return 0;
}
void
_initialize_x86_shared_tdep (void)
{
add_setshow_zinteger_cmd ("x86bt", class_maintenance, &debug_x86bt, _("\
Set x86 backtrace debugging."), _("\
Show x86 backtrace debugging."), _("\
When non-zero, x86 backtrace specific debugging is enabled."),
NULL,
show_debug_x86bt,
&setdebuglist, &showdebuglist);
}