/* Intel 386 target-dependent stuff.
- Copyright (C) 1988, 1989, 1991 Free Software Foundation, Inc.
+ Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 1998, 1999, 2000, 2001
+ Free Software Foundation, Inc.
-This file is part of GDB.
+ This file is part of GDB.
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
-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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ 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. */
#include "defs.h"
+#include "gdb_string.h"
#include "frame.h"
#include "inferior.h"
#include "gdbcore.h"
#include "target.h"
+#include "floatformat.h"
+#include "symtab.h"
+#include "gdbcmd.h"
+#include "command.h"
+#include "arch-utils.h"
+#include "regcache.h"
-static long
-i386_get_frame_setup PARAMS ((int));
+/* i386_register_byte[i] is the offset into the register file of the
+ start of register number i. We initialize this from
+ i386_register_raw_size. */
+int i386_register_byte[MAX_NUM_REGS];
-static void
-i386_follow_jump PARAMS ((void));
+/* i386_register_raw_size[i] is the number of bytes of storage in
+ GDB's register array occupied by register i. */
+int i386_register_raw_size[MAX_NUM_REGS] = {
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 10, 10, 10, 10,
+ 10, 10, 10, 10,
+ 4, 4, 4, 4,
+ 4, 4, 4, 4,
+ 16, 16, 16, 16,
+ 16, 16, 16, 16,
+ 4
+};
-static void
-codestream_read PARAMS ((unsigned char *, int));
+/* i386_register_virtual_size[i] is the size in bytes of the virtual
+ type of register i. */
+int i386_register_virtual_size[MAX_NUM_REGS];
+\f
-static void
-codestream_seek PARAMS ((int));
-
-static unsigned char
-codestream_fill PARAMS ((int));
-
-/* helper functions for tm-i386.h */
-
-/* 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. */
+/* This is the variable that is set with "set disassembly-flavor", and
+ its legitimate values. */
+static const char att_flavor[] = "att";
+static const char intel_flavor[] = "intel";
+static const char *valid_flavors[] =
+{
+ att_flavor,
+ intel_flavor,
+ NULL
+};
+static const char *disassembly_flavor = att_flavor;
+
+/* This is used to keep the bfd arch_info in sync with the disassembly
+ flavor. */
+static void set_disassembly_flavor_sfunc (char *, int,
+ struct cmd_list_element *);
+static void set_disassembly_flavor (void);
+\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_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++])
+#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 (peek_flag)
- int peek_flag;
+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());
+ return (codestream_peek ());
else
- return (codestream_get());
+ return (codestream_get ());
}
static void
-codestream_seek (place)
- int place;
+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)
+ while (codestream_tell () != place)
codestream_get ();
}
static void
-codestream_read (buf, count)
- unsigned char *buf;
- int count;
+codestream_read (unsigned char *buf, int count)
{
unsigned char *p;
int i;
for (i = 0; i < count; i++)
*p++ = codestream_get ();
}
+\f
-/* next instruction is a jump, move to target */
+/* If the next instruction is a jump, move to its target. */
static void
-i386_follow_jump ()
+i386_follow_jump (void)
{
- int long_delta;
- short short_delta;
- char byte_delta;
+ unsigned char buf[4];
+ long delta;
+
int data16;
- int pos;
-
+ CORE_ADDR pos;
+
pos = codestream_tell ();
-
+
data16 = 0;
if (codestream_peek () == 0x66)
{
codestream_get ();
data16 = 1;
}
-
+
switch (codestream_get ())
{
case 0xe9:
- /* relative jump: if data16 == 0, disp32, else disp16 */
+ /* Relative jump: if data16 == 0, disp32, else disp16. */
if (data16)
{
- codestream_read ((unsigned char *)&short_delta, 2);
+ codestream_read (buf, 2);
+ delta = extract_signed_integer (buf, 2);
- /* include size of jmp inst (including the 0x66 prefix). */
- pos += short_delta + 4;
+ /* Include the size of the jmp instruction (including the
+ 0x66 prefix). */
+ pos += delta + 4;
}
else
{
- codestream_read ((unsigned char *)&long_delta, 4);
- pos += long_delta + 5;
+ codestream_read (buf, 4);
+ delta = extract_signed_integer (buf, 4);
+
+ pos += delta + 5;
}
break;
case 0xeb:
- /* relative jump, disp8 (ignore data16) */
- codestream_read ((unsigned char *)&byte_delta, 1);
- pos += byte_delta + 2;
+ /* Relative jump, disp8 (ignore data16). */
+ codestream_read (buf, 1);
+ /* Sign-extend it. */
+ delta = extract_signed_integer (buf, 1);
+
+ pos += delta + 2;
break;
}
codestream_seek (pos);
}
-/*
- * find & return amound a local space allocated, and advance codestream to
- * first register push (if any)
- *
- * if entry sequence doesn't make sense, return -1, and leave
- * codestream pointer random
- */
+/* Find & return the amount a local space allocated, and advance the
+ codestream to the first register push (if any).
+
+ If the entry sequence doesn't make sense, return -1, and leave
+ codestream pointer at a random spot. */
static long
-i386_get_frame_setup (pc)
- int pc;
+i386_get_frame_setup (CORE_ADDR pc)
{
unsigned char op;
-
+
codestream_seek (pc);
-
+
i386_follow_jump ();
-
+
op = codestream_get ();
-
+
if (op == 0x58) /* popl %eax */
{
- /*
- * 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 5 compiler puts out the second xchg
- * inst, 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
- */
+ /* 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 };
+ 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 */
+ op = codestream_get (); /* Update next opcode. */
}
-
+
+ if (op == 0x68 || op == 0x6a)
+ {
+ /* This function may start with
+
+ pushl constant
+ call _probe
+ addl $4, %esp
+
+ followed by
+
+ pushl %ebp
+
+ etc. */
+ int pos;
+ unsigned char buf[8];
+
+ /* 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)
+ pos += 4;
+ else
+ pos += 1;
+ codestream_seek (pos);
+
+ /* Read the following 8 bytes, which should be "call _probe" (6
+ bytes) followed by "addl $4,%esp" (2 bytes). */
+ codestream_read (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. */
+ }
+
if (op == 0x55) /* pushl %ebp */
- {
- /* check for movl %esp, %ebp - can be written two ways */
+ {
+ /* Check for "movl %esp, %ebp" -- can be written in two ways. */
switch (codestream_get ())
{
case 0x8b:
if (codestream_get () != 0xec)
- return (-1);
+ return -1;
break;
case 0x89:
if (codestream_get () != 0xe5)
- return (-1);
+ return -1;
break;
default:
- return (-1);
+ return -1;
}
- /* check for stack adjustment
- *
- * subl $XXX, %esp
- *
- * 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
- */
+ /* Check for stack adjustment
+
+ subl $XXX, %esp
+
+ 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 immed */
+ /* `subl' with 8 bit immediate. */
codestream_get ();
if (codestream_get () != 0xec)
- /* Some instruction starting with 0x83 other than subl. */
+ /* 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());
+ /* `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 32 bit immedediate. */
- codestream_get();
+ /* Maybe it is `subl' with a 32 bit immedediate. */
+ codestream_get ();
if (codestream_get () != 0xec)
- /* Some instruction starting with 0x81 other than subl. */
+ /* Some instruction starting with 0x81 other than `subl'. */
{
codestream_seek (codestream_tell () - 2);
return 0;
}
- /* It is subl with 32 bit immediate. */
- codestream_read ((unsigned char *)buf, 4);
+ /* It is `subl' with a 32 bit immediate. */
+ codestream_read ((unsigned char *) buf, 4);
return extract_signed_integer (buf, 4);
}
else
{
- return (0);
+ return 0;
}
}
else if (op == 0xc8)
{
char buf[2];
- /* enter instruction: arg is 16 bit unsigned immed */
- codestream_read ((unsigned char *)buf, 2);
- codestream_get (); /* flush final byte of enter instruction */
+ /* `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);
}
+/* 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. */
+
+CORE_ADDR
+i386_frame_chain (struct frame_info *frame)
+{
+ if (frame->signal_handler_caller)
+ return frame->frame;
+
+ if (! inside_entry_file (frame->pc))
+ return read_memory_unsigned_integer (frame->frame, 4);
+
+ return 0;
+}
+
+/* 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. */
+
+int
+i386_frameless_function_invocation (struct frame_info *frame)
+{
+ if (frame->signal_handler_caller)
+ return 0;
+
+ return frameless_look_for_prologue (frame);
+}
+
+/* Return the saved program counter for FRAME. */
+
+CORE_ADDR
+i386_frame_saved_pc (struct frame_info *frame)
+{
+ /* FIXME: kettenis/2001-05-09: Conditionalizing the next bit of code
+ on SIGCONTEXT_PC_OFFSET and I386V4_SIGTRAMP_SAVED_PC should be
+ considered a temporary hack. I plan to come up with something
+ better when we go multi-arch. */
+#if defined (SIGCONTEXT_PC_OFFSET) || defined (I386V4_SIGTRAMP_SAVED_PC)
+ if (frame->signal_handler_caller)
+ return sigtramp_saved_pc (frame);
+#endif
+
+ return read_memory_unsigned_integer (frame->frame + 4, 4);
+}
+
+/* Immediately after a function call, return the saved pc. */
+
+CORE_ADDR
+i386_saved_pc_after_call (struct frame_info *frame)
+{
+ return read_memory_unsigned_integer (read_register (SP_REGNUM), 4);
+}
+
/* Return number of args passed to a frame.
Can return -1, meaning no way to tell. */
int
-i386_frame_num_args (fi)
- struct frame_info *fi;
+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. */
+ 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;
+ int retpc;
+ unsigned char op;
struct frame_info *pfi;
- /* on the 386, the instruction following the call could be:
+ /* 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 */
+ anything else - zero args. */
int frameless;
- FRAMELESS_FUNCTION_INVOCATION (fi, 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. */
+ /* 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_info (fi);
+ pfi = get_prev_frame (fi);
if (pfi == 0)
{
- /* Note: this can happen if we are looking at the frame for
- main, because 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. */
+ /* NOTE: This can happen if we are looking at the frame for
+ main, because 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;
+ retpc = pfi->pc;
+ op = read_memory_integer (retpc, 1);
+ if (op == 0x59) /* pop %ecx */
+ return 1;
else 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;
+ 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;
}
- else if (op == 0x81)
- { /* add with 32 bit immediate */
- op = read_memory_integer (retpc+1, 1);
- if (op == 0xc4)
- /* addl $<imm 32>, %esp */
- return read_memory_integer (retpc+2, 4) / 4;
+ else if (op == 0x81) /* `add' with 32 bit immediate. */
+ {
+ 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;
}
#endif
}
-/*
- * parse the first few instructions of the function to see
- * what registers were stored.
- *
- * We handle these cases:
- *
- * The startup sequence can be at the start of the function,
- * or the function can start with a branch to startup code at the end.
- *
- * %ebp can be set up with either the 'enter' instruction, or
- * 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
- * but was once used in the sys5 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.
- *
- * Next, the registers used by this function are pushed. In
- * the sys5 compiler they will always be in the order: %edi, %esi, %ebx
- * (and sometimes a harmless bug causes it to also save but not restore %eax);
- * however, the code below is willing to see the pushes in any order,
- * and will handle up to 8 of them.
- *
- * If the setup sequence is at the end of the function, then the
- * next instruction will be a branch back to the start.
- */
+/* Parse the first few instructions the function to see what registers
+ were stored.
+
+ We handle these cases:
+
+ The startup sequence can be at the start of the function, or the
+ function can start with a branch to startup code at the end.
+
+ %ebp can be set up with either the 'enter' instruction, or "pushl
+ %ebp, movl %esp, %ebp" (`enter' is too slow to be useful, but was
+ 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.
+
+ Next, the registers used by this function are pushed. With the
+ System V compiler they will always be in the order: %edi, %esi,
+ %ebx (and sometimes a harmless bug causes it to also save but not
+ restore %eax); however, the code below is willing to see the pushes
+ in any order, and will handle up to 8 of them.
+
+ If the setup sequence is at the end of the function, then the next
+ instruction will be a branch back to the start. */
void
-i386_frame_find_saved_regs (fip, fsrp)
- struct frame_info *fip;
- struct frame_saved_regs *fsrp;
+i386_frame_init_saved_regs (struct frame_info *fip)
{
- long locals;
+ long locals = -1;
unsigned char op;
CORE_ADDR dummy_bottom;
- CORE_ADDR adr;
+ CORE_ADDR addr;
+ CORE_ADDR pc;
int i;
-
- memset (fsrp, 0, sizeof *fsrp);
-
- /* if frame is the end of a dummy, compute where the
- * beginning would be
- */
+
+ if (fip->saved_regs)
+ return;
+
+ frame_saved_regs_zalloc (fip);
+
+ /* If the frame is the end of a dummy, compute where the beginning
+ would be. */
dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;
-
- /* check if the PC is in the stack, in a dummy frame */
- if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
+
+ /* Check if the PC points in the stack, in a dummy frame. */
+ if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
{
- /* all regs were saved by push_call_dummy () */
- adr = fip->frame;
- for (i = 0; i < NUM_REGS; i++)
+ /* All registers were saved by push_call_dummy. */
+ addr = fip->frame;
+ for (i = 0; i < NUM_REGS; i++)
{
- adr -= REGISTER_RAW_SIZE (i);
- fsrp->regs[i] = adr;
+ addr -= REGISTER_RAW_SIZE (i);
+ fip->saved_regs[i] = addr;
}
return;
}
-
- locals = i386_get_frame_setup (get_pc_function_start (fip->pc));
-
- if (locals >= 0)
+
+ pc = get_pc_function_start (fip->pc);
+ if (pc != 0)
+ locals = i386_get_frame_setup (pc);
+
+ if (locals >= 0)
{
- adr = fip->frame - 4 - locals;
- for (i = 0; i < 8; i++)
+ addr = fip->frame - 4 - locals;
+ for (i = 0; i < 8; i++)
{
op = codestream_get ();
if (op < 0x50 || op > 0x57)
break;
- fsrp->regs[op - 0x50] = adr;
- adr -= 4;
+#ifdef I386_REGNO_TO_SYMMETRY
+ /* Dynix uses different internal numbering. Ick. */
+ fip->saved_regs[I386_REGNO_TO_SYMMETRY (op - 0x50)] = addr;
+#else
+ fip->saved_regs[op - 0x50] = addr;
+#endif
+ addr -= 4;
}
}
-
- fsrp->regs[PC_REGNUM] = fip->frame + 4;
- fsrp->regs[FP_REGNUM] = fip->frame;
+
+ fip->saved_regs[PC_REGNUM] = fip->frame + 4;
+ fip->saved_regs[FP_REGNUM] = fip->frame;
}
-/* return pc of first real instruction */
+/* Return PC of first real instruction. */
int
-i386_skip_prologue (pc)
- int pc;
+i386_skip_prologue (int pc)
{
unsigned char op;
int i;
-
+ static unsigned char 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);
-
- /* found valid frame setup - codestream now points to
- * start of push instructions for saving registers
- */
-
- /* skip over register saves */
+
+ /* Found valid frame setup -- codestream now points to start of push
+ instructions for saving registers. */
+
+ /* Skip over register saves. */
for (i = 0; i < 8; i++)
{
op = codestream_peek ();
- /* break if not pushl inst */
- if (op < 0x50 || op > 0x57)
+ /* Break if not `pushl' instrunction. */
+ if (op < 0x50 || op > 0x57)
break;
codestream_get ();
}
-
+
+ /* 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
+
+ call 0x0
+ popl %ebx
+ movl %ebx,x(%ebp) (optional)
+ addl y,%ebx
+
+ This code is with the rest of the prologue (at the end of the
+ 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 ();
+ if (pic_pat[i] != op)
+ break;
+ }
+ if (i == 6)
+ {
+ unsigned char buf[4];
+ long delta = 6;
+
+ op = codestream_get ();
+ if (op == 0x89) /* movl %ebx, x(%ebp) */
+ {
+ op = codestream_get ();
+ if (op == 0x5d) /* One byte offset from %ebp. */
+ {
+ delta += 3;
+ codestream_read (buf, 1);
+ }
+ else if (op == 0x9d) /* Four byte offset from %ebp. */
+ {
+ delta += 6;
+ codestream_read (buf, 4);
+ }
+ else /* Unexpected instruction. */
+ delta = -1;
+ op = codestream_get ();
+ }
+ /* addl y,%ebx */
+ if (delta > 0 && op == 0x81 && codestream_get () == 0xc3)
+ {
+ pos += delta + 6;
+ }
+ }
+ codestream_seek (pos);
+
i386_follow_jump ();
-
+
return (codestream_tell ());
}
void
-i386_push_dummy_frame ()
+i386_push_dummy_frame (void)
{
CORE_ADDR sp = read_register (SP_REGNUM);
int regnum;
char regbuf[MAX_REGISTER_RAW_SIZE];
-
+
sp = push_word (sp, read_register (PC_REGNUM));
sp = push_word (sp, read_register (FP_REGNUM));
write_register (FP_REGNUM, sp);
write_register (SP_REGNUM, sp);
}
+/* Insert the (relative) function address into the call sequence
+ stored at DYMMY. */
+
void
-i386_pop_frame ()
+i386_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ value_ptr *args, struct type *type, int gcc_p)
{
- FRAME frame = get_current_frame ();
+ int from, to, delta, loc;
+
+ loc = (int)(read_register (SP_REGNUM) - CALL_DUMMY_LENGTH);
+ from = loc + 5;
+ to = (int)(fun);
+ delta = to - from;
+
+ *((char *)(dummy) + 1) = (delta & 0xff);
+ *((char *)(dummy) + 2) = ((delta >> 8) & 0xff);
+ *((char *)(dummy) + 3) = ((delta >> 16) & 0xff);
+ *((char *)(dummy) + 4) = ((delta >> 24) & 0xff);
+}
+
+void
+i386_pop_frame (void)
+{
+ struct frame_info *frame = get_current_frame ();
CORE_ADDR fp;
int regnum;
- struct frame_saved_regs fsr;
- struct frame_info *fi;
char regbuf[MAX_REGISTER_RAW_SIZE];
-
- fi = get_frame_info (frame);
- fp = fi->frame;
- get_frame_saved_regs (fi, &fsr);
- for (regnum = 0; regnum < NUM_REGS; regnum++)
+
+ fp = FRAME_FP (frame);
+ i386_frame_init_saved_regs (frame);
+
+ for (regnum = 0; regnum < NUM_REGS; regnum++)
{
- CORE_ADDR adr;
- adr = fsr.regs[regnum];
- if (adr)
+ CORE_ADDR addr;
+ addr = frame->saved_regs[regnum];
+ if (addr)
{
- read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
+ read_memory (addr, regbuf, REGISTER_RAW_SIZE (regnum));
write_register_bytes (REGISTER_BYTE (regnum), regbuf,
REGISTER_RAW_SIZE (regnum));
}
write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
write_register (SP_REGNUM, fp + 8);
flush_cached_frames ();
- set_current_frame ( create_new_frame (read_register (FP_REGNUM),
- read_pc ()));
}
+\f
#ifdef GET_LONGJMP_TARGET
-/* Figure out where the longjmp will land. Slurp the args out of the stack.
- We expect the first arg to be a pointer to the jmp_buf structure from which
- we extract the pc (JB_PC) that we will land at. The pc is copied into PC.
- This routine returns true on success. */
+/* Figure out where the longjmp will land. Slurp the args out of the
+ stack. We expect the first arg to be a pointer to the jmp_buf
+ structure from which we extract the pc (JB_PC) that we will land
+ at. The pc is copied into PC. This routine returns true on
+ success. */
int
-get_longjmp_target(pc)
- CORE_ADDR *pc;
+get_longjmp_target (CORE_ADDR *pc)
{
char buf[TARGET_PTR_BIT / TARGET_CHAR_BIT];
CORE_ADDR sp, jb_addr;
sp = read_register (SP_REGNUM);
- if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack */
+ if (target_read_memory (sp + SP_ARG0, /* Offset of first arg on stack. */
buf,
TARGET_PTR_BIT / TARGET_CHAR_BIT))
return 0;
}
#endif /* GET_LONGJMP_TARGET */
+\f
+
+CORE_ADDR
+i386_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp,
+ int struct_return, CORE_ADDR struct_addr)
+{
+ sp = default_push_arguments (nargs, args, sp, struct_return, struct_addr);
+
+ if (struct_return)
+ {
+ char buf[4];
+
+ sp -= 4;
+ store_address (buf, 4, struct_addr);
+ write_memory (sp, buf, 4);
+ }
+
+ return sp;
+}
+
+void
+i386_store_struct_return (CORE_ADDR addr, CORE_ADDR sp)
+{
+ /* Do nothing. Everything was already done by i386_push_arguments. */
+}
-#ifdef I386_AIX_TARGET
-/* On AIX, floating point values are returned in floating point registers. */
+/* 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 */
+
+/* Extract from an array REGBUF containing the (raw) register state, a
+ function return value of TYPE, and copy that, in virtual format,
+ into VALBUF. */
void
-i386_extract_return_value(type, regbuf, valbuf)
- struct type *type;
- char regbuf[REGISTER_BYTES];
- char *valbuf;
+i386_extract_return_value (struct type *type, char *regbuf, char *valbuf)
{
- if (TYPE_CODE_FLT == TYPE_CODE(type))
+ int len = TYPE_LENGTH (type);
+
+ if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+ && TYPE_NFIELDS (type) == 1)
{
- extern struct ext_format ext_format_i387;
- double d;
- /* 387 %st(0), gcc uses this */
- ieee_extended_to_double (&ext_format_i387,
- ®buf[REGISTER_BYTE(FP0_REGNUM)],
- &d);
- switch (TYPE_LENGTH(type))
+ i386_extract_return_value (TYPE_FIELD_TYPE (type, 0), regbuf, valbuf);
+ return;
+ }
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ if (NUM_FREGS == 0)
{
- case 4: /* float */
- {
- float f = (float) d;
- memcpy (valbuf, &f, 4);
- break;
- }
- case 8: /* double */
- memcpy (valbuf, &d, 8);
- break;
- default:
- error("Unknown floating point size");
- break;
+ warning ("Cannot find floating-point return value.");
+ memset (valbuf, 0, len);
+ return;
+ }
+
+ /* Floating-point return values can be found in %st(0).
+ FIXME: Does %st(0) always correspond to FP0? */
+ if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT
+ && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext)
+ {
+ /* Copy straight over, but take care of the padding. */
+ memcpy (valbuf, ®buf[REGISTER_BYTE (FP0_REGNUM)],
+ FPU_REG_RAW_SIZE);
+ memset (valbuf + FPU_REG_RAW_SIZE, 0, len - FPU_REG_RAW_SIZE);
+ }
+ else
+ {
+ /* Convert the extended floating-point number found in
+ %st(0) 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. */
+ DOUBLEST val;
+ floatformat_to_doublest (&floatformat_i387_ext,
+ ®buf[REGISTER_BYTE (FP0_REGNUM)], &val);
+ store_floating (valbuf, TYPE_LENGTH (type), val);
+ }
+ }
+ else
+ {
+ int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
+ int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+
+ if (len <= low_size)
+ memcpy (valbuf, ®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], len);
+ else if (len <= (low_size + high_size))
+ {
+ memcpy (valbuf,
+ ®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], low_size);
+ memcpy (valbuf + low_size,
+ ®buf[REGISTER_BYTE (HIGH_RETURN_REGNUM)], len - low_size);
}
+ else
+ internal_error (__FILE__, __LINE__,
+ "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. */
+
+void
+i386_store_return_value (struct type *type, char *valbuf)
+{
+ 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), valbuf);
+ return;
+ }
+
+ if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ {
+ unsigned int fstat;
+
+ if (NUM_FREGS == 0)
+ {
+ warning ("Cannot set floating-point return value.");
+ return;
+ }
+
+ /* Floating-point return values can be found in %st(0). */
+ if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT
+ && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext)
+ {
+ /* Copy straight over. */
+ write_register_bytes (REGISTER_BYTE (FP0_REGNUM), valbuf,
+ FPU_REG_RAW_SIZE);
+ }
+ else
+ {
+ char buf[FPU_REG_RAW_SIZE];
+ DOUBLEST val;
+
+ /* Convert the value found in VALBUF to the extended
+ floating point format used by the FPU. This is probably
+ not exactly how it would happen on the target itself, but
+ it is the best we can do. */
+ val = extract_floating (valbuf, TYPE_LENGTH (type));
+ floatformat_from_doublest (&floatformat_i387_ext, &val, buf);
+ write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf,
+ FPU_REG_RAW_SIZE);
+ }
+
+ /* Set the top of the floating point register stack to 7. That
+ makes sure that FP0 (which we set above) is indeed %st(0).
+ FIXME: Perhaps we should completely reset the status word? */
+ fstat = read_register (FSTAT_REGNUM);
+ fstat |= (7 << 11);
+ write_register (FSTAT_REGNUM, fstat);
+
+ /* Mark %st(1) through %st(7) as empty. */
+ write_register (FTAG_REGNUM, 0x3fff);
}
else
- {
- memcpy (valbuf, regbuf, TYPE_LENGTH (type));
+ {
+ int low_size = REGISTER_RAW_SIZE (LOW_RETURN_REGNUM);
+ int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM);
+
+ if (len <= low_size)
+ write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM), valbuf, len);
+ else if (len <= (low_size + high_size))
+ {
+ write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM),
+ valbuf, low_size);
+ write_register_bytes (REGISTER_BYTE (HIGH_RETURN_REGNUM),
+ valbuf + low_size, len - low_size);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ "Cannot store return value of %d bytes long.", len);
+ }
+}
+
+/* Extract from an array REGBUF containing the (raw) register state
+ the address in which a function should return its structure value,
+ as a CORE_ADDR. */
+
+CORE_ADDR
+i386_extract_struct_value_address (char *regbuf)
+{
+ return extract_address (®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)],
+ REGISTER_RAW_SIZE (LOW_RETURN_REGNUM));
+}
+\f
+
+/* 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. */
+
+struct type *
+i386_register_virtual_type (int regnum)
+{
+ if (regnum == PC_REGNUM || regnum == FP_REGNUM || regnum == SP_REGNUM)
+ return lookup_pointer_type (builtin_type_void);
+
+ if (IS_FP_REGNUM (regnum))
+ return builtin_type_long_double;
+
+ if (IS_SSE_REGNUM (regnum))
+ return builtin_type_v4sf;
+
+ return builtin_type_int;
+}
+
+/* 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. */
+
+int
+i386_register_convertible (int regnum)
+{
+ return IS_FP_REGNUM (regnum);
+}
+
+/* Convert data from raw format for register REGNUM in buffer FROM to
+ virtual format with type TYPE in buffer TO. In principle both
+ formats are identical except that the virtual format has two extra
+ bytes appended that aren't used. We set these to zero. */
+
+void
+i386_register_convert_to_virtual (int regnum, struct type *type,
+ char *from, char *to)
+{
+ /* Copy straight over, but take care of the padding. */
+ memcpy (to, from, FPU_REG_RAW_SIZE);
+ memset (to + FPU_REG_RAW_SIZE, 0, TYPE_LENGTH (type) - FPU_REG_RAW_SIZE);
+}
+
+/* Convert data from virtual format with type TYPE in buffer FROM to
+ raw format for register REGNUM in buffer TO. Simply omit the two
+ unused bytes. */
+
+void
+i386_register_convert_to_raw (struct type *type, int regnum,
+ char *from, char *to)
+{
+ memcpy (to, from, FPU_REG_RAW_SIZE);
+}
+\f
+
+#ifdef I386V4_SIGTRAMP_SAVED_PC
+/* Get saved user PC for sigtramp from the pushed ucontext on the
+ stack for all three variants of SVR4 sigtramps. */
+
+CORE_ADDR
+i386v4_sigtramp_saved_pc (struct frame_info *frame)
+{
+ CORE_ADDR saved_pc_offset = 4;
+ char *name = NULL;
+
+ find_pc_partial_function (frame->pc, &name, NULL, NULL);
+ if (name)
+ {
+ if (STREQ (name, "_sigreturn"))
+ saved_pc_offset = 132 + 14 * 4;
+ else if (STREQ (name, "_sigacthandler"))
+ saved_pc_offset = 80 + 14 * 4;
+ else if (STREQ (name, "sigvechandler"))
+ saved_pc_offset = 120 + 14 * 4;
+ }
+
+ if (frame->next)
+ return read_memory_integer (frame->next->frame + saved_pc_offset, 4);
+ return read_memory_integer (read_register (SP_REGNUM) + saved_pc_offset, 4);
+}
+#endif /* I386V4_SIGTRAMP_SAVED_PC */
+\f
+
+#ifdef STATIC_TRANSFORM_NAME
+/* SunPRO encodes the static variables. This is not related to C++
+ mangling, it is done for C too. */
+
+char *
+sunpro_static_transform_name (char *name)
+{
+ char *p;
+ if (IS_STATIC_TRANSFORM_NAME (name))
+ {
+ /* For file-local statics there will be a period, a bunch of
+ junk (the contents of which match a string given in the
+ N_OPT), a period and the name. For function-local statics
+ there will be a bunch of junk (which seems to change the
+ second character from 'A' to 'B'), a period, the name of the
+ function, and the name. So just skip everything before the
+ last period. */
+ p = strrchr (name, '.');
+ if (p != NULL)
+ name = p + 1;
+ }
+ return name;
+}
+#endif /* STATIC_TRANSFORM_NAME */
+\f
+
+/* Stuff for WIN32 PE style DLL's but is pretty generic really. */
+
+CORE_ADDR
+skip_trampoline_code (CORE_ADDR pc, char *name)
+{
+ if (pc && read_memory_unsigned_integer (pc, 2) == 0x25ff) /* jmp *(dest) */
+ {
+ unsigned long indirect = read_memory_unsigned_integer (pc + 2, 4);
+ struct minimal_symbol *indsym =
+ indirect ? lookup_minimal_symbol_by_pc (indirect) : 0;
+ char *symname = indsym ? SYMBOL_NAME (indsym) : 0;
+
+ if (symname)
+ {
+ if (strncmp (symname, "__imp_", 6) == 0
+ || strncmp (symname, "_imp_", 5) == 0)
+ return name ? 1 : read_memory_unsigned_integer (indirect, 4);
+ }
}
+ return 0; /* Not a trampoline. */
+}
+\f
+
+/* We have two flavours of disassembly. The machinery on this page
+ deals with switching between those. */
+
+static int
+gdb_print_insn_i386 (bfd_vma memaddr, disassemble_info *info)
+{
+ if (disassembly_flavor == att_flavor)
+ return print_insn_i386_att (memaddr, info);
+ else if (disassembly_flavor == intel_flavor)
+ return print_insn_i386_intel (memaddr, info);
+ /* Never reached -- disassembly_flavour is always either att_flavor
+ or intel_flavor. */
+ internal_error (__FILE__, __LINE__, "failed internal consistency check");
+}
+
+/* If the disassembly mode is intel, we have to also switch the bfd
+ mach_type. This function is run in the set disassembly_flavor
+ command, and does that. */
+
+static void
+set_disassembly_flavor_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
+{
+ set_disassembly_flavor ();
+}
+
+static void
+set_disassembly_flavor (void)
+{
+ if (disassembly_flavor == att_flavor)
+ set_architecture_from_arch_mach (bfd_arch_i386, bfd_mach_i386_i386);
+ else if (disassembly_flavor == intel_flavor)
+ set_architecture_from_arch_mach (bfd_arch_i386,
+ bfd_mach_i386_i386_intel_syntax);
+}
+\f
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+void _initialize_i386_tdep (void);
+
+void
+_initialize_i386_tdep (void)
+{
+ /* Initialize the table saying where each register starts in the
+ register file. */
+ {
+ int i, offset;
+
+ offset = 0;
+ for (i = 0; i < MAX_NUM_REGS; i++)
+ {
+ i386_register_byte[i] = offset;
+ offset += i386_register_raw_size[i];
+ }
+ }
+
+ /* Initialize the table of virtual register sizes. */
+ {
+ int i;
+
+ for (i = 0; i < MAX_NUM_REGS; i++)
+ i386_register_virtual_size[i] = TYPE_LENGTH (REGISTER_VIRTUAL_TYPE (i));
+ }
+
+ tm_print_insn = gdb_print_insn_i386;
+ tm_print_insn_info.mach = bfd_lookup_arch (bfd_arch_i386, 0)->mach;
+
+ /* 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);
+ new_cmd->function.sfunc = set_disassembly_flavor_sfunc;
+ add_show_from_set (new_cmd, &showlist);
+ }
+
+ /* Finally, initialize the disassembly flavor to the default given
+ in the disassembly_flavor variable. */
+ set_disassembly_flavor ();
}
-#endif /* I386_AIX_TARGET */