#include "symtab.h"
#include "gdbcmd.h"
#include "command.h"
+#include "arch-utils.h"
-static long i386_get_frame_setup PARAMS ((CORE_ADDR));
+static long i386_get_frame_setup (CORE_ADDR);
-static void i386_follow_jump PARAMS ((void));
+static void i386_follow_jump (void);
-static void codestream_read PARAMS ((unsigned char *, int));
+static void codestream_read (unsigned char *, int);
-static void codestream_seek PARAMS ((CORE_ADDR));
+static void codestream_seek (CORE_ADDR);
-static unsigned char codestream_fill PARAMS ((int));
+static unsigned char codestream_fill (int);
-CORE_ADDR skip_trampoline_code PARAMS ((CORE_ADDR, char *));
+CORE_ADDR skip_trampoline_code (CORE_ADDR, char *);
static int gdb_print_insn_i386 (bfd_vma, disassemble_info *);
-void _initialize_i386_tdep PARAMS ((void));
+void _initialize_i386_tdep (void);
/* i386_register_byte[i] is the offset into the register file of the
start of register number i. We initialize this from
/* This is the variable the is set with "set disassembly-flavor",
and its legitimate values. */
-static char att_flavor[] = "att";
-static char intel_flavor[] = "intel";
-static char *valid_flavors[] =
+static const char att_flavor[] = "att";
+static const char intel_flavor[] = "intel";
+static const char *valid_flavors[] =
{
att_flavor,
intel_flavor,
NULL
};
-static char *disassembly_flavor = att_flavor;
+static const char *disassembly_flavor = att_flavor;
-static void i386_print_register PARAMS ((char *, int, int));
+static void i386_print_register (char *, int, int);
/* This is used to keep the bfd arch_info in sync with the disassembly flavor. */
-static void set_disassembly_flavor_sfunc PARAMS ((char *, int, struct cmd_list_element *));
-static void set_disassembly_flavor PARAMS ((void));
+static void set_disassembly_flavor_sfunc (char *, int,
+ struct cmd_list_element *);
+static void set_disassembly_flavor (void);
/* Stdio style buffering was used to minimize calls to ptrace, but this
buffering did not take into account that the code section being accessed
codestream_fill(0) : codestream_buf[codestream_off++])
static unsigned char
-codestream_fill (peek_flag)
- int peek_flag;
+codestream_fill (int peek_flag)
{
codestream_addr = codestream_next_addr;
codestream_next_addr += CODESTREAM_BUFSIZ;
}
static void
-codestream_seek (place)
- CORE_ADDR place;
+codestream_seek (CORE_ADDR place)
{
codestream_next_addr = place / CODESTREAM_BUFSIZ;
codestream_next_addr *= CODESTREAM_BUFSIZ;
}
static void
-codestream_read (buf, count)
- unsigned char *buf;
- int count;
+codestream_read (unsigned char *buf, int count)
{
unsigned char *p;
int i;
/* next instruction is a jump, move to target */
static void
-i386_follow_jump ()
+i386_follow_jump (void)
{
unsigned char buf[4];
long delta;
*/
static long
-i386_get_frame_setup (pc)
- CORE_ADDR pc;
+i386_get_frame_setup (CORE_ADDR pc)
{
unsigned char op;
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;
*/
void
-i386_frame_init_saved_regs (fip)
- struct frame_info *fip;
+i386_frame_init_saved_regs (struct frame_info *fip)
{
long locals = -1;
unsigned char op;
/* return pc of first real instruction */
int
-i386_skip_prologue (pc)
- int pc;
+i386_skip_prologue (int pc)
{
unsigned char op;
int i;
}
void
-i386_push_dummy_frame ()
+i386_push_dummy_frame (void)
{
CORE_ADDR sp = read_register (SP_REGNUM);
int regnum;
write_register (SP_REGNUM, sp);
}
+/* Insert the (relative) function address into the call sequence
+ stored at DYMMY. */
+
+void
+i386_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
+ value_ptr *args, struct type *type, int gcc_p)
+{
+ 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 ()
+i386_pop_frame (void)
{
struct frame_info *frame = get_current_frame ();
CORE_ADDR fp;
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;
#endif /* GET_LONGJMP_TARGET */
+/* 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)
{
- /* On AIX, i386 GNU/Linux and DJGPP, floating point values are
- returned in floating point registers. */
- /* FIXME: cagney/2000-02-29: This function needs to be rewritten
- using multi-arch. Please don't keep adding to this #ifdef
- spaghetti. */
-#if defined(I386_AIX_TARGET) || defined(I386_GNULINUX_TARGET) || defined(I386_DJGPP_TARGET)
+ int len = TYPE_LENGTH (type);
+
if (TYPE_CODE_FLT == TYPE_CODE (type))
{
- double d;
- /* 387 %st(0), gcc uses this */
- floatformat_to_double (&floatformat_i387_ext,
-#if defined(FPDATA_REGNUM)
- ®buf[REGISTER_BYTE (FPDATA_REGNUM)],
-#else /* !FPDATA_REGNUM */
- ®buf[REGISTER_BYTE (FP0_REGNUM)],
-#endif /* FPDATA_REGNUM */
-
- &d);
- store_floating (valbuf, TYPE_LENGTH (type), d);
+ if (NUM_FREGS == 0)
+ {
+ warning ("Cannot find floating-point return value.");
+ memset (valbuf, 0, len);
+ }
+
+ /* 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, 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
-#endif /* I386_AIX_TARGET || I386_GNULINUX_TARGET || I386_DJGPP_TARGET */
{
-#if defined(LOW_RETURN_REGNUM)
- int len = 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)
- memcpy (valbuf, regbuf + REGISTER_BYTE (LOW_RETURN_REGNUM), len);
+ memcpy (valbuf, ®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], len);
else if (len <= (low_size + high_size))
{
memcpy (valbuf,
- regbuf + REGISTER_BYTE (LOW_RETURN_REGNUM),
- low_size);
+ ®buf[REGISTER_BYTE (LOW_RETURN_REGNUM)], low_size);
memcpy (valbuf + low_size,
- regbuf + REGISTER_BYTE (HIGH_RETURN_REGNUM),
- len - low_size);
+ ®buf[REGISTER_BYTE (HIGH_RETURN_REGNUM)], len - low_size);
}
else
- error ("GDB bug: i386-tdep.c (i386_extract_return_value): Don't know how to find a return value %d bytes long", len);
-#else /* !LOW_RETURN_REGNUM */
- memcpy (valbuf, regbuf, TYPE_LENGTH (type));
-#endif /* LOW_RETURN_REGNUM */
+ internal_error ("Cannot extract return value of %d bytes long.", len);
}
}
+/* 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 (frame)
- struct frame_info *frame;
+i386v4_sigtramp_saved_pc (struct frame_info *frame)
{
CORE_ADDR saved_pc_offset = 4;
char *name = NULL;
}
#endif /* I386V4_SIGTRAMP_SAVED_PC */
-#ifdef I386_LINUX_SIGTRAMP
-
-/* Linux has two flavors of signals. Normal signal handlers, and
- "realtime" (RT) signals. The RT signals can provide additional
- information to the signal handler if the SA_SIGINFO flag is set
- when establishing a signal handler using `sigaction'. It is not
- unlikely that future versions of Linux will support SA_SIGINFO for
- normal signals too. */
-
-/* When the i386 Linux kernel calls a signal handler and the
- SA_RESTORER flag isn't set, the return address points to a bit of
- code on the stack. This function returns whether the PC appears to
- be within this bit of code.
-
- The instruction sequence for normal signals is
- pop %eax
- mov $0x77,%eax
- int $0x80
- or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
-
- Checking for the code sequence should be somewhat reliable, because
- the effect is to call the system call sigreturn. This is unlikely
- to occur anywhere other than a signal trampoline.
-
- It kind of sucks that we have to read memory from the process in
- order to identify a signal trampoline, but there doesn't seem to be
- any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to
- only call us if no function name could be identified, which should
- be the case since the code is on the stack.
-
- Detection of signal trampolines for handlers that set the
- SA_RESTORER flag is in general not possible. Unfortunately this is
- what the GNU C Library has been doing for quite some time now.
- However, as of version 2.1.2, the GNU C Library uses signal
- trampolines (named __restore and __restore_rt) that are identical
- to the ones used by the kernel. Therefore, these trampolines are
- supported too. */
-
-#define LINUX_SIGTRAMP_INSN0 (0x58) /* pop %eax */
-#define LINUX_SIGTRAMP_OFFSET0 (0)
-#define LINUX_SIGTRAMP_INSN1 (0xb8) /* mov $NNNN,%eax */
-#define LINUX_SIGTRAMP_OFFSET1 (1)
-#define LINUX_SIGTRAMP_INSN2 (0xcd) /* int */
-#define LINUX_SIGTRAMP_OFFSET2 (6)
-
-static const unsigned char linux_sigtramp_code[] =
-{
- LINUX_SIGTRAMP_INSN0, /* pop %eax */
- LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77,%eax */
- LINUX_SIGTRAMP_INSN2, 0x80 /* int $0x80 */
-};
-
-#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
-
-/* If PC is in a sigtramp routine, return the address of the start of
- the routine. Otherwise, return 0. */
-
-static CORE_ADDR
-i386_linux_sigtramp_start (CORE_ADDR pc)
-{
- unsigned char buf[LINUX_SIGTRAMP_LEN];
-
- /* We only recognize a signal trampoline if PC is at the start of
- one of the three instructions. We optimize for finding the PC at
- the start, as will be the case when the trampoline is not the
- first frame on the stack. We assume that in the case where the
- PC is not at the start of the instruction sequence, there will be
- a few trailing readable bytes on the stack. */
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
-
- if (buf[0] != LINUX_SIGTRAMP_INSN0)
- {
- int adjust;
-
- switch (buf[0])
- {
- case LINUX_SIGTRAMP_INSN1:
- adjust = LINUX_SIGTRAMP_OFFSET1;
- break;
- case LINUX_SIGTRAMP_INSN2:
- adjust = LINUX_SIGTRAMP_OFFSET2;
- break;
- default:
- return 0;
- }
-
- pc -= adjust;
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
- }
-
- if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
-
- return pc;
-}
-
-/* This function does the same for RT signals. Here the instruction
- sequence is
- mov $0xad,%eax
- int $0x80
- or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
-
- The effect is to call the system call rt_sigreturn. */
-
-#define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
-#define LINUX_RT_SIGTRAMP_OFFSET0 (0)
-#define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
-#define LINUX_RT_SIGTRAMP_OFFSET1 (5)
-
-static const unsigned char linux_rt_sigtramp_code[] =
-{
- LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00, /* mov $0xad,%eax */
- LINUX_RT_SIGTRAMP_INSN1, 0x80 /* int $0x80 */
-};
-
-#define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
-
-/* If PC is in a RT sigtramp routine, return the address of the start
- of the routine. Otherwise, return 0. */
-
-static CORE_ADDR
-i386_linux_rt_sigtramp_start (CORE_ADDR pc)
-{
- unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
-
- /* We only recognize a signal trampoline if PC is at the start of
- one of the two instructions. We optimize for finding the PC at
- the start, as will be the case when the trampoline is not the
- first frame on the stack. We assume that in the case where the
- PC is not at the start of the instruction sequence, there will be
- a few trailing readable bytes on the stack. */
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
-
- if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
- {
- if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
- return 0;
-
- pc -= LINUX_RT_SIGTRAMP_OFFSET1;
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
- }
-
- if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
-
- return pc;
-}
-
-/* Return whether PC is in a Linux sigtramp routine. */
-
-int
-i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
-{
- if (name)
- return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
-
- return (i386_linux_sigtramp_start (pc) != 0
- || i386_linux_rt_sigtramp_start (pc) != 0);
-}
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the address
- of the associated sigcontext structure. */
-
-CORE_ADDR
-i386_linux_sigcontext_addr (struct frame_info *frame)
-{
- CORE_ADDR pc;
-
- pc = i386_linux_sigtramp_start (frame->pc);
- if (pc)
- {
- CORE_ADDR sp;
-
- if (frame->next)
- /* If this isn't the top frame, the next frame must be for the
- signal handler itself. The sigcontext structure lives on
- the stack, right after the signum argument. */
- return frame->next->frame + 12;
-
- /* This is the top frame. We'll have to find the address of the
- sigcontext structure by looking at the stack pointer. Keep
- in mind that the first instruction of the sigtramp code is
- "pop %eax". If the PC is at this instruction, adjust the
- returned value accordingly. */
- sp = read_register (SP_REGNUM);
- if (pc == frame->pc)
- return sp + 4;
- return sp;
- }
-
- pc = i386_linux_rt_sigtramp_start (frame->pc);
- if (pc)
- {
- if (frame->next)
- /* If this isn't the top frame, the next frame must be for the
- signal handler itself. The sigcontext structure is part of
- the user context. A pointer to the user context is passed
- as the third argument to the signal handler. */
- return read_memory_integer (frame->next->frame + 16, 4) + 20;
-
- /* This is the top frame. Again, use the stack pointer to find
- the address of the sigcontext structure. */
- return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
- }
-
- error ("Couldn't recognize signal trampoline.");
- return 0;
-}
-
-/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
-#define LINUX_SIGCONTEXT_PC_OFFSET (56)
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the saved
- program counter. */
-
-CORE_ADDR
-i386_linux_sigtramp_saved_pc (struct frame_info *frame)
-{
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
-}
-
-/* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */
-#define LINUX_SIGCONTEXT_SP_OFFSET (28)
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the saved
- stack pointer. */
-
-CORE_ADDR
-i386_linux_sigtramp_saved_sp (struct frame_info *frame)
-{
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
-}
-
-#endif /* I386_LINUX_SIGTRAMP */
#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 (name)
- char *name;
+sunpro_static_transform_name (char *name)
{
char *p;
if (IS_STATIC_TRANSFORM_NAME (name))
/* Stuff for WIN32 PE style DLL's but is pretty generic really. */
CORE_ADDR
-skip_trampoline_code (pc, name)
- CORE_ADDR pc;
- char *name;
+skip_trampoline_code (CORE_ADDR pc, char *name)
{
if (pc && read_memory_unsigned_integer (pc, 2) == 0x25ff) /* jmp *(dest) */
{
}
static int
-gdb_print_insn_i386 (memaddr, info)
- bfd_vma memaddr;
- disassemble_info *info;
+gdb_print_insn_i386 (bfd_vma memaddr, disassemble_info *info)
{
if (disassembly_flavor == att_flavor)
return print_insn_i386_att (memaddr, info);
command, and does that. */
static void
-set_disassembly_flavor_sfunc (args, from_tty, c)
- char *args;
- int from_tty;
- struct cmd_list_element *c;
+set_disassembly_flavor_sfunc (char *args, int from_tty,
+ struct cmd_list_element *c)
{
set_disassembly_flavor ();
}
static void
-set_disassembly_flavor ()
+set_disassembly_flavor (void)
{
if (disassembly_flavor == att_flavor)
set_architecture_from_arch_mach (bfd_arch_i386, bfd_mach_i386_i386);
void
-_initialize_i386_tdep ()
+_initialize_i386_tdep (void)
{
/* Initialize the table saying where each register starts in the
register file. */
new_cmd = add_set_enum_cmd ("disassembly-flavor", no_class,
valid_flavors,
- (char *) &disassembly_flavor,
+ &disassembly_flavor,
"Set the disassembly flavor, the valid values are \"att\" and \"intel\", \
and the default value is \"att\".",
&setlist);