#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
+ i386_register_raw_size. */
+int i386_register_byte[MAX_NUM_REGS];
+
+/* 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
+};
+
+/* 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];
+
/* 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;
-/* 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 ();
+static void i386_print_register (char *, int, int);
-void (*disassembly_flavor_hook) PARAMS ((char *args, int from_tty));
+/* 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);
/* 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, floating point values are returned in floating point registers. */
-#ifdef I386_AIX_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,
- ®buf[REGISTER_BYTE (FP0_REGNUM)],
- &d);
- store_floating (valbuf, TYPE_LENGTH (type), d);
+ if (NUM_FREGS == 0)
+ {
+ warning ("Cannot find floating-point return value.");
+ memset (valbuf, 0, len);
+ 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, 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 */
{
- 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)
+ 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 ("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_FLT == TYPE_CODE (type))
+ {
+ 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);
+ }
+ }
+ else
+ {
+ 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 ("Cannot store 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 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 ();
-
- if (disassembly_flavor_hook != NULL)
- disassembly_flavor_hook (args, from_tty);
}
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);
set_architecture_from_arch_mach (bfd_arch_i386, bfd_mach_i386_i386_intel_syntax);
}
+
void
-_initialize_i386_tdep ()
+_initialize_i386_tdep (void)
{
- struct cmd_list_element *new_cmd;
+ /* 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,
- (char *) &disassembly_flavor,
- "Set the disassembly flavor, the valid values are \"att\" and \"intel\", \
+ 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);
+ &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 ();
-
}