/* Intel 386 target-dependent stuff.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
+#include "opcode/i386.h"
#include "arch-utils.h"
#include "command.h"
#include "dummy-frame.h"
return break_insn;
}
\f
+/* Displaced instruction handling. */
+
+/* Skip the legacy instruction prefixes in INSN.
+ Not all prefixes are valid for any particular insn
+ but we needn't care, the insn will fault if it's invalid.
+ The result is a pointer to the first opcode byte,
+ or NULL if we run off the end of the buffer. */
+
+static gdb_byte *
+i386_skip_prefixes (gdb_byte *insn, size_t max_len)
+{
+ gdb_byte *end = insn + max_len;
+
+ while (insn < end)
+ {
+ switch (*insn)
+ {
+ case DATA_PREFIX_OPCODE:
+ case ADDR_PREFIX_OPCODE:
+ case CS_PREFIX_OPCODE:
+ case DS_PREFIX_OPCODE:
+ case ES_PREFIX_OPCODE:
+ case FS_PREFIX_OPCODE:
+ case GS_PREFIX_OPCODE:
+ case SS_PREFIX_OPCODE:
+ case LOCK_PREFIX_OPCODE:
+ case REPE_PREFIX_OPCODE:
+ case REPNE_PREFIX_OPCODE:
+ ++insn;
+ continue;
+ default:
+ return insn;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+i386_absolute_jmp_p (const gdb_byte *insn)
+{
+ /* jmp far (absolute address in operand) */
+ if (insn[0] == 0xea)
+ return 1;
+
+ if (insn[0] == 0xff)
+ {
+ /* jump near, absolute indirect (/4) */
+ if ((insn[1] & 0x38) == 0x20)
+ return 1;
+
+ /* jump far, absolute indirect (/5) */
+ if ((insn[1] & 0x38) == 0x28)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+i386_absolute_call_p (const gdb_byte *insn)
+{
+ /* call far, absolute */
+ if (insn[0] == 0x9a)
+ return 1;
+
+ if (insn[0] == 0xff)
+ {
+ /* Call near, absolute indirect (/2) */
+ if ((insn[1] & 0x38) == 0x10)
+ return 1;
+
+ /* Call far, absolute indirect (/3) */
+ if ((insn[1] & 0x38) == 0x18)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+i386_ret_p (const gdb_byte *insn)
+{
+ switch (insn[0])
+ {
+ case 0xc2: /* ret near, pop N bytes */
+ case 0xc3: /* ret near */
+ case 0xca: /* ret far, pop N bytes */
+ case 0xcb: /* ret far */
+ case 0xcf: /* iret */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static int
+i386_call_p (const gdb_byte *insn)
+{
+ if (i386_absolute_call_p (insn))
+ return 1;
+
+ /* call near, relative */
+ if (insn[0] == 0xe8)
+ return 1;
+
+ return 0;
+}
+
+/* Return non-zero if INSN is a system call, and set *LENGTHP to its
+ length in bytes. Otherwise, return zero. */
+
+static int
+i386_syscall_p (const gdb_byte *insn, ULONGEST *lengthp)
+{
+ if (insn[0] == 0xcd)
+ {
+ *lengthp = 2;
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Fix up the state of registers and memory after having single-stepped
+ a displaced instruction. */
+
+void
+i386_displaced_step_fixup (struct gdbarch *gdbarch,
+ struct displaced_step_closure *closure,
+ CORE_ADDR from, CORE_ADDR to,
+ struct regcache *regs)
+{
+ /* The offset we applied to the instruction's address.
+ This could well be negative (when viewed as a signed 32-bit
+ value), but ULONGEST won't reflect that, so take care when
+ applying it. */
+ ULONGEST insn_offset = to - from;
+
+ /* Since we use simple_displaced_step_copy_insn, our closure is a
+ copy of the instruction. */
+ gdb_byte *insn = (gdb_byte *) closure;
+ /* The start of the insn, needed in case we see some prefixes. */
+ gdb_byte *insn_start = insn;
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: fixup (0x%s, 0x%s), "
+ "insn = 0x%02x 0x%02x ...\n",
+ paddr_nz (from), paddr_nz (to), insn[0], insn[1]);
+
+ /* The list of issues to contend with here is taken from
+ resume_execution in arch/i386/kernel/kprobes.c, Linux 2.6.20.
+ Yay for Free Software! */
+
+ /* Relocate the %eip, if necessary. */
+
+ /* The instruction recognizers we use assume any leading prefixes
+ have been skipped. */
+ {
+ /* This is the size of the buffer in closure. */
+ size_t max_insn_len = gdbarch_max_insn_length (gdbarch);
+ gdb_byte *opcode = i386_skip_prefixes (insn, max_insn_len);
+ /* If there are too many prefixes, just ignore the insn.
+ It will fault when run. */
+ if (opcode != NULL)
+ insn = opcode;
+ }
+
+ /* Except in the case of absolute or indirect jump or call
+ instructions, or a return instruction, the new eip is relative to
+ the displaced instruction; make it relative. Well, signal
+ handler returns don't need relocation either, but we use the
+ value of %eip to recognize those; see below. */
+ if (! i386_absolute_jmp_p (insn)
+ && ! i386_absolute_call_p (insn)
+ && ! i386_ret_p (insn))
+ {
+ ULONGEST orig_eip;
+ ULONGEST insn_len;
+
+ regcache_cooked_read_unsigned (regs, I386_EIP_REGNUM, &orig_eip);
+
+ /* A signal trampoline system call changes the %eip, resuming
+ execution of the main program after the signal handler has
+ returned. That makes them like 'return' instructions; we
+ shouldn't relocate %eip.
+
+ But most system calls don't, and we do need to relocate %eip.
+
+ Our heuristic for distinguishing these cases: if stepping
+ over the system call instruction left control directly after
+ the instruction, the we relocate --- control almost certainly
+ doesn't belong in the displaced copy. Otherwise, we assume
+ the instruction has put control where it belongs, and leave
+ it unrelocated. Goodness help us if there are PC-relative
+ system calls. */
+ if (i386_syscall_p (insn, &insn_len)
+ && orig_eip != to + (insn - insn_start) + insn_len)
+ {
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: syscall changed %%eip; "
+ "not relocating\n");
+ }
+ else
+ {
+ ULONGEST eip = (orig_eip - insn_offset) & 0xffffffffUL;
+
+ /* 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, I386_EIP_REGNUM, eip);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: "
+ "relocated %%eip from 0x%s to 0x%s\n",
+ paddr_nz (orig_eip), paddr_nz (eip));
+ }
+ }
+
+ /* If the instruction was PUSHFL, then the TF bit will be set in the
+ pushed value, and should be cleared. We'll leave this for later,
+ since GDB already messes up the TF flag when stepping over a
+ pushfl. */
+
+ /* If the instruction was a call, the return address now atop the
+ stack is the address following the copied instruction. We need
+ to make it the address following the original instruction. */
+ if (i386_call_p (insn))
+ {
+ ULONGEST esp;
+ ULONGEST retaddr;
+ const ULONGEST retaddr_len = 4;
+
+ regcache_cooked_read_unsigned (regs, I386_ESP_REGNUM, &esp);
+ retaddr = read_memory_unsigned_integer (esp, retaddr_len);
+ retaddr = (retaddr - insn_offset) & 0xffffffffUL;
+ write_memory_unsigned_integer (esp, retaddr_len, retaddr);
+
+ if (debug_displaced)
+ fprintf_unfiltered (gdb_stdlog,
+ "displaced: relocated return addr at 0x%s "
+ "to 0x%s\n",
+ paddr_nz (esp),
+ paddr_nz (retaddr));
+ }
+}
+\f
#ifdef I386_REGNO_TO_SYMMETRY
#error "The Sequent Symmetry is no longer supported."
#endif
/* Saved registers. */
CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
CORE_ADDR saved_sp;
- int stack_align;
+ int saved_sp_reg;
int pc_in_eax;
/* Stack space reserved for local variables. */
for (i = 0; i < I386_NUM_SAVED_REGS; i++)
cache->saved_regs[i] = -1;
cache->saved_sp = 0;
- cache->stack_align = 0;
+ cache->saved_sp_reg = -1;
cache->pc_in_eax = 0;
/* Frameless until proven otherwise. */
i386_analyze_stack_align (CORE_ADDR pc, CORE_ADDR current_pc,
struct i386_frame_cache *cache)
{
- /* The register used by the compiler to perform the stack re-alignment
- is, in order of preference, either %ecx, %edx, or %eax. GCC should
- never use %ebx as it always treats it as callee-saved, whereas
- the compiler can only use caller-saved registers. */
- static const gdb_byte insns_ecx[10] = {
- 0x8d, 0x4c, 0x24, 0x04, /* leal 4(%esp), %ecx */
- 0x83, 0xe4, 0xf0, /* andl $-16, %esp */
- 0xff, 0x71, 0xfc /* pushl -4(%ecx) */
- };
- static const gdb_byte insns_edx[10] = {
- 0x8d, 0x54, 0x24, 0x04, /* leal 4(%esp), %edx */
- 0x83, 0xe4, 0xf0, /* andl $-16, %esp */
- 0xff, 0x72, 0xfc /* pushl -4(%edx) */
- };
- static const gdb_byte insns_eax[10] = {
- 0x8d, 0x44, 0x24, 0x04, /* leal 4(%esp), %eax */
- 0x83, 0xe4, 0xf0, /* andl $-16, %esp */
- 0xff, 0x70, 0xfc /* pushl -4(%eax) */
+ /* There are 2 code sequences to re-align stack before the frame
+ gets set up:
+
+ 1. Use a caller-saved saved register:
+
+ leal 4(%esp), %reg
+ andl $-XXX, %esp
+ pushl -4(%reg)
+
+ 2. Use a callee-saved saved register:
+
+ pushl %reg
+ leal 8(%esp), %reg
+ andl $-XXX, %esp
+ pushl -4(%reg)
+
+ "andl $-XXX, %esp" can be either 3 bytes or 6 bytes:
+
+ 0x83 0xe4 0xf0 andl $-16, %esp
+ 0x81 0xe4 0x00 0xff 0xff 0xff andl $-256, %esp
+ */
+
+ gdb_byte buf[14];
+ int reg;
+ int offset, offset_and;
+ static int regnums[8] = {
+ I386_EAX_REGNUM, /* %eax */
+ I386_ECX_REGNUM, /* %ecx */
+ I386_EDX_REGNUM, /* %edx */
+ I386_EBX_REGNUM, /* %ebx */
+ I386_ESP_REGNUM, /* %esp */
+ I386_EBP_REGNUM, /* %ebp */
+ I386_ESI_REGNUM, /* %esi */
+ I386_EDI_REGNUM /* %edi */
};
- gdb_byte buf[10];
- if (target_read_memory (pc, buf, sizeof buf)
- || (memcmp (buf, insns_ecx, sizeof buf) != 0
- && memcmp (buf, insns_edx, sizeof buf) != 0
- && memcmp (buf, insns_eax, sizeof buf) != 0))
+ if (target_read_memory (pc, buf, sizeof buf))
+ return pc;
+
+ /* Check caller-saved saved register. The first instruction has
+ to be "leal 4(%esp), %reg". */
+ if (buf[0] == 0x8d && buf[2] == 0x24 && buf[3] == 0x4)
+ {
+ /* MOD must be binary 10 and R/M must be binary 100. */
+ if ((buf[1] & 0xc7) != 0x44)
+ return pc;
+
+ /* REG has register number. */
+ reg = (buf[1] >> 3) & 7;
+ offset = 4;
+ }
+ else
+ {
+ /* Check callee-saved saved register. The first instruction
+ has to be "pushl %reg". */
+ if ((buf[0] & 0xf8) != 0x50)
+ return pc;
+
+ /* Get register. */
+ reg = buf[0] & 0x7;
+
+ /* The next instruction has to be "leal 8(%esp), %reg". */
+ if (buf[1] != 0x8d || buf[3] != 0x24 || buf[4] != 0x8)
+ return pc;
+
+ /* MOD must be binary 10 and R/M must be binary 100. */
+ if ((buf[2] & 0xc7) != 0x44)
+ return pc;
+
+ /* REG has register number. Registers in pushl and leal have to
+ be the same. */
+ if (reg != ((buf[2] >> 3) & 7))
+ return pc;
+
+ offset = 5;
+ }
+
+ /* Rigister can't be %esp nor %ebp. */
+ if (reg == 4 || reg == 5)
+ return pc;
+
+ /* The next instruction has to be "andl $-XXX, %esp". */
+ if (buf[offset + 1] != 0xe4
+ || (buf[offset] != 0x81 && buf[offset] != 0x83))
return pc;
- if (current_pc > pc + 4)
- cache->stack_align = 1;
+ offset_and = offset;
+ offset += buf[offset] == 0x81 ? 6 : 3;
+
+ /* The next instruction has to be "pushl -4(%reg)". 8bit -4 is
+ 0xfc. REG must be binary 110 and MOD must be binary 01. */
+ if (buf[offset] != 0xff
+ || buf[offset + 2] != 0xfc
+ || (buf[offset + 1] & 0xf8) != 0x70)
+ return pc;
+
+ /* R/M has register. Registers in leal and pushl have to be the
+ same. */
+ if (reg != (buf[offset + 1] & 7))
+ return pc;
- return min (pc + 10, current_pc);
+ if (current_pc > pc + offset_and)
+ cache->saved_sp_reg = regnums[reg];
+
+ return min (pc + offset + 3, current_pc);
}
/* Maximum instruction length we need to handle. */
-#define I386_MAX_INSN_LEN 6
+#define I386_MAX_MATCHED_INSN_LEN 6
/* Instruction description. */
struct i386_insn
{
size_t len;
- gdb_byte insn[I386_MAX_INSN_LEN];
- gdb_byte mask[I386_MAX_INSN_LEN];
+ gdb_byte insn[I386_MAX_MATCHED_INSN_LEN];
+ gdb_byte mask[I386_MAX_MATCHED_INSN_LEN];
};
/* Search for the instruction at PC in the list SKIP_INSNS. Return
{
if ((op & insn->mask[0]) == insn->insn[0])
{
- gdb_byte buf[I386_MAX_INSN_LEN - 1];
+ gdb_byte buf[I386_MAX_MATCHED_INSN_LEN - 1];
int insn_matched = 1;
size_t i;
gdb_assert (insn->len > 1);
- gdb_assert (insn->len <= I386_MAX_INSN_LEN);
+ gdb_assert (insn->len <= I386_MAX_MATCHED_INSN_LEN);
target_read_memory (pc + 1, buf, insn->len - 1);
for (i = 1; i < insn->len; i++)
return pc;
}
+/* Check that the code pointed to by PC corresponds to a call to
+ __main, skip it if so. Return PC otherwise. */
+
+CORE_ADDR
+i386_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ gdb_byte op;
+
+ target_read_memory (pc, &op, 1);
+ if (op == 0xe8)
+ {
+ gdb_byte buf[4];
+
+ if (target_read_memory (pc + 1, buf, sizeof buf) == 0)
+ {
+ /* Make sure address is computed correctly as a 32bit
+ integer even if CORE_ADDR is 64 bit wide. */
+ struct minimal_symbol *s;
+ CORE_ADDR call_dest = pc + 5 + extract_signed_integer (buf, 4);
+
+ call_dest = call_dest & 0xffffffffU;
+ s = lookup_minimal_symbol_by_pc (call_dest);
+ if (s != NULL
+ && SYMBOL_LINKAGE_NAME (s) != NULL
+ && strcmp (SYMBOL_LINKAGE_NAME (s), "__main") == 0)
+ pc += 5;
+ }
+ }
+
+ return pc;
+}
+
/* This function is 64-bit safe. */
static CORE_ADDR
gdb_byte buf[8];
frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
- return extract_typed_address (buf, builtin_type_void_func_ptr);
+ return extract_typed_address (buf, builtin_type (gdbarch)->builtin_func_ptr);
}
\f
if (cache->pc != 0)
i386_analyze_prologue (cache->pc, get_frame_pc (this_frame), cache);
- if (cache->stack_align)
+ if (cache->saved_sp_reg != -1)
{
- /* Saved stack pointer has been saved in %ecx. */
- get_frame_register (this_frame, I386_ECX_REGNUM, buf);
+ /* Saved stack pointer has been saved. */
+ get_frame_register (this_frame, cache->saved_sp_reg, buf);
cache->saved_sp = extract_unsigned_integer(buf, 4);
}
frame by looking at the stack pointer. For truly "frameless"
functions this might work too. */
- if (cache->stack_align)
+ if (cache->saved_sp_reg != -1)
{
/* We're halfway aligning the stack. */
cache->base = ((cache->saved_sp - 4) & 0xfffffff0) - 4;
}
\f
+/* Check whether TYPE must be 16-byte-aligned when passed as a
+ function argument. 16-byte vectors, _Decimal128 and structures or
+ unions containing such types must be 16-byte-aligned; other
+ arguments are 4-byte-aligned. */
+
+static int
+i386_16_byte_align_p (struct type *type)
+{
+ type = check_typedef (type);
+ if ((TYPE_CODE (type) == TYPE_CODE_DECFLOAT
+ || (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)))
+ && TYPE_LENGTH (type) == 16)
+ return 1;
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ return i386_16_byte_align_p (TYPE_TARGET_TYPE (type));
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION)
+ {
+ int i;
+ for (i = 0; i < TYPE_NFIELDS (type); i++)
+ {
+ if (i386_16_byte_align_p (TYPE_FIELD_TYPE (type, i)))
+ return 1;
+ }
+ }
+ return 0;
+}
+
static CORE_ADDR
i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
{
gdb_byte buf[4];
int i;
+ int write_pass;
+ int args_space = 0;
+
+ /* Determine the total space required for arguments and struct
+ return address in a first pass (allowing for 16-byte-aligned
+ arguments), then push arguments in a second pass. */
- /* Push arguments in reverse order. */
- for (i = nargs - 1; i >= 0; i--)
+ for (write_pass = 0; write_pass < 2; write_pass++)
{
- int len = TYPE_LENGTH (value_enclosing_type (args[i]));
+ int args_space_used = 0;
+ int have_16_byte_aligned_arg = 0;
- /* The System V ABI says that:
+ if (struct_return)
+ {
+ if (write_pass)
+ {
+ /* Push value address. */
+ store_unsigned_integer (buf, 4, struct_addr);
+ write_memory (sp, buf, 4);
+ args_space_used += 4;
+ }
+ else
+ args_space += 4;
+ }
+
+ for (i = 0; i < nargs; i++)
+ {
+ int len = TYPE_LENGTH (value_enclosing_type (args[i]));
- "An argument's size is increased, if necessary, to make it a
- multiple of [32-bit] words. This may require tail padding,
- depending on the size of the argument."
+ if (write_pass)
+ {
+ if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+ args_space_used = align_up (args_space_used, 16);
- This makes sure the stack stays word-aligned. */
- sp -= (len + 3) & ~3;
- write_memory (sp, value_contents_all (args[i]), len);
- }
+ write_memory (sp + args_space_used,
+ value_contents_all (args[i]), len);
+ /* The System V ABI says that:
- /* Push value address. */
- if (struct_return)
- {
- sp -= 4;
- store_unsigned_integer (buf, 4, struct_addr);
- write_memory (sp, buf, 4);
+ "An argument's size is increased, if necessary, to make it a
+ multiple of [32-bit] words. This may require tail padding,
+ depending on the size of the argument."
+
+ This makes sure the stack stays word-aligned. */
+ args_space_used += align_up (len, 4);
+ }
+ else
+ {
+ if (i386_16_byte_align_p (value_enclosing_type (args[i])))
+ {
+ args_space = align_up (args_space, 16);
+ have_16_byte_aligned_arg = 1;
+ }
+ args_space += align_up (len, 4);
+ }
+ }
+
+ if (!write_pass)
+ {
+ if (have_16_byte_aligned_arg)
+ args_space = align_up (args_space, 16);
+ sp -= args_space;
+ }
}
/* Store return address. */
(i386_frame_this_id, i386_sigtramp_frame_this_id,
i386_dummy_id). It's there, since all frame unwinders for
a given target have to agree (within a certain margin) on the
- definition of the stack address of a frame. Otherwise
- frame_id_inner() won't work correctly. Since DWARF2/GCC uses the
+ definition of the stack address of a frame. Otherwise frame id
+ comparison might not work correctly. Since DWARF2/GCC uses the
stack address *before* the function call as a frame's CFA. On
the i386, when %ebp is used as a frame pointer, the offset
between the contents %ebp and the CFA as defined by GCC. */
append_composite_type_field (t, "v8_int8",
init_vector_type (builtin_type_int8, 8));
- TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_VECTOR (t) = 1;
TYPE_NAME (t) = "builtin_type_vec64i";
tdep->i386_mmx_type = t;
}
t = init_composite_type ("__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
append_composite_type_field (t, "v4_float",
- init_vector_type (builtin_type_float, 4));
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_float, 4));
append_composite_type_field (t, "v2_double",
- init_vector_type (builtin_type_double, 2));
+ init_vector_type (builtin_type (gdbarch)
+ ->builtin_double, 2));
append_composite_type_field (t, "v16_int8",
init_vector_type (builtin_type_int8, 16));
append_composite_type_field (t, "v8_int16",
init_vector_type (builtin_type_int64, 2));
append_composite_type_field (t, "uint128", builtin_type_int128);
- TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR;
+ TYPE_VECTOR (t) = 1;
TYPE_NAME (t) = "builtin_type_vec128i";
tdep->i386_sse_type = t;
}
i386_register_type (struct gdbarch *gdbarch, int regnum)
{
if (regnum == I386_EIP_REGNUM)
- return builtin_type_void_func_ptr;
+ return builtin_type (gdbarch)->builtin_func_ptr;
if (regnum == I386_EFLAGS_REGNUM)
return i386_eflags_type;
if (regnum == I386_EBP_REGNUM || regnum == I386_ESP_REGNUM)
- return builtin_type_void_data_ptr;
+ return builtin_type (gdbarch)->builtin_data_ptr;
if (i386_fp_regnum_p (gdbarch, regnum))
return builtin_type_i387_ext;
if (regnum == I387_MXCSR_REGNUM (gdbarch_tdep (gdbarch)))
return i386_mxcsr_type;
- return builtin_type_int;
+ return builtin_type (gdbarch)->builtin_int;
}
/* Map a cooked register onto a raw register or memory. For the i386,
/* Return whether the THIS_FRAME corresponds to a sigtramp
routine. */
-static int
+int
i386_sigtramp_p (struct frame_info *this_frame)
{
CORE_ADDR pc = get_frame_pc (this_frame);
return read_memory_unsigned_integer (sp + (4 * (argi + 1)), 4);
}
+static void
+i386_skip_permanent_breakpoint (struct regcache *regcache)
+{
+ CORE_ADDR current_pc = regcache_read_pc (regcache);
+
+ /* On i386, breakpoint is exactly 1 byte long, so we just
+ adjust the PC in the regcache. */
+ current_pc += 1;
+ regcache_write_pc (regcache, current_pc);
+}
+
+
\f
static struct gdbarch *
i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);
- /* Use the SVR4 register numbering scheme for DWARF and DWARF 2. */
- set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+ /* Use the SVR4 register numbering scheme for DWARF 2. */
set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
/* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 1);
+ set_gdbarch_max_insn_length (gdbarch, I386_MAX_INSN_LEN);
set_gdbarch_frame_args_skip (gdbarch, 8);
if (tdep->mm0_regnum == 0)
tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
+ set_gdbarch_skip_permanent_breakpoint (gdbarch,
+ i386_skip_permanent_breakpoint);
+
return gdbarch;
}