X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fi386-tdep.c;h=32fb68eb5367455703bfc597f38920663f0fd80d;hb=f4ded5b12117d22df18a92b5e0c5b895df64fb59;hp=bd4eb9e76120adfa1da8543727f08ed3c02e0cb5;hpb=b4671f856bd5aa0846faf528493fae41a8127d01;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c index bd4eb9e761..32fb68eb53 100644 --- a/gdb/i386-tdep.c +++ b/gdb/i386-tdep.c @@ -25,6 +25,7 @@ #include "frame.h" #include "inferior.h" #include "gdbcore.h" +#include "objfiles.h" #include "target.h" #include "floatformat.h" #include "symfile.h" @@ -36,6 +37,7 @@ #include "doublest.h" #include "value.h" #include "gdb_assert.h" +#include "reggroups.h" #include "i386-tdep.h" #include "i387-tdep.h" @@ -69,11 +71,43 @@ static const int mmx_num_regs = (sizeof (i386_mmx_names) #define MM0_REGNUM (NUM_REGS) static int -mmx_regnum_p (int reg) +i386_mmx_regnum_p (int reg) { return (reg >= MM0_REGNUM && reg < MM0_REGNUM + mmx_num_regs); } +/* FP register? */ + +int +i386_fp_regnum_p (int regnum) +{ + return (regnum < NUM_REGS + && (FP0_REGNUM && FP0_REGNUM <= (regnum) && (regnum) < FPC_REGNUM)); +} + +int +i386_fpc_regnum_p (int regnum) +{ + return (regnum < NUM_REGS + && (FPC_REGNUM <= (regnum) && (regnum) < XMM0_REGNUM)); +} + +/* SSE register? */ + +int +i386_sse_regnum_p (int regnum) +{ + return (regnum < NUM_REGS + && (XMM0_REGNUM <= (regnum) && (regnum) < MXCSR_REGNUM)); +} + +int +i386_mxcsr_regnum_p (int regnum) +{ + return (regnum < NUM_REGS + && (regnum == MXCSR_REGNUM)); +} + /* Return the name of register REG. */ const char * @@ -81,7 +115,7 @@ i386_register_name (int reg) { if (reg < 0) return NULL; - if (mmx_regnum_p (reg)) + if (i386_mmx_regnum_p (reg)) return i386_mmx_names[reg - MM0_REGNUM]; if (reg >= sizeof (i386_register_names) / sizeof (*i386_register_names)) return NULL; @@ -438,17 +472,16 @@ i386_get_frame_setup (CORE_ADDR pc) frame -- that is, the frame which was in progress when the signal trampoline was entered. GDB mostly treats this frame pointer value as a magic cookie. We detect the case of a signal trampoline by - looking at the SIGNAL_HANDLER_CALLER field, which is set based on - PC_IN_SIGTRAMP. + testing for get_frame_type() == SIGTRAMP_FRAME, which is set based + on PC_IN_SIGTRAMP. When a signal trampoline is invoked from a frameless function, we essentially have two frameless functions in a row. In this case, we use the same magic cookie for three frames in a row. We detect - this case by seeing whether the next frame has - SIGNAL_HANDLER_CALLER set, and, if it does, checking whether the - current frame is actually frameless. In this case, we need to get - the PC by looking at the SP register value stored in the signal - context. + this case by seeing whether the next frame is a SIGTRAMP_FRAME, + and, if it does, checking whether the current frame is actually + frameless. In this case, we need to get the PC by looking at the + SP register value stored in the signal context. This should work in most cases except in horrible situations where a signal occurs just as we enter a function but before the frame @@ -461,10 +494,10 @@ i386_get_frame_setup (CORE_ADDR pc) /* Return non-zero if we're dealing with a frameless signal, that is, a signal trampoline invoked from a frameless function. */ -static int +int i386_frameless_signal_p (struct frame_info *frame) { - return (frame->next && frame->next->signal_handler_caller + return (frame->next && get_frame_type (frame->next) == SIGTRAMP_FRAME && (frameless_look_for_prologue (frame) || frame->pc == get_pc_function_start (frame->pc))); } @@ -479,7 +512,7 @@ i386_frame_chain (struct frame_info *frame) if (PC_IN_CALL_DUMMY (frame->pc, 0, 0)) return frame->frame; - if (frame->signal_handler_caller + if (get_frame_type (frame) == SIGTRAMP_FRAME || i386_frameless_signal_p (frame)) return frame->frame; @@ -496,7 +529,7 @@ i386_frame_chain (struct frame_info *frame) static int i386_frameless_function_invocation (struct frame_info *frame) { - if (frame->signal_handler_caller) + if (get_frame_type (frame) == SIGTRAMP_FRAME) return 0; return frameless_look_for_prologue (frame); @@ -534,10 +567,14 @@ static CORE_ADDR i386_frame_saved_pc (struct frame_info *frame) { if (PC_IN_CALL_DUMMY (frame->pc, 0, 0)) - return generic_read_register_dummy (frame->pc, frame->frame, - PC_REGNUM); + { + ULONGEST pc; - if (frame->signal_handler_caller) + frame_unwind_unsigned_register (frame, PC_REGNUM, &pc); + return pc; + } + + if (get_frame_type (frame) == SIGTRAMP_FRAME) return i386_sigtramp_saved_pc (frame); if (i386_frameless_signal_p (frame)) @@ -554,7 +591,7 @@ i386_frame_saved_pc (struct frame_info *frame) static CORE_ADDR i386_saved_pc_after_call (struct frame_info *frame) { - if (frame->signal_handler_caller) + if (get_frame_type (frame) == SIGTRAMP_FRAME) return i386_sigtramp_saved_pc (frame); return read_memory_unsigned_integer (read_register (SP_REGNUM), 4); @@ -833,8 +870,7 @@ i386_do_pop_frame (struct frame_info *frame) if (addr) { read_memory (addr, regbuf, REGISTER_RAW_SIZE (regnum)); - write_register_bytes (REGISTER_BYTE (regnum), regbuf, - REGISTER_RAW_SIZE (regnum)); + deprecated_write_register_gen (regnum, regbuf); } } write_register (FP_REGNUM, read_memory_integer (fp, 4)); @@ -917,8 +953,9 @@ i386_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) static void i386_extract_return_value (struct type *type, struct regcache *regcache, - char *valbuf) + void *dst) { + bfd_byte *valbuf = dst; int len = TYPE_LENGTH (type); char buf[I386_MAX_REGISTER_SIZE]; @@ -972,20 +1009,21 @@ i386_extract_return_value (struct type *type, struct regcache *regcache, in VALBUF of type TYPE, given in virtual format. */ static void -i386_store_return_value (struct type *type, char *valbuf) +i386_store_return_value (struct type *type, struct regcache *regcache, + const void *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); + i386_store_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf); return; } if (TYPE_CODE (type) == TYPE_CODE_FLT) { - unsigned int fstat; + ULONGEST fstat; char buf[FPU_REG_RAW_SIZE]; if (FP0_REGNUM == 0) @@ -1003,21 +1041,20 @@ i386_store_return_value (struct type *type, char *valbuf) not exactly how it would happen on the target itself, but it is the best we can do. */ convert_typed_floating (valbuf, type, buf, builtin_type_i387_ext); - write_register_bytes (REGISTER_BYTE (FP0_REGNUM), buf, - FPU_REG_RAW_SIZE); + regcache_raw_write (regcache, FP0_REGNUM, buf); /* 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); + regcache_raw_read_unsigned (regcache, FSTAT_REGNUM, &fstat); fstat |= (7 << 11); - write_register (FSTAT_REGNUM, fstat); + regcache_raw_write_unsigned (regcache, 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); + regcache_raw_write_unsigned (regcache, FTAG_REGNUM, 0x3fff); } else { @@ -1025,13 +1062,12 @@ i386_store_return_value (struct type *type, char *valbuf) int high_size = REGISTER_RAW_SIZE (HIGH_RETURN_REGNUM); if (len <= low_size) - write_register_bytes (REGISTER_BYTE (LOW_RETURN_REGNUM), valbuf, len); + regcache_raw_write_part (regcache, LOW_RETURN_REGNUM, 0, len, valbuf); 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); + regcache_raw_write (regcache, LOW_RETURN_REGNUM, valbuf); + regcache_raw_write_part (regcache, HIGH_RETURN_REGNUM, 0, + len - low_size, (char *) valbuf + low_size); } else internal_error (__FILE__, __LINE__, @@ -1039,25 +1075,17 @@ i386_store_return_value (struct type *type, char *valbuf) } } -/* 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. */ +/* Extract from REGCACHE, which contains the (raw) register state, the + address in which a function should return its structure value, as a + CORE_ADDR. */ static CORE_ADDR i386_extract_struct_value_address (struct regcache *regcache) { - /* NOTE: cagney/2002-08-12: Replaced a call to - regcache_raw_read_as_address() with a call to - regcache_cooked_read_unsigned(). The old, ...as_address function - was eventually calling extract_unsigned_integer (via - extract_address) to unpack the registers value. The below is - doing an unsigned extract so that it is functionally equivalent. - The read needs to be cooked as, otherwise, it will never - correctly return the value of a register in the [NUM_REGS - .. NUM_REGS+NUM_PSEUDO_REGS) range. */ - ULONGEST val; - regcache_cooked_read_unsigned (regcache, LOW_RETURN_REGNUM, &val); - return val; + ULONGEST addr; + + regcache_raw_read_unsigned (regcache, LOW_RETURN_REGNUM, &addr); + return addr; } @@ -1102,13 +1130,13 @@ 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)) + if (i386_fp_regnum_p (regnum)) return builtin_type_i387_ext; - if (IS_SSE_REGNUM (regnum)) + if (i386_sse_regnum_p (regnum)) return builtin_type_vec128i; - if (mmx_regnum_p (regnum)) + if (i386_mmx_regnum_p (regnum)) return builtin_type_vec64i; return builtin_type_int; @@ -1135,7 +1163,7 @@ static void i386_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, int regnum, void *buf) { - if (mmx_regnum_p (regnum)) + if (i386_mmx_regnum_p (regnum)) { char *mmx_buf = alloca (MAX_REGISTER_RAW_SIZE); int fpnum = mmx_regnum_to_fp_regnum (regcache, regnum); @@ -1151,7 +1179,7 @@ static void i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int regnum, const void *buf) { - if (mmx_regnum_p (regnum)) + if (i386_mmx_regnum_p (regnum)) { char *mmx_buf = alloca (MAX_REGISTER_RAW_SIZE); int fpnum = mmx_regnum_to_fp_regnum (regcache, regnum); @@ -1175,7 +1203,7 @@ i386_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, static int i386_register_convertible (int regnum) { - return IS_FP_REGNUM (regnum); + return i386_fp_regnum_p (regnum); } /* Convert data from raw format for register REGNUM in buffer FROM to @@ -1185,7 +1213,7 @@ static void i386_register_convert_to_virtual (int regnum, struct type *type, char *from, char *to) { - gdb_assert (IS_FP_REGNUM (regnum)); + gdb_assert (i386_fp_regnum_p (regnum)); /* We only support floating-point values. */ if (TYPE_CODE (type) != TYPE_CODE_FLT) @@ -1208,7 +1236,7 @@ static void i386_register_convert_to_raw (struct type *type, int regnum, char *from, char *to) { - gdb_assert (IS_FP_REGNUM (regnum)); + gdb_assert (i386_fp_regnum_p (regnum)); /* We only support floating-point values. */ if (TYPE_CODE (type) != TYPE_CODE_FLT) @@ -1288,15 +1316,17 @@ i386_pc_in_sigtramp (CORE_ADDR pc, char *name) deals with switching between those. */ static int -gdb_print_insn_i386 (bfd_vma memaddr, disassemble_info *info) +i386_print_insn (bfd_vma pc, 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"); + gdb_assert (disassembly_flavor == att_flavor + || disassembly_flavor == intel_flavor); + + /* FIXME: kettenis/20020915: Until disassembler_options is properly + constified, cast to prevent a compiler warning. */ + info->disassembler_options = (char *) disassembly_flavor; + info->mach = gdbarch_bfd_arch_info (current_gdbarch)->mach; + + return print_insn_i386 (pc, info); } @@ -1372,6 +1402,10 @@ i386_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* System V Release 4 uses ELF. */ i386_elf_init_abi (info, gdbarch); + /* System V Release 4 has shared libraries. */ + set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section); + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + /* FIXME: kettenis/20020511: Why do we override this function here? */ set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid); @@ -1409,6 +1443,56 @@ i386_nw_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) } +/* i386 register groups. In addition to the normal groups, add "mmx" + and "sse". */ + +static struct reggroup *i386_sse_reggroup; +static struct reggroup *i386_mmx_reggroup; + +static void +i386_init_reggroups (void) +{ + i386_sse_reggroup = reggroup_new ("sse", USER_REGGROUP); + i386_mmx_reggroup = reggroup_new ("mmx", USER_REGGROUP); +} + +static void +i386_add_reggroups (struct gdbarch *gdbarch) +{ + reggroup_add (gdbarch, i386_sse_reggroup); + reggroup_add (gdbarch, i386_mmx_reggroup); + reggroup_add (gdbarch, general_reggroup); + reggroup_add (gdbarch, float_reggroup); + reggroup_add (gdbarch, all_reggroup); + reggroup_add (gdbarch, save_reggroup); + reggroup_add (gdbarch, restore_reggroup); + reggroup_add (gdbarch, vector_reggroup); + reggroup_add (gdbarch, system_reggroup); +} + +int +i386_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + struct reggroup *group) +{ + int sse_regnum_p = (i386_sse_regnum_p (regnum) + || i386_mxcsr_regnum_p (regnum)); + int fp_regnum_p = (i386_fp_regnum_p (regnum) + || i386_fpc_regnum_p (regnum)); + int mmx_regnum_p = (i386_mmx_regnum_p (regnum)); + if (group == i386_mmx_reggroup) + return mmx_regnum_p; + if (group == i386_sse_reggroup) + return sse_regnum_p; + if (group == vector_reggroup) + return (mmx_regnum_p || sse_regnum_p); + if (group == float_reggroup) + return fp_regnum_p; + if (group == general_reggroup) + return (!fp_regnum_p && !mmx_regnum_p && !sse_regnum_p); + return default_register_reggroup_p (gdbarch, regnum, group); +} + + static struct gdbarch * i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { @@ -1456,7 +1540,7 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) on having a `long double' that's not `long' at all. */ set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext); - /* Although the i386 extended floating-point has only 80 significant + /* Although the i387 extended floating-point has only 80 significant bits, a `long double' actually takes up 96, probably to enforce alignment. */ set_gdbarch_long_double_bit (gdbarch, 96); @@ -1465,11 +1549,11 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tm-symmetry.h currently override this. Sigh. */ set_gdbarch_num_regs (gdbarch, I386_NUM_GREGS + I386_NUM_FREGS); - set_gdbarch_sp_regnum (gdbarch, 4); - set_gdbarch_fp_regnum (gdbarch, 5); - set_gdbarch_pc_regnum (gdbarch, 8); - set_gdbarch_ps_regnum (gdbarch, 9); - set_gdbarch_fp0_regnum (gdbarch, 16); + set_gdbarch_sp_regnum (gdbarch, 4); /* %esp */ + set_gdbarch_fp_regnum (gdbarch, 5); /* %ebp */ + set_gdbarch_pc_regnum (gdbarch, 8); /* %eip */ + set_gdbarch_ps_regnum (gdbarch, 9); /* %eflags */ + set_gdbarch_fp0_regnum (gdbarch, 16); /* %st(0) */ /* Use the "default" register numbering scheme for stabs and COFF. */ set_gdbarch_stab_reg_to_regnum (gdbarch, i386_stab_reg_to_regnum); @@ -1513,9 +1597,6 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) i386_register_convert_to_virtual); set_gdbarch_register_convert_to_raw (gdbarch, i386_register_convert_to_raw); - set_gdbarch_get_saved_register (gdbarch, generic_unwind_get_saved_register); - set_gdbarch_push_arguments (gdbarch, i386_push_arguments); - set_gdbarch_pc_in_call_dummy (gdbarch, pc_in_call_dummy_at_entry_point); /* "An argument's size is increased, if necessary, to make it a @@ -1555,8 +1636,6 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_frame_chain (gdbarch, i386_frame_chain); set_gdbarch_frame_chain_valid (gdbarch, generic_file_frame_chain_valid); set_gdbarch_frame_saved_pc (gdbarch, i386_frame_saved_pc); - set_gdbarch_frame_args_address (gdbarch, default_frame_address); - set_gdbarch_frame_locals_address (gdbarch, default_frame_address); set_gdbarch_saved_pc_after_call (gdbarch, i386_saved_pc_after_call); set_gdbarch_frame_num_args (gdbarch, i386_frame_num_args); set_gdbarch_pc_in_sigtramp (gdbarch, i386_pc_in_sigtramp); @@ -1566,6 +1645,12 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_pseudo_register_read (gdbarch, i386_pseudo_register_read); set_gdbarch_pseudo_register_write (gdbarch, i386_pseudo_register_write); + set_gdbarch_print_insn (gdbarch, i386_print_insn); + + /* Add the i386 register groups. */ + i386_add_reggroups (gdbarch); + set_gdbarch_register_reggroup_p (gdbarch, i386_register_reggroup_p); + /* Hook in ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch, osabi); @@ -1597,9 +1682,6 @@ _initialize_i386_tdep (void) { register_gdbarch_init (bfd_arch_i386, i386_gdbarch_init); - 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; @@ -1620,7 +1702,7 @@ and the default value is \"att\".", struct cmd_list_element *new_cmd; new_cmd = add_set_enum_cmd ("struct-convention", no_class, - valid_conventions, + valid_conventions, &struct_convention, "\ Set the convention for returning small structs, valid values \ are \"default\", \"pcc\" and \"reg\", and the default value is \"default\".", @@ -1639,4 +1721,7 @@ are \"default\", \"pcc\" and \"reg\", and the default value is \"default\".", i386_go32_init_abi); gdbarch_register_osabi (bfd_arch_i386, GDB_OSABI_NETWARE, i386_nw_init_abi); + + /* Initialize the i386 specific register groups. */ + i386_init_reggroups (); }