From: Yao Qi Date: Mon, 30 Aug 2010 15:26:28 +0000 (+0000) Subject: 2010-08-30 Yao Qi X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=25b41d01eaa6f8f68491ef2eb65ca403907269f7;p=deliverable%2Fbinutils-gdb.git 2010-08-30 Yao Qi * arm-linux-tdep.c (arm_linux_sigreturn_return_addr): New. (arm_linux_syscall_next_pc): New. (arm_linux_copy_svc): Use arm_linux_sigreturn_return_addr instead. (arm_linux_init_abi): Initialize syscall_next_pc. * arm-tdep.c (thumb_get_next_pc_raw): Get next pc of SWI in Thumb mode. (arm_get_next_pc_raw): Get next pc of SWI in ARM mode. * arm-tdep.h (struct gdbarch_tdep): Add a function pointer syscall_next_pc. Declare arm_frame_is_thumb. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4d74734f6c..7312034e52 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,14 @@ +2010-08-30 Yao Qi + + * arm-linux-tdep.c (arm_linux_sigreturn_return_addr): New. + (arm_linux_syscall_next_pc): New. + (arm_linux_copy_svc): Use arm_linux_sigreturn_return_addr instead. + (arm_linux_init_abi): Initialize syscall_next_pc. + * arm-tdep.c (thumb_get_next_pc_raw): Get next pc of SWI in Thumb mode. + (arm_get_next_pc_raw): Get next pc of SWI in ARM mode. + * arm-tdep.h (struct gdbarch_tdep): Add a function pointer syscall_next_pc. + Declare arm_frame_is_thumb. + 2010-08-30 Jan Kratochvil Code cleanup. diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index 682054c44b..aa7d0af2b1 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -630,6 +630,82 @@ arm_linux_regset_from_core_section (struct gdbarch *gdbarch, return NULL; } +/* Copy the value of next pc of sigreturn and rt_sigrturn into PC, + and return 1. Return 0 if it is not a rt_sigreturn/sigreturn + syscall. */ +static int +arm_linux_sigreturn_return_addr (struct frame_info *frame, + unsigned long svc_number, + CORE_ADDR *pc) +{ + /* Is this a sigreturn or rt_sigreturn syscall? */ + if (svc_number == 119 || svc_number == 173) + { + if (get_frame_type (frame) == SIGTRAMP_FRAME) + { + *pc = frame_unwind_caller_pc (frame); + return 1; + } + } + return 0; +} + +/* When FRAME is at a syscall instruction, return the PC of the next + instruction to be executed. */ + +static CORE_ADDR +arm_linux_syscall_next_pc (struct frame_info *frame) +{ + CORE_ADDR pc = get_frame_pc (frame); + CORE_ADDR return_addr = 0; + int is_thumb = arm_frame_is_thumb (frame); + ULONGEST svc_number = 0; + int is_sigreturn = 0; + + if (is_thumb) + { + svc_number = get_frame_register_unsigned (frame, 7); + } + else + { + struct gdbarch *gdbarch = get_frame_arch (frame); + enum bfd_endian byte_order_for_code = + gdbarch_byte_order_for_code (gdbarch); + unsigned long this_instr = + read_memory_unsigned_integer (pc, 4, byte_order_for_code); + + unsigned long svc_operand = (0x00ffffff & this_instr); + if (svc_operand) /* OABI. */ + { + svc_number = svc_operand - 0x900000; + } + else /* EABI. */ + { + svc_number = get_frame_register_unsigned (frame, 7); + } + } + + is_sigreturn = arm_linux_sigreturn_return_addr (frame, svc_number, + &return_addr); + + if (is_sigreturn) + return return_addr; + + if (is_thumb) + { + return_addr = pc + 2; + /* Addresses for calling Thumb functions have the bit 0 set. */ + return_addr |= 1; + } + else + { + return_addr = pc + 4; + } + + return return_addr; +} + + /* Insert a single step breakpoint at the next executed instruction. */ static int @@ -688,8 +764,11 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to, struct regcache *regs, struct displaced_step_closure *dsc) { CORE_ADDR from = dsc->insn_addr; + CORE_ADDR return_to = 0; + struct frame_info *frame; unsigned int svc_number = displaced_read_reg (regs, from, 7); + int is_sigreturn = 0; if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: copying Linux svc insn %.8lx\n", @@ -697,13 +776,10 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to, frame = get_current_frame (); - /* Is this a sigreturn or rt_sigreturn syscall? Note: these are only useful - for EABI. */ - if (svc_number == 119 || svc_number == 173) + is_sigreturn = arm_linux_sigreturn_return_addr(frame, svc_number, + &return_to); + if (is_sigreturn) { - if (get_frame_type (frame) == SIGTRAMP_FRAME) - { - CORE_ADDR return_to; struct symtab_and_line sal; if (debug_displaced) @@ -711,7 +787,6 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to, "sigreturn/rt_sigreturn SVC call. PC in frame = %lx\n", (unsigned long) get_frame_pc (frame)); - return_to = frame_unwind_caller_pc (frame); if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: unwind pc = %lx. " "Setting momentary breakpoint.\n", (unsigned long) return_to); @@ -743,7 +818,7 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, uint32_t insn, CORE_ADDR to, else if (debug_displaced) fprintf_unfiltered (gdb_stdlog, "displaced: sigreturn/rt_sigreturn " "SVC call not in signal trampoline frame\n"); - } + /* Preparation: If we detect sigreturn, set momentary breakpoint at resume location, else nothing. @@ -946,6 +1021,9 @@ arm_linux_init_abi (struct gdbarch_info info, set_gdbarch_displaced_step_free_closure (gdbarch, simple_displaced_step_free_closure); set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point); + + + tdep->syscall_next_pc = arm_linux_syscall_next_pc; } /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 5a7e76d711..4a028c8385 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -270,7 +270,7 @@ arm_psr_thumb_bit (struct gdbarch *gdbarch) /* Determine if FRAME is executing in Thumb mode. */ -static int +int arm_frame_is_thumb (struct frame_info *frame) { CORE_ADDR cpsr; @@ -2828,7 +2828,16 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt) else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */ { unsigned long cond = bits (inst1, 8, 11); - if (cond != 0x0f && condition_true (cond, status)) /* 0x0f = SWI */ + if (cond == 0x0f) /* 0x0f = SWI */ + { + struct gdbarch_tdep *tdep; + tdep = gdbarch_tdep (gdbarch); + + if (tdep->syscall_next_pc != NULL) + nextpc = tdep->syscall_next_pc (frame); + + } + else if (cond != 0x0f && condition_true (cond, status)) nextpc = pc_val + (sbits (inst1, 0, 7) << 1); } else if ((inst1 & 0xf800) == 0xe000) /* unconditional branch */ @@ -3277,7 +3286,16 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc, int insert_bkpt) case 0xc: case 0xd: case 0xe: /* coproc ops */ + break; case 0xf: /* SWI */ + { + struct gdbarch_tdep *tdep; + tdep = gdbarch_tdep (gdbarch); + + if (tdep->syscall_next_pc != NULL) + nextpc = tdep->syscall_next_pc (frame); + + } break; default: diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h index 87387aabb6..61cdb5d5ea 100644 --- a/gdb/arm-tdep.h +++ b/gdb/arm-tdep.h @@ -196,6 +196,10 @@ struct gdbarch_tdep struct type *arm_ext_type; struct type *neon_double_type; struct type *neon_quad_type; + + /* Return the expected next PC if FRAME is stopped at a syscall + instruction. */ + CORE_ADDR (*syscall_next_pc) (struct frame_info *frame); }; /* Structures used for displaced stepping. */ @@ -297,6 +301,7 @@ extern void CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR); CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR); int arm_software_single_step (struct frame_info *); +int arm_frame_is_thumb (struct frame_info *frame); extern struct displaced_step_closure * arm_displaced_step_copy_insn (struct gdbarch *, CORE_ADDR, CORE_ADDR,