]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/aarch64-linux-tdep.c
Add multi-arch capable 'fbsd_make_corefile_notes' variant
[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
MS
44/* Signal frame handling.
45
f2205de0
HZ
46 +------------+ ^
47 | saved lr | |
48 +->| saved fp |--+
49 | | |
50 | | |
51 | +------------+
52 | | saved lr |
53 +--| saved fp |
54 ^ | |
55 | | |
56 | +------------+
57 ^ | |
58 | | signal |
59 | | | SIGTRAMP_FRAME (struct rt_sigframe)
60 | | saved regs |
61 +--| saved sp |--> interrupted_sp
62 | | saved pc |--> interrupted_pc
63 | | |
64 | +------------+
65 | | saved lr |--> default_restorer (movz x8, NR_sys_rt_sigreturn; svc 0)
66 +--| saved fp |<- FP
67 | | NORMAL_FRAME
68 | |<- SP
69 +------------+
1ae3db19
MS
70
71 On signal delivery, the kernel will create a signal handler stack
72 frame and setup the return address in LR to point at restorer stub.
73 The signal stack frame is defined by:
74
75 struct rt_sigframe
76 {
77 siginfo_t info;
78 struct ucontext uc;
79 };
80
81 typedef struct
82 {
83 ... 128 bytes
84 } siginfo_t;
85
86 The ucontext has the following form:
87 struct ucontext
88 {
89 unsigned long uc_flags;
90 struct ucontext *uc_link;
91 stack_t uc_stack;
92 sigset_t uc_sigmask;
93 struct sigcontext uc_mcontext;
94 };
95
96 typedef struct sigaltstack
97 {
98 void *ss_sp;
99 int ss_flags;
100 size_t ss_size;
101 } stack_t;
102
103 struct sigcontext
104 {
105 unsigned long fault_address;
106 unsigned long regs[31];
107 unsigned long sp; / * 31 * /
108 unsigned long pc; / * 32 * /
109 unsigned long pstate; / * 33 * /
110 __u8 __reserved[4096]
111 };
112
113 The restorer stub will always have the form:
114
115 d28015a8 movz x8, #0xad
116 d4000001 svc #0x0
117
f2205de0
HZ
118 This is a system call sys_rt_sigreturn.
119
1ae3db19
MS
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);
1ae3db19
MS
143 CORE_ADDR sigcontext_addr =
144 sp
145 + AARCH64_RT_SIGFRAME_UCONTEXT_OFFSET
146 + AARCH64_UCONTEXT_SIGCONTEXT_OFFSET;
147 int i;
148
149 for (i = 0; i < 31; i++)
150 {
151 trad_frame_set_reg_addr (this_cache,
152 AARCH64_X0_REGNUM + i,
153 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
154 + i * AARCH64_SIGCONTEXT_REG_SIZE);
155 }
f2205de0
HZ
156 trad_frame_set_reg_addr (this_cache, AARCH64_SP_REGNUM,
157 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
158 + 31 * AARCH64_SIGCONTEXT_REG_SIZE);
159 trad_frame_set_reg_addr (this_cache, AARCH64_PC_REGNUM,
160 sigcontext_addr + AARCH64_SIGCONTEXT_XO_OFFSET
161 + 32 * AARCH64_SIGCONTEXT_REG_SIZE);
162
163 trad_frame_set_id (this_cache, frame_id_build (sp, func));
1ae3db19
MS
164}
165
166static const struct tramp_frame aarch64_linux_rt_sigframe =
167{
168 SIGTRAMP_FRAME,
169 4,
170 {
171 /* movz x8, 0x8b (S=1,o=10,h=0,i=0x8b,r=8)
172 Soo1 0010 1hhi iiii iiii iiii iiir rrrr */
173 {0xd2801168, -1},
174
175 /* svc 0x0 (o=0, l=1)
176 1101 0100 oooi iiii iiii iiii iii0 00ll */
177 {0xd4000001, -1},
178 {TRAMP_SENTINEL_INSN, -1}
179 },
180 aarch64_linux_sigframe_init
181};
182
d4d793bf 183/* Register maps. */
1ae3db19 184
d4d793bf
AA
185static const struct regcache_map_entry aarch64_linux_gregmap[] =
186 {
187 { 31, AARCH64_X0_REGNUM, 8 }, /* x0 ... x30 */
188 { 1, AARCH64_SP_REGNUM, 8 },
189 { 1, AARCH64_PC_REGNUM, 8 },
190 { 1, AARCH64_CPSR_REGNUM, 8 },
191 { 0 }
192 };
1ae3db19 193
d4d793bf
AA
194static const struct regcache_map_entry aarch64_linux_fpregmap[] =
195 {
196 { 32, AARCH64_V0_REGNUM, 16 }, /* v0 ... v31 */
197 { 1, AARCH64_FPSR_REGNUM, 4 },
198 { 1, AARCH64_FPCR_REGNUM, 4 },
199 { 0 }
200 };
1ae3db19 201
d4d793bf 202/* Register set definitions. */
a069a2bd 203
d4d793bf 204const struct regset aarch64_linux_gregset =
a069a2bd 205 {
d4d793bf
AA
206 aarch64_linux_gregmap,
207 regcache_supply_regset, regcache_collect_regset
a069a2bd
AA
208 };
209
d4d793bf 210const struct regset aarch64_linux_fpregset =
a069a2bd 211 {
d4d793bf
AA
212 aarch64_linux_fpregmap,
213 regcache_supply_regset, regcache_collect_regset
a069a2bd
AA
214 };
215
1ae3db19
MS
216/* Implement the "regset_from_core_section" gdbarch method. */
217
218static const struct regset *
219aarch64_linux_regset_from_core_section (struct gdbarch *gdbarch,
220 const char *sect_name,
221 size_t sect_size)
222{
1ae3db19
MS
223 if (strcmp (sect_name, ".reg") == 0
224 && sect_size == AARCH64_LINUX_SIZEOF_GREGSET)
a069a2bd 225 return &aarch64_linux_gregset;
1ae3db19
MS
226
227 if (strcmp (sect_name, ".reg2") == 0
228 && sect_size == AARCH64_LINUX_SIZEOF_FPREGSET)
a069a2bd
AA
229 return &aarch64_linux_fpregset;
230
1ae3db19
MS
231 return NULL;
232}
233
08248ca9
SDJ
234/* Implementation of `gdbarch_stap_is_single_operand', as defined in
235 gdbarch.h. */
236
237static int
238aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
239{
240 return (*s == '#' || isdigit (*s) /* Literal number. */
241 || *s == '[' /* Register indirection. */
242 || isalpha (*s)); /* Register value. */
243}
244
245/* This routine is used to parse a special token in AArch64's assembly.
246
247 The special tokens parsed by it are:
248
249 - Register displacement (e.g, [fp, #-8])
250
251 It returns one if the special token has been parsed successfully,
252 or zero if the current token is not considered special. */
253
254static int
255aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
256 struct stap_parse_info *p)
257{
258 if (*p->arg == '[')
259 {
260 /* Temporary holder for lookahead. */
261 const char *tmp = p->arg;
262 char *endp;
263 /* Used to save the register name. */
264 const char *start;
265 char *regname;
266 int len;
267 int got_minus = 0;
268 long displacement;
269 struct stoken str;
270
271 ++tmp;
272 start = tmp;
273
274 /* Register name. */
275 while (isalnum (*tmp))
276 ++tmp;
277
278 if (*tmp != ',')
279 return 0;
280
281 len = tmp - start;
282 regname = alloca (len + 2);
283
284 strncpy (regname, start, len);
285 regname[len] = '\0';
286
287 if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
288 error (_("Invalid register name `%s' on expression `%s'."),
289 regname, p->saved_arg);
290
291 ++tmp;
292 tmp = skip_spaces_const (tmp);
293 /* Now we expect a number. It can begin with '#' or simply
294 a digit. */
295 if (*tmp == '#')
296 ++tmp;
297
298 if (*tmp == '-')
299 {
300 ++tmp;
301 got_minus = 1;
302 }
303 else if (*tmp == '+')
304 ++tmp;
305
306 if (!isdigit (*tmp))
307 return 0;
308
309 displacement = strtol (tmp, &endp, 10);
310 tmp = endp;
311
312 /* Skipping last `]'. */
313 if (*tmp++ != ']')
314 return 0;
315
316 /* The displacement. */
410a0ff2
SDJ
317 write_exp_elt_opcode (&p->pstate, OP_LONG);
318 write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
319 write_exp_elt_longcst (&p->pstate, displacement);
320 write_exp_elt_opcode (&p->pstate, OP_LONG);
08248ca9 321 if (got_minus)
410a0ff2 322 write_exp_elt_opcode (&p->pstate, UNOP_NEG);
08248ca9
SDJ
323
324 /* The register name. */
410a0ff2 325 write_exp_elt_opcode (&p->pstate, OP_REGISTER);
08248ca9
SDJ
326 str.ptr = regname;
327 str.length = len;
410a0ff2
SDJ
328 write_exp_string (&p->pstate, str);
329 write_exp_elt_opcode (&p->pstate, OP_REGISTER);
08248ca9 330
410a0ff2 331 write_exp_elt_opcode (&p->pstate, BINOP_ADD);
08248ca9
SDJ
332
333 /* Casting to the expected type. */
410a0ff2
SDJ
334 write_exp_elt_opcode (&p->pstate, UNOP_CAST);
335 write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
336 write_exp_elt_opcode (&p->pstate, UNOP_CAST);
08248ca9 337
410a0ff2 338 write_exp_elt_opcode (&p->pstate, UNOP_IND);
08248ca9
SDJ
339
340 p->arg = tmp;
341 }
342 else
343 return 0;
344
345 return 1;
346}
347
1ae3db19
MS
348static void
349aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
350{
08248ca9
SDJ
351 static const char *const stap_integer_prefixes[] = { "#", "", NULL };
352 static const char *const stap_register_prefixes[] = { "", NULL };
353 static const char *const stap_register_indirection_prefixes[] = { "[",
354 NULL };
355 static const char *const stap_register_indirection_suffixes[] = { "]",
356 NULL };
1ae3db19
MS
357 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
358
359 tdep->lowest_pc = 0x8000;
360
05feb193
WN
361 linux_init_abi (info, gdbarch);
362
1ae3db19
MS
363 set_solib_svr4_fetch_link_map_offsets (gdbarch,
364 svr4_lp64_fetch_link_map_offsets);
365
45e25a36
MS
366 /* Enable TLS support. */
367 set_gdbarch_fetch_tls_load_module_address (gdbarch,
368 svr4_fetch_objfile_link_map);
369
1ae3db19
MS
370 /* Shared library handling. */
371 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
372
373 set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
374 tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe);
375
376 /* Enable longjmp. */
377 tdep->jb_pc = 11;
378
379 set_gdbarch_regset_from_core_section (gdbarch,
380 aarch64_linux_regset_from_core_section);
08248ca9
SDJ
381
382 /* SystemTap related. */
383 set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
384 set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
385 set_gdbarch_stap_register_indirection_prefixes (gdbarch,
386 stap_register_indirection_prefixes);
387 set_gdbarch_stap_register_indirection_suffixes (gdbarch,
388 stap_register_indirection_suffixes);
389 set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand);
390 set_gdbarch_stap_parse_special_token (gdbarch,
391 aarch64_stap_parse_special_token);
1ae3db19
MS
392}
393
394/* Provide a prototype to silence -Wmissing-prototypes. */
395extern initialize_file_ftype _initialize_aarch64_linux_tdep;
396
397void
398_initialize_aarch64_linux_tdep (void)
399{
400 gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
401 aarch64_linux_init_abi);
402}