3d13a75d1cf2752533ad64f6f1068325618effbf
[deliverable/binutils-gdb.git] / gdb / alpha-linux-tdep.c
1 /* Target-dependent code for GNU/Linux on Alpha.
2 Copyright (C) 2002-2014 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #include "defs.h"
20 #include "frame.h"
21 #include <string.h>
22 #include "osabi.h"
23 #include "solib-svr4.h"
24 #include "symtab.h"
25 #include "regset.h"
26 #include "regcache.h"
27 #include "linux-tdep.h"
28 #include "alpha-tdep.h"
29
30 /* This enum represents the signals' numbers on the Alpha
31 architecture. It just contains the signal definitions which are
32 different from the generic implementation.
33
34 It is derived from the file <arch/alpha/include/uapi/asm/signal.h>,
35 from the Linux kernel tree. */
36
37 enum
38 {
39 /* SIGABRT is the same as in the generic implementation, but is
40 defined here because SIGIOT depends on it. */
41 ALPHA_LINUX_SIGABRT = 6,
42 ALPHA_LINUX_SIGEMT = 7,
43 ALPHA_LINUX_SIGBUS = 10,
44 ALPHA_LINUX_SIGSYS = 12,
45 ALPHA_LINUX_SIGURG = 16,
46 ALPHA_LINUX_SIGSTOP = 17,
47 ALPHA_LINUX_SIGTSTP = 18,
48 ALPHA_LINUX_SIGCONT = 19,
49 ALPHA_LINUX_SIGCHLD = 20,
50 ALPHA_LINUX_SIGIO = 23,
51 ALPHA_LINUX_SIGINFO = 29,
52 ALPHA_LINUX_SIGUSR1 = 30,
53 ALPHA_LINUX_SIGUSR2 = 31,
54 ALPHA_LINUX_SIGPOLL = ALPHA_LINUX_SIGIO,
55 ALPHA_LINUX_SIGPWR = ALPHA_LINUX_SIGINFO,
56 ALPHA_LINUX_SIGIOT = ALPHA_LINUX_SIGABRT,
57 };
58
59 /* Under GNU/Linux, signal handler invocations can be identified by
60 the designated code sequence that is used to return from a signal
61 handler. In particular, the return address of a signal handler
62 points to a sequence that copies $sp to $16, loads $0 with the
63 appropriate syscall number, and finally enters the kernel.
64
65 This is somewhat complicated in that:
66 (1) the expansion of the "mov" assembler macro has changed over
67 time, from "bis src,src,dst" to "bis zero,src,dst",
68 (2) the kernel has changed from using "addq" to "lda" to load the
69 syscall number,
70 (3) there is a "normal" sigreturn and an "rt" sigreturn which
71 has a different stack layout. */
72
73 static long
74 alpha_linux_sigtramp_offset_1 (struct gdbarch *gdbarch, CORE_ADDR pc)
75 {
76 switch (alpha_read_insn (gdbarch, pc))
77 {
78 case 0x47de0410: /* bis $30,$30,$16 */
79 case 0x47fe0410: /* bis $31,$30,$16 */
80 return 0;
81
82 case 0x43ecf400: /* addq $31,103,$0 */
83 case 0x201f0067: /* lda $0,103($31) */
84 case 0x201f015f: /* lda $0,351($31) */
85 return 4;
86
87 case 0x00000083: /* call_pal callsys */
88 return 8;
89
90 default:
91 return -1;
92 }
93 }
94
95 static LONGEST
96 alpha_linux_sigtramp_offset (struct gdbarch *gdbarch, CORE_ADDR pc)
97 {
98 long i, off;
99
100 if (pc & 3)
101 return -1;
102
103 /* Guess where we might be in the sequence. */
104 off = alpha_linux_sigtramp_offset_1 (gdbarch, pc);
105 if (off < 0)
106 return -1;
107
108 /* Verify that the other two insns of the sequence are as we expect. */
109 pc -= off;
110 for (i = 0; i < 12; i += 4)
111 {
112 if (i == off)
113 continue;
114 if (alpha_linux_sigtramp_offset_1 (gdbarch, pc + i) != i)
115 return -1;
116 }
117
118 return off;
119 }
120
121 static int
122 alpha_linux_pc_in_sigtramp (struct gdbarch *gdbarch,
123 CORE_ADDR pc, const char *func_name)
124 {
125 return alpha_linux_sigtramp_offset (gdbarch, pc) >= 0;
126 }
127
128 static CORE_ADDR
129 alpha_linux_sigcontext_addr (struct frame_info *this_frame)
130 {
131 struct gdbarch *gdbarch = get_frame_arch (this_frame);
132 CORE_ADDR pc;
133 ULONGEST sp;
134 long off;
135
136 pc = get_frame_pc (this_frame);
137 sp = get_frame_register_unsigned (this_frame, ALPHA_SP_REGNUM);
138
139 off = alpha_linux_sigtramp_offset (gdbarch, pc);
140 gdb_assert (off >= 0);
141
142 /* __NR_rt_sigreturn has a couple of structures on the stack. This is:
143
144 struct rt_sigframe {
145 struct siginfo info;
146 struct ucontext uc;
147 };
148
149 offsetof (struct rt_sigframe, uc.uc_mcontext); */
150
151 if (alpha_read_insn (gdbarch, pc - off + 4) == 0x201f015f)
152 return sp + 176;
153
154 /* __NR_sigreturn has the sigcontext structure at the top of the stack. */
155 return sp;
156 }
157
158 /* Supply register REGNUM from the buffer specified by GREGS and LEN
159 in the general-purpose register set REGSET to register cache
160 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
161
162 static void
163 alpha_linux_supply_gregset (const struct regset *regset,
164 struct regcache *regcache,
165 int regnum, const void *gregs, size_t len)
166 {
167 const gdb_byte *regs = gregs;
168 int i;
169 gdb_assert (len >= 32 * 8);
170
171 for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
172 {
173 if (regnum == i || regnum == -1)
174 regcache_raw_supply (regcache, i, regs + i * 8);
175 }
176
177 if (regnum == ALPHA_PC_REGNUM || regnum == -1)
178 regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
179
180 if (regnum == ALPHA_UNIQUE_REGNUM || regnum == -1)
181 regcache_raw_supply (regcache, ALPHA_UNIQUE_REGNUM,
182 len >= 33 * 8 ? regs + 32 * 8 : NULL);
183 }
184
185 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
186 in the floating-point register set REGSET to register cache
187 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
188
189 static void
190 alpha_linux_supply_fpregset (const struct regset *regset,
191 struct regcache *regcache,
192 int regnum, const void *fpregs, size_t len)
193 {
194 const gdb_byte *regs = fpregs;
195 int i;
196 gdb_assert (len >= 32 * 8);
197
198 for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
199 {
200 if (regnum == i || regnum == -1)
201 regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
202 }
203
204 if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
205 regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 31 * 8);
206 }
207
208 static const struct regset alpha_linux_gregset =
209 {
210 NULL,
211 alpha_linux_supply_gregset
212 };
213
214 static const struct regset alpha_linux_fpregset =
215 {
216 NULL,
217 alpha_linux_supply_fpregset
218 };
219
220 /* Return the appropriate register set for the core section identified
221 by SECT_NAME and SECT_SIZE. */
222
223 static const struct regset *
224 alpha_linux_regset_from_core_section (struct gdbarch *gdbarch,
225 const char *sect_name, size_t sect_size)
226 {
227 if (strcmp (sect_name, ".reg") == 0 && sect_size >= 32 * 8)
228 return &alpha_linux_gregset;
229
230 if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 32 * 8)
231 return &alpha_linux_fpregset;
232
233 return NULL;
234 }
235
236 /* Implementation of `gdbarch_gdb_signal_from_target', as defined in
237 gdbarch.h. */
238
239 static enum gdb_signal
240 alpha_linux_gdb_signal_from_target (struct gdbarch *gdbarch,
241 int signal)
242 {
243 switch (signal)
244 {
245 case ALPHA_LINUX_SIGEMT:
246 return GDB_SIGNAL_EMT;
247
248 case ALPHA_LINUX_SIGBUS:
249 return GDB_SIGNAL_BUS;
250
251 case ALPHA_LINUX_SIGSYS:
252 return GDB_SIGNAL_SYS;
253
254 case ALPHA_LINUX_SIGURG:
255 return GDB_SIGNAL_URG;
256
257 case ALPHA_LINUX_SIGSTOP:
258 return GDB_SIGNAL_STOP;
259
260 case ALPHA_LINUX_SIGTSTP:
261 return GDB_SIGNAL_TSTP;
262
263 case ALPHA_LINUX_SIGCONT:
264 return GDB_SIGNAL_CONT;
265
266 case ALPHA_LINUX_SIGCHLD:
267 return GDB_SIGNAL_CHLD;
268
269 /* No way to differentiate between SIGIO and SIGPOLL.
270 Therefore, we just handle the first one. */
271 case ALPHA_LINUX_SIGIO:
272 return GDB_SIGNAL_IO;
273
274 /* No way to differentiate between SIGINFO and SIGPWR.
275 Therefore, we just handle the first one. */
276 case ALPHA_LINUX_SIGINFO:
277 return GDB_SIGNAL_INFO;
278
279 case ALPHA_LINUX_SIGUSR1:
280 return GDB_SIGNAL_USR1;
281
282 case ALPHA_LINUX_SIGUSR2:
283 return GDB_SIGNAL_USR2;
284 }
285
286 return linux_gdb_signal_from_target (gdbarch, signal);
287 }
288
289 /* Implementation of `gdbarch_gdb_signal_to_target', as defined in
290 gdbarch.h. */
291
292 static int
293 alpha_linux_gdb_signal_to_target (struct gdbarch *gdbarch,
294 enum gdb_signal signal)
295 {
296 switch (signal)
297 {
298 case GDB_SIGNAL_EMT:
299 return ALPHA_LINUX_SIGEMT;
300
301 case GDB_SIGNAL_BUS:
302 return ALPHA_LINUX_SIGBUS;
303
304 case GDB_SIGNAL_SYS:
305 return ALPHA_LINUX_SIGSYS;
306
307 case GDB_SIGNAL_URG:
308 return ALPHA_LINUX_SIGURG;
309
310 case GDB_SIGNAL_STOP:
311 return ALPHA_LINUX_SIGSTOP;
312
313 case GDB_SIGNAL_TSTP:
314 return ALPHA_LINUX_SIGTSTP;
315
316 case GDB_SIGNAL_CONT:
317 return ALPHA_LINUX_SIGCONT;
318
319 case GDB_SIGNAL_CHLD:
320 return ALPHA_LINUX_SIGCHLD;
321
322 case GDB_SIGNAL_IO:
323 return ALPHA_LINUX_SIGIO;
324
325 case GDB_SIGNAL_INFO:
326 return ALPHA_LINUX_SIGINFO;
327
328 case GDB_SIGNAL_USR1:
329 return ALPHA_LINUX_SIGUSR1;
330
331 case GDB_SIGNAL_USR2:
332 return ALPHA_LINUX_SIGUSR2;
333
334 case GDB_SIGNAL_POLL:
335 return ALPHA_LINUX_SIGPOLL;
336
337 case GDB_SIGNAL_PWR:
338 return ALPHA_LINUX_SIGPWR;
339 }
340
341 return linux_gdb_signal_to_target (gdbarch, signal);
342 }
343
344 static void
345 alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
346 {
347 struct gdbarch_tdep *tdep;
348
349 linux_init_abi (info, gdbarch);
350
351 /* Hook into the DWARF CFI frame unwinder. */
352 alpha_dwarf2_init_abi (info, gdbarch);
353
354 /* Hook into the MDEBUG frame unwinder. */
355 alpha_mdebug_init_abi (info, gdbarch);
356
357 tdep = gdbarch_tdep (gdbarch);
358 tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset;
359 tdep->sigcontext_addr = alpha_linux_sigcontext_addr;
360 tdep->pc_in_sigtramp = alpha_linux_pc_in_sigtramp;
361 tdep->jb_pc = 2;
362 tdep->jb_elt_size = 8;
363
364 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
365
366 set_solib_svr4_fetch_link_map_offsets
367 (gdbarch, svr4_lp64_fetch_link_map_offsets);
368
369 /* Enable TLS support. */
370 set_gdbarch_fetch_tls_load_module_address (gdbarch,
371 svr4_fetch_objfile_link_map);
372
373 set_gdbarch_regset_from_core_section
374 (gdbarch, alpha_linux_regset_from_core_section);
375
376 set_gdbarch_gdb_signal_from_target (gdbarch,
377 alpha_linux_gdb_signal_from_target);
378 set_gdbarch_gdb_signal_to_target (gdbarch,
379 alpha_linux_gdb_signal_to_target);
380 }
381
382 /* Provide a prototype to silence -Wmissing-prototypes. */
383 extern initialize_file_ftype _initialize_alpha_linux_tdep;
384
385 void
386 _initialize_alpha_linux_tdep (void)
387 {
388 gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
389 alpha_linux_init_abi);
390 }
This page took 0.036383 seconds and 4 git commands to generate.