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