]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/alpha-linux-tdep.c
* configure.ac: Switch license to GPLv3.
[thirdparty/binutils-gdb.git] / gdb / alpha-linux-tdep.c
CommitLineData
3379287a 1/* Target-dependent code for GNU/Linux on Alpha.
6aba47ca 2 Copyright (C) 2002, 2003, 2007 Free Software Foundation, Inc.
3379287a
JT
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 2 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, write to the Free Software
197e01b6
EZ
18 Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA. */
3379287a
JT
20
21#include "defs.h"
5868c862 22#include "frame.h"
d2427a71 23#include "gdb_assert.h"
b02f9d57 24#include "gdb_string.h"
f1a559ae 25#include "osabi.h"
b2756930 26#include "solib-svr4.h"
982e9687 27#include "symtab.h"
b02f9d57
UW
28#include "regset.h"
29#include "regcache.h"
3379287a
JT
30
31#include "alpha-tdep.h"
32
d2427a71
RH
33/* Under GNU/Linux, signal handler invocations can be identified by
34 the designated code sequence that is used to return from a signal
3379287a 35 handler. In particular, the return address of a signal handler
d2427a71
RH
36 points to a sequence that copies $sp to $16, loads $0 with the
37 appropriate syscall number, and finally enters the kernel.
38
39 This is somewhat complicated in that:
40 (1) the expansion of the "mov" assembler macro has changed over
41 time, from "bis src,src,dst" to "bis zero,src,dst",
42 (2) the kernel has changed from using "addq" to "lda" to load the
43 syscall number,
44 (3) there is a "normal" sigreturn and an "rt" sigreturn which
45 has a different stack layout.
46*/
47
48static long
49alpha_linux_sigtramp_offset_1 (CORE_ADDR pc)
3379287a 50{
d2427a71
RH
51 switch (alpha_read_insn (pc))
52 {
53 case 0x47de0410: /* bis $30,$30,$16 */
54 case 0x47fe0410: /* bis $31,$30,$16 */
55 return 0;
3379287a 56
d2427a71
RH
57 case 0x43ecf400: /* addq $31,103,$0 */
58 case 0x201f0067: /* lda $0,103($31) */
59 case 0x201f015f: /* lda $0,351($31) */
60 return 4;
61
62 case 0x00000083: /* call_pal callsys */
63 return 8;
3379287a 64
3379287a
JT
65 default:
66 return -1;
67 }
d2427a71
RH
68}
69
70static LONGEST
71alpha_linux_sigtramp_offset (CORE_ADDR pc)
72{
73 long i, off;
74
75 if (pc & 3)
76 return -1;
77
78 /* Guess where we might be in the sequence. */
79 off = alpha_linux_sigtramp_offset_1 (pc);
80 if (off < 0)
81 return -1;
82
83 /* Verify that the other two insns of the sequence are as we expect. */
3379287a 84 pc -= off;
d2427a71 85 for (i = 0; i < 12; i += 4)
3379287a 86 {
d2427a71
RH
87 if (i == off)
88 continue;
89 if (alpha_linux_sigtramp_offset_1 (pc + i) != i)
90 return -1;
3379287a 91 }
3379287a 92
d2427a71 93 return off;
3379287a
JT
94}
95
6c72f9f9
JT
96static int
97alpha_linux_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
98{
d2427a71 99 return alpha_linux_sigtramp_offset (pc) >= 0;
6c72f9f9
JT
100}
101
5868c862 102static CORE_ADDR
d2427a71 103alpha_linux_sigcontext_addr (struct frame_info *next_frame)
5868c862 104{
d2427a71
RH
105 CORE_ADDR pc;
106 ULONGEST sp;
107 long off;
108
109 pc = frame_pc_unwind (next_frame);
110 frame_unwind_unsigned_register (next_frame, ALPHA_SP_REGNUM, &sp);
111
112 off = alpha_linux_sigtramp_offset (pc);
113 gdb_assert (off >= 0);
114
115 /* __NR_rt_sigreturn has a couple of structures on the stack. This is:
116
117 struct rt_sigframe {
118 struct siginfo info;
119 struct ucontext uc;
120 };
121
122 offsetof (struct rt_sigframe, uc.uc_mcontext);
123 */
124 if (alpha_read_insn (pc - off + 4) == 0x201f015f)
125 return sp + 176;
126
127 /* __NR_sigreturn has the sigcontext structure at the top of the stack. */
128 return sp;
5868c862
JT
129}
130
b02f9d57
UW
131/* Supply register REGNUM from the buffer specified by GREGS and LEN
132 in the general-purpose register set REGSET to register cache
133 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
134
135static void
136alpha_linux_supply_gregset (const struct regset *regset,
137 struct regcache *regcache,
138 int regnum, const void *gregs, size_t len)
139{
140 const gdb_byte *regs = gregs;
141 int i;
142 gdb_assert (len >= 32 * 8);
143
144 for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
145 {
146 if (regnum == i || regnum == -1)
147 regcache_raw_supply (regcache, i, regs + i * 8);
148 }
149
150 if (regnum == ALPHA_PC_REGNUM || regnum == -1)
151 regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
152
153 if (regnum == ALPHA_UNIQUE_REGNUM || regnum == -1)
154 regcache_raw_supply (regcache, ALPHA_UNIQUE_REGNUM,
155 len >= 33 * 8 ? regs + 32 * 8 : NULL);
156}
157
158/* Supply register REGNUM from the buffer specified by FPREGS and LEN
159 in the floating-point register set REGSET to register cache
160 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
161
162static void
163alpha_linux_supply_fpregset (const struct regset *regset,
164 struct regcache *regcache,
165 int regnum, const void *fpregs, size_t len)
166{
167 const gdb_byte *regs = fpregs;
168 int i;
169 gdb_assert (len >= 32 * 8);
170
171 for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
172 {
173 if (regnum == i || regnum == -1)
174 regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
175 }
176
177 if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
6afb1f32 178 regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 31 * 8);
b02f9d57
UW
179}
180
181static struct regset alpha_linux_gregset =
182{
183 NULL,
184 alpha_linux_supply_gregset
185};
186
187static struct regset alpha_linux_fpregset =
188{
189 NULL,
190 alpha_linux_supply_fpregset
191};
192
193/* Return the appropriate register set for the core section identified
194 by SECT_NAME and SECT_SIZE. */
195
196const struct regset *
197alpha_linux_regset_from_core_section (struct gdbarch *gdbarch,
198 const char *sect_name, size_t sect_size)
199{
200 if (strcmp (sect_name, ".reg") == 0 && sect_size >= 32 * 8)
201 return &alpha_linux_gregset;
202
203 if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 32 * 8)
204 return &alpha_linux_fpregset;
205
206 return NULL;
207}
208
3379287a 209static void
baa490c4 210alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
3379287a 211{
d2427a71
RH
212 struct gdbarch_tdep *tdep;
213
f1a559ae 214 /* Hook into the DWARF CFI frame unwinder. */
baa490c4 215 alpha_dwarf2_init_abi (info, gdbarch);
f1a559ae
RH
216
217 /* Hook into the MDEBUG frame unwinder. */
d2427a71 218 alpha_mdebug_init_abi (info, gdbarch);
36a6271d 219
d2427a71 220 tdep = gdbarch_tdep (gdbarch);
36a6271d 221 tdep->dynamic_sigtramp_offset = alpha_linux_sigtramp_offset;
5868c862 222 tdep->sigcontext_addr = alpha_linux_sigcontext_addr;
f2524b93 223 tdep->pc_in_sigtramp = alpha_linux_pc_in_sigtramp;
accc6d1f
JT
224 tdep->jb_pc = 2;
225 tdep->jb_elt_size = 8;
b2756930 226
982e9687
UW
227 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
228
b2756930
KB
229 /* Enable TLS support. */
230 set_gdbarch_fetch_tls_load_module_address (gdbarch,
231 svr4_fetch_objfile_link_map);
b02f9d57
UW
232
233 set_gdbarch_regset_from_core_section
234 (gdbarch, alpha_linux_regset_from_core_section);
3379287a
JT
235}
236
237void
238_initialize_alpha_linux_tdep (void)
239{
05816f70 240 gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_LINUX,
70f80edf 241 alpha_linux_init_abi);
3379287a 242}