Enable TLS support in aarch64-linux-tdep.c
[platform/upstream/binutils.git] / gdb / aarch64-linux-tdep.c
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
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 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
165 static 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
185 void
186 aarch64_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
199 static void
200 supply_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
210 void
211 aarch64_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
229 static void
230 supply_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
239 static const struct regset *
240 aarch64_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
266 static void
267 aarch64_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   /* Enable TLS support.  */
277   set_gdbarch_fetch_tls_load_module_address (gdbarch,
278                                              svr4_fetch_objfile_link_map);
279
280   /* Shared library handling.  */
281   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
282
283   set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
284   tramp_frame_prepend_unwinder (gdbarch, &aarch64_linux_rt_sigframe);
285
286   /* Enable longjmp.  */
287   tdep->jb_pc = 11;
288
289   set_gdbarch_regset_from_core_section (gdbarch,
290                                         aarch64_linux_regset_from_core_section);
291 }
292
293 /* Provide a prototype to silence -Wmissing-prototypes.  */
294 extern initialize_file_ftype _initialize_aarch64_linux_tdep;
295
296 void
297 _initialize_aarch64_linux_tdep (void)
298 {
299   gdbarch_register_osabi (bfd_arch_aarch64, 0, GDB_OSABI_LINUX,
300                           aarch64_linux_init_abi);
301 }