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