This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [Patch,ARM] Next pc of sigreturn/rt_sigreturn syscall
On Tue, Aug 24, 2010 at 10:12:57AM -0400, Daniel Jacobowitz wrote:
> On Tue, Aug 24, 2010 at 01:27:03PM +0200, Mark Kettenis wrote:
> > > Date: Mon, 23 Aug 2010 23:38:54 -0700
> > > From: Yao Qi <yao@codesourcery.com>
> > >
> > > Hi,
> > > This patch is to calculate correct address of 'next pc' of syscall
> > > sigreturn and rt_sigreturn.
> >
> > You're polluting the genric arm code with Linux-specific stuff.
> > Please don't do that. If something like this is needed, it should be
> > added to code in arm-linux-tdep.c.
>
> There's a couple of ways to do that; one example is
> mips_linux_syscall_next_pc.
Here is the updated patch, in which:
1. Add arm_linux_syscall_next_pc, similar to
mips_linux_syscall_next_pc. Compute the return address of SWI in both
ARM mode and Thumb mode.
2. Extract some common code from arm_linux_copy_svc.
Tested on armv7l-unknown-linux-gnueabi again. Result is the same as
my previous post.
--
Yao Qi
CodeSourcery
yao@codesourcery.com
(650) 331-3385 x739
2010-08-25 Yao Qi <yao@codesourcery.com>
* 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/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 682054c..106cd85 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -630,6 +630,53 @@ arm_linux_regset_from_core_section (struct gdbarch *gdbarch,
return NULL;
}
+/* Get the value of next pc of sigreturn and rt_sigrturn. 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)
+{
+ /* Is this a sigreturn or rt_sigreturn syscall? Note: these are only useful
+ for EABI. */
+ if (svc_number == 119 || svc_number == 173)
+ {
+ if (get_frame_type (frame) == SIGTRAMP_FRAME)
+ {
+ return frame_unwind_caller_pc (frame);
+ }
+ }
+ 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;
+ return_addr = arm_linux_sigreturn_return_addr(frame,
+ get_frame_register_unsigned (frame, 7));
+
+ if (return_addr)
+ return return_addr;
+
+ if (arm_frame_is_thumb (frame))
+ {
+ 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,6 +735,8 @@ 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);
@@ -697,13 +746,9 @@ 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)
- {
- if (get_frame_type (frame) == SIGTRAMP_FRAME)
+ return_to = arm_linux_sigreturn_return_addr(frame, svc_number);
+ if (return_to)
{
- CORE_ADDR return_to;
struct symtab_and_line sal;
if (debug_displaced)
@@ -711,7 +756,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 +787,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 +990,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 1ac8817..518e4e8 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -257,7 +257,7 @@ int arm_apcs_32 = 1;
/* Determine if FRAME is executing in Thumb mode. */
-static int
+int
arm_frame_is_thumb (struct frame_info *frame)
{
CORE_ADDR cpsr;
@@ -2808,7 +2808,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 (get_frame_arch (frame));
+
+ 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 */
@@ -3257,7 +3266,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 (get_frame_arch (frame));
+
+ 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 b6283ef..2f4e99b 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -193,6 +193,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. */
@@ -294,6 +298,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,