#include "defs.h"
#include "arch-utils.h"
#include "command.h"
#include "dummy-frame.h"
#include "dwarf2-frame.h"
#include "doublest.h"
#include "floatformat.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "inferior.h"
#include "gdbcmd.h"
#include "gdbcore.h"
#include "objfiles.h"
#include "osabi.h"
#include "regcache.h"
#include "reggroups.h"
#include "regset.h"
#include "symfile.h"
#include "symtab.h"
#include "target.h"
#include "value.h"
#include "gdb_assert.h"
#include "reggroups.h"
#include "dummy-frame.h"
#include "osabi.h"
#include "bfd.h"
#include "elf-bfd.h"
#include "dis-asm.h"
#include "gdb_assert.h"
#include "gdb_string.h"
#include "i386-tdep.h"
#include "i387-tdep.h"
#include "macosx-tdep.h"
static char *i386_register_names[] =
{
"eax", "ecx", "edx", "ebx",
"esp", "ebp", "esi", "edi",
"eip", "eflags", "cs", "ss",
"ds", "es", "fs", "gs",
"st0", "st1", "st2", "st3",
"st4", "st5", "st6", "st7",
"fctrl", "fstat", "ftag", "fiseg",
"fioff", "foseg", "fooff", "fop",
"xmm0", "xmm1", "xmm2", "xmm3",
"xmm4", "xmm5", "xmm6", "xmm7",
"mxcsr"
};
static const int i386_num_register_names = ARRAY_SIZE (i386_register_names);
static char *i386_mmx_names[] =
{
"mm0", "mm1", "mm2", "mm3",
"mm4", "mm5", "mm6", "mm7"
};
static const int i386_num_mmx_regs = ARRAY_SIZE (i386_mmx_names);
struct type *builtin_type_vec128i_big = NULL;
static int
i386_mmx_regnum_p (struct gdbarch *gdbarch, int regnum)
{
int mm0_regnum = gdbarch_tdep (gdbarch)->mm0_regnum;
if (mm0_regnum < 0)
return 0;
return (regnum >= mm0_regnum && regnum < mm0_regnum + i386_num_mmx_regs);
}
static int
i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
#define I387_ST0_REGNUM tdep->st0_regnum
#define I387_NUM_XMM_REGS tdep->num_xmm_regs
if (I387_NUM_XMM_REGS == 0)
return 0;
return (I387_XMM0_REGNUM <= regnum && regnum < I387_MXCSR_REGNUM);
#undef I387_ST0_REGNUM
#undef I387_NUM_XMM_REGS
}
static int
i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
#define I387_ST0_REGNUM tdep->st0_regnum
#define I387_NUM_XMM_REGS tdep->num_xmm_regs
if (I387_NUM_XMM_REGS == 0)
return 0;
return (regnum == I387_MXCSR_REGNUM);
#undef I387_ST0_REGNUM
#undef I387_NUM_XMM_REGS
}
#define I387_ST0_REGNUM (gdbarch_tdep (current_gdbarch)->st0_regnum)
#define I387_MM0_REGNUM (gdbarch_tdep (current_gdbarch)->mm0_regnum)
#define I387_NUM_XMM_REGS (gdbarch_tdep (current_gdbarch)->num_xmm_regs)
int
i386_fp_regnum_p (int regnum)
{
if (I387_ST0_REGNUM < 0)
return 0;
return (I387_ST0_REGNUM <= regnum && regnum < I387_FCTRL_REGNUM);
}
int
i386_fpc_regnum_p (int regnum)
{
if (I387_ST0_REGNUM < 0)
return 0;
return (I387_FCTRL_REGNUM <= regnum && regnum < I387_XMM0_REGNUM);
}
const char *
i386_register_name (int regnum)
{
if (i386_mmx_regnum_p (current_gdbarch, regnum))
return i386_mmx_names[regnum - I387_MM0_REGNUM];
if (regnum >= 0 && regnum < i386_num_register_names)
return i386_register_names[regnum];
return NULL;
}
static int
i386_dbx_reg_to_regnum (int reg)
{
if (reg >= 0 && reg <= 7)
{
if (reg == 4)
return 5;
else if (reg == 5)
return 4;
else return reg;
}
else if (reg >= 12 && reg <= 19)
{
return reg - 12 + I387_ST0_REGNUM;
}
else if (reg >= 21 && reg <= 28)
{
return reg - 21 + I387_XMM0_REGNUM;
}
else if (reg >= 29 && reg <= 36)
{
return reg - 29 + I387_MM0_REGNUM;
}
return NUM_REGS + NUM_PSEUDO_REGS;
}
static int
i386_svr4_reg_to_regnum (int reg)
{
if (reg >= 0 && reg <= 9)
{
return reg;
}
else if (reg >= 11 && reg <= 18)
{
return reg - 11 + I387_ST0_REGNUM;
}
else if (reg >= 21)
{
return i386_dbx_reg_to_regnum (reg);
}
return NUM_REGS + NUM_PSEUDO_REGS;
}
#undef I387_ST0_REGNUM
#undef I387_MM0_REGNUM
#undef I387_NUM_XMM_REGS
static const char att_flavor[] = "att";
static const char intel_flavor[] = "intel";
static const char *valid_flavors[] =
{
att_flavor,
intel_flavor,
NULL
};
static const char *disassembly_flavor = att_flavor;
static const gdb_byte *
i386_breakpoint_from_pc (CORE_ADDR *pc, int *len)
{
static gdb_byte break_insn[] = { 0xcc };
*len = sizeof (break_insn);
return break_insn;
}
#ifdef I386_REGNO_TO_SYMMETRY
#error "The Sequent Symmetry is no longer supported."
#endif
#define I386_NUM_SAVED_REGS I386_NUM_GREGS
struct i386_frame_cache
{
CORE_ADDR base;
LONGEST sp_offset;
CORE_ADDR pc;
CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
CORE_ADDR saved_sp;
int pc_in_eax;
long locals;
};
static struct i386_frame_cache *
i386_alloc_frame_cache (void)
{
struct i386_frame_cache *cache;
int i;
cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
cache->base = 0;
cache->sp_offset = -4;
cache->pc = 0;
for (i = 0; i < I386_NUM_SAVED_REGS; i++)
cache->saved_regs[i] = -1;
cache->saved_sp = 0;
cache->pc_in_eax = 0;
cache->locals = -1;
return cache;
}
static CORE_ADDR
i386_follow_jump (CORE_ADDR pc)
{
gdb_byte op;
long delta = 0;
int data16 = 0;
unsigned long pc_32 = (unsigned long) pc;
if (macosx_skip_trampoline_code (pc) != 0)
return pc;
op = read_memory_unsigned_integer (pc, 1);
if (op == 0x66)
{
data16 = 1;
op = read_memory_unsigned_integer (pc + 1, 1);
}
switch (op)
{
case 0xe9:
if (data16)
{
delta = read_memory_integer (pc + 2, 2);
delta += 4;
}
else
{
delta = read_memory_integer (pc + 1, 4);
delta += 5;
}
break;
case 0xeb:
delta = read_memory_integer (pc + data16 + 1, 1);
delta += data16 + 2;
break;
}
pc_32 += delta;
return (CORE_ADDR) pc_32;
}
static CORE_ADDR
i386_analyze_struct_return (CORE_ADDR pc, CORE_ADDR current_pc,
struct i386_frame_cache *cache)
{
static gdb_byte proto1[3] = { 0x87, 0x04, 0x24 };
static gdb_byte proto2[4] = { 0x87, 0x44, 0x24, 0x00 };
gdb_byte buf[4];
gdb_byte op;
if (current_pc <= pc)
return pc;
op = read_memory_unsigned_integer (pc, 1);
if (op != 0x58)
return pc;
read_memory (pc + 1, buf, 4);
if (memcmp (buf, proto1, 3) != 0 && memcmp (buf, proto2, 4) != 0)
return pc;
if (current_pc == pc)
{
cache->sp_offset += 4;
return current_pc;
}
if (current_pc == pc + 1)
{
cache->pc_in_eax = 1;
return current_pc;
}
if (buf[1] == proto1[1])
return pc + 4;
else
return pc + 5;
}
static CORE_ADDR
i386_skip_probe (CORE_ADDR pc)
{
gdb_byte buf[8];
gdb_byte op;
op = read_memory_unsigned_integer (pc, 1);
if (op == 0x68 || op == 0x6a)
{
int delta;
if (op == 0x68)
delta = 5;
else
delta = 2;
read_memory (pc + delta, buf, sizeof (buf));
if (buf[0] == 0xe8 && buf[6] == 0xc4 && buf[7] == 0x4)
pc += delta + sizeof (buf);
}
return pc;
}
#define I386_MAX_INSN_LEN 7
struct i386_insn
{
size_t len;
unsigned char insn[I386_MAX_INSN_LEN];
unsigned char mask[I386_MAX_INSN_LEN];
};
static struct i386_insn *
i386_match_insn (CORE_ADDR pc, struct i386_insn *skip_insns,
int avoid_prologue_insns)
{
struct i386_insn *insn;
unsigned char op;
op = read_memory_unsigned_integer (pc, 1);
if (avoid_prologue_insns && (op == 0x55 || op == 0x6a))
return NULL;
for (insn = skip_insns; insn->len > 0; insn++)
{
if ((op & insn->mask[0]) == insn->insn[0])
{
gdb_byte buf[I386_MAX_INSN_LEN - 1];
int insn_matched = 1;
size_t i;
if (insn->len == 1)
return insn;
gdb_assert (insn->len > 1);
gdb_assert (insn->len <= I386_MAX_INSN_LEN);
read_memory (pc + 1, buf, insn->len - 1);
if (avoid_prologue_insns && insn->len == 2
&& (op == 0x89 && buf[0] == 0xe5))
continue;
insn_matched = 1;
for (i = 1; i < insn->len; i++)
{
if ((buf[i - 1] & insn->mask[i]) != insn->insn[i])
insn_matched = 0;
}
if (insn_matched)
return insn;
}
}
return NULL;
}
struct i386_insn i386_frame_setup_skip_insns[] =
{
{ 2, { 0xb0, 0x00 }, { 0xfa, 0x00 } },
{ 2, { 0xb2, 0x00 }, { 0xfb, 0x00 } },
{ 5, { 0xb8 }, { 0xfe } },
{ 5, { 0xba }, { 0xff } },
{ 5, { 0xa1 }, { 0xff } },
{ 6, { 0x89, 0x05 }, {0xff, 0xf7 } },
{ 6, { 0x89, 0x15 }, {0xff, 0xff } },
{ 2, { 0x01, 0xd0 }, { 0xff, 0xd0 } },
{ 3, { 0x0f, 0x57 }, { 0xff, 0xff } },
{ 3, { 0x0f, 0xb6, 0xc0 }, { 0xff, 0xff, 0xc0 } },
{ 3, { 0x0f, 0xb7, 0xc0 }, { 0xff, 0xff, 0xc0 } },
{ 5, { 0x25 }, { 0xff } },
{ 2, { 0x31, 0xc0 }, { 0xff, 0xc0 } },
{ 1, { 0x40 }, { 0xf8 } },
{ 1, { 0x48 }, { 0xf8 } },
{ 1, { 0x50 }, { 0xf8 } },
{ 1, { 0x58 }, { 0xf8 } },
{ 4, { 0x66, 0xb8 }, { 0xff, 0xf8 } },
{ 2, { 0x74 }, { 0xff } },
{ 3, { 0x80, 0x38 }, { 0xff, 0xf8 } },
{ 6, { 0x81, 0xe0 }, { 0xff, 0xf8 } },
{ 6, { 0x81, 0xc0 }, { 0xff, 0xf8 } },
{ 7, { 0x83, 0x3d }, { 0xff, 0xff } },
{ 3, { 0x83, 0xc0 }, { 0xff, 0xf8 } },
{ 3, { 0x83, 0xc8 }, { 0xff, 0xf8 } },
{ 3, { 0x83, 0xe0 }, { 0xff, 0xf8 } },
{ 3, { 0x83, 0xe8 }, { 0xff, 0xf8 } },
{ 3, { 0x83, 0xf8 }, { 0xff, 0xf8 } },
{ 2, { 0x85, 0xc0 }, { 0xff, 0xc0 } },
{ 2, { 0x89, 0x00 }, { 0xff, 0xf8 } },
{ 2, { 0x89, 0x10 }, { 0xff, 0xf8 } },
{ 2, { 0x89, 0xc0 }, { 0xff, 0xc0 } },
{ 3, { 0x8b, 0x40 }, { 0xff, 0xf8 } },
{ 6, { 0x8b, 0x80 }, { 0xff, 0xf8 } },
{ 6, { 0x8b, 0x90 }, { 0xff, 0xf8 } },
{ 3, { 0x8d, 0x48 }, { 0xff, 0xf8 } },
{ 6, { 0x8d, 0x90 }, { 0xff, 0xf8 } },
{ 1, { 0x90 }, { 0xff } },
{ 5, { 0xa9 }, { 0xff } },
{ 3, { 0xc1, 0xe0 }, { 0xff, 0xf8 } },
{ 3, { 0xc1, 0xf8 }, { 0xff, 0xf8 } },
{ 3, { 0xc6, 0x00 }, { 0xff, 0xf8 } },
{ 2, { 0xd9, 0xee }, { 0xff, 0xff } },
{ 5, { 0xe8 }, { 0xff } },
{ 2, { 0xeb }, { 0xff } },
{ 2, { 0xf7, 0xf0 }, { 0xff, 0xf8 } },
{ 1, { 0xfc }, { 0xff } },
{ 6, { 0xff, 0xb0 }, { 0xff, 0xf8 } },
{ 2, { 0xff, 0xe0 }, { 0xff, 0xf8 } },
{ 2, { 0x29, 0xc0 }, { 0xfd, 0xff } },
{ 2, { 0x29, 0xc9 }, { 0xfd, 0xff } },
{ 2, { 0x29, 0xd2 }, { 0xfd, 0xff } },
{ 2, { 0x31, 0xc0 }, { 0xfd, 0xff } },
{ 2, { 0x31, 0xc9 }, { 0xfd, 0xff } },
{ 2, { 0x31, 0xd2 }, { 0xfd, 0xff } },
{ 0 }
};
static CORE_ADDR
i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR limit,
struct i386_frame_cache *cache)
{
struct i386_insn *insn;
gdb_byte op;
int skip = 0;
CORE_ADDR end_of_frame_setup = pc;
if (limit <= pc)
return limit;
op = read_memory_unsigned_integer (pc + skip, 1);
while (op != 0x55
&& (op != 0x6a || read_memory_unsigned_integer (pc + skip + 1, 1) != 0)
&& pc + skip <= limit)
{
insn = i386_match_insn (pc + skip, i386_frame_setup_skip_insns, 1);
if (insn)
{
skip += insn->len;
op = read_memory_unsigned_integer (pc + skip, 1);
}
else
break;
}
pc = pc + skip;
skip = 0;
if (limit <= pc)
return end_of_frame_setup;
if (op == 0x55 || op == 0x6a)
{
cache->saved_regs[I386_EBP_REGNUM] = 0;
cache->sp_offset += 4;
if (op == 0x6a)
pc += 2;
else
pc++;
end_of_frame_setup = pc;
if (limit <= pc)
return end_of_frame_setup;
while (pc + skip < limit)
{
insn = i386_match_insn (pc + skip, i386_frame_setup_skip_insns, 1);
if (insn == NULL)
break;
skip += insn->len;
}
if (limit <= pc + skip)
return end_of_frame_setup;
op = read_memory_unsigned_integer (pc + skip, 1);
switch (op)
{
case 0x8b:
if (read_memory_unsigned_integer (pc + skip + 1, 1) != 0xec)
return end_of_frame_setup;
break;
case 0x89:
if (read_memory_unsigned_integer (pc + skip + 1, 1) != 0xe5)
return end_of_frame_setup;
break;
default:
return end_of_frame_setup;
}
cache->locals = 0;
pc += (skip + 2);
end_of_frame_setup = pc;
if (limit <= pc)
return end_of_frame_setup;
op = read_memory_unsigned_integer (pc, 1);
if (op == 0x83)
{
if (read_memory_unsigned_integer (pc + 1, 1) != 0xec)
return pc;
cache->locals = read_memory_integer (pc + 2, 1);
end_of_frame_setup = pc + 3;
return end_of_frame_setup;
}
else if (op == 0x81)
{
if (read_memory_unsigned_integer (pc + 1, 1) != 0xec)
return end_of_frame_setup;
cache->locals = read_memory_integer (pc + 2, 4);
end_of_frame_setup = pc + 6;
return end_of_frame_setup;
}
else
{
return end_of_frame_setup;
}
}
else if (op == 0xc8)
{
cache->locals = read_memory_unsigned_integer (pc + 1, 2);
end_of_frame_setup = pc + 4;
return end_of_frame_setup;
}
return end_of_frame_setup;
}
struct i386_insn i386_frame_setup_insns[] =
{
{ 1, { 0x50 }, { 0xf8 } },
{ 2, { 0x89, 0xe5 }, { 0xff, 0xff } },
{ 2, { 0x8b, 0xec }, { 0xff, 0xff } },
{ 3, { 0x83, 0xec }, { 0xff, 0xff } },
{ 6, { 0x81, 0xec }, { 0xff, 0xff } },
{ 4, { 0xc8 }, { 0xff} },
{ 0 }
};
int
i386_find_picbase_setup (CORE_ADDR pc, CORE_ADDR *picbase_addr,
enum i386_regnum *picbase_reg)
{
int limit = 32;
int skip = 0;
struct i386_insn *insn;
int found_call_insn = 0;
unsigned char op;
if (picbase_addr != NULL)
*picbase_addr = -1;
while (skip < limit)
{
insn = i386_match_insn (pc + skip, i386_frame_setup_insns, 0);
if (insn)
{
skip += insn->len;
continue;
}
insn = i386_match_insn (pc + skip, i386_frame_setup_skip_insns, 1);
if (insn == NULL)
{
break;
}
if (insn->insn[0] == 0xe8 && insn->len == 5)
{
found_call_insn = 1;
break;
}
skip += insn->len;
}
if (!found_call_insn)
return 0;
uint32_t rel32 = read_memory_unsigned_integer (pc + skip + 1, 4);
uint32_t offset_from = pc + skip + 5;
struct minimal_symbol *dest;
if (rel32 == 0x0)
{
op = read_memory_unsigned_integer (offset_from, 1);
if ((op & 0xf8) != 0x58)
return 0;
if (picbase_addr != NULL)
*picbase_addr = offset_from;
if (picbase_reg != NULL)
*picbase_reg = (enum i386_regnum) op | 0x7;
return 1;
}
dest = lookup_minimal_symbol_by_pc ((uint32_t) rel32 + offset_from);
if (dest == NULL || SYMBOL_LINKAGE_NAME (dest) == NULL)
return 0;
if (strcmp (SYMBOL_LINKAGE_NAME (dest), "__i686.get_pc_thunk.ax") == 0)
{
if (picbase_addr != NULL)
*picbase_addr = offset_from;
if (picbase_reg != NULL)
*picbase_reg = I386_EAX_REGNUM;
return 1;
}
if (strcmp (SYMBOL_LINKAGE_NAME (dest), "__i686.get_pc_thunk.bx") == 0)
{
if (picbase_addr != NULL)
*picbase_addr = offset_from;
if (picbase_reg != NULL)
*picbase_reg = I386_EBX_REGNUM;
return 1;
}
if (strcmp (SYMBOL_LINKAGE_NAME (dest), "__i686.get_pc_thunk.cx") == 0)
{
if (picbase_addr != NULL)
*picbase_addr = offset_from;
if (picbase_reg != NULL)
*picbase_reg = I386_ECX_REGNUM;
return 1;
}
if (strcmp (SYMBOL_LINKAGE_NAME (dest), "__i686.get_pc_thunk.dx") == 0)
{
if (picbase_addr != NULL)
*picbase_addr = offset_from;
if (picbase_reg != NULL)
*picbase_reg = I386_EDX_REGNUM;
return 1;
}
return 0;
}
static int
i386_find_esp_adjustments (CORE_ADDR pc, CORE_ADDR current_pc)
{
unsigned char op, next_op;
int esp_change = 0;
struct i386_insn *insn;
if (pc == current_pc)
return esp_change;
while (pc < current_pc)
{
op = read_memory_unsigned_integer (pc, 1);
next_op = read_memory_unsigned_integer (pc + 1, 1);
if (op == 0x55)
return esp_change;
if (op == 0xc3)
return esp_change;
if ((op & 0xf8) == 0x50)
{
esp_change -= 4;
pc += 1;
continue;
}
if ((op & 0xf8) == 0x58)
{
esp_change += 4;
pc += 1;
continue;
}
if (op == 0x83 && next_op == 0xec)
{
uint8_t imm8 = read_memory_integer (pc + 2, 1);
esp_change -= imm8;
pc += 3;
continue;
}
if (op == 0x81 && next_op == 0xec)
{
uint32_t imm32 = read_memory_integer (pc + 2, 4);
esp_change -= imm32;
pc += 6;
continue;
}
if (op == 0x83 && next_op == 0xc4)
{
uint8_t imm8 = read_memory_integer (pc + 2, 1);
esp_change += imm8;
pc += 3;
continue;
}
if (op == 0x81 && next_op == 0xc4)
{
uint32_t imm32 = read_memory_integer (pc + 2, 4);
esp_change += imm32;
pc += 6;
continue;
}
insn = i386_match_insn (pc, i386_frame_setup_skip_insns, 1);
if (insn)
pc += insn->len;
else
return esp_change;
}
return esp_change;
}
static CORE_ADDR
i386_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
struct i386_frame_cache *cache)
{
CORE_ADDR offset = 0;
gdb_byte op;
int i;
if (cache->locals > 0)
offset -= cache->locals;
for (i = 0; i < 8 && pc < current_pc; i++)
{
op = read_memory_unsigned_integer (pc, 1);
if (op < 0x50 || op > 0x57)
break;
offset -= 4;
cache->saved_regs[op - 0x50] = offset;
cache->sp_offset += 4;
pc++;
}
return pc;
}
static int
i386_frame_num_args (struct frame_info *fi)
{
#if 1
return -1;
#else
int retpc;
unsigned char op;
struct frame_info *pfi;
int frameless;
frameless = FRAMELESS_FUNCTION_INVOCATION (fi);
if (frameless)
return -1;
pfi = get_prev_frame (fi);
if (pfi == 0)
{
return -1;
}
else
{
retpc = pfi->pc;
op = read_memory_integer (retpc, 1);
if (op == 0x59)
return 1;
else if (op == 0x83)
{
op = read_memory_integer (retpc + 1, 1);
if (op == 0xc4)
return (read_memory_integer (retpc + 2, 1) & 0xff) / 4;
else
return 0;
}
else if (op == 0x81)
{
op = read_memory_integer (retpc + 1, 1);
if (op == 0xc4)
return read_memory_integer (retpc + 2, 4) / 4;
else
return 0;
}
else
{
return 0;
}
}
#endif
}
static CORE_ADDR
i386_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
struct i386_frame_cache *cache)
{
pc = i386_follow_jump (pc);
pc = i386_analyze_struct_return (pc, current_pc, cache);
pc = i386_skip_probe (pc);
pc = i386_analyze_frame_setup (pc, current_pc, cache);
return i386_analyze_register_saves (pc, current_pc, cache);
}
static CORE_ADDR
i386_skip_prologue (CORE_ADDR start_pc)
{
static gdb_byte pic_pat[6] =
{
0xe8, 0, 0, 0, 0,
0x5b,
};
struct i386_frame_cache cache;
CORE_ADDR pc;
gdb_byte op;
int i;
cache.locals = -1;
pc = i386_analyze_prologue (start_pc, 0xffffffff, &cache);
if (cache.locals < 0)
return start_pc;
for (i = 0; i < 6; i++)
{
op = read_memory_unsigned_integer (pc + i, 1);
if (pic_pat[i] != op)
break;
}
if (i == 6)
{
int delta = 6;
op = read_memory_unsigned_integer (pc + delta, 1);
if (op == 0x89)
{
op = read_memory_unsigned_integer (pc + delta + 1, 1);
if (op == 0x5d)
delta += 3;
else if (op == 0x9d)
delta += 6;
else
delta = 0;
op = read_memory_unsigned_integer (pc + delta, 1);
}
if (delta > 0 && op == 0x81
&& read_memory_unsigned_integer (pc + delta + 1, 1) == 0xc3)
{
pc += delta + 6;
}
}
if (i386_follow_jump (start_pc) != start_pc)
pc = i386_follow_jump (pc);
return pc;
}
static CORE_ADDR
i386_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
gdb_byte buf[8];
frame_unwind_register (next_frame, PC_REGNUM, buf);
return extract_typed_address (buf, builtin_type_void_func_ptr);
}
static struct i386_frame_cache *
i386_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct i386_frame_cache *cache;
gdb_byte buf[4];
int i;
int potentially_frameless;
CORE_ADDR prologue_parsed_to = 0;
CORE_ADDR current_pc;
potentially_frameless = frame_relative_level (next_frame) == -1
|| get_frame_type (next_frame) == SIGTRAMP_FRAME;
if (*this_cache)
return *this_cache;
cache = i386_alloc_frame_cache ();
*this_cache = cache;
cache->saved_regs[I386_EIP_REGNUM] = 4;
cache->saved_regs[I386_EBP_REGNUM] = 0;
frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 4);
if (cache->base == 0)
return cache;
cache->pc = frame_func_unwind (next_frame);
current_pc = frame_pc_unwind (next_frame);
if (cache->pc != 0)
prologue_parsed_to = i386_analyze_prologue (cache->pc, current_pc, cache);
if ((cache->pc != 0 || current_pc == 0)
&& prologue_parsed_to == cache->pc
&& potentially_frameless)
{
int esp_offset;
CORE_ADDR actual_frame_base;
esp_offset = i386_find_esp_adjustments (cache->pc, current_pc);
frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
actual_frame_base = extract_unsigned_integer (buf, 4) - esp_offset;
cache->base = extract_unsigned_integer (buf, 4);
cache->saved_sp = actual_frame_base + 4;
cache->saved_regs[I386_EBP_REGNUM] = -1;
cache->saved_regs[I386_EIP_REGNUM] = 0;
for (i = 0; i < I386_NUM_SAVED_REGS; i++)
if (cache->saved_regs[i] != -1)
cache->saved_regs[i] += actual_frame_base;
return cache;
}
if (cache->locals < 0 && potentially_frameless)
{
frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
}
cache->saved_sp = cache->base + 8;
for (i = 0; i < I386_NUM_SAVED_REGS; i++)
if (cache->saved_regs[i] != -1)
cache->saved_regs[i] += cache->base;
return cache;
}
static void
i386_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
if (cache->base == 0)
{
*this_id = null_frame_id;
return;
}
else
{
ULONGEST prev_frame_addr = 0;
if (safe_read_memory_unsigned_integer
(cache->base, TARGET_PTR_BIT / 8, &prev_frame_addr))
{
if (prev_frame_addr == 0)
{
*this_id = null_frame_id;
return;
}
}
}
(*this_id) = frame_id_build (cache->base + 8, cache->pc);
}
static void
i386_frame_prev_register (struct frame_info *next_frame, void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
gdb_assert (regnum >= 0);
if (regnum == I386_EFLAGS_REGNUM)
{
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
ULONGEST val;
val = frame_unwind_register_unsigned (next_frame,
I386_EFLAGS_REGNUM);
val &= ~(1 << 10);
store_unsigned_integer (valuep, 4, val);
}
return;
}
if (regnum == I386_EIP_REGNUM && cache->pc_in_eax)
{
*optimizedp = 0;
*lvalp = lval_register;
*addrp = 0;
*realnump = I386_EAX_REGNUM;
if (valuep)
frame_unwind_register (next_frame, (*realnump), valuep);
return;
}
if (regnum == I386_ESP_REGNUM && cache->saved_sp)
{
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (valuep)
{
store_unsigned_integer (valuep, 4, cache->saved_sp);
}
return;
}
if (regnum < I386_NUM_SAVED_REGS && cache->saved_regs[regnum] != -1)
{
*optimizedp = 0;
*lvalp = lval_memory;
*addrp = cache->saved_regs[regnum];
*realnump = -1;
if (valuep)
{
read_memory (*addrp, valuep,
register_size (current_gdbarch, regnum));
}
return;
}
*optimizedp = 0;
*lvalp = lval_register;
*addrp = 0;
*realnump = regnum;
if (valuep)
frame_unwind_register (next_frame, (*realnump), valuep);
}
static const struct frame_unwind i386_frame_unwind =
{
NORMAL_FRAME,
i386_frame_this_id,
i386_frame_prev_register
};
static const struct frame_unwind *
i386_frame_sniffer (struct frame_info *next_frame)
{
return &i386_frame_unwind;
}
static struct i386_frame_cache *
i386_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache)
{
struct i386_frame_cache *cache;
struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
CORE_ADDR addr;
gdb_byte buf[4];
if (*this_cache)
return *this_cache;
cache = i386_alloc_frame_cache ();
frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
cache->base = extract_unsigned_integer (buf, 4) - 4;
addr = tdep->sigcontext_addr (next_frame);
if (tdep->sc_reg_offset)
{
int i;
gdb_assert (tdep->sc_num_regs <= I386_NUM_SAVED_REGS);
for (i = 0; i < tdep->sc_num_regs; i++)
if (tdep->sc_reg_offset[i] != -1)
cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
}
else
{
cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
}
*this_cache = cache;
return cache;
}
static void
i386_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
struct i386_frame_cache *cache =
i386_sigtramp_frame_cache (next_frame, this_cache);
(*this_id) = frame_id_build (cache->base + 8, frame_pc_unwind (next_frame));
}
static void
i386_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep)
{
i386_sigtramp_frame_cache (next_frame, this_cache);
i386_frame_prev_register (next_frame, this_cache, regnum,
optimizedp, lvalp, addrp, realnump, valuep);
}
static const struct frame_unwind i386_sigtramp_frame_unwind =
{
SIGTRAMP_FRAME,
i386_sigtramp_frame_this_id,
i386_sigtramp_frame_prev_register
};
static const struct frame_unwind *
i386_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
if (tdep->sigcontext_addr == NULL)
return NULL;
if (tdep->sigtramp_p != NULL)
{
if (tdep->sigtramp_p (next_frame))
return &i386_sigtramp_frame_unwind;
}
if (tdep->sigtramp_start != 0)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
gdb_assert (tdep->sigtramp_end != 0);
if (pc >= tdep->sigtramp_start && pc < tdep->sigtramp_end)
return &i386_sigtramp_frame_unwind;
}
return NULL;
}
static CORE_ADDR
i386_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
return cache->base;
}
static const struct frame_base i386_frame_base =
{
&i386_frame_unwind,
i386_frame_base_address,
i386_frame_base_address,
i386_frame_base_address
};
static struct frame_id
i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
gdb_byte buf[4];
CORE_ADDR fp;
frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
fp = extract_unsigned_integer (buf, 4);
return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
}
static int
i386_get_longjmp_target (CORE_ADDR *pc)
{
gdb_byte buf[8];
CORE_ADDR sp, jb_addr;
int jb_pc_offset = gdbarch_tdep (current_gdbarch)->jb_pc_offset;
int len = TYPE_LENGTH (builtin_type_void_func_ptr);
if (jb_pc_offset == -1)
return 0;
regcache_cooked_read (current_regcache, SP_REGNUM, buf);
sp = extract_typed_address (buf, builtin_type_void_data_ptr);
if (target_read_memory (sp + len, buf, len))
return 0;
jb_addr = extract_typed_address (buf, builtin_type_void_data_ptr);
if (target_read_memory (jb_addr + jb_pc_offset, buf, len))
return 0;
*pc = extract_typed_address (buf, builtin_type_void_func_ptr);
return 1;
}
static CORE_ADDR
i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
gdb_byte buf[4];
int i;
int argument_bytes = 0;
int alignment_pad_bytes;
for (i = nargs - 1; i >= 0; i--)
{
int len = TYPE_LENGTH (value_enclosing_type (args[i]));
argument_bytes += (len + 3) & ~3;
}
if (struct_return)
argument_bytes += 4;
alignment_pad_bytes = (sp - argument_bytes) - ((sp - argument_bytes) & ~15);
sp -= alignment_pad_bytes;
for (i = nargs - 1; i >= 0; i--)
{
int len = TYPE_LENGTH (value_enclosing_type (args[i]));
sp -= (len + 3) & ~3;
write_memory (sp, value_contents_all (args[i]), len);
}
if (struct_return)
{
sp -= 4;
store_unsigned_integer (buf, 4, struct_addr);
write_memory (sp, buf, 4);
}
sp -= 4;
store_unsigned_integer (buf, 4, bp_addr);
write_memory (sp, buf, 4);
store_unsigned_integer (buf, 4, sp);
regcache_cooked_write (regcache, I386_ESP_REGNUM, buf);
#if 0
regcache_cooked_write (regcache, I386_EBP_REGNUM, buf);
#endif
return read_register (I386_EBP_REGNUM) + 8;
}
#define LOW_RETURN_REGNUM I386_EAX_REGNUM
#define HIGH_RETURN_REGNUM I386_EDX_REGNUM
static void
i386_extract_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, gdb_byte *valbuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int len = TYPE_LENGTH (type);
gdb_byte buf[I386_MAX_REGISTER_SIZE];
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
if (tdep->st0_regnum < 0)
{
warning (_("Cannot find floating-point return value."));
memset (valbuf, 0, len);
return;
}
regcache_raw_read (regcache, I386_ST0_REGNUM, buf);
convert_typed_floating (buf, builtin_type_i387_ext, valbuf, type);
}
else
{
int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
if (len <= low_size)
{
regcache_raw_read (regcache, LOW_RETURN_REGNUM, buf);
memcpy (valbuf, buf, len);
}
else if (len <= (low_size + high_size))
{
regcache_raw_read (regcache, LOW_RETURN_REGNUM, buf);
memcpy (valbuf, buf, low_size);
regcache_raw_read (regcache, HIGH_RETURN_REGNUM, buf);
memcpy (valbuf + low_size, buf, len - low_size);
}
else
internal_error (__FILE__, __LINE__,
_("Cannot extract return value of %d bytes long."), len);
}
}
static void
i386_store_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, const gdb_byte *valbuf)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int len = TYPE_LENGTH (type);
#define I387_ST0_REGNUM I386_ST0_REGNUM
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
ULONGEST fstat;
gdb_byte buf[I386_MAX_REGISTER_SIZE];
if (tdep->st0_regnum < 0)
{
warning (_("Cannot set floating-point return value."));
return;
}
convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext);
regcache_raw_write (regcache, I386_ST0_REGNUM, buf);
regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
fstat |= (7 << 11);
regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
}
else
{
int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
if (len <= low_size)
regcache_raw_write_part (regcache, LOW_RETURN_REGNUM, 0, len, valbuf);
else if (len <= (low_size + high_size))
{
regcache_raw_write (regcache, LOW_RETURN_REGNUM, valbuf);
regcache_raw_write_part (regcache, HIGH_RETURN_REGNUM, 0,
len - low_size, valbuf + low_size);
}
else
internal_error (__FILE__, __LINE__,
_("Cannot store return value of %d bytes long."), len);
}
#undef I387_ST0_REGNUM
}
static const char default_struct_convention[] = "default";
static const char pcc_struct_convention[] = "pcc";
static const char reg_struct_convention[] = "reg";
static const char *valid_conventions[] =
{
default_struct_convention,
pcc_struct_convention,
reg_struct_convention,
NULL
};
static const char *struct_convention = default_struct_convention;
static int
i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum type_code code = TYPE_CODE (type);
int len = TYPE_LENGTH (type);
gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION);
if (struct_convention == pcc_struct_convention
|| (struct_convention == default_struct_convention
&& tdep->struct_return == pcc_struct_return))
return 0;
if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
{
type = check_typedef (TYPE_FIELD_TYPE (type, 0));
if (TYPE_CODE (type) == TYPE_CODE_FLT)
return (len == 4 || len == 8 || len == 12);
}
return (len == 1 || len == 2 || len == 4 || len == 8);
}
static enum return_value_convention
i386_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, gdb_byte *readbuf,
const gdb_byte *writebuf)
{
enum type_code code = TYPE_CODE (type);
if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
&& !i386_reg_struct_return_p (gdbarch, type))
{
if (readbuf)
{
ULONGEST addr;
regcache_raw_read_unsigned (regcache, I386_EAX_REGNUM, &addr);
read_memory (addr, readbuf, TYPE_LENGTH (type));
}
return RETURN_VALUE_ABI_RETURNS_ADDRESS;
}
if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
{
type = check_typedef (TYPE_FIELD_TYPE (type, 0));
return i386_return_value (gdbarch, type, regcache, readbuf, writebuf);
}
if (readbuf)
i386_extract_return_value (gdbarch, type, regcache, readbuf);
if (writebuf)
i386_store_return_value (gdbarch, type, regcache, writebuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
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;
}
static 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;
}
static struct type *i386_mmx_type;
static struct type *i386_sse_type;
static struct type *
i386_build_mmx_type (void)
{
#if 0
union __gdb_builtin_type_vec64i
{
int64_t uint64;
int32_t v2_int32[2];
int16_t v4_int16[4];
int8_t v8_int8[8];
};
#endif
if (! i386_mmx_type)
{
struct type *t;
t = init_composite_type ("__gdb_builtin_type_vec64i", TYPE_CODE_UNION);
append_composite_type_field (t, "uint64", builtin_type_int64);
append_composite_type_field (t, "v2_int32", builtin_type_v2_int32);
append_composite_type_field (t, "v4_int16", builtin_type_v4_int16);
append_composite_type_field (t, "v8_int8", builtin_type_v8_int8);
TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
TYPE_NAME (t) = "builtin_type_vec64i";
i386_mmx_type = t;
}
return i386_mmx_type;
}
static struct type *
i386_build_sse_type (void)
{
if (! i386_sse_type)
{
struct type *t;
t = init_composite_type ("__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
append_composite_type_field (t, "v4_float", builtin_type_v4_float);
append_composite_type_field (t, "v2_double", builtin_type_v2_double);
append_composite_type_field (t, "v16_int8", builtin_type_v16_int8);
append_composite_type_field (t, "v8_int16", builtin_type_v8_int16);
append_composite_type_field (t, "v4_int32", builtin_type_v4_int32);
append_composite_type_field (t, "v2_int64", builtin_type_v2_int64);
append_composite_type_field (t, "uint128", builtin_type_int128);
TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
TYPE_NAME (t) = "builtin_type_vec128i";
i386_sse_type = t;
}
return i386_sse_type;
}
static struct type *
i386_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum == I386_EIP_REGNUM)
return builtin_type_void_func_ptr;
if (regnum == I386_EBP_REGNUM || regnum == I386_ESP_REGNUM)
return builtin_type_void_data_ptr;
if (i386_fp_regnum_p (regnum))
return builtin_type_i387_ext;
if (i386_sse_regnum_p (gdbarch, regnum))
return builtin_type_vec128i_big;
if (i386_mmx_regnum_p (gdbarch, regnum))
return i386_build_mmx_type ();
return builtin_type_int;
}
static int
i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
int mmxreg, fpreg;
ULONGEST fstat;
int tos;
#define I387_ST0_REGNUM tdep->st0_regnum
mmxreg = regnum - tdep->mm0_regnum;
regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
tos = (fstat >> 11) & 0x7;
fpreg = (mmxreg + tos) % 8;
return (I387_ST0_REGNUM + fpreg);
#undef I387_ST0_REGNUM
}
static void
i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, gdb_byte *buf)
{
if (i386_mmx_regnum_p (gdbarch, regnum))
{
gdb_byte mmx_buf[MAX_REGISTER_SIZE];
int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
regcache_raw_read (regcache, fpnum, mmx_buf);
memcpy (buf, mmx_buf, register_size (gdbarch, regnum));
}
else
regcache_raw_read (regcache, regnum, buf);
}
static void
i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, const gdb_byte *buf)
{
if (i386_mmx_regnum_p (gdbarch, regnum))
{
gdb_byte mmx_buf[MAX_REGISTER_SIZE];
int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
regcache_raw_read (regcache, fpnum, mmx_buf);
memcpy (mmx_buf, buf, register_size (gdbarch, regnum));
regcache_raw_write (regcache, fpnum, mmx_buf);
}
else
regcache_raw_write (regcache, regnum, buf);
}
static int
i386_next_regnum (int regnum)
{
static int next_regnum[] =
{
I386_EDX_REGNUM,
I386_EBX_REGNUM,
I386_ECX_REGNUM,
I386_ESI_REGNUM,
-1, -1,
I386_EDI_REGNUM,
I386_EBP_REGNUM
};
if (regnum >= 0 && regnum < sizeof (next_regnum) / sizeof (next_regnum[0]))
return next_regnum[regnum];
return -1;
}
static int
i386_convert_register_p (int regnum, struct type *type)
{
int len = TYPE_LENGTH (type);
if (len > 4 && len % 4 == 0)
{
int last_regnum = regnum;
while (len > 4)
{
last_regnum = i386_next_regnum (last_regnum);
len -= 4;
}
if (last_regnum != -1)
return 1;
}
return i386_fp_regnum_p (regnum);
}
static void
i386_register_to_value (struct frame_info *frame, int regnum,
struct type *type, gdb_byte *to)
{
int len = TYPE_LENGTH (type);
if (i386_fp_regnum_p (regnum))
{
i387_register_to_value (frame, regnum, type, to);
return;
}
gdb_assert (len > 4 && len % 4 == 0);
while (len > 0)
{
gdb_assert (regnum != -1);
gdb_assert (register_size (current_gdbarch, regnum) == 4);
get_frame_register (frame, regnum, to);
regnum = i386_next_regnum (regnum);
len -= 4;
to += 4;
}
}
static void
i386_value_to_register (struct frame_info *frame, int regnum,
struct type *type, const gdb_byte *from)
{
int len = TYPE_LENGTH (type);
if (i386_fp_regnum_p (regnum))
{
i387_value_to_register (frame, regnum, type, from);
return;
}
gdb_assert (len > 4 && len % 4 == 0);
while (len > 0)
{
gdb_assert (regnum != -1);
gdb_assert (register_size (current_gdbarch, regnum) == 4);
put_frame_register (frame, regnum, from);
regnum = i386_next_regnum (regnum);
len -= 4;
from += 4;
}
}
void
i386_supply_gregset (const struct regset *regset, struct regcache *regcache,
int regnum, const void *gregs, size_t len)
{
const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
const gdb_byte *regs = gregs;
int i;
gdb_assert (len == tdep->sizeof_gregset);
for (i = 0; i < tdep->gregset_num_regs; i++)
{
if ((regnum == i || regnum == -1)
&& tdep->gregset_reg_offset[i] != -1)
regcache_raw_supply (regcache, i, regs + tdep->gregset_reg_offset[i]);
}
}
void
i386_collect_gregset (const struct regset *regset,
const struct regcache *regcache,
int regnum, void *gregs, size_t len)
{
const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
gdb_byte *regs = gregs;
int i;
gdb_assert (len == tdep->sizeof_gregset);
for (i = 0; i < tdep->gregset_num_regs; i++)
{
if ((regnum == i || regnum == -1)
&& tdep->gregset_reg_offset[i] != -1)
regcache_raw_collect (regcache, i, regs + tdep->gregset_reg_offset[i]);
}
}
static void
i386_supply_fpregset (const struct regset *regset, struct regcache *regcache,
int regnum, const void *fpregs, size_t len)
{
const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
if (len == I387_SIZEOF_FXSAVE)
{
i387_supply_fxsave (regcache, regnum, fpregs);
return;
}
gdb_assert (len == tdep->sizeof_fpregset);
i387_supply_fsave (regcache, regnum, fpregs);
}
static void
i386_collect_fpregset (const struct regset *regset,
const struct regcache *regcache,
int regnum, void *fpregs, size_t len)
{
const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
if (len == I387_SIZEOF_FXSAVE)
{
i387_collect_fxsave (regcache, regnum, fpregs);
return;
}
gdb_assert (len == tdep->sizeof_fpregset);
i387_collect_fsave (regcache, regnum, fpregs);
}
const struct regset *
i386_regset_from_core_section (struct gdbarch *gdbarch,
const char *sect_name, size_t sect_size)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
if (strcmp (sect_name, ".reg") == 0 && sect_size == tdep->sizeof_gregset)
{
if (tdep->gregset == NULL)
tdep->gregset = regset_alloc (gdbarch, i386_supply_gregset,
i386_collect_gregset);
return tdep->gregset;
}
if ((strcmp (sect_name, ".reg2") == 0 && sect_size == tdep->sizeof_fpregset)
|| (strcmp (sect_name, ".reg-xfp") == 0
&& sect_size == I387_SIZEOF_FXSAVE))
{
if (tdep->fpregset == NULL)
tdep->fpregset = regset_alloc (gdbarch, i386_supply_fpregset,
i386_collect_fpregset);
return tdep->fpregset;
}
return NULL;
}
#ifdef STATIC_TRANSFORM_NAME
char *
sunpro_static_transform_name (char *name)
{
char *p;
if (IS_STATIC_TRANSFORM_NAME (name))
{
p = strrchr (name, '.');
if (p != NULL)
name = p + 1;
}
return name;
}
#endif
CORE_ADDR
i386_pe_skip_trampoline_code (CORE_ADDR pc, char *name)
{
if (pc && read_memory_unsigned_integer (pc, 2) == 0x25ff)
{
unsigned long indirect = read_memory_unsigned_integer (pc + 2, 4);
struct minimal_symbol *indsym =
indirect ? lookup_minimal_symbol_by_pc (indirect) : 0;
char *symname = indsym ? SYMBOL_LINKAGE_NAME (indsym) : 0;
if (symname)
{
if (strncmp (symname, "__imp_", 6) == 0
|| strncmp (symname, "_imp_", 5) == 0)
return name ? 1 : read_memory_unsigned_integer (indirect, 4);
}
}
return 0;
}
static int
i386_sigtramp_p (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
return (name && strcmp ("_sigtramp", name) == 0);
}
static int
i386_print_insn (bfd_vma pc, struct disassemble_info *info)
{
gdb_assert (disassembly_flavor == att_flavor
|| disassembly_flavor == intel_flavor);
info->disassembler_options = (char *) disassembly_flavor;
info->mach = gdbarch_bfd_arch_info (current_gdbarch)->mach;
return print_insn_i386 (pc, info);
}
static int
i386_svr4_sigtramp_p (struct frame_info *next_frame)
{
CORE_ADDR pc = frame_pc_unwind (next_frame);
char *name;
find_pc_partial_function (pc, &name, NULL, NULL);
return (name && (strcmp ("_sigreturn", name) == 0
|| strcmp ("_sigacthandler", name) == 0
|| strcmp ("sigvechandler", name) == 0));
}
static CORE_ADDR
i386_svr4_sigcontext_addr (struct frame_info *next_frame)
{
gdb_byte buf[4];
CORE_ADDR sp;
frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
sp = extract_unsigned_integer (buf, 4);
return read_memory_unsigned_integer (sp + 8, 4);
}
void
i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
}
void
i386_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
i386_elf_init_abi (info, gdbarch);
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
tdep->sigtramp_p = i386_svr4_sigtramp_p;
tdep->sigcontext_addr = i386_svr4_sigcontext_addr;
tdep->sc_pc_offset = 36 + 14 * 4;
tdep->sc_sp_offset = 36 + 17 * 4;
tdep->jb_pc_offset = 20;
}
static void
i386_go32_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
tdep->sigtramp_p = NULL;
tdep->jb_pc_offset = 36;
}
static void
i386_nw_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
tdep->jb_pc_offset = 24;
}
static struct reggroup *i386_sse_reggroup;
static struct reggroup *i386_mmx_reggroup;
static void
i386_init_reggroups (void)
{
i386_sse_reggroup = reggroup_new ("sse", USER_REGGROUP);
i386_mmx_reggroup = reggroup_new ("mmx", USER_REGGROUP);
}
static void
i386_add_reggroups (struct gdbarch *gdbarch)
{
reggroup_add (gdbarch, i386_sse_reggroup);
reggroup_add (gdbarch, i386_mmx_reggroup);
reggroup_add (gdbarch, general_reggroup);
reggroup_add (gdbarch, float_reggroup);
reggroup_add (gdbarch, all_reggroup);
reggroup_add (gdbarch, save_reggroup);
reggroup_add (gdbarch, restore_reggroup);
reggroup_add (gdbarch, vector_reggroup);
reggroup_add (gdbarch, system_reggroup);
}
int
i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
int sse_regnum_p = (i386_sse_regnum_p (gdbarch, regnum)
|| i386_mxcsr_regnum_p (gdbarch, regnum));
int fp_regnum_p = (i386_fp_regnum_p (regnum)
|| i386_fpc_regnum_p (regnum));
int mmx_regnum_p = (i386_mmx_regnum_p (gdbarch, regnum));
if (group == i386_mmx_reggroup)
return mmx_regnum_p;
if (group == i386_sse_reggroup)
return sse_regnum_p;
if (group == vector_reggroup)
return (mmx_regnum_p || sse_regnum_p);
if (group == float_reggroup)
return fp_regnum_p;
if (group == general_reggroup)
return (!fp_regnum_p && !mmx_regnum_p && !sse_regnum_p);
return default_register_reggroup_p (gdbarch, regnum, group);
}
static CORE_ADDR
i386_fetch_pointer_argument (struct frame_info *frame, int argi,
struct type *type)
{
CORE_ADDR sp = get_frame_register_unsigned (frame, I386_ESP_REGNUM);
return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
}
static struct gdbarch *
i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
struct gdbarch_tdep *tdep;
struct gdbarch *gdbarch;
arches = gdbarch_list_lookup_by_info (arches, &info);
if (arches != NULL)
return arches->gdbarch;
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
tdep->wordsize = 4;
tdep->gregset = NULL;
tdep->gregset_reg_offset = NULL;
tdep->gregset_num_regs = I386_NUM_GREGS;
tdep->sizeof_gregset = 0;
tdep->fpregset = NULL;
tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
tdep->st0_regnum = I386_ST0_REGNUM;
tdep->mm0_regnum = 0;
tdep->num_xmm_regs = I386_NUM_XREGS - 1;
tdep->jb_pc_offset = -1;
tdep->struct_return = pcc_struct_return;
tdep->sigtramp_start = 0;
tdep->sigtramp_end = 0;
tdep->sigtramp_p = i386_sigtramp_p;
tdep->sigcontext_addr = NULL;
tdep->sc_reg_offset = NULL;
tdep->sc_pc_offset = -1;
tdep->sc_sp_offset = -1;
set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
set_gdbarch_long_double_bit (gdbarch, 128);
set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS);
set_gdbarch_register_name (gdbarch, i386_register_name);
set_gdbarch_register_type (gdbarch, i386_register_type);
set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM);
set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM);
set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM);
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
set_gdbarch_register_to_value (gdbarch, i386_register_to_value);
set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
set_gdbarch_return_value (gdbarch, i386_return_value);
set_gdbarch_skip_prologue (gdbarch, i386_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 1);
set_gdbarch_frame_args_skip (gdbarch, 8);
set_gdbarch_num_pseudo_regs (gdbarch, i386_num_mmx_regs);
set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write);
set_gdbarch_print_insn (gdbarch, i386_print_insn);
set_gdbarch_unwind_dummy_id (gdbarch, i386_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, i386_unwind_pc);
i386_add_reggroups (gdbarch);
set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p);
set_gdbarch_fetch_pointer_argument (gdbarch, i386_fetch_pointer_argument);
frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
frame_base_set_default (gdbarch, &i386_frame_base);
gdbarch_init_osabi (info, gdbarch);
frame_unwind_append_sniffer (gdbarch, i386_sigtramp_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, i386_frame_sniffer);
if (tdep->gregset_reg_offset
&& !gdbarch_regset_from_core_section_p (gdbarch))
set_gdbarch_regset_from_core_section (gdbarch,
i386_regset_from_core_section);
if (tdep->mm0_regnum == 0)
tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
return gdbarch;
}
static enum gdb_osabi
i386_coff_osabi_sniffer (bfd *abfd)
{
if (strcmp (bfd_get_target (abfd), "coff-go32-exe") == 0
|| strcmp (bfd_get_target (abfd), "coff-go32") == 0)
return GDB_OSABI_GO32;
return GDB_OSABI_UNKNOWN;
}
static enum gdb_osabi
i386_nlm_osabi_sniffer (bfd *abfd)
{
return GDB_OSABI_NETWARE;
}
static void
maintenance_i386_prologue_parser (char *arg, int from_tty)
{
char **argv;
CORE_ADDR start_address, end_address;
CORE_ADDR parsed_to;
int argc;
struct cleanup *cleanups;
struct i386_frame_cache *cache;
struct minimal_symbol *func;
int parse_failed = 0;
if (arg == NULL || arg[0] == '\0')
return;
argv = buildargv (arg);
if (argv == NULL)
return;
cleanups = make_cleanup_freeargv (argv);
for (argc = 0; argv[argc] != NULL && argv[argc][0] != '\0'; argc++)
;
if (argc == 0)
{
do_cleanups (cleanups);
return;
}
start_address = parse_and_eval_address (argv[0]);
if (argc == 2)
end_address = strtoul (argv[1], NULL, 16);
else
end_address = start_address + 48;
cache = i386_alloc_frame_cache ();
cache->saved_regs[I386_EBP_REGNUM] = -1;
cache->locals = -1;
parsed_to = i386_analyze_frame_setup (start_address, end_address + 1, cache);
func = lookup_minimal_symbol_by_pc_section (start_address, NULL);
printf_filtered ("Analyzing the prologue of '%s' 0x%s.\n",
SYMBOL_LINKAGE_NAME (func),
paddr_nz (SYMBOL_VALUE_ADDRESS (func)));
if (func != lookup_minimal_symbol_by_pc_section (parsed_to, NULL))
{
printf_filtered ("Prologue scanner went to 0x%s (off the end of '%s')"
" trying to\nfind a prologue. %s is frameless?\n",
paddr_nz (parsed_to),
SYMBOL_LINKAGE_NAME (func), SYMBOL_LINKAGE_NAME (func));
parse_failed = 1;
}
else
{
printf_filtered ("Prologue parser parsed to address 0x%s",
paddr_nz (parsed_to));
if (parsed_to == end_address -1)
printf_filtered (" which is the entire length of the function\n");
else
{
printf_filtered (".\n");
if (cache->saved_regs[I386_EBP_REGNUM] == -1)
{
printf_filtered ("Didn't find push %%ebp and didn't parse the full range: prologue parse failed (frameless function?)\n");
parse_failed = 1;
}
}
}
printf_filtered ("\n");
if (cache->saved_regs[I386_EBP_REGNUM] == -1)
{
printf_filtered ("Did not find the push %%ebp\n");
parse_failed = 1;
}
else
printf_filtered ("Found push %%ebp\n");
if (cache->locals == -1)
{
printf_filtered ("Did not find mov %%esp, %%ebp\n");
parse_failed = 1;
}
if (cache->locals >= 0)
printf_filtered ("Found mov %%esp, %%ebp\n");
if (cache->locals > 0)
printf_filtered ("Found local storage setup\n");
if (parse_failed)
printf_filtered ("\nFAILED TO PARSE func %s startaddr 0x%s\n\n",
SYMBOL_LINKAGE_NAME (func), paddr_nz (start_address));
do_cleanups (cleanups);
}
void _initialize_i386_tdep (void);
void
_initialize_i386_tdep (void)
{
register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);
builtin_type_vec128i_big = build_builtin_type_vec128i_big ();
add_setshow_enum_cmd ("disassembly-flavor", no_class, valid_flavors,
&disassembly_flavor, _("\
Set the disassembly flavor."), _("\
Show the disassembly flavor."), _("\
The valid values are \"att\" and \"intel\", and the default value is \"att\"."),
NULL,
NULL,
&setlist, &showlist);
add_cmd ("i386-prologue-parser", class_maintenance,
maintenance_i386_prologue_parser,
"Run the i386 prologue analyzer on a function.\n"
"arg1 is start address of function\n"
"arg2 is optional end-address, defaulting to startaddr + 32 bytes.",
&maintenancelist);
add_setshow_enum_cmd ("struct-convention", no_class, valid_conventions,
&struct_convention, _("\
Set the convention for returning small structs."), _("\
Show the convention for returning small structs."), _("\
Valid values are \"default\", \"pcc\" and \"reg\", and the default value\n\
is \"default\"."),
NULL,
NULL,
&setlist, &showlist);
gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
i386_coff_osabi_sniffer);
gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_nlm_flavour,
i386_nlm_osabi_sniffer);
gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_SVR4,
i386_svr4_init_abi);
gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_GO32,
i386_go32_init_abi);
gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETWARE,
i386_nw_init_abi);
i386_init_reggroups ();
}