/* Common target dependent code for GNU/Linux on ARM systems.
- Copyright (C) 1999-2015 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#include "common-defs.h"
+#include "gdbsupport/common-defs.h"
+#include "gdbsupport/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. */
r0_offset += ARM_UCONTEXT_SIGCONTEXT + ARM_SIGCONTEXT_R0;
}
- pc_offset = r0_offset + INT_REGISTER_SIZE * ARM_PC_REGNUM;
+ pc_offset = r0_offset + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM;
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 <label> and BLX <label> */
+ bl_blx_p = 1;
+ pc_incr = 4;
+ }
+ }
+
+ pc_incr = MAKE_THUMB_ADDR (pc_incr);
+ }
+ else
+ {
+ unsigned int insn
+ = self->ops->read_mem_uint (pc, 4, self->byte_order_for_code);
+
+ if (bits (insn, 28, 31) == INST_NV)
+ {
+ if (bits (insn, 25, 27) == 0x5) /* BLX <label> */
+ bl_blx_p = 1;
+ }
+ else
+ {
+ if (bits (insn, 24, 27) == 0xb /* BL <label> */
+ || bits (insn, 4, 27) == 0x12fff3 /* BLX Rm */)
+ bl_blx_p = 1;
+ }
+
+ pc_incr = 4;
+ }
+
+ /* If the instruction BL or BLX, the target address is the following
+ instruction of BL or BLX, otherwise, the target address is in LR
+ already. */
+ if (bl_blx_p)
+ nextpc = pc + pc_incr;
+ else
+ nextpc = regcache_raw_get_unsigned (self->regcache, ARM_LR_REGNUM);
+ }
+ return nextpc;
+}