diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 99b8f54209..e58b216a7b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2008-07-27 Daniel Jacobowitz + + * mips-linux-tdep.c (mips_linux_syscall_next_pc): New function. + (mips_linux_init_abi): Set tdep->syscall_next_pc. + * mips-tdep.c (enum mips_fpu_type, struct gdbarch_tdep): Move to + mips-tdep.h. + (mips32_next_pc): Handle the syscall instruction. + * mips-tdep.h (enum mips_fpu_type, struct gdbarch_tdep): New, + from mips-tdep.c. Add syscall_next_pc to gdbarch_tdep. + 2008-07-26 Tom Tromey PR gdb/1158: diff --git a/gdb/mips-linux-tdep.c b/gdb/mips-linux-tdep.c index d631a7b3c3..8f30aef45f 100644 --- a/gdb/mips-linux-tdep.c +++ b/gdb/mips-linux-tdep.c @@ -1101,6 +1101,26 @@ mips_linux_restart_reg_p (struct gdbarch *gdbarch) return register_size (gdbarch, MIPS_RESTART_REGNUM) > 0; } +/* When FRAME is at a syscall instruction, return the PC of the next + instruction to be executed. */ + +CORE_ADDR +mips_linux_syscall_next_pc (struct frame_info *frame) +{ + CORE_ADDR pc = get_frame_pc (frame); + ULONGEST v0 = get_frame_register_unsigned (frame, MIPS_V0_REGNUM); + + /* If we are about to make a sigreturn syscall, use the unwinder to + decode the signal frame. */ + if (v0 == MIPS_NR_sigreturn + || v0 == MIPS_NR_rt_sigreturn + || v0 == MIPS_NR_N64_rt_sigreturn + || v0 == MIPS_NR_N32_rt_sigreturn) + return frame_pc_unwind (get_current_frame ()); + + return pc + 4; +} + /* Initialize one of the GNU/Linux OS ABIs. */ static void @@ -1175,6 +1195,8 @@ mips_linux_init_abi (struct gdbarch_info info, set_gdbarch_core_read_description (gdbarch, mips_linux_core_read_description); + tdep->syscall_next_pc = mips_linux_syscall_next_pc; + if (tdesc_data) { const struct tdesc_feature *feature; diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 98d033b71a..4469754d9e 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -142,16 +142,6 @@ const struct register_alias mips_register_aliases[] = { { "fsr", MIPS_EMBED_FP0_REGNUM + 32 } }; -/* Some MIPS boards don't support floating point while others only - support single-precision floating-point operations. */ - -enum mips_fpu_type -{ - MIPS_FPU_DOUBLE, /* Full double precision floating point. */ - MIPS_FPU_SINGLE, /* Single precision floating point (R4650). */ - MIPS_FPU_NONE /* No floating point. */ -}; - #ifndef MIPS_DEFAULT_FPU_TYPE #define MIPS_DEFAULT_FPU_TYPE MIPS_FPU_DOUBLE #endif @@ -168,37 +158,6 @@ static int mips_debug = 0; struct target_desc *mips_tdesc_gp32; struct target_desc *mips_tdesc_gp64; -/* MIPS specific per-architecture information */ -struct gdbarch_tdep -{ - /* from the elf header */ - int elf_flags; - - /* mips options */ - enum mips_abi mips_abi; - enum mips_abi found_abi; - enum mips_fpu_type mips_fpu_type; - int mips_last_arg_regnum; - int mips_last_fp_arg_regnum; - int default_mask_address_p; - /* Is the target using 64-bit raw integer registers but only - storing a left-aligned 32-bit value in each? */ - int mips64_transfers_32bit_regs_p; - /* Indexes for various registers. IRIX and embedded have - different values. This contains the "public" fields. Don't - add any that do not need to be public. */ - const struct mips_regnum *regnum; - /* Register names table for the current register set. */ - const char **mips_processor_reg_names; - - /* The size of register data available from the target, if known. - This doesn't quite obsolete the manual - mips64_transfers_32bit_regs_p, since that is documented to force - left alignment even for big endian (very strange). */ - int register_size_valid_p; - int register_size; -}; - const struct mips_regnum * mips_regnum (struct gdbarch *gdbarch) { @@ -1018,6 +977,17 @@ mips32_next_pc (struct frame_info *frame, CORE_ADDR pc) /* Set PC to that address */ pc = get_frame_register_signed (frame, rtype_rs (inst)); break; + case 12: /* SYSCALL */ + { + struct gdbarch_tdep *tdep; + + tdep = gdbarch_tdep (get_frame_arch (frame)); + if (tdep->syscall_next_pc != NULL) + pc = tdep->syscall_next_pc (frame); + else + pc += 4; + } + break; default: pc += 4; } diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h index 3917951f84..85c40d9489 100644 --- a/gdb/mips-tdep.h +++ b/gdb/mips-tdep.h @@ -56,6 +56,51 @@ struct mips_regnum }; extern const struct mips_regnum *mips_regnum (struct gdbarch *gdbarch); +/* Some MIPS boards don't support floating point while others only + support single-precision floating-point operations. */ + +enum mips_fpu_type +{ + MIPS_FPU_DOUBLE, /* Full double precision floating point. */ + MIPS_FPU_SINGLE, /* Single precision floating point (R4650). */ + MIPS_FPU_NONE /* No floating point. */ +}; + +/* MIPS specific per-architecture information */ +struct gdbarch_tdep +{ + /* from the elf header */ + int elf_flags; + + /* mips options */ + enum mips_abi mips_abi; + enum mips_abi found_abi; + enum mips_fpu_type mips_fpu_type; + int mips_last_arg_regnum; + int mips_last_fp_arg_regnum; + int default_mask_address_p; + /* Is the target using 64-bit raw integer registers but only + storing a left-aligned 32-bit value in each? */ + int mips64_transfers_32bit_regs_p; + /* Indexes for various registers. IRIX and embedded have + different values. This contains the "public" fields. Don't + add any that do not need to be public. */ + const struct mips_regnum *regnum; + /* Register names table for the current register set. */ + const char **mips_processor_reg_names; + + /* The size of register data available from the target, if known. + This doesn't quite obsolete the manual + mips64_transfers_32bit_regs_p, since that is documented to force + left alignment even for big endian (very strange). */ + int register_size_valid_p; + int register_size; + + /* Return the expected next PC if FRAME is stopped at a syscall + instruction. */ + CORE_ADDR (*syscall_next_pc) (struct frame_info *frame); +}; + /* Register numbers of various important registers. */ enum