[ARM] Fixup PC in software single step
authorYao Qi <yao.qi@linaro.org>
Mon, 8 Feb 2016 16:05:31 +0000 (16:05 +0000)
committerYao Qi <yao.qi@linaro.org>
Fri, 12 Feb 2016 15:58:52 +0000 (15:58 +0000)
When I exercise GDBserver software single step, I see the following
error, which has been already handled by GDB properly.

In GDBserver log, we can see, GDBserver tries to single step instruction
on 0xb6e0a6e4, and destination address is 0xffff0fe0,

 stop pc is 0xb6e0a6e4
 Writing f001f0e7 to 0xffff0fe0 in process 7132
 Failed to insert breakpoint at 0xffff0fe0 (Input/output error).
 Failed to insert breakpoint at 0xffff0fe0 (-1).

(gdb) disassemble __aeabi_read_tp,+8
Dump of assembler code from 0xb6e0a6e0 to 0xb6e0a6e8:
   0xb6e0a6e0 <__aeabi_read_tp+0>: mvn r0, #61440 ; 0xf000
   0xb6e0a6e4 <__aeabi_read_tp+4>: sub pc, r0, #31

however, it fails inserting breakpoint there.  This problem has already
fixed by GDB, see comments in arm-linux-tdep.c:arm_linux_software_single_step

      /* The Linux kernel offers some user-mode helpers in a high page.  We can
 not read this page (as of 2.6.23), and even if we could then we
 couldn't set breakpoints in it, and even if we could then the atomic
 operations would fail when interrupted.  They are all called as
 functions and return to the address in LR, so step to there
 instead.  */

so we need to do the same thing in GDB side as well.  This patch adds
a new field fixup in arm_get_next_pcs_ops, so that we can fix up PC
for arm-linux target.  In this way, both GDB and GDBserver can single
step instructions going to kernel helpers.

gdb:

2016-02-12  Yao Qi  <yao.qi@linaro.org>

* arch/arm-get-next-pcs.c (arm_get_next_pcs): Call
self->ops->fixup if it isn't NULL.
* arch/arm-get-next-pcs.h: Include gdb_vecs.h.
(struct arm_get_next_pcs_ops) <fixup>: New field.
* arch/arm-linux.c: Include common-regcache.h and
arch/arm-get-next-pcs.h.
(arm_linux_get_next_pcs_fixup): New function.
* arch/arm-linux.h (arm_linux_get_next_pcs_fixup): Declare.
* arm-linux-tdep.c (arm_linux_get_next_pcs_ops): Initialize
it with arm_linux_get_next_pcs_fixup.
(arm_linux_software_single_step): Move code to
arm_linux_get_next_pcs_fixup.
* arm-tdep.c (arm_get_next_pcs_ops): Initialize it.

gdb/gdbserver:

2016-02-12  Yao Qi  <yao.qi@linaro.org>

* linux-arm-low.c (get_next_pcs_ops): Initialize it with
arm_linux_get_next_pcs_fixup.

gdb/ChangeLog
gdb/arch/arm-get-next-pcs.c
gdb/arch/arm-get-next-pcs.h
gdb/arch/arm-linux.c
gdb/arch/arm-linux.h
gdb/arm-linux-tdep.c
gdb/arm-tdep.c
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-arm-low.c

index 4e8dfb54f6c111a491dbc17bec918bcdadea9a69..15d81577cfb28c3f5d15c5b01f15b646059f5e32 100644 (file)
@@ -1,3 +1,19 @@
+2016-02-12  Yao Qi  <yao.qi@linaro.org>
+
+       * arch/arm-get-next-pcs.c (arm_get_next_pcs): Call
+       self->ops->fixup if it isn't NULL.
+       * arch/arm-get-next-pcs.h: Include gdb_vecs.h.
+       (struct arm_get_next_pcs_ops) <fixup>: New field.
+       * arch/arm-linux.c: Include common-regcache.h and
+       arch/arm-get-next-pcs.h.
+       (arm_linux_get_next_pcs_fixup): New function.
+       * arch/arm-linux.h (arm_linux_get_next_pcs_fixup): Declare.
+       * arm-linux-tdep.c (arm_linux_get_next_pcs_ops): Initialize
+       it with arm_linux_get_next_pcs_fixup.
+       (arm_linux_software_single_step): Move code to
+       arm_linux_get_next_pcs_fixup.
+       * arm-tdep.c (arm_get_next_pcs_ops): Initialize it.
+
 2016-02-12  Marcin Koƛcielnicki  <koriakin@0x04.net>
 
        * xml-tdesc.c (target_fetch_description_xml) [!HAVE_LIBEXPAT]: Warn
index e84014742ebff69343617581d9e6b05e87395390..840486979874daac10300a55b0edd038fd0e76c8 100644 (file)
@@ -923,5 +923,16 @@ arm_get_next_pcs (struct arm_get_next_pcs *self)
        next_pcs = arm_get_next_pcs_raw (self);
     }
 
+  if (self->ops->fixup != NULL)
+    {
+      CORE_ADDR nextpc;
+      int i;
+
+      for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, nextpc); i++)
+       {
+         nextpc = self->ops->fixup (self, nextpc);
+         VEC_replace (CORE_ADDR, next_pcs, i, nextpc);
+       }
+    }
   return next_pcs;
 }
index 7cb0858cc70998910337b9d0b1f51082af225669..e038982c5148135f8b7f8e27fef5a836305c7706 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifndef ARM_GET_NEXT_PCS_H
 #define ARM_GET_NEXT_PCS_H 1
+#include "gdb_vecs.h"
 
 /* Forward declaration.  */
 struct arm_get_next_pcs;
@@ -30,6 +31,9 @@ struct arm_get_next_pcs_ops
   CORE_ADDR (*syscall_next_pc) (struct arm_get_next_pcs *self, CORE_ADDR pc);
   CORE_ADDR (*addr_bits_remove) (struct arm_get_next_pcs *self, CORE_ADDR val);
   int (*is_thumb) (struct arm_get_next_pcs *self);
+
+  /* Fix up PC if needed.  */
+  CORE_ADDR (*fixup) (struct arm_get_next_pcs *self, CORE_ADDR pc);
 };
 
 /* Context for a get_next_pcs call on ARM.  */
index b43e4845d5e74fa91a35ceab5ee084e620b2053d..457080c27ffe0878fa6cfef1537378616109cdaa 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "common-defs.h"
+#include "common-regcache.h"
 #include "arch/arm.h"
 #include "arm-linux.h"
+#include "arch/arm-get-next-pcs.h"
 
 /* Calculate the offset from stack pointer of the pc register on the stack
    in the case of a sigreturn or sigreturn_rt syscall.  */
@@ -55,3 +57,21 @@ arm_linux_sigreturn_next_pc_offset (unsigned long sp,
 
   return pc_offset;
 }
+
+/* Implementation of "fixup" method of struct arm_get_next_pcs_ops
+   for arm-linux.  */
+
+CORE_ADDR
+arm_linux_get_next_pcs_fixup (struct arm_get_next_pcs *self,
+                             CORE_ADDR nextpc)
+{
+  /* The Linux kernel offers some user-mode helpers in a high page.  We can
+     not read this page (as of 2.6.23), and even if we could then we
+     couldn't set breakpoints in it, and even if we could then the atomic
+     operations would fail when interrupted.  They are all called as
+     functions and return to the address in LR, so step to there
+     instead.  */
+  if (nextpc > 0xffff0000)
+    nextpc = regcache_raw_get_unsigned (self->regcache, ARM_LR_REGNUM);
+  return nextpc;
+}
index 31cb35150e7726c9a815e4a75e8080095fdf0d87..dfd634c5ffa3c4aba2071397dd9946eee753e3b3 100644 (file)
@@ -71,4 +71,8 @@ arm_linux_sigreturn_next_pc_offset (unsigned long sp,
                                    unsigned long svc_number,
                                    int is_sigreturn);
 
+struct arm_get_next_pcs;
+
+CORE_ADDR arm_linux_get_next_pcs_fixup (struct arm_get_next_pcs *self,
+                                       CORE_ADDR pc);
 #endif /* ARM_LINUX_H */
index 53169633b5695d57103b2f7ff876a98c78166bbe..e416e28fefa3a3e9361ce66d6feaa14a14986d94 100644 (file)
@@ -274,7 +274,8 @@ static struct arm_get_next_pcs_ops arm_linux_get_next_pcs_ops = {
   arm_get_next_pcs_read_memory_unsigned_integer,
   arm_linux_get_next_pcs_syscall_next_pc,
   arm_get_next_pcs_addr_bits_remove,
-  arm_get_next_pcs_is_thumb
+  arm_get_next_pcs_is_thumb,
+  arm_linux_get_next_pcs_fixup,
 };
 
 static void
@@ -950,18 +951,7 @@ arm_linux_software_single_step (struct frame_info *frame)
   next_pcs = arm_get_next_pcs (&next_pcs_ctx);
 
   for (i = 0; VEC_iterate (CORE_ADDR, next_pcs, i, pc); i++)
-    {
-      /* The Linux kernel offers some user-mode helpers in a high page.  We can
-        not read this page (as of 2.6.23), and even if we could then we
-        couldn't set breakpoints in it, and even if we could then the atomic
-        operations would fail when interrupted.  They are all called as
-        functions and return to the address in LR, so step to there
-        instead.  */
-      if (pc > 0xffff0000)
-       pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
-
-      arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
-    }
+    arm_insert_single_step_breakpoint (gdbarch, aspace, pc);
 
   do_cleanups (old_chain);
 
index 7308a40795a3d97997eb6c25d42543caa3ccc426..048406aca8d4c42f0381e75cdd7803332a013648 100644 (file)
@@ -247,7 +247,8 @@ static struct arm_get_next_pcs_ops arm_get_next_pcs_ops = {
   arm_get_next_pcs_read_memory_unsigned_integer,
   arm_get_next_pcs_syscall_next_pc,
   arm_get_next_pcs_addr_bits_remove,
-  arm_get_next_pcs_is_thumb
+  arm_get_next_pcs_is_thumb,
+  NULL,
 };
 
 struct arm_prologue_cache
index ca82f9153e1f90b02d22492df296ee0134603942..8d026475e57e48942b6868f3842ec82f56ee99fa 100644 (file)
@@ -1,3 +1,8 @@
+2016-02-12  Yao Qi  <yao.qi@linaro.org>
+
+       * linux-arm-low.c (get_next_pcs_ops): Initialize it with
+       arm_linux_get_next_pcs_fixup.
+
 2016-02-12  Marcin Koƛcielnicki  <koriakin@0x04.net>
 
        * tracepoint.c (x_tracepoint_action_download): Change
index 0f627069e0ed6678b3a11ce733c199c719d1a813..365f1c932227713d77c12dc1fd4eae29ee4972fc 100644 (file)
@@ -157,7 +157,8 @@ static struct arm_get_next_pcs_ops get_next_pcs_ops = {
   get_next_pcs_read_memory_unsigned_integer,
   get_next_pcs_syscall_next_pc,
   get_next_pcs_addr_bits_remove,
-  get_next_pcs_is_thumb
+  get_next_pcs_is_thumb,
+  arm_linux_get_next_pcs_fixup,
 };
 
 static int