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