xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/aarch64-linux-tdep.c (revision b83ebeba7f767758d2778bb0f9d7a76534253621)
1 /* Target-dependent code for GNU/Linux AArch64.
2 
3    Copyright (C) 2009-2015 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 #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 
44 /* Signal frame handling.
45 
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       +------------+
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 
118   This is a system call sys_rt_sigreturn.
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 
135 static void
136 aarch64_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 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     }
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));
164 }
165 
166 static 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 
183 /* Register maps.  */
184 
185 static 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   };
193 
194 static 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   };
201 
202 /* Register set definitions.  */
203 
204 const struct regset aarch64_linux_gregset =
205   {
206     aarch64_linux_gregmap,
207     regcache_supply_regset, regcache_collect_regset
208   };
209 
210 const struct regset aarch64_linux_fpregset =
211   {
212     aarch64_linux_fpregmap,
213     regcache_supply_regset, regcache_collect_regset
214   };
215 
216 /* Implement the "regset_from_core_section" gdbarch method.  */
217 
218 static void
219 aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
220 					    iterate_over_regset_sections_cb *cb,
221 					    void *cb_data,
222 					    const struct regcache *regcache)
223 {
224   cb (".reg", AARCH64_LINUX_SIZEOF_GREGSET, &aarch64_linux_gregset,
225       NULL, cb_data);
226   cb (".reg2", AARCH64_LINUX_SIZEOF_FPREGSET, &aarch64_linux_fpregset,
227       NULL, cb_data);
228 }
229 
230 /* Implementation of `gdbarch_stap_is_single_operand', as defined in
231    gdbarch.h.  */
232 
233 static int
234 aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s)
235 {
236   return (*s == '#' || isdigit (*s) /* Literal number.  */
237 	  || *s == '[' /* Register indirection.  */
238 	  || isalpha (*s)); /* Register value.  */
239 }
240 
241 /* This routine is used to parse a special token in AArch64's assembly.
242 
243    The special tokens parsed by it are:
244 
245       - Register displacement (e.g, [fp, #-8])
246 
247    It returns one if the special token has been parsed successfully,
248    or zero if the current token is not considered special.  */
249 
250 static int
251 aarch64_stap_parse_special_token (struct gdbarch *gdbarch,
252 				  struct stap_parse_info *p)
253 {
254   if (*p->arg == '[')
255     {
256       /* Temporary holder for lookahead.  */
257       const char *tmp = p->arg;
258       char *endp;
259       /* Used to save the register name.  */
260       const char *start;
261       char *regname;
262       int len;
263       int got_minus = 0;
264       long displacement;
265       struct stoken str;
266 
267       ++tmp;
268       start = tmp;
269 
270       /* Register name.  */
271       while (isalnum (*tmp))
272 	++tmp;
273 
274       if (*tmp != ',')
275 	return 0;
276 
277       len = tmp - start;
278       regname = alloca (len + 2);
279 
280       strncpy (regname, start, len);
281       regname[len] = '\0';
282 
283       if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1)
284 	error (_("Invalid register name `%s' on expression `%s'."),
285 	       regname, p->saved_arg);
286 
287       ++tmp;
288       tmp = skip_spaces_const (tmp);
289       /* Now we expect a number.  It can begin with '#' or simply
290 	 a digit.  */
291       if (*tmp == '#')
292 	++tmp;
293 
294       if (*tmp == '-')
295 	{
296 	  ++tmp;
297 	  got_minus = 1;
298 	}
299       else if (*tmp == '+')
300 	++tmp;
301 
302       if (!isdigit (*tmp))
303 	return 0;
304 
305       displacement = strtol (tmp, &endp, 10);
306       tmp = endp;
307 
308       /* Skipping last `]'.  */
309       if (*tmp++ != ']')
310 	return 0;
311 
312       /* The displacement.  */
313       write_exp_elt_opcode (&p->pstate, OP_LONG);
314       write_exp_elt_type (&p->pstate, builtin_type (gdbarch)->builtin_long);
315       write_exp_elt_longcst (&p->pstate, displacement);
316       write_exp_elt_opcode (&p->pstate, OP_LONG);
317       if (got_minus)
318 	write_exp_elt_opcode (&p->pstate, UNOP_NEG);
319 
320       /* The register name.  */
321       write_exp_elt_opcode (&p->pstate, OP_REGISTER);
322       str.ptr = regname;
323       str.length = len;
324       write_exp_string (&p->pstate, str);
325       write_exp_elt_opcode (&p->pstate, OP_REGISTER);
326 
327       write_exp_elt_opcode (&p->pstate, BINOP_ADD);
328 
329       /* Casting to the expected type.  */
330       write_exp_elt_opcode (&p->pstate, UNOP_CAST);
331       write_exp_elt_type (&p->pstate, lookup_pointer_type (p->arg_type));
332       write_exp_elt_opcode (&p->pstate, UNOP_CAST);
333 
334       write_exp_elt_opcode (&p->pstate, UNOP_IND);
335 
336       p->arg = tmp;
337     }
338   else
339     return 0;
340 
341   return 1;
342 }
343 
344 static void
345 aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
346 {
347   static const char *const stap_integer_prefixes[] = { "#", "", NULL };
348   static const char *const stap_register_prefixes[] = { "", NULL };
349   static const char *const stap_register_indirection_prefixes[] = { "[",
350 								    NULL };
351   static const char *const stap_register_indirection_suffixes[] = { "]",
352 								    NULL };
353   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
354 
355   tdep->lowest_pc = 0x8000;
356 
357   linux_init_abi (info, gdbarch);
358 
359   set_solib_svr4_fetch_link_map_offsets (gdbarch,
360 					 svr4_lp64_fetch_link_map_offsets);
361 
362   /* Enable TLS support.  */
363   set_gdbarch_fetch_tls_load_module_address (gdbarch,
364                                              svr4_fetch_objfile_link_map);
365 
366   /* Shared library handling.  */
367   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
368 
369   set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
370   tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe);
371 
372   /* Enable longjmp.  */
373   tdep->jb_pc = 11;
374 
375   set_gdbarch_iterate_over_regset_sections
376     (gdbarch, aarch64_linux_iterate_over_regset_sections);
377 
378   /* SystemTap related.  */
379   set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes);
380   set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes);
381   set_gdbarch_stap_register_indirection_prefixes (gdbarch,
382 					    stap_register_indirection_prefixes);
383   set_gdbarch_stap_register_indirection_suffixes (gdbarch,
384 					    stap_register_indirection_suffixes);
385   set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand);
386   set_gdbarch_stap_parse_special_token (gdbarch,
387 					aarch64_stap_parse_special_token);
388 }
389 
390 /* Provide a prototype to silence -Wmissing-prototypes.  */
391 extern initialize_file_ftype _initialize_aarch64_linux_tdep;
392 
393 void
394 _initialize_aarch64_linux_tdep (void)
395 {
396   gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
397 			  aarch64_linux_init_abi);
398 }
399