X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fi386-tdep.c;h=c55757e76a69a318507fdb6e91852dfd612b9bcb;hb=56e2d25ab5b69584198204090fe049e920cd57db;hp=49cc7966d7abb7cfc6abf71a50dfc520b7487be6;hpb=3df1b9b49d36c0fb42077b2deece480317978e5b;p=binutils-gdb.git diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index 49cc7966d7a..c55757e76a6 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -32,6 +32,9 @@ #include "command.h" #include "arch-utils.h" #include "regcache.h" +#include "doublest.h" + +#include "gdb_assert.h" /* i386_register_byte[i] is the offset into the register file of the start of register number i. We initialize this from @@ -57,6 +60,68 @@ int i386_register_raw_size[MAX_NUM_REGS] = { /* 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]; + +/* Convert stabs register number REG to the appropriate register + number used by GDB. */ + +int +i386_stab_reg_to_regnum (int reg) +{ + /* This implements what GCC calls the "default" register map. */ + if (reg >= 0 && reg <= 7) + { + /* General registers. */ + return reg; + } + else if (reg >= 12 && reg <= 19) + { + /* Floating-point registers. */ + return reg - 12 + FP0_REGNUM; + } + else if (reg >= 21 && reg <= 28) + { + /* SSE registers. */ + return reg - 21 + XMM0_REGNUM; + } + else if (reg >= 29 && reg <= 36) + { + /* MMX registers. */ + /* FIXME: kettenis/2001-07-28: Should we have the MMX registers + as pseudo-registers? */ + return reg - 29 + FP0_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. */ + +int +i386_dwarf_reg_to_regnum (int reg) +{ + /* The DWARF register numbering includes %eip and %eflags, and + numbers the floating point registers differently. */ + if (reg >= 0 && reg <= 9) + { + /* General registers. */ + return reg; + } + else if (reg >= 11 && reg <= 18) + { + /* Floating-point registers. */ + return reg - 11 + FP0_REGNUM; + } + else if (reg >= 21) + { + /* The SSE and MMX registers have identical numbers as in stabs. */ + return i386_stab_reg_to_regnum (reg); + } + + /* This will hopefully provoke a warning. */ + return NUM_REGS + NUM_PSEUDO_REGS; +} /* This is the variable that is set with "set disassembly-flavor", and @@ -349,6 +414,60 @@ i386_get_frame_setup (CORE_ADDR pc) 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. */ @@ -615,7 +734,7 @@ i386_push_dummy_frame (void) void i386_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs, - value_ptr *args, struct type *type, int gcc_p) + struct value **args, struct type *type, int gcc_p) { int from, to, delta, loc; @@ -695,7 +814,7 @@ get_longjmp_target (CORE_ADDR *pc) CORE_ADDR -i386_push_arguments (int nargs, value_ptr *args, CORE_ADDR sp, +i386_push_arguments (int nargs, struct value **args, CORE_ADDR sp, int struct_return, CORE_ADDR struct_addr) { sp = default_push_arguments (nargs, args, sp, struct_return, struct_addr); @@ -807,13 +926,18 @@ i386_store_return_value (struct type *type, char *valbuf) 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). */ + /* Returning floating-point values is a bit tricky. Apart from + storing the return value in %st(0), we have to simulate the + state of the FPU at function return point. */ + if (len == TARGET_LONG_DOUBLE_BIT / TARGET_CHAR_BIT && TARGET_LONG_DOUBLE_FORMAT == &floatformat_i387_ext) { @@ -827,7 +951,7 @@ i386_store_return_value (struct type *type, char *valbuf) DOUBLEST val; /* Convert the value found in VALBUF to the extended - floating point format used by the FPU. This is probably + 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)); @@ -835,6 +959,19 @@ i386_store_return_value (struct type *type, char *valbuf) write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf, FPU_REG_RAW_SIZE); } + + /* 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. */ + fstat = read_register (FSTAT_REGNUM); + fstat |= (7 << 11); + write_register (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. */ + write_register (FTAG_REGNUM, 0x3fff); } else { @@ -868,28 +1005,77 @@ i386_extract_struct_value_address (char *regbuf) } +/* 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. */ + virtual format with type TYPE in buffer TO. */ 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); + char buf[12]; + DOUBLEST d; + + /* We only support floating-point values. */ + if (TYPE_CODE (type) != TYPE_CODE_FLT) + { + warning ("Cannot convert floating-point register value " + "to non-floating-point type."); + memset (to, 0, TYPE_LENGTH (type)); + return; + } + + /* First add the necessary padding. */ + memcpy (buf, from, FPU_REG_RAW_SIZE); + memset (buf + FPU_REG_RAW_SIZE, 0, sizeof buf - FPU_REG_RAW_SIZE); + + /* Convert to TYPE. This should be a no-op, if TYPE is equivalent + to the extended floating-point format used by the FPU. */ + d = extract_floating (buf, sizeof buf); + store_floating (to, TYPE_LENGTH (type), d); } /* 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. */ + raw format for register REGNUM in buffer TO. */ void i386_register_convert_to_raw (struct type *type, int regnum, char *from, char *to) { + gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT + && TYPE_LENGTH (type) == 12); + + /* Simply omit the two unused bytes. */ memcpy (to, from, FPU_REG_RAW_SIZE); }