X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Farch%2Farm-linux.c;h=943efe7aa544a0ccd690968e91901ff652c620a6;hb=61baf725eca99af2569262d10aca03dcde2698f6;hp=b43e4845d5e74fa91a35ceab5ee084e620b2053d;hpb=618f726fcb851883a0094aa7fa17003889b7189f;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/arch/arm-linux.c b/gdb/arch/arm-linux.c
index b43e4845d5..943efe7aa5 100644
--- a/gdb/arch/arm-linux.c
+++ b/gdb/arch/arm-linux.c
@@ -1,6 +1,6 @@
/* Common target dependent code for GNU/Linux on ARM systems.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
This file is part of GDB.
@@ -18,8 +18,10 @@
along with this program. If not, see . */
#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,83 @@ 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 (tail) called
+ as functions and return to the address in LR. However, when GDB single
+ step this instruction, this instruction isn't executed yet, and LR
+ may not be updated yet. In other words, GDB can get the target
+ address from LR if this instruction isn't BL or BLX. */
+ if (nextpc > 0xffff0000)
+ {
+ int bl_blx_p = 0;
+ CORE_ADDR pc = regcache_read_pc (self->regcache);
+ int pc_incr = 0;
+
+ if (self->ops->is_thumb (self))
+ {
+ unsigned short inst1
+ = self->ops->read_mem_uint (pc, 2, self->byte_order_for_code);
+
+ if (bits (inst1, 8, 15) == 0x47 && bit (inst1, 7))
+ {
+ /* BLX Rm */
+ bl_blx_p = 1;
+ pc_incr = 2;
+ }
+ else if (thumb_insn_size (inst1) == 4)
+ {
+ unsigned short inst2;
+
+ inst2 = self->ops->read_mem_uint (pc + 2, 2,
+ self->byte_order_for_code);
+
+ if ((inst1 & 0xf800) == 0xf000 && bits (inst2, 14, 15) == 0x3)
+ {
+ /* BL