1d0317114Schristos /* Common target dependent code for GNU/Linux on ARM systems.
2d0317114Schristos
3*56bb7041Schristos Copyright (C) 1999-2020 Free Software Foundation, Inc.
4d0317114Schristos
5d0317114Schristos This file is part of GDB.
6d0317114Schristos
7d0317114Schristos This program is free software; you can redistribute it and/or modify
8d0317114Schristos it under the terms of the GNU General Public License as published by
9d0317114Schristos the Free Software Foundation; either version 3 of the License, or
10d0317114Schristos (at your option) any later version.
11d0317114Schristos
12d0317114Schristos This program is distributed in the hope that it will be useful,
13d0317114Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
14d0317114Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15d0317114Schristos GNU General Public License for more details.
16d0317114Schristos
17d0317114Schristos You should have received a copy of the GNU General Public License
18d0317114Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */
19d0317114Schristos
20*56bb7041Schristos #include "gdbsupport/common-defs.h"
21*56bb7041Schristos #include "gdbsupport/common-regcache.h"
22d0317114Schristos #include "arch/arm.h"
23d0317114Schristos #include "arm-linux.h"
24d0317114Schristos #include "arch/arm-get-next-pcs.h"
25d0317114Schristos
26d0317114Schristos /* Calculate the offset from stack pointer of the pc register on the stack
27d0317114Schristos in the case of a sigreturn or sigreturn_rt syscall. */
28d0317114Schristos int
arm_linux_sigreturn_next_pc_offset(unsigned long sp,unsigned long sp_data,unsigned long svc_number,int is_sigreturn)29d0317114Schristos arm_linux_sigreturn_next_pc_offset (unsigned long sp,
30d0317114Schristos unsigned long sp_data,
31d0317114Schristos unsigned long svc_number,
32d0317114Schristos int is_sigreturn)
33d0317114Schristos {
34d0317114Schristos /* Offset of R0 register. */
35d0317114Schristos int r0_offset = 0;
36d0317114Schristos /* Offset of PC register. */
37d0317114Schristos int pc_offset = 0;
38d0317114Schristos
39d0317114Schristos if (is_sigreturn)
40d0317114Schristos {
41d0317114Schristos if (sp_data == ARM_NEW_SIGFRAME_MAGIC)
42d0317114Schristos r0_offset = ARM_UCONTEXT_SIGCONTEXT + ARM_SIGCONTEXT_R0;
43d0317114Schristos else
44d0317114Schristos r0_offset = ARM_SIGCONTEXT_R0;
45d0317114Schristos }
46d0317114Schristos else
47d0317114Schristos {
48d0317114Schristos if (sp_data == sp + ARM_OLD_RT_SIGFRAME_SIGINFO)
49d0317114Schristos r0_offset = ARM_OLD_RT_SIGFRAME_UCONTEXT;
50d0317114Schristos else
51d0317114Schristos r0_offset = ARM_NEW_RT_SIGFRAME_UCONTEXT;
52d0317114Schristos
53d0317114Schristos r0_offset += ARM_UCONTEXT_SIGCONTEXT + ARM_SIGCONTEXT_R0;
54d0317114Schristos }
55d0317114Schristos
56*56bb7041Schristos pc_offset = r0_offset + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM;
57d0317114Schristos
58d0317114Schristos return pc_offset;
59d0317114Schristos }
60d0317114Schristos
61d0317114Schristos /* Implementation of "fixup" method of struct arm_get_next_pcs_ops
62d0317114Schristos for arm-linux. */
63d0317114Schristos
64d0317114Schristos CORE_ADDR
arm_linux_get_next_pcs_fixup(struct arm_get_next_pcs * self,CORE_ADDR nextpc)65d0317114Schristos arm_linux_get_next_pcs_fixup (struct arm_get_next_pcs *self,
66d0317114Schristos CORE_ADDR nextpc)
67d0317114Schristos {
68d0317114Schristos /* The Linux kernel offers some user-mode helpers in a high page. We can
69d0317114Schristos not read this page (as of 2.6.23), and even if we could then we
70d0317114Schristos couldn't set breakpoints in it, and even if we could then the atomic
71d0317114Schristos operations would fail when interrupted. They are all (tail) called
72d0317114Schristos as functions and return to the address in LR. However, when GDB single
73d0317114Schristos step this instruction, this instruction isn't executed yet, and LR
74d0317114Schristos may not be updated yet. In other words, GDB can get the target
75d0317114Schristos address from LR if this instruction isn't BL or BLX. */
76d0317114Schristos if (nextpc > 0xffff0000)
77d0317114Schristos {
78d0317114Schristos int bl_blx_p = 0;
79d0317114Schristos CORE_ADDR pc = regcache_read_pc (self->regcache);
80d0317114Schristos int pc_incr = 0;
81d0317114Schristos
82d0317114Schristos if (self->ops->is_thumb (self))
83d0317114Schristos {
84d0317114Schristos unsigned short inst1
85d0317114Schristos = self->ops->read_mem_uint (pc, 2, self->byte_order_for_code);
86d0317114Schristos
87d0317114Schristos if (bits (inst1, 8, 15) == 0x47 && bit (inst1, 7))
88d0317114Schristos {
89d0317114Schristos /* BLX Rm */
90d0317114Schristos bl_blx_p = 1;
91d0317114Schristos pc_incr = 2;
92d0317114Schristos }
93d0317114Schristos else if (thumb_insn_size (inst1) == 4)
94d0317114Schristos {
95d0317114Schristos unsigned short inst2;
96d0317114Schristos
97d0317114Schristos inst2 = self->ops->read_mem_uint (pc + 2, 2,
98d0317114Schristos self->byte_order_for_code);
99d0317114Schristos
100d0317114Schristos if ((inst1 & 0xf800) == 0xf000 && bits (inst2, 14, 15) == 0x3)
101d0317114Schristos {
102d0317114Schristos /* BL <label> and BLX <label> */
103d0317114Schristos bl_blx_p = 1;
104d0317114Schristos pc_incr = 4;
105d0317114Schristos }
106d0317114Schristos }
107d0317114Schristos
108d0317114Schristos pc_incr = MAKE_THUMB_ADDR (pc_incr);
109d0317114Schristos }
110d0317114Schristos else
111d0317114Schristos {
112d0317114Schristos unsigned int insn
113d0317114Schristos = self->ops->read_mem_uint (pc, 4, self->byte_order_for_code);
114d0317114Schristos
115d0317114Schristos if (bits (insn, 28, 31) == INST_NV)
116d0317114Schristos {
117d0317114Schristos if (bits (insn, 25, 27) == 0x5) /* BLX <label> */
118d0317114Schristos bl_blx_p = 1;
119d0317114Schristos }
120d0317114Schristos else
121d0317114Schristos {
122d0317114Schristos if (bits (insn, 24, 27) == 0xb /* BL <label> */
123d0317114Schristos || bits (insn, 4, 27) == 0x12fff3 /* BLX Rm */)
124d0317114Schristos bl_blx_p = 1;
125d0317114Schristos }
126d0317114Schristos
127d0317114Schristos pc_incr = 4;
128d0317114Schristos }
129d0317114Schristos
130d0317114Schristos /* If the instruction BL or BLX, the target address is the following
131d0317114Schristos instruction of BL or BLX, otherwise, the target address is in LR
132d0317114Schristos already. */
133d0317114Schristos if (bl_blx_p)
134d0317114Schristos nextpc = pc + pc_incr;
135d0317114Schristos else
136d0317114Schristos nextpc = regcache_raw_get_unsigned (self->regcache, ARM_LR_REGNUM);
137d0317114Schristos }
138d0317114Schristos return nextpc;
139d0317114Schristos }
140