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