/* Intel 386 target-dependent stuff.
- Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
-#include "gdb_string.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 "target.h"
-#include "floatformat.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "reggroups.h"
+#include "regset.h"
#include "symfile.h"
#include "symtab.h"
-#include "gdbcmd.h"
-#include "command.h"
-#include "arch-utils.h"
-#include "regcache.h"
-#include "doublest.h"
+#include "target.h"
#include "value.h"
+#include "dis-asm.h"
+
#include "gdb_assert.h"
-#include "reggroups.h"
-#include "dummy-frame.h"
-#include "osabi.h"
+#include "gdb_string.h"
#include "i386-tdep.h"
#include "i387-tdep.h"
-/* Names of the registers. The first 10 registers match the register
- numbering scheme used by GCC for stabs and DWARF. */
+/* Register names. */
+
static char *i386_register_names[] =
{
"eax", "ecx", "edx", "ebx",
"mxcsr"
};
-/* MMX registers. */
+static const int i386_num_register_names = ARRAY_SIZE (i386_register_names);
+
+/* Register names for MMX pseudo-registers. */
static char *i386_mmx_names[] =
{
"mm0", "mm1", "mm2", "mm3",
"mm4", "mm5", "mm6", "mm7"
};
-static const int mmx_num_regs = (sizeof (i386_mmx_names)
- / sizeof (i386_mmx_names[0]));
-#define MM0_REGNUM (NUM_REGS)
+
+static const int i386_num_mmx_regs = ARRAY_SIZE (i386_mmx_names);
static int
-i386_mmx_regnum_p (int reg)
+i386_mmx_regnum_p (struct gdbarch *gdbarch, int regnum)
{
- return (reg >= MM0_REGNUM && reg < MM0_REGNUM + mmx_num_regs);
+ 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);
}
-/* FP register? */
+/* SSE register? */
-int
-i386_fp_regnum_p (int regnum)
+static int
+i386_sse_regnum_p (struct gdbarch *gdbarch, int regnum)
{
- return (regnum < NUM_REGS
- && (FP0_REGNUM && FP0_REGNUM <= (regnum) && (regnum) < FPC_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
}
-int
-i386_fpc_regnum_p (int regnum)
+static int
+i386_mxcsr_regnum_p (struct gdbarch *gdbarch, int regnum)
{
- return (regnum < NUM_REGS
- && (FPC_REGNUM <= (regnum) && (regnum) < XMM0_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
}
-/* SSE register? */
+#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)
+
+/* FP register? */
int
-i386_sse_regnum_p (int regnum)
+i386_fp_regnum_p (int regnum)
{
- return (regnum < NUM_REGS
- && (XMM0_REGNUM <= (regnum) && (regnum) < MXCSR_REGNUM));
+ if (I387_ST0_REGNUM < 0)
+ return 0;
+
+ return (I387_ST0_REGNUM <= regnum && regnum < I387_FCTRL_REGNUM);
}
int
-i386_mxcsr_regnum_p (int regnum)
+i386_fpc_regnum_p (int regnum)
{
- return (regnum < NUM_REGS
- && (regnum == MXCSR_REGNUM));
+ if (I387_ST0_REGNUM < 0)
+ return 0;
+
+ return (I387_FCTRL_REGNUM <= regnum && regnum < I387_XMM0_REGNUM);
}
-/* Return the name of register REG. */
+/* Return the name of register REGNUM. */
const char *
-i386_register_name (int reg)
+i386_register_name (int regnum)
{
- if (reg < 0)
- return NULL;
- if (i386_mmx_regnum_p (reg))
- return i386_mmx_names[reg - MM0_REGNUM];
- if (reg >= sizeof (i386_register_names) / sizeof (*i386_register_names))
- return NULL;
+ 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 i386_register_names[reg];
+ return NULL;
}
-/* Convert stabs register number REG to the appropriate register
+/* Convert a dbx register number REG to the appropriate register
number used by GDB. */
static int
-i386_stab_reg_to_regnum (int reg)
+i386_dbx_reg_to_regnum (int reg)
{
- /* This implements what GCC calls the "default" register map. */
+ /* This implements what GCC calls the "default" register map
+ (dbx_register_map[]). */
+
if (reg >= 0 && reg <= 7)
{
- /* General registers. */
- return reg;
+ /* General-purpose registers. The debug info calls %ebp
+ register 4, and %esp register 5. */
+ if (reg == 4)
+ return 5;
+ else if (reg == 5)
+ return 4;
+ else return reg;
}
else if (reg >= 12 && reg <= 19)
{
/* Floating-point registers. */
- return reg - 12 + FP0_REGNUM;
+ return reg - 12 + I387_ST0_REGNUM;
}
else if (reg >= 21 && reg <= 28)
{
/* SSE registers. */
- return reg - 21 + XMM0_REGNUM;
+ return reg - 21 + I387_XMM0_REGNUM;
}
else if (reg >= 29 && reg <= 36)
{
/* MMX registers. */
- return reg - 29 + MM0_REGNUM;
+ return reg - 29 + I387_MM0_REGNUM;
}
/* This will hopefully provoke a warning. */
return NUM_REGS + NUM_PSEUDO_REGS;
}
-/* Convert DWARF register number REG to the appropriate register
- number used by GDB. */
+/* Convert SVR4 register number REG to the appropriate register number
+ used by GDB. */
static int
-i386_dwarf_reg_to_regnum (int reg)
+i386_svr4_reg_to_regnum (int reg)
{
- /* The DWARF register numbering includes %eip and %eflags, and
+ /* This implements the GCC register map that tries to be compatible
+ with the SVR4 C compiler for DWARF (svr4_dbx_register_map[]). */
+
+ /* The SVR4 register numbering includes %eip and %eflags, and
numbers the floating point registers differently. */
if (reg >= 0 && reg <= 9)
{
- /* General registers. */
+ /* General-purpose registers. */
return reg;
}
else if (reg >= 11 && reg <= 18)
{
/* Floating-point registers. */
- return reg - 11 + FP0_REGNUM;
+ return reg - 11 + I387_ST0_REGNUM;
}
- else if (reg >= 21)
+ else if (reg >= 21 && reg <= 36)
{
- /* The SSE and MMX registers have identical numbers as in stabs. */
- return i386_stab_reg_to_regnum (reg);
+ /* The SSE and MMX registers have the same numbers as with dbx. */
+ return i386_dbx_reg_to_regnum (reg);
+ }
+
+ switch (reg)
+ {
+ case 37: return I387_FCTRL_REGNUM;
+ case 38: return I387_FSTAT_REGNUM;
+ case 39: return I387_MXCSR_REGNUM;
+ case 40: return I386_ES_REGNUM;
+ case 41: return I386_CS_REGNUM;
+ case 42: return I386_SS_REGNUM;
+ case 43: return I386_DS_REGNUM;
+ case 44: return I386_FS_REGNUM;
+ case 45: return I386_GS_REGNUM;
}
/* This will hopefully provoke a warning. */
return NUM_REGS + NUM_PSEUDO_REGS;
}
+
+#undef I387_ST0_REGNUM
+#undef I387_MM0_REGNUM
+#undef I387_NUM_XMM_REGS
\f
/* This is the variable that is set with "set disassembly-flavor", and
NULL
};
static const char *disassembly_flavor = att_flavor;
+\f
-/* Stdio style buffering was used to minimize calls to ptrace, but
- this buffering did not take into account that the code section
- being accessed may not be an even number of buffers long (even if
- the buffer is only sizeof(int) long). In cases where the code
- section size happened to be a non-integral number of buffers long,
- attempting to read the last buffer would fail. Simply using
- target_read_memory and ignoring errors, rather than read_memory, is
- not the correct solution, since legitimate access errors would then
- be totally ignored. To properly handle this situation and continue
- to use buffering would require that this code be able to determine
- the minimum code section size granularity (not the alignment of the
- section itself, since the actual failing case that pointed out this
- problem had a section alignment of 4 but was not a multiple of 4
- bytes long), on a target by target basis, and then adjust it's
- buffer size accordingly. This is messy, but potentially feasible.
- It probably needs the bfd library's help and support. For now, the
- buffer size is set to 1. (FIXME -fnf) */
-
-#define CODESTREAM_BUFSIZ 1 /* Was sizeof(int), see note above. */
-static CORE_ADDR codestream_next_addr;
-static CORE_ADDR codestream_addr;
-static unsigned char codestream_buf[CODESTREAM_BUFSIZ];
-static int codestream_off;
-static int codestream_cnt;
-
-#define codestream_tell() (codestream_addr + codestream_off)
-#define codestream_peek() \
- (codestream_cnt == 0 ? \
- codestream_fill(1) : codestream_buf[codestream_off])
-#define codestream_get() \
- (codestream_cnt-- == 0 ? \
- codestream_fill(0) : codestream_buf[codestream_off++])
-
-static unsigned char
-codestream_fill (int peek_flag)
-{
- codestream_addr = codestream_next_addr;
- codestream_next_addr += CODESTREAM_BUFSIZ;
- codestream_off = 0;
- codestream_cnt = CODESTREAM_BUFSIZ;
- read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);
-
- if (peek_flag)
- return (codestream_peek ());
- else
- return (codestream_get ());
-}
+/* Use the program counter to determine the contents and size of a
+ breakpoint instruction. Return a pointer to a string of bytes that
+ encode a breakpoint instruction, store the length of the string in
+ *LEN and optionally adjust *PC to point to the correct memory
+ location for inserting the breakpoint.
-static void
-codestream_seek (CORE_ADDR place)
-{
- codestream_next_addr = place / CODESTREAM_BUFSIZ;
- codestream_next_addr *= CODESTREAM_BUFSIZ;
- codestream_cnt = 0;
- codestream_fill (1);
- while (codestream_tell () != place)
- codestream_get ();
-}
+ On the i386 we have a single breakpoint that fits in a single byte
+ and can be inserted anywhere.
-static void
-codestream_read (unsigned char *buf, int count)
+ This function is 64-bit safe. */
+
+static const gdb_byte *
+i386_breakpoint_from_pc (CORE_ADDR *pc, int *len)
{
- unsigned char *p;
- int i;
- p = buf;
- for (i = 0; i < count; i++)
- *p++ = codestream_get ();
+ static gdb_byte break_insn[] = { 0xcc }; /* int 3 */
+
+ *len = sizeof (break_insn);
+ return break_insn;
}
\f
+#ifdef I386_REGNO_TO_SYMMETRY
+#error "The Sequent Symmetry is no longer supported."
+#endif
-/* If the next instruction is a jump, move to its target. */
+/* According to the System V ABI, the registers %ebp, %ebx, %edi, %esi
+ and %esp "belong" to the calling function. Therefore these
+ registers should be saved if they're going to be modified. */
-static void
-i386_follow_jump (void)
+/* The maximum number of saved registers. This should include all
+ registers mentioned above, and %eip. */
+#define I386_NUM_SAVED_REGS I386_NUM_GREGS
+
+struct i386_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ LONGEST sp_offset;
+ CORE_ADDR pc;
+
+ /* Saved registers. */
+ CORE_ADDR saved_regs[I386_NUM_SAVED_REGS];
+ CORE_ADDR saved_sp;
+ int pc_in_eax;
+
+ /* Stack space reserved for local variables. */
+ long locals;
+};
+
+/* Allocate and initialize a frame cache. */
+
+static struct i386_frame_cache *
+i386_alloc_frame_cache (void)
{
- unsigned char buf[4];
- long delta;
+ struct i386_frame_cache *cache;
+ int i;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct i386_frame_cache);
+
+ /* Base address. */
+ cache->base = 0;
+ cache->sp_offset = -4;
+ cache->pc = 0;
+
+ /* Saved registers. We initialize these to -1 since zero is a valid
+ offset (that's where %ebp is supposed to be stored). */
+ for (i = 0; i < I386_NUM_SAVED_REGS; i++)
+ cache->saved_regs[i] = -1;
+ cache->saved_sp = 0;
+ cache->pc_in_eax = 0;
+
+ /* Frameless until proven otherwise. */
+ cache->locals = -1;
+
+ return cache;
+}
- int data16;
- CORE_ADDR pos;
+/* If the instruction at PC is a jump, return the address of its
+ target. Otherwise, return PC. */
- pos = codestream_tell ();
+static CORE_ADDR
+i386_follow_jump (CORE_ADDR pc)
+{
+ gdb_byte op;
+ long delta = 0;
+ int data16 = 0;
- data16 = 0;
- if (codestream_peek () == 0x66)
+ op = read_memory_unsigned_integer (pc, 1);
+ if (op == 0x66)
{
- codestream_get ();
data16 = 1;
+ op = read_memory_unsigned_integer (pc + 1, 1);
}
- switch (codestream_get ())
+ switch (op)
{
case 0xe9:
/* Relative jump: if data16 == 0, disp32, else disp16. */
if (data16)
{
- codestream_read (buf, 2);
- delta = extract_signed_integer (buf, 2);
+ delta = read_memory_integer (pc + 2, 2);
/* Include the size of the jmp instruction (including the
0x66 prefix). */
- pos += delta + 4;
+ delta += 4;
}
else
{
- codestream_read (buf, 4);
- delta = extract_signed_integer (buf, 4);
+ delta = read_memory_integer (pc + 1, 4);
- pos += delta + 5;
+ /* Include the size of the jmp instruction. */
+ delta += 5;
}
break;
case 0xeb:
/* Relative jump, disp8 (ignore data16). */
- codestream_read (buf, 1);
- /* Sign-extend it. */
- delta = extract_signed_integer (buf, 1);
+ delta = read_memory_integer (pc + data16 + 1, 1);
- pos += delta + 2;
+ delta += data16 + 2;
break;
}
- codestream_seek (pos);
-}
-/* Find & return the amount a local space allocated, and advance the
- codestream to the first register push (if any).
+ return pc + delta;
+}
- If the entry sequence doesn't make sense, return -1, and leave
- codestream pointer at a random spot. */
+/* Check whether PC points at a prologue for a function returning a
+ structure or union. If so, it updates CACHE and returns the
+ address of the first instruction after the code sequence that
+ removes the "hidden" argument from the stack or CURRENT_PC,
+ whichever is smaller. Otherwise, return PC. */
-static long
-i386_get_frame_setup (CORE_ADDR pc)
+static CORE_ADDR
+i386_analyze_struct_return (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
{
- unsigned char op;
+ /* Functions that return a structure or union start with:
- codestream_seek (pc);
+ popl %eax 0x58
+ xchgl %eax, (%esp) 0x87 0x04 0x24
+ or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
- i386_follow_jump ();
+ (the System V compiler puts out the second `xchg' instruction,
+ and the assembler doesn't try to optimize it, so the 'sib' form
+ gets generated). This sequence is used to get the address of the
+ return buffer for a function that returns a structure. */
+ static gdb_byte proto1[3] = { 0x87, 0x04, 0x24 };
+ static gdb_byte proto2[4] = { 0x87, 0x44, 0x24, 0x00 };
+ gdb_byte buf[4];
+ gdb_byte op;
- op = codestream_get ();
+ if (current_pc <= pc)
+ return pc;
- if (op == 0x58) /* popl %eax */
+ op = read_memory_unsigned_integer (pc, 1);
+
+ if (op != 0x58) /* popl %eax */
+ 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)
{
- /* This function must start with
-
- popl %eax 0x58
- xchgl %eax, (%esp) 0x87 0x04 0x24
- or xchgl %eax, 0(%esp) 0x87 0x44 0x24 0x00
-
- (the System V compiler puts out the second `xchg'
- instruction, and the assembler doesn't try to optimize it, so
- the 'sib' form gets generated). This sequence is used to get
- the address of the return buffer for a function that returns
- a structure. */
- int pos;
- unsigned char buf[4];
- static unsigned char proto1[3] = { 0x87, 0x04, 0x24 };
- static unsigned char proto2[4] = { 0x87, 0x44, 0x24, 0x00 };
-
- pos = codestream_tell ();
- codestream_read (buf, 4);
- if (memcmp (buf, proto1, 3) == 0)
- pos += 3;
- else if (memcmp (buf, proto2, 4) == 0)
- pos += 4;
-
- codestream_seek (pos);
- op = codestream_get (); /* Update next opcode. */
+ cache->sp_offset += 4;
+ return current_pc;
}
- if (op == 0x68 || op == 0x6a)
+ if (current_pc == pc + 1)
{
- /* This function may start with
+ 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)
+{
+ /* A function may start with
- pushl constant
- call _probe
- addl $4, %esp
+ pushl constant
+ call _probe
+ addl $4, %esp
- followed by
+ followed by
+
+ pushl %ebp
- pushl %ebp
+ etc. */
+ gdb_byte buf[8];
+ gdb_byte op;
- etc. */
- int pos;
- unsigned char buf[8];
+ op = read_memory_unsigned_integer (pc, 1);
- /* Skip past the `pushl' instruction; it has either a one-byte
- or a four-byte operand, depending on the opcode. */
- pos = codestream_tell ();
+ if (op == 0x68 || op == 0x6a)
+ {
+ int delta;
+
+ /* Skip past the `pushl' instruction; it has either a one-byte or a
+ four-byte operand, depending on the opcode. */
if (op == 0x68)
- pos += 4;
+ delta = 5;
else
- pos += 1;
- codestream_seek (pos);
+ delta = 2;
- /* Read the following 8 bytes, which should be "call _probe" (6
- bytes) followed by "addl $4,%esp" (2 bytes). */
- codestream_read (buf, sizeof (buf));
+ /* Read the following 8 bytes, which should be `call _probe' (6
+ bytes) followed by `addl $4,%esp' (2 bytes). */
+ read_memory (pc + delta, buf, sizeof (buf));
if (buf[0] == 0xe8 && buf[6] == 0xc4 && buf[7] == 0x4)
- pos += sizeof (buf);
- codestream_seek (pos);
- op = codestream_get (); /* Update next opcode. */
+ pc += delta + sizeof (buf);
}
- if (op == 0x55) /* pushl %ebp */
- {
- /* Check for "movl %esp, %ebp" -- can be written in two ways. */
- switch (codestream_get ())
- {
- case 0x8b:
- if (codestream_get () != 0xec)
- return -1;
- break;
- case 0x89:
- if (codestream_get () != 0xe5)
- return -1;
- break;
- default:
- return -1;
- }
- /* Check for stack adjustment
+ return pc;
+}
- subl $XXX, %esp
+/* Maximum instruction length we need to handle. */
+#define I386_MAX_INSN_LEN 6
- NOTE: You can't subtract a 16 bit immediate from a 32 bit
- reg, so we don't have to worry about a data16 prefix. */
- op = codestream_peek ();
- if (op == 0x83)
- {
- /* `subl' with 8 bit immediate. */
- codestream_get ();
- if (codestream_get () != 0xec)
- /* Some instruction starting with 0x83 other than `subl'. */
- {
- codestream_seek (codestream_tell () - 2);
- return 0;
- }
- /* `subl' with signed byte immediate (though it wouldn't
- make sense to be negative). */
- return (codestream_get ());
- }
- else if (op == 0x81)
- {
- char buf[4];
- /* Maybe it is `subl' with a 32 bit immedediate. */
- codestream_get ();
- if (codestream_get () != 0xec)
- /* Some instruction starting with 0x81 other than `subl'. */
- {
- codestream_seek (codestream_tell () - 2);
- return 0;
- }
- /* It is `subl' with a 32 bit immediate. */
- codestream_read ((unsigned char *) buf, 4);
- return extract_signed_integer (buf, 4);
- }
- else
- {
- return 0;
- }
- }
- else if (op == 0xc8)
- {
- char buf[2];
- /* `enter' with 16 bit unsigned immediate. */
- codestream_read ((unsigned char *) buf, 2);
- codestream_get (); /* Flush final byte of enter instruction. */
- return extract_unsigned_integer (buf, 2);
- }
- return (-1);
-}
-
-/* Signal trampolines don't have a meaningful frame. The frame
- pointer value we use is actually the frame pointer of the calling
- frame -- that is, the frame which was in progress when the signal
- trampoline was entered. GDB mostly treats this frame pointer value
- as a magic cookie. We detect the case of a signal trampoline by
- testing for get_frame_type() == SIGTRAMP_FRAME, which is set based
- on PC_IN_SIGTRAMP.
-
- When a signal trampoline is invoked from a frameless function, we
- essentially have two frameless functions in a row. In this case,
- we use the same magic cookie for three frames in a row. We detect
- this case by seeing whether the next frame is a SIGTRAMP_FRAME,
- and, if it does, checking whether the current frame is actually
- frameless. In this case, we need to get the PC by looking at the
- SP register value stored in the signal context.
-
- This should work in most cases except in horrible situations where
- a signal occurs just as we enter a function but before the frame
- has been set up. Incidentally, that's just what happens when we
- call a function from GDB with a signal pending (there's a test in
- the testsuite that makes this happen). Therefore we pretend that
- we have a frameless function if we're stopped at the start of a
- function. */
-
-/* Return non-zero if we're dealing with a frameless signal, that is,
- a signal trampoline invoked from a frameless function. */
-
-int
-i386_frameless_signal_p (struct frame_info *frame)
+/* Instruction description. */
+struct i386_insn
{
- return (get_next_frame (frame)
- && get_frame_type (get_next_frame (frame)) == SIGTRAMP_FRAME
- && (frameless_look_for_prologue (frame)
- || get_frame_pc (frame) == get_pc_function_start (get_frame_pc (frame))));
-}
+ size_t len;
+ gdb_byte insn[I386_MAX_INSN_LEN];
+ gdb_byte mask[I386_MAX_INSN_LEN];
+};
-/* Return the chain-pointer for FRAME. In the case of the i386, the
- frame's nominal address is the address of a 4-byte word containing
- the calling frame's address. */
+/* Search for the instruction at PC in the list SKIP_INSNS. Return
+ the first instruction description that matches. Otherwise, return
+ NULL. */
-static CORE_ADDR
-i386_frame_chain (struct frame_info *frame)
+static struct i386_insn *
+i386_match_insn (CORE_ADDR pc, struct i386_insn *skip_insns)
{
- if (pc_in_dummy_frame (get_frame_pc (frame)))
- return get_frame_base (frame);
+ struct i386_insn *insn;
+ gdb_byte op;
- if (get_frame_type (frame) == SIGTRAMP_FRAME
- || i386_frameless_signal_p (frame))
- return get_frame_base (frame);
+ op = read_memory_unsigned_integer (pc, 1);
- if (! inside_entry_file (get_frame_pc (frame)))
- return read_memory_unsigned_integer (get_frame_base (frame), 4);
+ 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;
- return 0;
-}
+ gdb_assert (insn->len > 1);
+ gdb_assert (insn->len <= I386_MAX_INSN_LEN);
-/* Determine whether the function invocation represented by FRAME does
- not have a from on the stack associated with it. If it does not,
- return non-zero, otherwise return zero. */
+ read_memory (pc + 1, buf, insn->len - 1);
+ for (i = 1; i < insn->len; i++)
+ {
+ if ((buf[i - 1] & insn->mask[i]) != insn->insn[i])
+ insn_matched = 0;
+ }
-static int
-i386_frameless_function_invocation (struct frame_info *frame)
-{
- if (get_frame_type (frame) == SIGTRAMP_FRAME)
- return 0;
+ if (insn_matched)
+ return insn;
+ }
+ }
- return frameless_look_for_prologue (frame);
+ return NULL;
}
-/* Assuming FRAME is for a sigtramp routine, return the saved program
- counter. */
+/* Some special instructions that might be migrated by GCC into the
+ part of the prologue that sets up the new stack frame. Because the
+ stack frame hasn't been setup yet, no registers have been saved
+ yet, and only the scratch registers %eax, %ecx and %edx can be
+ touched. */
-static CORE_ADDR
-i386_sigtramp_saved_pc (struct frame_info *frame)
+struct i386_insn i386_frame_setup_skip_insns[] =
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- CORE_ADDR addr;
-
- addr = tdep->sigcontext_addr (frame);
- return read_memory_unsigned_integer (addr + tdep->sc_pc_offset, 4);
-}
+ /* Check for `movb imm8, r' and `movl imm32, r'.
+
+ ??? Should we handle 16-bit operand-sizes here? */
+
+ /* `movb imm8, %al' and `movb imm8, %ah' */
+ /* `movb imm8, %cl' and `movb imm8, %ch' */
+ { 2, { 0xb0, 0x00 }, { 0xfa, 0x00 } },
+ /* `movb imm8, %dl' and `movb imm8, %dh' */
+ { 2, { 0xb2, 0x00 }, { 0xfb, 0x00 } },
+ /* `movl imm32, %eax' and `movl imm32, %ecx' */
+ { 5, { 0xb8 }, { 0xfe } },
+ /* `movl imm32, %edx' */
+ { 5, { 0xba }, { 0xff } },
+
+ /* Check for `mov imm32, r32'. Note that there is an alternative
+ encoding for `mov m32, %eax'.
+
+ ??? Should we handle SIB adressing here?
+ ??? Should we handle 16-bit operand-sizes here? */
+
+ /* `movl m32, %eax' */
+ { 5, { 0xa1 }, { 0xff } },
+ /* `movl m32, %eax' and `mov; m32, %ecx' */
+ { 6, { 0x89, 0x05 }, {0xff, 0xf7 } },
+ /* `movl m32, %edx' */
+ { 6, { 0x89, 0x15 }, {0xff, 0xff } },
+
+ /* Check for `xorl r32, r32' and the equivalent `subl r32, r32'.
+ Because of the symmetry, there are actually two ways to encode
+ these instructions; opcode bytes 0x29 and 0x2b for `subl' and
+ opcode bytes 0x31 and 0x33 for `xorl'. */
+
+ /* `subl %eax, %eax' */
+ { 2, { 0x29, 0xc0 }, { 0xfd, 0xff } },
+ /* `subl %ecx, %ecx' */
+ { 2, { 0x29, 0xc9 }, { 0xfd, 0xff } },
+ /* `subl %edx, %edx' */
+ { 2, { 0x29, 0xd2 }, { 0xfd, 0xff } },
+ /* `xorl %eax, %eax' */
+ { 2, { 0x31, 0xc0 }, { 0xfd, 0xff } },
+ /* `xorl %ecx, %ecx' */
+ { 2, { 0x31, 0xc9 }, { 0xfd, 0xff } },
+ /* `xorl %edx, %edx' */
+ { 2, { 0x31, 0xd2 }, { 0xfd, 0xff } },
+ { 0 }
+};
-/* Assuming FRAME is for a sigtramp routine, return the saved stack
- pointer. */
+/* Check whether PC points at a code that sets up a new stack frame.
+ If so, it updates CACHE and returns the address of the first
+ instruction after the sequence that sets up the frame or LIMIT,
+ whichever is smaller. If we don't recognize the code, return PC. */
static CORE_ADDR
-i386_sigtramp_saved_sp (struct frame_info *frame)
+i386_analyze_frame_setup (CORE_ADDR pc, CORE_ADDR limit,
+ struct i386_frame_cache *cache)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
- CORE_ADDR addr;
+ struct i386_insn *insn;
+ gdb_byte op;
+ int skip = 0;
- addr = tdep->sigcontext_addr (frame);
- return read_memory_unsigned_integer (addr + tdep->sc_sp_offset, 4);
-}
+ if (limit <= pc)
+ return limit;
-/* Return the saved program counter for FRAME. */
+ op = read_memory_unsigned_integer (pc, 1);
-static CORE_ADDR
-i386_frame_saved_pc (struct frame_info *frame)
-{
- if (pc_in_dummy_frame (get_frame_pc (frame)))
+ if (op == 0x55) /* pushl %ebp */
{
- ULONGEST pc;
+ /* Take into account that we've executed the `pushl %ebp' that
+ starts this instruction sequence. */
+ cache->saved_regs[I386_EBP_REGNUM] = 0;
+ cache->sp_offset += 4;
+ pc++;
+
+ /* If that's all, return now. */
+ if (limit <= pc)
+ return limit;
+
+ /* Check for some special instructions that might be migrated by
+ GCC into the prologue and skip them. At this point in the
+ prologue, code should only touch the scratch registers %eax,
+ %ecx and %edx, so while the number of posibilities is sheer,
+ it is limited.
+
+ Make sure we only skip these instructions if we later see the
+ `movl %esp, %ebp' that actually sets up the frame. */
+ while (pc + skip < limit)
+ {
+ insn = i386_match_insn (pc + skip, i386_frame_setup_skip_insns);
+ if (insn == NULL)
+ break;
- frame_unwind_unsigned_register (frame, PC_REGNUM, &pc);
- return pc;
- }
+ skip += insn->len;
+ }
- if (get_frame_type (frame) == SIGTRAMP_FRAME)
- return i386_sigtramp_saved_pc (frame);
+ /* If that's all, return now. */
+ if (limit <= pc + skip)
+ return limit;
- if (i386_frameless_signal_p (frame))
- {
- CORE_ADDR sp = i386_sigtramp_saved_sp (get_next_frame (frame));
- return read_memory_unsigned_integer (sp, 4);
- }
+ op = read_memory_unsigned_integer (pc + skip, 1);
- return read_memory_unsigned_integer (get_frame_base (frame) + 4, 4);
-}
+ /* Check for `movl %esp, %ebp' -- can be written in two ways. */
+ switch (op)
+ {
+ case 0x8b:
+ if (read_memory_unsigned_integer (pc + skip + 1, 1) != 0xec)
+ return pc;
+ break;
+ case 0x89:
+ if (read_memory_unsigned_integer (pc + skip + 1, 1) != 0xe5)
+ return pc;
+ break;
+ default:
+ return pc;
+ }
-/* Immediately after a function call, return the saved pc. */
+ /* OK, we actually have a frame. We just don't know how large
+ it is yet. Set its size to zero. We'll adjust it if
+ necessary. We also now commit to skipping the special
+ instructions mentioned before. */
+ cache->locals = 0;
+ pc += (skip + 2);
-static CORE_ADDR
-i386_saved_pc_after_call (struct frame_info *frame)
-{
- if (get_frame_type (frame) == SIGTRAMP_FRAME)
- return i386_sigtramp_saved_pc (frame);
+ /* If that's all, return now. */
+ if (limit <= pc)
+ return limit;
- return read_memory_unsigned_integer (read_register (SP_REGNUM), 4);
-}
+ /* Check for stack adjustment
-/* Return number of args passed to a frame.
- Can return -1, meaning no way to tell. */
+ subl $XXX, %esp
-static int
-i386_frame_num_args (struct frame_info *fi)
-{
-#if 1
- return -1;
-#else
- /* This loses because not only might the compiler not be popping the
- args right after the function call, it might be popping args from
- both this call and a previous one, and we would say there are
- more args than there really are. */
-
- int retpc;
- unsigned char op;
- struct frame_info *pfi;
-
- /* On the i386, the instruction following the call could be:
- popl %ecx - one arg
- addl $imm, %esp - imm/4 args; imm may be 8 or 32 bits
- anything else - zero args. */
-
- int frameless;
-
- frameless = FRAMELESS_FUNCTION_INVOCATION (fi);
- if (frameless)
- /* In the absence of a frame pointer, GDB doesn't get correct
- values for nameless arguments. Return -1, so it doesn't print
- any nameless arguments. */
- return -1;
-
- pfi = get_prev_frame (fi);
- if (pfi == 0)
- {
- /* NOTE: This can happen if we are looking at the frame for
- main, because DEPRECATED_FRAME_CHAIN_VALID won't let us go
- into start. If we have debugging symbols, that's not really
- a big deal; it just means it will only show as many arguments
- to main as are declared. */
- return -1;
- }
- else
- {
- retpc = pfi->pc;
- op = read_memory_integer (retpc, 1);
- if (op == 0x59) /* pop %ecx */
- return 1;
- else if (op == 0x83)
+ NOTE: You can't subtract a 16-bit immediate from a 32-bit
+ reg, so we don't have to worry about a data16 prefix. */
+ op = read_memory_unsigned_integer (pc, 1);
+ if (op == 0x83)
{
- op = read_memory_integer (retpc + 1, 1);
- if (op == 0xc4)
- /* addl $<signed imm 8 bits>, %esp */
- return (read_memory_integer (retpc + 2, 1) & 0xff) / 4;
- else
- return 0;
+ /* `subl' with 8-bit immediate. */
+ if (read_memory_unsigned_integer (pc + 1, 1) != 0xec)
+ /* Some instruction starting with 0x83 other than `subl'. */
+ return pc;
+
+ /* `subl' with signed 8-bit immediate (though it wouldn't
+ make sense to be negative). */
+ cache->locals = read_memory_integer (pc + 2, 1);
+ return pc + 3;
}
- else if (op == 0x81) /* `add' with 32 bit immediate. */
+ else if (op == 0x81)
{
- op = read_memory_integer (retpc + 1, 1);
- if (op == 0xc4)
- /* addl $<imm 32>, %esp */
- return read_memory_integer (retpc + 2, 4) / 4;
- else
- return 0;
+ /* Maybe it is `subl' with a 32-bit immediate. */
+ if (read_memory_unsigned_integer (pc + 1, 1) != 0xec)
+ /* Some instruction starting with 0x81 other than `subl'. */
+ return pc;
+
+ /* It is `subl' with a 32-bit immediate. */
+ cache->locals = read_memory_integer (pc + 2, 4);
+ return pc + 6;
}
else
{
- return 0;
+ /* Some instruction other than `subl'. */
+ return pc;
}
}
-#endif
+ else if (op == 0xc8) /* enter */
+ {
+ cache->locals = read_memory_unsigned_integer (pc + 1, 2);
+ return pc + 4;
+ }
+
+ return pc;
}
-/* Parse the first few instructions the function to see what registers
- were stored.
-
+/* Check whether PC points at code that saves registers on the stack.
+ If so, it updates CACHE and returns the address of the first
+ instruction after the register saves or CURRENT_PC, whichever is
+ smaller. Otherwise, return PC. */
+
+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;
+}
+
+/* Do a full analysis of the prologue at PC and update CACHE
+ accordingly. Bail out early if CURRENT_PC is reached. Return the
+ address where the analysis stopped.
+
We handle these cases:
The startup sequence can be at the start of the function, or the
once used in the System V compiler).
Local space is allocated just below the saved %ebp by either the
- 'enter' instruction, or by "subl $<size>, %esp". 'enter' has a 16
- bit unsigned argument for space to allocate, and the 'addl'
- instruction could have either a signed byte, or 32 bit immediate.
+ 'enter' instruction, or by "subl $<size>, %esp". 'enter' has a
+ 16-bit unsigned argument for space to allocate, and the 'addl'
+ instruction could have either a signed byte, or 32-bit immediate.
Next, the registers used by this function are pushed. With the
System V compiler they will always be in the order: %edi, %esi,
If the setup sequence is at the end of the function, then the next
instruction will be a branch back to the start. */
-static void
-i386_frame_init_saved_regs (struct frame_info *fip)
+static CORE_ADDR
+i386_analyze_prologue (CORE_ADDR pc, CORE_ADDR current_pc,
+ struct i386_frame_cache *cache)
{
- long locals = -1;
- unsigned char op;
- CORE_ADDR addr;
- CORE_ADDR pc;
- int i;
-
- if (get_frame_saved_regs (fip))
- return;
-
- frame_saved_regs_zalloc (fip);
-
- pc = get_pc_function_start (get_frame_pc (fip));
- if (pc != 0)
- locals = i386_get_frame_setup (pc);
-
- if (locals >= 0)
- {
- addr = get_frame_base (fip) - 4 - locals;
- for (i = 0; i < 8; i++)
- {
- op = codestream_get ();
- if (op < 0x50 || op > 0x57)
- break;
-#ifdef I386_REGNO_TO_SYMMETRY
- /* Dynix uses different internal numbering. Ick. */
- get_frame_saved_regs (fip)[I386_REGNO_TO_SYMMETRY (op - 0x50)] = addr;
-#else
- get_frame_saved_regs (fip)[op - 0x50] = addr;
-#endif
- addr -= 4;
- }
- }
-
- get_frame_saved_regs (fip)[PC_REGNUM] = get_frame_base (fip) + 4;
- get_frame_saved_regs (fip)[FP_REGNUM] = get_frame_base (fip);
+ 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);
}
/* Return PC of first real instruction. */
static CORE_ADDR
-i386_skip_prologue (CORE_ADDR pc)
+i386_skip_prologue (CORE_ADDR start_pc)
{
- unsigned char op;
- int i;
- static unsigned char pic_pat[6] =
- { 0xe8, 0, 0, 0, 0, /* call 0x0 */
- 0x5b, /* popl %ebx */
+ static gdb_byte pic_pat[6] =
+ {
+ 0xe8, 0, 0, 0, 0, /* call 0x0 */
+ 0x5b, /* popl %ebx */
};
- CORE_ADDR pos;
-
- if (i386_get_frame_setup (pc) < 0)
- return (pc);
+ struct i386_frame_cache cache;
+ CORE_ADDR pc;
+ gdb_byte op;
+ int i;
- /* Found valid frame setup -- codestream now points to start of push
- instructions for saving registers. */
+ cache.locals = -1;
+ pc = i386_analyze_prologue (start_pc, 0xffffffff, &cache);
+ if (cache.locals < 0)
+ return start_pc;
- /* Skip over register saves. */
- for (i = 0; i < 8; i++)
- {
- op = codestream_peek ();
- /* Break if not `pushl' instrunction. */
- if (op < 0x50 || op > 0x57)
- break;
- codestream_get ();
- }
+ /* Found valid frame setup. */
/* The native cc on SVR4 in -K PIC mode inserts the following code
to get the address of the global offset table (GOT) into register
- %ebx
-
+ %ebx:
+
call 0x0
popl %ebx
movl %ebx,x(%ebp) (optional)
function), so we have to skip it to get to the first real
instruction at the start of the function. */
- pos = codestream_tell ();
for (i = 0; i < 6; i++)
{
- op = codestream_get ();
+ op = read_memory_unsigned_integer (pc + i, 1);
if (pic_pat[i] != op)
break;
}
if (i == 6)
{
- unsigned char buf[4];
- long delta = 6;
+ int delta = 6;
+
+ op = read_memory_unsigned_integer (pc + delta, 1);
- op = codestream_get ();
if (op == 0x89) /* movl %ebx, x(%ebp) */
{
- op = codestream_get ();
+ op = read_memory_unsigned_integer (pc + delta + 1, 1);
+
if (op == 0x5d) /* One byte offset from %ebp. */
- {
- delta += 3;
- codestream_read (buf, 1);
- }
+ delta += 3;
else if (op == 0x9d) /* Four byte offset from %ebp. */
- {
- delta += 6;
- codestream_read (buf, 4);
- }
+ delta += 6;
else /* Unexpected instruction. */
- delta = -1;
- op = codestream_get ();
+ delta = 0;
+
+ op = read_memory_unsigned_integer (pc + delta, 1);
}
+
/* addl y,%ebx */
- if (delta > 0 && op == 0x81 && codestream_get () == 0xc3)
+ if (delta > 0 && op == 0x81
+ && read_memory_unsigned_integer (pc + delta + 1, 1) == 0xc3);
{
- pos += delta + 6;
+ pc += delta + 6;
}
}
- codestream_seek (pos);
- i386_follow_jump ();
+ /* If the function starts with a branch (to startup code at the end)
+ the last instruction should bring us back to the first
+ instruction of the real code. */
+ if (i386_follow_jump (start_pc) != start_pc)
+ pc = i386_follow_jump (pc);
+
+ return pc;
+}
+
+/* This function is 64-bit safe. */
+
+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);
+}
+\f
+
+/* Normal frames. */
+
+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;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = i386_alloc_frame_cache ();
+ *this_cache = cache;
+
+ /* In principle, for normal frames, %ebp holds the frame pointer,
+ which holds the base address for the current stack frame.
+ However, for functions that don't need it, the frame pointer is
+ optional. For these "frameless" functions the frame pointer is
+ actually the frame pointer of the calling frame. Signal
+ trampolines are just a special case of a "frameless" function.
+ They (usually) share their frame pointer with the frame that was
+ in progress when the signal occurred. */
+
+ frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4);
+ if (cache->base == 0)
+ return cache;
+
+ /* For normal frames, %eip is stored at 4(%ebp). */
+ cache->saved_regs[I386_EIP_REGNUM] = 4;
+
+ cache->pc = frame_func_unwind (next_frame);
+ if (cache->pc != 0)
+ i386_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
+
+ if (cache->locals < 0)
+ {
+ /* We didn't find a valid frame, which means that CACHE->base
+ currently holds the frame pointer for our calling frame. If
+ we're at the start of a function, or somewhere half-way its
+ prologue, the function's frame probably hasn't been fully
+ setup yet. Try to reconstruct the base address for the stack
+ frame by looking at the stack pointer. For truly "frameless"
+ functions this might work too. */
+
+ frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+ cache->base = extract_unsigned_integer (buf, 4) + cache->sp_offset;
+ }
+
+ /* Now that we have the base address for the stack frame we can
+ calculate the value of %esp in the calling frame. */
+ cache->saved_sp = cache->base + 8;
+
+ /* Adjust all the saved registers such that they contain addresses
+ instead of offsets. */
+ 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);
+
+ /* This marks the outermost frame. */
+ if (cache->base == 0)
+ return;
+
+ /* See the end of i386_push_dummy_call. */
+ (*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);
+
+ /* The System V ABI says that:
+
+ "The flags register contains the system flags, such as the
+ direction flag and the carry flag. The direction flag must be
+ set to the forward (that is, zero) direction before entry and
+ upon exit from a function. Other user flags have no specified
+ role in the standard calling sequence and are not preserved."
+
+ To guarantee the "upon exit" part of that statement we fake a
+ saved flags register that has its direction flag cleared.
+
+ Note that GCC doesn't seem to rely on the fact that the direction
+ flag is cleared after a function return; it always explicitly
+ clears the flag before operations where it matters.
+
+ FIXME: kettenis/20030316: I'm not quite sure whether this is the
+ right thing to do. The way we fake the flags register here makes
+ it impossible to change it. */
+
+ if (regnum == I386_EFLAGS_REGNUM)
+ {
+ *optimizedp = 0;
+ *lvalp = not_lval;
+ *addrp = 0;
+ *realnump = -1;
+ if (valuep)
+ {
+ ULONGEST val;
+
+ /* Clear the direction flag. */
+ 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 the value. */
+ 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 the value in from memory. */
+ 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;
+}
+\f
+
+/* Signal trampolines. */
+
+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);
+
+ /* See the end of i386_push_dummy_call. */
+ (*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)
+{
+ /* Make sure we've initialized the cache. */
+ i386_sigtramp_frame_cache (next_frame, this_cache);
- return (codestream_tell ());
+ i386_frame_prev_register (next_frame, this_cache, regnum,
+ optimizedp, lvalp, addrp, realnump, valuep);
}
-/* Use the program counter to determine the contents and size of a
- breakpoint instruction. Return a pointer to a string of bytes that
- encode a breakpoint instruction, store the length of the string in
- *LEN and optionally adjust *PC to point to the correct memory
- location for inserting the breakpoint.
+static const struct frame_unwind i386_sigtramp_frame_unwind =
+{
+ SIGTRAMP_FRAME,
+ i386_sigtramp_frame_this_id,
+ i386_sigtramp_frame_prev_register
+};
- On the i386 we have a single breakpoint that fits in a single byte
- and can be inserted anywhere. */
-
-static const unsigned char *
-i386_breakpoint_from_pc (CORE_ADDR *pc, int *len)
+static const struct frame_unwind *
+i386_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
- static unsigned char break_insn[] = { 0xcc }; /* int 3 */
-
- *len = sizeof (break_insn);
- return break_insn;
-}
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+
+ /* We shouldn't even bother if we don't have a sigcontext_addr
+ handler. */
+ 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;
+ }
-/* Push the return address (pointing to the call dummy) onto the stack
- and return the new value for the stack pointer. */
+ return NULL;
+}
+\f
static CORE_ADDR
-i386_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+i386_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
- char buf[4];
+ struct i386_frame_cache *cache = i386_frame_cache (next_frame, this_cache);
- store_unsigned_integer (buf, 4, CALL_DUMMY_ADDRESS ());
- write_memory (sp - 4, buf, 4);
- return sp - 4;
+ return cache->base;
}
-static void
-i386_do_pop_frame (struct frame_info *frame)
+static const struct frame_base i386_frame_base =
{
- CORE_ADDR fp;
- int regnum;
- char regbuf[I386_MAX_REGISTER_SIZE];
+ &i386_frame_unwind,
+ i386_frame_base_address,
+ i386_frame_base_address,
+ i386_frame_base_address
+};
- fp = get_frame_base (frame);
- i386_frame_init_saved_regs (frame);
+static struct frame_id
+i386_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ gdb_byte buf[4];
+ CORE_ADDR fp;
- for (regnum = 0; regnum < NUM_REGS; regnum++)
- {
- CORE_ADDR addr;
- addr = get_frame_saved_regs (frame)[regnum];
- if (addr)
- {
- read_memory (addr, regbuf, REGISTER_RAW_SIZE (regnum));
- deprecated_write_register_gen (regnum, regbuf);
- }
- }
- write_register (FP_REGNUM, read_memory_integer (fp, 4));
- write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
- write_register (SP_REGNUM, fp + 8);
- flush_cached_frames ();
-}
+ frame_unwind_register (next_frame, I386_EBP_REGNUM, buf);
+ fp = extract_unsigned_integer (buf, 4);
-static void
-i386_pop_frame (void)
-{
- generic_pop_current_frame (i386_do_pop_frame);
+ /* See the end of i386_push_dummy_call. */
+ return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
}
\f
stack. We expect the first arg to be a pointer to the jmp_buf
structure from which we extract the address that we will land at.
This address is copied into PC. This routine returns non-zero on
- success. */
+ success.
+
+ This function is 64-bit safe. */
static int
i386_get_longjmp_target (CORE_ADDR *pc)
{
- char buf[8];
+ gdb_byte buf[8];
CORE_ADDR sp, jb_addr;
int jb_pc_offset = gdbarch_tdep (current_gdbarch)->jb_pc_offset;
- int len = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ int len = TYPE_LENGTH (builtin_type_void_func_ptr);
/* If JB_PC_OFFSET is -1, we have no way to find out where the
longjmp will land. */
if (jb_pc_offset == -1)
return 0;
- sp = read_register (SP_REGNUM);
+ /* Don't use I386_ESP_REGNUM here, since this function is also used
+ for AMD64. */
+ 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_address (buf, len);
+ 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_address (buf, len);
+ *pc = extract_typed_address (buf, builtin_type_void_func_ptr);
return 1;
}
\f
static CORE_ADDR
-i386_push_arguments (int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_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)
{
- sp = legacy_push_arguments (nargs, args, sp, struct_return, struct_addr);
-
- if (struct_return)
+ gdb_byte buf[4];
+ int i;
+
+ /* Push arguments in reverse order. */
+ for (i = nargs - 1; i >= 0; i--)
{
- char buf[4];
+ int len = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ /* The System V ABI says that:
+ "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 says word-aligned. */
+ sp -= (len + 3) & ~3;
+ write_memory (sp, value_contents_all (args[i]), len);
+ }
+
+ /* Push value address. */
+ if (struct_return)
+ {
sp -= 4;
- store_address (buf, 4, struct_addr);
+ store_unsigned_integer (buf, 4, struct_addr);
write_memory (sp, buf, 4);
}
- return sp;
+ /* Store return address. */
+ sp -= 4;
+ store_unsigned_integer (buf, 4, bp_addr);
+ write_memory (sp, buf, 4);
+
+ /* Finally, update the stack pointer... */
+ store_unsigned_integer (buf, 4, sp);
+ regcache_cooked_write (regcache, I386_ESP_REGNUM, buf);
+
+ /* ...and fake a frame pointer. */
+ regcache_cooked_write (regcache, I386_EBP_REGNUM, buf);
+
+ /* MarkK wrote: This "+ 8" is all over the place:
+ (i386_frame_this_id, i386_sigtramp_frame_this_id,
+ i386_unwind_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
+ 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. */
+ return sp + 8;
}
/* These registers are used for returning integers (and on some
targets also for returning `struct' and `union' values when their
size and alignment match an integer type). */
-#define LOW_RETURN_REGNUM 0 /* %eax */
-#define HIGH_RETURN_REGNUM 2 /* %edx */
+#define LOW_RETURN_REGNUM I386_EAX_REGNUM /* %eax */
+#define HIGH_RETURN_REGNUM I386_EDX_REGNUM /* %edx */
-/* Extract from an array REGBUF containing the (raw) register state, a
- function return value of TYPE, and copy that, in virtual format,
- into VALBUF. */
+/* Read, for architecture GDBARCH, a function return value of TYPE
+ from REGCACHE, and copy that into VALBUF. */
static void
-i386_extract_return_value (struct type *type, struct regcache *regcache,
- void *dst)
+i386_extract_return_value (struct gdbarch *gdbarch, struct type *type,
+ struct regcache *regcache, gdb_byte *valbuf)
{
- bfd_byte *valbuf = dst;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
int len = TYPE_LENGTH (type);
- char buf[I386_MAX_REGISTER_SIZE];
-
- if (TYPE_CODE (type) == TYPE_CODE_STRUCT
- && TYPE_NFIELDS (type) == 1)
- {
- i386_extract_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf);
- return;
- }
+ gdb_byte buf[I386_MAX_REGISTER_SIZE];
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
- if (FP0_REGNUM == 0)
+ if (tdep->st0_regnum < 0)
{
- warning ("Cannot find floating-point return value.");
+ warning (_("Cannot find floating-point return value."));
memset (valbuf, 0, len);
return;
}
its contents to the desired type. This is probably not
exactly how it would happen on the target itself, but it is
the best we can do. */
- regcache_raw_read (regcache, FP0_REGNUM, buf);
+ regcache_raw_read (regcache, I386_ST0_REGNUM, buf);
convert_typed_floating (buf, builtin_type_i387_ext, valbuf, type);
}
else
{
- int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
- int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+ int low_size = register_size (current_gdbarch, LOW_RETURN_REGNUM);
+ int high_size = register_size (current_gdbarch, HIGH_RETURN_REGNUM);
if (len <= low_size)
{
}
else
internal_error (__FILE__, __LINE__,
- "Cannot extract return value of %d bytes long.", len);
+ _("Cannot extract return value of %d bytes long."), len);
}
}
-/* Write into the appropriate registers a function return value stored
- in VALBUF of type TYPE, given in virtual format. */
+/* Write, for architecture GDBARCH, a function return value of TYPE
+ from VALBUF into REGCACHE. */
static void
-i386_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+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);
- if (TYPE_CODE (type) == TYPE_CODE_STRUCT
- && TYPE_NFIELDS (type) == 1)
- {
- i386_store_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf);
- return;
- }
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for the architecture. */
+#define I387_ST0_REGNUM I386_ST0_REGNUM
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
ULONGEST fstat;
- char buf[FPU_REG_RAW_SIZE];
+ gdb_byte buf[I386_MAX_REGISTER_SIZE];
- if (FP0_REGNUM == 0)
+ if (tdep->st0_regnum < 0)
{
- warning ("Cannot set floating-point return value.");
+ warning (_("Cannot set floating-point return value."));
return;
}
not exactly how it would happen on the target itself, but
it is the best we can do. */
convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext);
- regcache_raw_write (regcache, FP0_REGNUM, buf);
+ regcache_raw_write (regcache, I386_ST0_REGNUM, buf);
/* Set the top of the floating-point register stack to 7. The
actual value doesn't really matter, but 7 is what a normal
function return would end up with if the program started out
with a freshly initialized FPU. */
- regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat);
+ regcache_raw_read_unsigned (regcache, I387_FSTAT_REGNUM, &fstat);
fstat |= (7 << 11);
- regcache_raw_write_unsigned (regcache, FSTAT_REGNUM, fstat);
+ regcache_raw_write_unsigned (regcache, I387_FSTAT_REGNUM, fstat);
/* Mark %st(1) through %st(7) as empty. Since we set the top of
the floating-point register stack to 7, the appropriate value
for the tag word is 0x3fff. */
- regcache_raw_write_unsigned (regcache, FTAG_REGNUM, 0x3fff);
+ regcache_raw_write_unsigned (regcache, I387_FTAG_REGNUM, 0x3fff);
}
else
{
- int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
- int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+ 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);
{
regcache_raw_write (regcache, LOW_RETURN_REGNUM, valbuf);
regcache_raw_write_part (regcache, HIGH_RETURN_REGNUM, 0,
- len - low_size, (char *) valbuf + low_size);
+ len - low_size, valbuf + low_size);
}
else
internal_error (__FILE__, __LINE__,
- "Cannot store return value of %d bytes long.", len);
+ _("Cannot store return value of %d bytes long."), len);
}
-}
-
-/* Extract from REGCACHE, which contains the (raw) register state, the
- address in which a function should return its structure value, as a
- CORE_ADDR. */
-static CORE_ADDR
-i386_extract_struct_value_address (struct regcache *regcache)
-{
- ULONGEST addr;
-
- regcache_raw_read_unsigned (regcache, LOW_RETURN_REGNUM, &addr);
- return addr;
+#undef I387_ST0_REGNUM
}
\f
};
static const char *struct_convention = default_struct_convention;
+/* Return non-zero if TYPE, which is assumed to be a structure,
+ a union type, or an array type, should be returned in registers
+ for architecture GDBARCH. */
+
static int
-i386_use_struct_convention (int gcc_p, struct type *type)
+i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
{
- enum struct_return struct_return;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ enum type_code code = TYPE_CODE (type);
+ int len = TYPE_LENGTH (type);
- if (struct_convention == default_struct_convention)
- struct_return = gdbarch_tdep (current_gdbarch)->struct_return;
- else if (struct_convention == pcc_struct_convention)
- struct_return = pcc_struct_return;
- else
- struct_return = reg_struct_return;
+ gdb_assert (code == TYPE_CODE_STRUCT
+ || code == TYPE_CODE_UNION
+ || code == TYPE_CODE_ARRAY);
+
+ if (struct_convention == pcc_struct_convention
+ || (struct_convention == default_struct_convention
+ && tdep->struct_return == pcc_struct_return))
+ return 0;
+
+ /* Structures consisting of a single `float', `double' or 'long
+ double' member are returned in %st(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);
+}
+
+/* Determine, for architecture GDBARCH, how a return value of TYPE
+ should be returned. If it is supposed to be returned in registers,
+ and READBUF is non-zero, read the appropriate value from REGCACHE,
+ and copy it into READBUF. If WRITEBUF is non-zero, write the value
+ from WRITEBUF into REGCACHE. */
+
+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
+ || code == TYPE_CODE_ARRAY)
+ && !i386_reg_struct_return_p (gdbarch, type))
+ {
+ /* The System V ABI says that:
+
+ "A function that returns a structure or union also sets %eax
+ to the value of the original address of the caller's area
+ before it returns. Thus when the caller receives control
+ again, the address of the returned object resides in register
+ %eax and can be used to access the object."
- return generic_use_struct_convention (struct_return == reg_struct_return,
- type);
+ So the ABI guarantees that we can always find the return
+ value just after the function has returned. */
+
+ /* Note that the ABI doesn't mention functions returning arrays,
+ which is something possible in certain languages such as Ada.
+ In this case, the value is returned as if it was wrapped in
+ a record, so the convention applied to records also applies
+ to arrays. */
+
+ 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;
+ }
+
+ /* This special case is for structures consisting of a single
+ `float', `double' or 'long double' member. These structures are
+ returned in %st(0). For these structures, we call ourselves
+ recursively, changing TYPE into the type of the first member of
+ the structure. Since that should work for all structures that
+ have only one member, we don't bother to check the member's type
+ here. */
+ 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;
}
\f
+/* Type for %eflags. */
+struct type *i386_eflags_type;
+
+/* Types for the MMX and SSE registers. */
+struct type *i386_mmx_type;
+struct type *i386_sse_type;
+
+/* Construct types for ISA-specific registers. */
+static void
+i386_init_types (void)
+{
+ struct type *type;
+
+ type = init_flags_type ("builtin_type_i386_eflags", 4);
+ append_flags_type_flag (type, 0, "CF");
+ append_flags_type_flag (type, 1, NULL);
+ append_flags_type_flag (type, 2, "PF");
+ append_flags_type_flag (type, 4, "AF");
+ append_flags_type_flag (type, 6, "ZF");
+ append_flags_type_flag (type, 7, "SF");
+ append_flags_type_flag (type, 8, "TF");
+ append_flags_type_flag (type, 9, "IF");
+ append_flags_type_flag (type, 10, "DF");
+ append_flags_type_flag (type, 11, "OF");
+ append_flags_type_flag (type, 14, "NT");
+ append_flags_type_flag (type, 16, "RF");
+ append_flags_type_flag (type, 17, "VM");
+ append_flags_type_flag (type, 18, "AC");
+ append_flags_type_flag (type, 19, "VIF");
+ append_flags_type_flag (type, 20, "VIP");
+ append_flags_type_flag (type, 21, "ID");
+ i386_eflags_type = type;
+
+ /* The type we're building is this: */
+#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
+
+ type = init_composite_type ("__gdb_builtin_type_vec64i", TYPE_CODE_UNION);
+ append_composite_type_field (type, "uint64", builtin_type_int64);
+ append_composite_type_field (type, "v2_int32", builtin_type_v2_int32);
+ append_composite_type_field (type, "v4_int16", builtin_type_v4_int16);
+ append_composite_type_field (type, "v8_int8", builtin_type_v8_int8);
+ TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (type) = "builtin_type_vec64i";
+ i386_mmx_type = type;
+
+ /* The type we're building is this: */
+#if 0
+ union __gdb_builtin_type_vec128i
+ {
+ int128_t uint128;
+ int64_t v2_int64[2];
+ int32_t v4_int32[4];
+ int16_t v8_int16[8];
+ int8_t v16_int8[16];
+ double v2_double[2];
+ float v4_float[4];
+ };
+#endif
+
+ type = init_composite_type ("__gdb_builtin_type_vec128i", TYPE_CODE_UNION);
+ append_composite_type_field (type, "v4_float", builtin_type_v4_float);
+ append_composite_type_field (type, "v2_double", builtin_type_v2_double);
+ append_composite_type_field (type, "v16_int8", builtin_type_v16_int8);
+ append_composite_type_field (type, "v8_int16", builtin_type_v8_int16);
+ append_composite_type_field (type, "v4_int32", builtin_type_v4_int32);
+ append_composite_type_field (type, "v2_int64", builtin_type_v2_int64);
+ append_composite_type_field (type, "uint128", builtin_type_int128);
+ TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
+ TYPE_NAME (type) = "builtin_type_vec128i";
+ i386_sse_type = type;
+}
+
/* Return the GDB type object for the "standard" data type of data in
register REGNUM. Perhaps %esi and %edi should go here, but
potentially they could be used for things other than address. */
static struct type *
i386_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (regnum == PC_REGNUM || regnum == FP_REGNUM || regnum == SP_REGNUM)
- return lookup_pointer_type (builtin_type_void);
+ if (regnum == I386_EIP_REGNUM)
+ return builtin_type_void_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;
if (i386_fp_regnum_p (regnum))
return builtin_type_i387_ext;
- if (i386_sse_regnum_p (regnum))
- return builtin_type_vec128i;
+ if (i386_sse_regnum_p (gdbarch, regnum))
+ return i386_sse_type;
- if (i386_mmx_regnum_p (regnum))
- return builtin_type_vec64i;
+ if (i386_mmx_regnum_p (gdbarch, regnum))
+ return i386_mmx_type;
return builtin_type_int;
}
the MMX registers need to be mapped onto floating point registers. */
static int
-mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
+i386_mmx_regnum_to_fp_regnum (struct regcache *regcache, int regnum)
{
- int mmxi;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
+ int mmxreg, fpreg;
ULONGEST fstat;
int tos;
- int fpi;
- mmxi = regnum - MM0_REGNUM;
- regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat);
+
+ /* Define I387_ST0_REGNUM such that we use the proper definitions
+ for REGCACHE's architecture. */
+#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;
- fpi = (mmxi + tos) % 8;
- return (FP0_REGNUM + fpi);
+ 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, void *buf)
+ int regnum, gdb_byte *buf)
{
- if (i386_mmx_regnum_p (regnum))
+ if (i386_mmx_regnum_p (gdbarch, regnum))
{
- char *mmx_buf = alloca (MAX_REGISTER_RAW_SIZE);
- int fpnum = mmx_regnum_to_fp_regnum (regcache, regnum);
- regcache_raw_read (regcache, fpnum, mmx_buf);
+ gdb_byte mmx_buf[MAX_REGISTER_SIZE];
+ int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+
/* Extract (always little endian). */
- memcpy (buf, mmx_buf, REGISTER_RAW_SIZE (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 void *buf)
+ int regnum, const gdb_byte *buf)
{
- if (i386_mmx_regnum_p (regnum))
+ if (i386_mmx_regnum_p (gdbarch, regnum))
{
- char *mmx_buf = alloca (MAX_REGISTER_RAW_SIZE);
- int fpnum = mmx_regnum_to_fp_regnum (regcache, regnum);
+ gdb_byte mmx_buf[MAX_REGISTER_SIZE];
+ int fpnum = i386_mmx_regnum_to_fp_regnum (regcache, regnum);
+
/* Read ... */
regcache_raw_read (regcache, fpnum, mmx_buf);
/* ... Modify ... (always little endian). */
- memcpy (mmx_buf, buf, REGISTER_RAW_SIZE (regnum));
+ memcpy (mmx_buf, buf, register_size (gdbarch, regnum));
/* ... Write. */
regcache_raw_write (regcache, fpnum, mmx_buf);
}
else
regcache_raw_write (regcache, regnum, buf);
}
+\f
+
+/* Return the register number of the register allocated by GCC after
+ REGNUM, or -1 if there is no such register. */
+
+static int
+i386_next_regnum (int regnum)
+{
+ /* GCC allocates the registers in the order:
+
+ %eax, %edx, %ecx, %ebx, %esi, %edi, %ebp, %esp, ...
+
+ Since storing a variable in %esp doesn't make any sense we return
+ -1 for %ebp and for %esp itself. */
+ static int next_regnum[] =
+ {
+ I386_EDX_REGNUM, /* Slot for %eax. */
+ I386_EBX_REGNUM, /* Slot for %ecx. */
+ I386_ECX_REGNUM, /* Slot for %edx. */
+ I386_ESI_REGNUM, /* Slot for %ebx. */
+ -1, -1, /* Slots for %esp and %ebp. */
+ I386_EDI_REGNUM, /* Slot for %esi. */
+ I386_EBP_REGNUM /* Slot for %edi. */
+ };
+
+ if (regnum >= 0 && regnum < sizeof (next_regnum) / sizeof (next_regnum[0]))
+ return next_regnum[regnum];
+
+ return -1;
+}
-/* Return true iff register REGNUM's virtual format is different from
- its raw format. Note that this definition assumes that the host
- supports IEEE 32-bit floats, since it doesn't say that SSE
- registers need conversion. Even if we can't find a counterexample,
- this is still sloppy. */
+/* Return nonzero if a value of type TYPE stored in register REGNUM
+ needs any special handling. */
static int
-i386_register_convertible (int regnum)
+i386_convert_register_p (int regnum, struct type *type)
{
+ int len = TYPE_LENGTH (type);
+
+ /* Values may be spread across multiple registers. Most debugging
+ formats aren't expressive enough to specify the locations, so
+ some heuristics is involved. Right now we only handle types that
+ have a length that is a multiple of the word size, since GCC
+ doesn't seem to put any other types into registers. */
+ 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);
}
-/* Convert data from raw format for register REGNUM in buffer FROM to
- virtual format with type TYPE in buffer TO. */
+/* Read a value of type TYPE from register REGNUM in frame FRAME, and
+ return its contents in TO. */
+
+static void
+i386_register_to_value (struct frame_info *frame, int regnum,
+ struct type *type, gdb_byte *to)
+{
+ int len = TYPE_LENGTH (type);
+
+ /* FIXME: kettenis/20030609: What should we do if REGNUM isn't
+ available in FRAME (i.e. if it wasn't saved)? */
+
+ if (i386_fp_regnum_p (regnum))
+ {
+ i387_register_to_value (frame, regnum, type, to);
+ return;
+ }
+
+ /* Read a value spread across multiple registers. */
+
+ 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;
+ }
+}
+
+/* Write the contents FROM of a value of type TYPE into register
+ REGNUM in frame FRAME. */
+
+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;
+ }
+
+ /* Write a value spread across multiple registers. */
+
+ 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;
+ }
+}
+\f
+/* Supply register REGNUM from the buffer specified by GREGS and LEN
+ in the general-purpose register set REGSET to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
+
+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]);
+ }
+}
+
+/* Collect register REGNUM from the register cache REGCACHE and store
+ it in the buffer specified by GREGS and LEN as described by the
+ general-purpose register set REGSET. If REGNUM is -1, do this for
+ all registers in REGSET. */
+
+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]);
+ }
+}
+
+/* Supply register REGNUM from the buffer specified by FPREGS and LEN
+ in the floating-point register set REGSET to register cache
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
static void
-i386_register_convert_to_virtual (int regnum, struct type *type,
- char *from, char *to)
+i386_supply_fpregset (const struct regset *regset, struct regcache *regcache,
+ int regnum, const void *fpregs, size_t len)
{
- gdb_assert (i386_fp_regnum_p (regnum));
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
- /* We only support floating-point values. */
- if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ if (len == I387_SIZEOF_FXSAVE)
{
- warning ("Cannot convert floating-point register value "
- "to non-floating-point type.");
- memset (to, 0, TYPE_LENGTH (type));
+ i387_supply_fxsave (regcache, regnum, fpregs);
return;
}
- /* Convert to TYPE. This should be a no-op if TYPE is equivalent to
- the extended floating-point format used by the FPU. */
- convert_typed_floating (from, builtin_type_i387_ext, to, type);
+ gdb_assert (len == tdep->sizeof_fpregset);
+ i387_supply_fsave (regcache, regnum, fpregs);
}
-/* Convert data from virtual format with type TYPE in buffer FROM to
- raw format for register REGNUM in buffer TO. */
+/* Collect register REGNUM from the register cache REGCACHE and store
+ it in the buffer specified by FPREGS and LEN as described by the
+ floating-point register set REGSET. If REGNUM is -1, do this for
+ all registers in REGSET. */
static void
-i386_register_convert_to_raw (struct type *type, int regnum,
- char *from, char *to)
+i386_collect_fpregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *fpregs, size_t len)
{
- gdb_assert (i386_fp_regnum_p (regnum));
+ const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
- /* We only support floating-point values. */
- if (TYPE_CODE (type) != TYPE_CODE_FLT)
+ if (len == I387_SIZEOF_FXSAVE)
{
- warning ("Cannot convert non-floating-point type "
- "to floating-point register value.");
- memset (to, 0, TYPE_LENGTH (type));
+ i387_collect_fxsave (regcache, regnum, fpregs);
return;
}
- /* Convert from TYPE. This should be a no-op if TYPE is equivalent
- to the extended floating-point format used by the FPU. */
- convert_typed_floating (from, type, to, builtin_type_i387_ext);
+ gdb_assert (len == tdep->sizeof_fpregset);
+ i387_collect_fsave (regcache, regnum, fpregs);
+}
+
+/* Return the appropriate register set for the core section identified
+ by SECT_NAME and SECT_SIZE. */
+
+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;
}
-\f
+\f
#ifdef STATIC_TRANSFORM_NAME
/* SunPRO encodes the static variables. This is not related to C++
}
\f
-/* Return non-zero if PC and NAME show that we are in a signal
- trampoline. */
+/* Return whether the frame preceding NEXT_FRAME corresponds to a
+ sigtramp routine. */
static int
-i386_pc_in_sigtramp (CORE_ADDR pc, char *name)
+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);
}
\f
deals with switching between those. */
static int
-i386_print_insn (bfd_vma pc, disassemble_info *info)
+i386_print_insn (bfd_vma pc, struct disassemble_info *info)
{
gdb_assert (disassembly_flavor == att_flavor
|| disassembly_flavor == intel_flavor);
/* System V Release 4 (SVR4). */
+/* Return whether the frame preceding NEXT_FRAME corresponds to a SVR4
+ sigtramp routine. */
+
static int
-i386_svr4_pc_in_sigtramp (CORE_ADDR pc, char *name)
+i386_svr4_sigtramp_p (struct frame_info *next_frame)
{
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
+ char *name;
+
+ /* UnixWare uses _sigacthandler. The origin of the other symbols is
+ currently unknown. */
+ find_pc_partial_function (pc, &name, NULL, NULL);
return (name && (strcmp ("_sigreturn", name) == 0
|| strcmp ("_sigacthandler", name) == 0
|| strcmp ("sigvechandler", name) == 0));
}
-/* Get address of the pushed ucontext (sigcontext) on the stack for
- all three variants of SVR4 sigtramps. */
+/* Assuming NEXT_FRAME is for a frame following a SVR4 sigtramp
+ routine, return the address of the associated sigcontext (ucontext)
+ structure. */
static CORE_ADDR
-i386_svr4_sigcontext_addr (struct frame_info *frame)
+i386_svr4_sigcontext_addr (struct frame_info *next_frame)
{
- int sigcontext_offset = -1;
- char *name = NULL;
-
- find_pc_partial_function (get_frame_pc (frame), &name, NULL, NULL);
- if (name)
- {
- if (strcmp (name, "_sigreturn") == 0)
- sigcontext_offset = 132;
- else if (strcmp (name, "_sigacthandler") == 0)
- sigcontext_offset = 80;
- else if (strcmp (name, "sigvechandler") == 0)
- sigcontext_offset = 120;
- }
-
- gdb_assert (sigcontext_offset != -1);
-
- if (get_next_frame (frame))
- return get_frame_base (get_next_frame (frame)) + sigcontext_offset;
- return read_register (SP_REGNUM) + sigcontext_offset;
-}
-\f
+ gdb_byte buf[4];
+ CORE_ADDR sp;
-/* DJGPP. */
+ frame_unwind_register (next_frame, I386_ESP_REGNUM, buf);
+ sp = extract_unsigned_integer (buf, 4);
-static int
-i386_go32_pc_in_sigtramp (CORE_ADDR pc, char *name)
-{
- /* DJGPP doesn't have any special frames for signal handlers. */
- return 0;
+ return read_memory_unsigned_integer (sp + 8, 4);
}
\f
void
i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
- /* We typically use stabs-in-ELF with the DWARF register numbering. */
- set_gdbarch_stab_reg_to_regnum (gdbarch, i386_dwarf_reg_to_regnum);
+ /* We typically use stabs-in-ELF with the SVR4 register numbering. */
+ set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
}
/* System V Release 4 (SVR4). */
i386_elf_init_abi (info, gdbarch);
/* System V Release 4 has shared libraries. */
- set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
- set_gdbarch_pc_in_sigtramp (gdbarch, i386_svr4_pc_in_sigtramp);
+ tdep->sigtramp_p = i386_svr4_sigtramp_p;
tdep->sigcontext_addr = i386_svr4_sigcontext_addr;
- tdep->sc_pc_offset = 14 * 4;
- tdep->sc_sp_offset = 7 * 4;
+ tdep->sc_pc_offset = 36 + 14 * 4;
+ tdep->sc_sp_offset = 36 + 17 * 4;
tdep->jb_pc_offset = 20;
}
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- set_gdbarch_pc_in_sigtramp (gdbarch, i386_go32_pc_in_sigtramp);
+ /* DJGPP doesn't have any special frames for signal handlers. */
+ tdep->sigtramp_p = NULL;
tdep->jb_pc_offset = 36;
}
i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
{
- int sse_regnum_p = (i386_sse_regnum_p (regnum)
- || i386_mxcsr_regnum_p (regnum));
+ 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 (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 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);
}
+\f
+
+/* Get the ARGIth function argument for the current function. */
+
+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);
+}
\f
static struct gdbarch *
tdep = XMALLOC (struct gdbarch_tdep);
gdbarch = gdbarch_alloc (&info, tdep);
- /* NOTE: cagney/2002-12-06: This can be deleted when this arch is
- ready to unwind the PC first (see frame.c:get_prev_frame()). */
- set_gdbarch_deprecated_init_frame_pc (gdbarch, init_frame_pc_default);
+ /* General-purpose registers. */
+ tdep->gregset = NULL;
+ tdep->gregset_reg_offset = NULL;
+ tdep->gregset_num_regs = I386_NUM_GREGS;
+ tdep->sizeof_gregset = 0;
+
+ /* Floating-point registers. */
+ tdep->fpregset = NULL;
+ tdep->sizeof_fpregset = I387_SIZEOF_FSAVE;
+
+ /* The default settings include the FPU registers, the MMX registers
+ and the SSE registers. This can be overridden for a specific ABI
+ by adjusting the members `st0_regnum', `mm0_regnum' and
+ `num_xmm_regs' of `struct gdbarch_tdep', otherwise the registers
+ will show up in the output of "info all-registers". Ideally we
+ should try to autodetect whether they are available, such that we
+ can prevent "info all-registers" from displaying registers that
+ aren't available.
- /* The i386 default settings don't include the SSE registers.
- FIXME: kettenis/20020614: They do include the FPU registers for
- now, which probably is not quite right. */
- tdep->num_xmm_regs = 0;
+ NOTE: kevinb/2003-07-13: ... if it's a choice between printing
+ [the SSE registers] always (even when they don't exist) or never
+ showing them to the user (even when they do exist), I prefer the
+ former over the latter. */
+
+ tdep->st0_regnum = I386_ST0_REGNUM;
+
+ /* The MMX registers are implemented as pseudo-registers. Put off
+ calculating the register number for %mm0 until we know the number
+ of raw registers. */
+ tdep->mm0_regnum = 0;
+
+ /* I386_NUM_XREGS includes %mxcsr, so substract one. */
+ 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;
alignment. */
set_gdbarch_long_double_bit (gdbarch, 96);
- /* NOTE: tm-i386aix.h, tm-i386bsd.h, tm-i386os9k.h, tm-ptx.h,
- tm-symmetry.h currently override this. Sigh. */
- set_gdbarch_num_regs (gdbarch, I386_NUM_GREGS + I386_NUM_FREGS);
-
- set_gdbarch_sp_regnum (gdbarch, 4); /* %esp */
- set_gdbarch_fp_regnum (gdbarch, 5); /* %ebp */
- set_gdbarch_pc_regnum (gdbarch, 8); /* %eip */
- set_gdbarch_ps_regnum (gdbarch, 9); /* %eflags */
- set_gdbarch_fp0_regnum (gdbarch, 16); /* %st(0) */
-
- /* Use the "default" register numbering scheme for stabs and COFF. */
- set_gdbarch_stab_reg_to_regnum (gdbarch, i386_stab_reg_to_regnum);
- set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_stab_reg_to_regnum);
+ /* The default ABI includes general-purpose registers,
+ floating-point registers, and the SSE registers. */
+ 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);
- /* Use the DWARF register numbering scheme for DWARF and DWARF 2. */
- set_gdbarch_dwarf_reg_to_regnum (gdbarch, i386_dwarf_reg_to_regnum);
- set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_dwarf_reg_to_regnum);
+ /* Register numbers of various important registers. */
+ set_gdbarch_sp_regnum (gdbarch, I386_ESP_REGNUM); /* %esp */
+ set_gdbarch_pc_regnum (gdbarch, I386_EIP_REGNUM); /* %eip */
+ set_gdbarch_ps_regnum (gdbarch, I386_EFLAGS_REGNUM); /* %eflags */
+ set_gdbarch_fp0_regnum (gdbarch, I386_ST0_REGNUM); /* %st(0) */
+
+ /* NOTE: kettenis/20040418: GCC does have two possible register
+ numbering schemes on the i386: dbx and SVR4. These schemes
+ differ in how they number %ebp, %esp, %eflags, and the
+ floating-point registers, and are implemented by the arrays
+ dbx_register_map[] and svr4_dbx_register_map in
+ gcc/config/i386.c. GCC also defines a third numbering scheme in
+ gcc/config/i386.c, which it designates as the "default" register
+ map used in 64bit mode. This last register numbering scheme is
+ implemented in dbx64_register_map, and is used for AMD64; see
+ amd64-tdep.c.
+
+ Currently, each GCC i386 target always uses the same register
+ numbering scheme across all its supported debugging formats
+ i.e. SDB (COFF), stabs and DWARF 2. This is because
+ gcc/sdbout.c, gcc/dbxout.c and gcc/dwarf2out.c all use the
+ DBX_REGISTER_NUMBER macro which is defined by each target's
+ respective config header in a manner independent of the requested
+ output debugging format.
+
+ This does not match the arrangement below, which presumes that
+ the SDB and stabs numbering schemes differ from the DWARF and
+ DWARF 2 ones. The reason for this arrangement is that it is
+ likely to get the numbering scheme for the target's
+ default/native debug format right. For targets where GCC is the
+ native compiler (FreeBSD, NetBSD, OpenBSD, GNU/Linux) or for
+ targets where the native toolchain uses a different numbering
+ scheme for a particular debug format (stabs-in-ELF on Solaris)
+ the defaults below will have to be overridden, like
+ i386_elf_init_abi() does. */
+
+ /* Use the dbx register numbering scheme for stabs and COFF. */
+ 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);
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
/* We don't define ECOFF_REG_TO_REGNUM, since ECOFF doesn't seem to
be in use on any of the supported i386 targets. */
- set_gdbarch_register_name (gdbarch, i386_register_name);
- set_gdbarch_register_size (gdbarch, 4);
- set_gdbarch_register_bytes (gdbarch, I386_SIZEOF_GREGS + I386_SIZEOF_FREGS);
- set_gdbarch_register_type (gdbarch, i386_register_type);
-
set_gdbarch_print_float_info (gdbarch, i387_print_float_info);
set_gdbarch_get_longjmp_target (gdbarch, i386_get_longjmp_target);
/* Call dummy code. */
- set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
- set_gdbarch_call_dummy_start_offset (gdbarch, 0);
- set_gdbarch_call_dummy_breakpoint_offset (gdbarch, 0);
- set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
- set_gdbarch_call_dummy_length (gdbarch, 0);
- set_gdbarch_call_dummy_p (gdbarch, 1);
- set_gdbarch_call_dummy_words (gdbarch, NULL);
- set_gdbarch_sizeof_call_dummy_words (gdbarch, 0);
- set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
-
- set_gdbarch_register_convertible (gdbarch, i386_register_convertible);
- set_gdbarch_register_convert_to_virtual (gdbarch,
- i386_register_convert_to_virtual);
- set_gdbarch_register_convert_to_raw (gdbarch, i386_register_convert_to_raw);
-
- /* "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" -- from the x86 ABI. */
- set_gdbarch_parm_boundary (gdbarch, 32);
-
- set_gdbarch_extract_return_value (gdbarch, i386_extract_return_value);
- set_gdbarch_deprecated_push_arguments (gdbarch, i386_push_arguments);
- set_gdbarch_deprecated_push_return_address (gdbarch, i386_push_return_address);
- set_gdbarch_deprecated_pop_frame (gdbarch, i386_pop_frame);
- set_gdbarch_store_return_value (gdbarch, i386_store_return_value);
- set_gdbarch_extract_struct_value_address (gdbarch,
- i386_extract_struct_value_address);
- set_gdbarch_use_struct_convention (gdbarch, i386_use_struct_convention);
-
- set_gdbarch_deprecated_frame_init_saved_regs (gdbarch, i386_frame_init_saved_regs);
+ 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);
/* Stack grows downward. */
set_gdbarch_breakpoint_from_pc (gdbarch, i386_breakpoint_from_pc);
set_gdbarch_decr_pc_after_break (gdbarch, 1);
- set_gdbarch_function_start_offset (gdbarch, 0);
-
- /* The following redefines make backtracing through sigtramp work.
- They manufacture a fake sigtramp frame and obtain the saved pc in
- sigtramp from the sigcontext structure which is pushed by the
- kernel on the user stack, along with a pointer to it. */
set_gdbarch_frame_args_skip (gdbarch, 8);
- set_gdbarch_frameless_function_invocation (gdbarch,
- i386_frameless_function_invocation);
- set_gdbarch_deprecated_frame_chain (gdbarch, i386_frame_chain);
- set_gdbarch_deprecated_frame_saved_pc (gdbarch, i386_frame_saved_pc);
- set_gdbarch_saved_pc_after_call (gdbarch, i386_saved_pc_after_call);
- set_gdbarch_frame_num_args (gdbarch, i386_frame_num_args);
- set_gdbarch_pc_in_sigtramp (gdbarch, i386_pc_in_sigtramp);
/* Wire in the MMX registers. */
- set_gdbarch_num_pseudo_regs (gdbarch, mmx_num_regs);
+ 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);
+
/* Add the i386 register groups. */
i386_add_reggroups (gdbarch);
set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p);
- /* Should be using push_dummy_call. */
- set_gdbarch_deprecated_dummy_write_sp (gdbarch, generic_target_write_sp);
+ /* Helper for function argument information. */
+ set_gdbarch_fetch_pointer_argument (gdbarch, i386_fetch_pointer_argument);
+
+ /* Hook in the DWARF CFI frame unwinder. */
+ frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
+
+ frame_base_set_default (gdbarch, &i386_frame_base);
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
+ frame_unwind_append_sniffer (gdbarch, i386_sigtramp_frame_sniffer);
+ frame_unwind_append_sniffer (gdbarch, i386_frame_sniffer);
+
+ /* If we have a register mapping, enable the generic core file
+ support, unless it has already been enabled. */
+ if (tdep->gregset_reg_offset
+ && !gdbarch_regset_from_core_section_p (gdbarch))
+ set_gdbarch_regset_from_core_section (gdbarch,
+ i386_regset_from_core_section);
+
+ /* Unless support for MMX has been disabled, make %mm0 the first
+ pseudo-register. */
+ if (tdep->mm0_regnum == 0)
+ tdep->mm0_regnum = gdbarch_num_regs (gdbarch);
+
return gdbarch;
}
register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init);
/* Add the variable that controls the disassembly flavor. */
- {
- struct cmd_list_element *new_cmd;
-
- new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class,
- valid_flavors,
- &disassembly_flavor,
- "\
-Set the disassembly flavor, the valid values are \"att\" and \"intel\", \
-and the default value is \"att\".",
- &setlist);
- add_show_from_set (new_cmd, &showlist);
- }
+ 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, /* FIXME: i18n: */
+ &setlist, &showlist);
/* Add the variable that controls the convention for returning
structs. */
- {
- struct cmd_list_element *new_cmd;
-
- new_cmd = add_set_enum_cmd ("struct-convention", no_class,
- valid_conventions,
- &struct_convention, "\
-Set the convention for returning small structs, valid values \
-are \"default\", \"pcc\" and \"reg\", and the default value is \"default\".",
- &setlist);
- add_show_from_set (new_cmd, &showlist);
- }
+ 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, /* FIXME: i18n: */
+ &setlist, &showlist);
gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_coff_flavour,
i386_coff_osabi_sniffer);
gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETWARE,
i386_nw_init_abi);
- /* Initialize the i386 specific register groups. */
+ /* Initialize the i386-specific register groups & types. */
i386_init_reggroups ();
+ i386_init_types();
}