#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_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 = -1;
unsigned char op;
CORE_ADDR pc;
int i;
- memset (fsrp, 0, sizeof *fsrp);
+ if (fip->saved_regs)
+ return;
+
+ frame_saved_regs_zalloc (fip);
/* if frame is the end of a dummy, compute where the
* beginning would be
for (i = 0; i < NUM_REGS; i++)
{
adr -= REGISTER_RAW_SIZE (i);
- fsrp->regs[i] = adr;
+ fip->saved_regs[i] = adr;
}
return;
}
break;
#ifdef I386_REGNO_TO_SYMMETRY
/* Dynix uses different internal numbering. Ick. */
- fsrp->regs[I386_REGNO_TO_SYMMETRY (op - 0x50)] = adr;
+ fip->saved_regs[I386_REGNO_TO_SYMMETRY (op - 0x50)] = adr;
#else
- fsrp->regs[op - 0x50] = adr;
+ fip->saved_regs[op - 0x50] = adr;
#endif
adr -= 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 */
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_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)
+{
+ 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;
char regbuf[MAX_REGISTER_RAW_SIZE];
fp = FRAME_FP (frame);
- get_frame_saved_regs (frame, &fsr);
+ i386_frame_init_saved_regs (frame);
+
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
CORE_ADDR adr;
- adr = fsr.regs[regnum];
+ adr = frame->saved_regs[regnum];
if (adr)
{
read_memory (adr, regbuf, REGISTER_RAW_SIZE (regnum));
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 and i386 GNU/Linux, floating point values are returned in
- floating point registers. */
-#if defined(I386_AIX_TARGET) || defined(I386_GNULINUX_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*/
{
-#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
-
-/* When the i386 Linux kernel calls a signal handler, 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 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. */
-
-#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 (pc)
- 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;
-}
-
-/* Return whether PC is in a Linux sigtramp routine. */
-
-int
-i386_linux_sigtramp (pc)
- CORE_ADDR pc;
-{
- return i386_linux_sigtramp_start (pc) != 0;
-}
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the saved
- program counter. The Linux kernel will set up a sigcontext
- structure immediately before the sigtramp routine on the stack. */
-
-CORE_ADDR
-i386_linux_sigtramp_saved_pc (frame)
- struct frame_info *frame;
-{
- CORE_ADDR pc;
-
- pc = i386_linux_sigtramp_start (frame->pc);
- if (pc == 0)
- error ("i386_linux_sigtramp_saved_pc called when no sigtramp");
- return read_memory_integer ((pc
- - LINUX_SIGCONTEXT_SIZE
- + LINUX_SIGCONTEXT_PC_OFFSET),
- 4);
-}
-
-/* Assuming FRAME is for a Linux sigtramp routine, return the saved
- stack pointer. The Linux kernel will set up a sigcontext structure
- immediately before the sigtramp routine on the stack. */
-
-CORE_ADDR
-i386_linux_sigtramp_saved_sp (frame)
- struct frame_info *frame;
-{
- CORE_ADDR pc;
-
- pc = i386_linux_sigtramp_start (frame->pc);
- if (pc == 0)
- error ("i386_linux_sigtramp_saved_sp called when no sigtramp");
- return read_memory_integer ((pc
- - LINUX_SIGCONTEXT_SIZE
- + 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);