Adding aarch64-linux-tdep support.
[deliverable/binutils-gdb.git] / gdb / aarch64-linux-tdep.c
CommitLineData
1ae3db19
MS
1/* Target-dependent code for GNU/Linux AArch64.
2
3 Copyright (C) 2009-2013 Free Software Foundation, Inc.
4 Contributed by ARM Ltd.
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20
21#include "defs.h"
22
23#include "gdbarch.h"
24#include "glibc-tdep.h"
25#include "linux-tdep.h"
26#include "aarch64-tdep.h"
27#include "aarch64-linux-tdep.h"
28#include "osabi.h"
29#include "solib-svr4.h"
30#include "symtab.h"
31#include "tramp-frame.h"
32#include "trad-frame.h"
33
34#include "inferior.h"
35#include "regcache.h"
36#include "regset.h"
37
38/* The general-purpose regset consists of 31 X registers, plus SP, PC,
39 PSTATE and two extra pseudo 64-bit registers, as defined in the
40 AArch64 port of the Linux kernel. */
41#define AARCH64_LINUX_SIZEOF_GREGSET (36 * X_REGISTER_SIZE)
42
43/* The fp regset consists of 32 V registers, plus FPCR and FPSR which
44 are 4 bytes wide each, and the whole structure is padded to 128 bit
45 alignment. */
46#define AARCH64_LINUX_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE)
47
48/* Signal frame handling.
49
50 +----------+ ^
51 | saved lr | |
52 +->| saved fp |--+
53 | | |
54 | | |
55 | +----------+
56 | | saved lr |
57 +--| saved fp |
58 ^ | |
59 | | |
60 | +----------+
61 ^ | |
62 | | signal |
63 | | |
64 | | saved lr |-->interrupted_function_pc
65 +--| saved fp |
66 | +----------+
67 | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
68 +--| saved fp |<- FP
69 | |
70 | |<- SP
71 +----------+
72
73 On signal delivery, the kernel will create a signal handler stack
74 frame and setup the return address in LR to point at restorer stub.
75 The signal stack frame is defined by:
76
77 struct rt_sigframe
78 {
79 siginfo_t info;
80 struct ucontext uc;
81 };
82
83 typedef struct
84 {
85 ... 128 bytes
86 } siginfo_t;
87
88 The ucontext has the following form:
89 struct ucontext
90 {
91 unsigned long uc_flags;
92 struct ucontext *uc_link;
93 stack_t uc_stack;
94 sigset_t uc_sigmask;
95 struct sigcontext uc_mcontext;
96 };
97
98 typedef struct sigaltstack
99 {
100 void *ss_sp;
101 int ss_flags;
102 size_t ss_size;
103 } stack_t;
104
105 struct sigcontext
106 {
107 unsigned long fault_address;
108 unsigned long regs[31];
109 unsigned long sp; / * 31 * /
110 unsigned long pc; / * 32 * /
111 unsigned long pstate; / * 33 * /
112 __u8 __reserved[4096]
113 };
114
115 The restorer stub will always have the form:
116
117 d28015a8 movz x8, #0xad
118 d4000001 svc #0x0
119
120 We detect signal frames by snooping the return code for the restorer
121 instruction sequence.
122
123 The handler then needs to recover the saved register set from
124 ucontext.uc_mcontext. */
125
126/* These magic numbers need to reflect the layout of the kernel
127 defined struct rt_sigframe and ucontext. */
128#define AARCH64_SIGCONTEXT_REG_SIZE 8
129#define AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET 128
130#define AARCH64_UCONTEXT_SIGCONTEXT_OFFSET 176
131#define AARCH64_SIGCONTEXT_XO_OFFSET 8
132
133/* Implement the "init" method of struct tramp_frame. */
134
135static void
136aarch64_linux_sigframe_init (const struct tramp_frame *self,
137 struct frame_info *this_frame,
138 struct trad_frame_cache *this_cache,
139 CORE_ADDR func)
140{
141 struct gdbarch *gdbarch = get_frame_arch (this_frame);
142 CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
143 CORE_ADDR fp = get_frame_register_unsigned (this_frame, AARCH64_FP_REGNUM);
144 CORE_ADDR sigcontext_addr =
145 sp
146 + AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET
147 + AARCH64_UCONTEXT_SIGCONTEXT_OFFSET;
148 int i;
149
150 for (i = 0; i < 31; i++)
151 {
152 trad_frame_set_reg_addr (this_cache,
153 AARCH64_X0_REGNUM + i,
154 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
155 + i * AARCH64_SIGCONTEXT_REG_SIZE);
156 }
157
158 trad_frame_set_reg_addr (this_cache, AARCH64_FP_REGNUM, fp);
159 trad_frame_set_reg_addr (this_cache, AARCH64_LR_REGNUM, fp + 8);
160 trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM, fp + 8);
161
162 trad_frame_set_id (this_cache, frame_id_build (fp, func));
163}
164
165static const struct tramp_frame aarch64_linux_rt_sigframe =
166{
167 SIGTRAMP_FRAME,
168 4,
169 {
170 /* movz x8, 0x8b (S=1,o=10,h=0,i=0x8b,r=8)
171 Soo1 0010 1hhi iiii iiii iiii iiir rrrr */
172 {0xd2801168, -1},
173
174 /* svc 0x0 (o=0, l=1)
175 1101 0100 oooi iiii iiii iiii iii0 00ll */
176 {0xd4000001, -1},
177 {TRAMP_SENTINEL_INSN, -1}
178 },
179 aarch64_linux_sigframe_init
180};
181
182/* Fill GDB's register array with the general-purpose register values
183 in the buffer pointed by GREGS_BUF. */
184
185void
186aarch64_linux_supply_gregset (struct regcache *regcache,
187 const gdb_byte *gregs_buf)
188{
189 int regno;
190
191 for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
192 regcache_raw_supply (regcache, regno,
193 gregs_buf + X_REGISTER_SIZE
194 * (regno - AARCH64_X0_REGNUM));
195}
196
197/* The "supply_regset" function for the general-purpose register set. */
198
199static void
200supply_gregset_from_core (const struct regset *regset,
201 struct regcache *regcache,
202 int regnum, const void *regbuf, size_t len)
203{
204 aarch64_linux_supply_gregset (regcache, (const gdb_byte *) regbuf);
205}
206
207/* Fill GDB's register array with the floating-point register values
208 in the buffer pointed by FPREGS_BUF. */
209
210void
211aarch64_linux_supply_fpregset (struct regcache *regcache,
212 const gdb_byte *fpregs_buf)
213{
214 int regno;
215
216 for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
217 regcache_raw_supply (regcache, regno,
218 fpregs_buf + V_REGISTER_SIZE
219 * (regno - AARCH64_V0_REGNUM));
220
221 regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM,
222 fpregs_buf + V_REGISTER_SIZE * 32);
223 regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM,
224 fpregs_buf + V_REGISTER_SIZE * 32 + 4);
225}
226
227/* The "supply_regset" function for the floating-point register set. */
228
229static void
230supply_fpregset_from_core (const struct regset *regset,
231 struct regcache *regcache,
232 int regnum, const void *regbuf, size_t len)
233{
234 aarch64_linux_supply_fpregset (regcache, (const gdb_byte *) regbuf);
235}
236
237/* Implement the "regset_from_core_section" gdbarch method. */
238
239static const struct regset *
240aarch64_linux_regset_from_core_section (struct gdbarch *gdbarch,
241 const char *sect_name,
242 size_t sect_size)
243{
244 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
245
246 if (strcmp (sect_name, ".reg") == 0
247 && sect_size == AARCH64_LINUX_SIZEOF_GREGSET)
248 {
249 if (tdep->gregset == NULL)
250 tdep->gregset = regset_alloc (gdbarch, supply_gregset_from_core,
251 NULL);
252 return tdep->gregset;
253 }
254
255 if (strcmp (sect_name, ".reg2") == 0
256 && sect_size == AARCH64_LINUX_SIZEOF_FPREGSET)
257 {
258 if (tdep->fpregset == NULL)
259 tdep->fpregset = regset_alloc (gdbarch, supply_fpregset_from_core,
260 NULL);
261 return tdep->fpregset;
262 }
263 return NULL;
264}
265
266static void
267aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
268{
269 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
270
271 tdep->lowest_pc = 0x8000;
272
273 set_solib_svr4_fetch_link_map_offsets (gdbarch,
274 svr4_lp64_fetch_link_map_offsets);
275
276 /* Shared library handling. */
277 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
278
279 set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
280 tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe);
281
282 /* Enable longjmp. */
283 tdep->jb_pc = 11;
284
285 set_gdbarch_regset_from_core_section (gdbarch,
286 aarch64_linux_regset_from_core_section);
287}
288
289/* Provide a prototype to silence -Wmissing-prototypes. */
290extern initialize_file_ftype _initialize_aarch64_linux_tdep;
291
292void
293_initialize_aarch64_linux_tdep (void)
294{
295 gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
296 aarch64_linux_init_abi);
297}
This page took 0.033056 seconds and 4 git commands to generate.