]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/aarch64-linux-tdep.c
Remove 'arch' field from regset structure.
[thirdparty/binutils-gdb.git] / gdb / aarch64-linux-tdep.c
CommitLineData
1ae3db19
MS
1/* Target-dependent code for GNU/Linux AArch64.
2
ecd75fc8 3 Copyright (C) 2009-2014 Free Software Foundation, Inc.
1ae3db19
MS
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
08248ca9
SDJ
38#include "cli/cli-utils.h"
39#include "stap-probe.h"
40#include "parser-defs.h"
41#include "user-regs.h"
42#include <ctype.h>
43
1ae3db19 44/* The general-purpose regset consists of 31 X registers, plus SP, PC,
b5dbc8d4
YZ
45 and PSTATE registers, as defined in the AArch64 port of the Linux
46 kernel. */
47#define AARCH64_LINUX_SIZEOF_GREGSET (34 * X_REGISTER_SIZE)
1ae3db19
MS
48
49/* The fp regset consists of 32 V registers, plus FPCR and FPSR which
50 are 4 bytes wide each, and the whole structure is padded to 128 bit
51 alignment. */
52#define AARCH64_LINUX_SIZEOF_FPREGSET (33 * V_REGISTER_SIZE)
53
54/* Signal frame handling.
55
f2205de0
HZ
56 +------------+ ^
57 | saved lr | |
58 +->| saved fp |--+
59 | | |
60 | | |
61 | +------------+
62 | | saved lr |
63 +--| saved fp |
64 ^ | |
65 | | |
66 | +------------+
67 ^ | |
68 | | signal |
69 | | | SIGTRAMP_FRAME (struct rt_sigframe)
70 | | saved regs |
71 +--| saved sp |--> interrupted_sp
72 | | saved pc |--> interrupted_pc
73 | | |
74 | +------------+
75 | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
76 +--| saved fp |<- FP
77 | | NORMAL_FRAME
78 | |<- SP
79 +------------+
1ae3db19
MS
80
81 On signal delivery, the kernel will create a signal handler stack
82 frame and setup the return address in LR to point at restorer stub.
83 The signal stack frame is defined by:
84
85 struct rt_sigframe
86 {
87 siginfo_t info;
88 struct ucontext uc;
89 };
90
91 typedef struct
92 {
93 ... 128 bytes
94 } siginfo_t;
95
96 The ucontext has the following form:
97 struct ucontext
98 {
99 unsigned long uc_flags;
100 struct ucontext *uc_link;
101 stack_t uc_stack;
102 sigset_t uc_sigmask;
103 struct sigcontext uc_mcontext;
104 };
105
106 typedef struct sigaltstack
107 {
108 void *ss_sp;
109 int ss_flags;
110 size_t ss_size;
111 } stack_t;
112
113 struct sigcontext
114 {
115 unsigned long fault_address;
116 unsigned long regs[31];
117 unsigned long sp; / * 31 * /
118 unsigned long pc; / * 32 * /
119 unsigned long pstate; / * 33 * /
120 __u8 __reserved[4096]
121 };
122
123 The restorer stub will always have the form:
124
125 d28015a8 movz x8, #0xad
126 d4000001 svc #0x0
127
f2205de0
HZ
128 This is a system call sys_rt_sigreturn.
129
1ae3db19
MS
130 We detect signal frames by snooping the return code for the restorer
131 instruction sequence.
132
133 The handler then needs to recover the saved register set from
134 ucontext.uc_mcontext. */
135
136/* These magic numbers need to reflect the layout of the kernel
137 defined struct rt_sigframe and ucontext. */
138#define AARCH64_SIGCONTEXT_REG_SIZE 8
139#define AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET 128
140#define AARCH64_UCONTEXT_SIGCONTEXT_OFFSET 176
141#define AARCH64_SIGCONTEXT_XO_OFFSET 8
142
143/* Implement the "init" method of struct tramp_frame. */
144
145static void
146aarch64_linux_sigframe_init (const struct tramp_frame *self,
147 struct frame_info *this_frame,
148 struct trad_frame_cache *this_cache,
149 CORE_ADDR func)
150{
151 struct gdbarch *gdbarch = get_frame_arch (this_frame);
152 CORE_ADDR sp = get_frame_register_unsigned (this_frame, AARCH64_SP_REGNUM);
1ae3db19
MS
153 CORE_ADDR sigcontext_addr =
154 sp
155 + AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET
156 + AARCH64_UCONTEXT_SIGCONTEXT_OFFSET;
157 int i;
158
159 for (i = 0; i < 31; i++)
160 {
161 trad_frame_set_reg_addr (this_cache,
162 AARCH64_X0_REGNUM + i,
163 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
164 + i * AARCH64_SIGCONTEXT_REG_SIZE);
165 }
f2205de0
HZ
166 trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM,
167 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
168 + 31 * AARCH64_SIGCONTEXT_REG_SIZE);
169 trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM,
170 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
171 + 32 * AARCH64_SIGCONTEXT_REG_SIZE);
172
173 trad_frame_set_id (this_cache, frame_id_build (sp, func));
1ae3db19
MS
174}
175
176static const struct tramp_frame aarch64_linux_rt_sigframe =
177{
178 SIGTRAMP_FRAME,
179 4,
180 {
181 /* movz x8, 0x8b (S=1,o=10,h=0,i=0x8b,r=8)
182 Soo1 0010 1hhi iiii iiii iiii iiir rrrr */
183 {0xd2801168, -1},
184
185 /* svc 0x0 (o=0, l=1)
186 1101 0100 oooi iiii iiii iiii iii0 00ll */
187 {0xd4000001, -1},
188 {TRAMP_SENTINEL_INSN, -1}
189 },
190 aarch64_linux_sigframe_init
191};
192
193/* Fill GDB's register array with the general-purpose register values
194 in the buffer pointed by GREGS_BUF. */
195
196void
197aarch64_linux_supply_gregset (struct regcache *regcache,
198 const gdb_byte *gregs_buf)
199{
200 int regno;
201
202 for (regno = AARCH64_X0_REGNUM; regno <= AARCH64_CPSR_REGNUM; regno++)
203 regcache_raw_supply (regcache, regno,
204 gregs_buf + X_REGISTER_SIZE
205 * (regno - AARCH64_X0_REGNUM));
206}
207
208/* The "supply_regset" function for the general-purpose register set. */
209
210static void
211supply_gregset_from_core (const struct regset *regset,
212 struct regcache *regcache,
213 int regnum, const void *regbuf, size_t len)
214{
215 aarch64_linux_supply_gregset (regcache, (const gdb_byte *) regbuf);
216}
217
218/* Fill GDB's register array with the floating-point register values
219 in the buffer pointed by FPREGS_BUF. */
220
221void
222aarch64_linux_supply_fpregset (struct regcache *regcache,
223 const gdb_byte *fpregs_buf)
224{
225 int regno;
226
227 for (regno = AARCH64_V0_REGNUM; regno <= AARCH64_V31_REGNUM; regno++)
228 regcache_raw_supply (regcache, regno,
229 fpregs_buf + V_REGISTER_SIZE
230 * (regno - AARCH64_V0_REGNUM));
231
232 regcache_raw_supply (regcache, AARCH64_FPSR_REGNUM,
233 fpregs_buf + V_REGISTER_SIZE * 32);
234 regcache_raw_supply (regcache, AARCH64_FPCR_REGNUM,
235 fpregs_buf + V_REGISTER_SIZE * 32 + 4);
236}
237
238/* The "supply_regset" function for the floating-point register set. */
239
240static void
241supply_fpregset_from_core (const struct regset *regset,
242 struct regcache *regcache,
243 int regnum, const void *regbuf, size_t len)
244{
245 aarch64_linux_supply_fpregset (regcache, (const gdb_byte *) regbuf);
246}
247
248/* Implement the "regset_from_core_section" gdbarch method. */
249
250static const struct regset *
251aarch64_linux_regset_from_core_section (struct gdbarch *gdbarch,
252 const char *sect_name,
253 size_t sect_size)
254{
255 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
256
257 if (strcmp (sect_name, ".reg") == 0
258 && sect_size == AARCH64_LINUX_SIZEOF_GREGSET)
259 {
260 if (tdep->gregset == NULL)
261 tdep->gregset = regset_alloc (gdbarch, supply_gregset_from_core,
262 NULL);
263 return tdep->gregset;
264 }
265
266 if (strcmp (sect_name, ".reg2") == 0
267 && sect_size == AARCH64_LINUX_SIZEOF_FPREGSET)
268 {
269 if (tdep->fpregset == NULL)
270 tdep->fpregset = regset_alloc (gdbarch, supply_fpregset_from_core,
271 NULL);
272 return tdep->fpregset;
273 }
274 return NULL;
275}
276
08248ca9
SDJ
277/* Implementation of `gdbarch_stap_is_single_operand', as defined in
278 gdbarch.h. */
279
280static int
281aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
282{
283 return (*s == '#' || isdigit (*s) /* Literal number. */
284 || *s == '[' /* Register indirection. */
285 || isalpha (*s)); /* Register value. */
286}
287
288/* This routine is used to parse a special token in AArch64's assembly.
289
290 The special tokens parsed by it are:
291
292 - Register displacement (e.g, [fp, #-8])
293
294 It returns one if the special token has been parsed successfully,
295 or zero if the current token is not considered special. */
296
297static int
298aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
299 struct stap_parse_info *p)
300{
301 if (*p->arg == '[')
302 {
303 /* Temporary holder for lookahead. */
304 const char *tmp = p->arg;
305 char *endp;
306 /* Used to save the register name. */
307 const char *start;
308 char *regname;
309 int len;
310 int got_minus = 0;
311 long displacement;
312 struct stoken str;
313
314 ++tmp;
315 start = tmp;
316
317 /* Register name. */
318 while (isalnum (*tmp))
319 ++tmp;
320
321 if (*tmp != ',')
322 return 0;
323
324 len = tmp - start;
325 regname = alloca (len + 2);
326
327 strncpy (regname, start, len);
328 regname[len] = '\0';
329
330 if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
331 error (_("Invalid register name `%s' on expression `%s'."),
332 regname, p->saved_arg);
333
334 ++tmp;
335 tmp = skip_spaces_const (tmp);
336 /* Now we expect a number. It can begin with '#' or simply
337 a digit. */
338 if (*tmp == '#')
339 ++tmp;
340
341 if (*tmp == '-')
342 {
343 ++tmp;
344 got_minus = 1;
345 }
346 else if (*tmp == '+')
347 ++tmp;
348
349 if (!isdigit (*tmp))
350 return 0;
351
352 displacement = strtol (tmp, &endp, 10);
353 tmp = endp;
354
355 /* Skipping last `]'. */
356 if (*tmp++ != ']')
357 return 0;
358
359 /* The displacement. */
410a0ff2
SDJ
360 write_exp_elt_opcode (&p->pstate, OP_LONG);
361 write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
362 write_exp_elt_longcst (&p->pstate, displacement);
363 write_exp_elt_opcode (&p->pstate, OP_LONG);
08248ca9 364 if (got_minus)
410a0ff2 365 write_exp_elt_opcode (&p->pstate, UNOP_NEG);
08248ca9
SDJ
366
367 /* The register name. */
410a0ff2 368 write_exp_elt_opcode (&p->pstate, OP_REGISTER);
08248ca9
SDJ
369 str.ptr = regname;
370 str.length = len;
410a0ff2
SDJ
371 write_exp_string (&p->pstate, str);
372 write_exp_elt_opcode (&p->pstate, OP_REGISTER);
08248ca9 373
410a0ff2 374 write_exp_elt_opcode (&p->pstate, BINOP_ADD);
08248ca9
SDJ
375
376 /* Casting to the expected type. */
410a0ff2
SDJ
377 write_exp_elt_opcode (&p->pstate, UNOP_CAST);
378 write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
379 write_exp_elt_opcode (&p->pstate, UNOP_CAST);
08248ca9 380
410a0ff2 381 write_exp_elt_opcode (&p->pstate, UNOP_IND);
08248ca9
SDJ
382
383 p->arg = tmp;
384 }
385 else
386 return 0;
387
388 return 1;
389}
390
1ae3db19
MS
391static void
392aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
393{
08248ca9
SDJ
394 static const char *const stap_integer_prefixes[] = { "#", "", NULL };
395 static const char *const stap_register_prefixes[] = { "", NULL };
396 static const char *const stap_register_indirection_prefixes[] = { "[",
397 NULL };
398 static const char *const stap_register_indirection_suffixes[] = { "]",
399 NULL };
1ae3db19
MS
400 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
401
402 tdep->lowest_pc = 0x8000;
403
05feb193
WN
404 linux_init_abi (info, gdbarch);
405
1ae3db19
MS
406 set_solib_svr4_fetch_link_map_offsets (gdbarch,
407 svr4_lp64_fetch_link_map_offsets);
408
45e25a36
MS
409 /* Enable TLS support. */
410 set_gdbarch_fetch_tls_load_module_address (gdbarch,
411 svr4_fetch_objfile_link_map);
412
1ae3db19
MS
413 /* Shared library handling. */
414 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
415
416 set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
417 tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe);
418
419 /* Enable longjmp. */
420 tdep->jb_pc = 11;
421
422 set_gdbarch_regset_from_core_section (gdbarch,
423 aarch64_linux_regset_from_core_section);
08248ca9
SDJ
424
425 /* SystemTap related. */
426 set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
427 set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
428 set_gdbarch_stap_register_indirection_prefixes (gdbarch,
429 stap_register_indirection_prefixes);
430 set_gdbarch_stap_register_indirection_suffixes (gdbarch,
431 stap_register_indirection_suffixes);
432 set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand);
433 set_gdbarch_stap_parse_special_token (gdbarch,
434 aarch64_stap_parse_special_token);
1ae3db19
MS
435}
436
437/* Provide a prototype to silence -Wmissing-prototypes. */
438extern initialize_file_ftype _initialize_aarch64_linux_tdep;
439
440void
441_initialize_aarch64_linux_tdep (void)
442{
443 gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
444 aarch64_linux_init_abi);
445}