]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/sparc64obsd-tdep.c
Add support for ELF core files on OpenBSD/sparc64.
[thirdparty/binutils-gdb.git] / gdb / sparc64obsd-tdep.c
CommitLineData
1e067c66
MK
1/* Target-dependent code for OpenBSD/sparc64.
2
ecd75fc8 3 Copyright (C) 2004-2014 Free Software Foundation, Inc.
1e067c66
MK
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
1e067c66
MK
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/>. */
1e067c66
MK
19
20#include "defs.h"
21#include "frame.h"
22#include "frame-unwind.h"
585e38ed 23#include "gdbcore.h"
1e067c66 24#include "osabi.h"
585e38ed 25#include "regcache.h"
1e067c66
MK
26#include "regset.h"
27#include "symtab.h"
3510d1f2 28#include "objfiles.h"
1e067c66
MK
29#include "trad-frame.h"
30
31#include "gdb_assert.h"
32
4807909c 33#include "obsd-tdep.h"
1e067c66 34#include "sparc64-tdep.h"
585e38ed
MK
35#include "solib-svr4.h"
36#include "bsd-uthread.h"
1e067c66 37
26fd9228
MK
38/* Older OpenBSD versions used the traditional NetBSD core file
39 format, even for ports that use ELF. These core files don't use
40 multiple register sets. Instead, the general-purpose and
41 floating-point registers are lumped together in a single section.
42 Unlike on NetBSD, OpenBSD uses a different layout for its
43 general-purpose registers than the layout used for ptrace(2).
44
45 Newer OpenBSD versions use ELF core files. Here the register sets
46 match the ptrace(2) layout. */
1e067c66
MK
47
48/* From <machine/reg.h>. */
26fd9228
MK
49const struct sparc_gregset sparc64obsd_gregset =
50{
51 0 * 8, /* "tstate" */
52 1 * 8, /* %pc */
53 2 * 8, /* %npc */
54 3 * 8, /* %y */
55 -1, /* %fprs */
56 -1,
57 5 * 8, /* %g1 */
58 20 * 8, /* %l0 */
59 4 /* sizeof (%y) */
60};
61
1e067c66
MK
62const struct sparc_gregset sparc64obsd_core_gregset =
63{
64 0 * 8, /* "tstate" */
65 1 * 8, /* %pc */
66 2 * 8, /* %npc */
67 3 * 8, /* %y */
68 -1, /* %fprs */
69 -1,
70 7 * 8, /* %g1 */
71 22 * 8, /* %l0 */
72 4 /* sizeof (%y) */
73};
74
75static void
76sparc64obsd_supply_gregset (const struct regset *regset,
77 struct regcache *regcache,
78 int regnum, const void *gregs, size_t len)
79{
26fd9228 80 const void *fpregs = (char *)gregs + 288;
1e067c66 81
26fd9228
MK
82 if (len < 832)
83 {
84 sparc64_supply_gregset (&sparc64obsd_gregset, regcache, regnum, gregs);
85 return;
86 }
87
88 sparc64_supply_gregset (&sparc64obsd_core_gregset, regcache, regnum, gregs);
89 sparc64_supply_fpregset (&sparc64_bsd_fpregset, regcache, regnum, fpregs);
90}
91
92static void
93sparc64obsd_supply_fpregset (const struct regset *regset,
94 struct regcache *regcache,
95 int regnum, const void *fpregs, size_t len)
96{
97 sparc64_supply_fpregset (&sparc64_bsd_fpregset, regcache, regnum, fpregs);
1e067c66
MK
98}
99\f
100
101/* Signal trampolines. */
102
47b4f830
MK
103/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
104 in virtual memory. The randomness makes it somewhat tricky to
105 detect it, but fortunately we can rely on the fact that the start
106 of the sigtramp routine is page-aligned. We recognize the
107 trampoline by looking for the code that invokes the sigreturn
108 system call. The offset where we can find that code varies from
109 release to release.
110
111 By the way, the mapping mentioned above is read-only, so you cannot
112 place a breakpoint in the signal trampoline. */
113
114/* Default page size. */
1e067c66 115static const int sparc64obsd_page_size = 8192;
47b4f830
MK
116
117/* Offset for sigreturn(2). */
118static const int sparc64obsd_sigreturn_offset[] = {
119 0xf0, /* OpenBSD 3.8 */
120 0xec, /* OpenBSD 3.6 */
121 0xe8, /* OpenBSD 3.2 */
122 -1
123};
1e067c66
MK
124
125static int
2c02bd72 126sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, const char *name)
1e067c66
MK
127{
128 CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
129 unsigned long insn;
dc856692 130 const int *offset;
1e067c66
MK
131
132 if (name)
133 return 0;
134
dc856692 135 for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
24f033e8 136 {
dc856692
MK
137 /* Check for "restore %g0, SYS_sigreturn, %g1". */
138 insn = sparc_fetch_instruction (start_pc + *offset);
139 if (insn != 0x83e82067)
140 continue;
1e067c66 141
dc856692
MK
142 /* Check for "t ST_SYSCALL". */
143 insn = sparc_fetch_instruction (start_pc + *offset + 8);
144 if (insn != 0x91d02000)
145 continue;
146
147 return 1;
5a5effe1 148 }
1e067c66 149
dc856692 150 return 0;
1e067c66
MK
151}
152
153static struct sparc_frame_cache *
94afd7a6 154sparc64obsd_frame_cache (struct frame_info *this_frame, void **this_cache)
1e067c66
MK
155{
156 struct sparc_frame_cache *cache;
157 CORE_ADDR addr;
158
159 if (*this_cache)
160 return *this_cache;
161
94afd7a6 162 cache = sparc_frame_cache (this_frame, this_cache);
1e067c66
MK
163 gdb_assert (cache == *this_cache);
164
165 /* If we couldn't find the frame's function, we're probably dealing
166 with an on-stack signal trampoline. */
167 if (cache->pc == 0)
168 {
94afd7a6 169 cache->pc = get_frame_pc (this_frame);
1e067c66
MK
170 cache->pc &= ~(sparc64obsd_page_size - 1);
171
172 /* Since we couldn't find the frame's function, the cache was
173 initialized under the assumption that we're frameless. */
369c397b 174 sparc_record_save_insn (cache);
94afd7a6 175 addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
5b2d44a0
MK
176 if (addr & 1)
177 addr += BIAS;
1e067c66
MK
178 cache->base = addr;
179 }
180
181 /* We find the appropriate instance of `struct sigcontext' at a
182 fixed offset in the signal frame. */
5b2d44a0 183 addr = cache->base + 128 + 16;
94afd7a6 184 cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, this_frame);
1e067c66
MK
185
186 return cache;
187}
188
189static void
94afd7a6 190sparc64obsd_frame_this_id (struct frame_info *this_frame, void **this_cache,
1e067c66
MK
191 struct frame_id *this_id)
192{
193 struct sparc_frame_cache *cache =
94afd7a6 194 sparc64obsd_frame_cache (this_frame, this_cache);
1e067c66
MK
195
196 (*this_id) = frame_id_build (cache->base, cache->pc);
197}
198
94afd7a6
UW
199static struct value *
200sparc64obsd_frame_prev_register (struct frame_info *this_frame,
201 void **this_cache, int regnum)
1e067c66
MK
202{
203 struct sparc_frame_cache *cache =
94afd7a6 204 sparc64obsd_frame_cache (this_frame, this_cache);
1e067c66 205
94afd7a6 206 return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
1e067c66
MK
207}
208
94afd7a6
UW
209static int
210sparc64obsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
211 struct frame_info *this_frame,
212 void **this_cache)
1e067c66 213{
94afd7a6 214 CORE_ADDR pc = get_frame_pc (this_frame);
2c02bd72 215 const char *name;
1e067c66
MK
216
217 find_pc_partial_function (pc, &name, NULL, NULL);
218 if (sparc64obsd_pc_in_sigtramp (pc, name))
94afd7a6 219 return 1;
1e067c66 220
94afd7a6 221 return 0;
1e067c66 222}
94afd7a6
UW
223
224static const struct frame_unwind sparc64obsd_frame_unwind =
225{
226 SIGTRAMP_FRAME,
8fbca658 227 default_frame_unwind_stop_reason,
94afd7a6
UW
228 sparc64obsd_frame_this_id,
229 sparc64obsd_frame_prev_register,
230 NULL,
231 sparc64obsd_sigtramp_frame_sniffer
232};
1e067c66 233\f
6df5070e
MK
234/* Kernel debugging support. */
235
236static struct sparc_frame_cache *
94afd7a6 237sparc64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
6df5070e
MK
238{
239 struct sparc_frame_cache *cache;
240 CORE_ADDR sp, trapframe_addr;
241 int regnum;
242
243 if (*this_cache)
244 return *this_cache;
245
94afd7a6 246 cache = sparc_frame_cache (this_frame, this_cache);
6df5070e
MK
247 gdb_assert (cache == *this_cache);
248
94afd7a6 249 sp = get_frame_register_unsigned (this_frame, SPARC_SP_REGNUM);
6df5070e
MK
250 trapframe_addr = sp + BIAS + 176;
251
94afd7a6 252 cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
6df5070e
MK
253
254 cache->saved_regs[SPARC64_STATE_REGNUM].addr = trapframe_addr;
255 cache->saved_regs[SPARC64_PC_REGNUM].addr = trapframe_addr + 8;
256 cache->saved_regs[SPARC64_NPC_REGNUM].addr = trapframe_addr + 16;
257
258 for (regnum = SPARC_G0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
259 cache->saved_regs[regnum].addr =
260 trapframe_addr + 48 + (regnum - SPARC_G0_REGNUM) * 8;
261
262 return cache;
263}
264
265static void
94afd7a6 266sparc64obsd_trapframe_this_id (struct frame_info *this_frame,
6df5070e
MK
267 void **this_cache, struct frame_id *this_id)
268{
269 struct sparc_frame_cache *cache =
94afd7a6 270 sparc64obsd_trapframe_cache (this_frame, this_cache);
6df5070e
MK
271
272 (*this_id) = frame_id_build (cache->base, cache->pc);
273}
274
94afd7a6
UW
275static struct value *
276sparc64obsd_trapframe_prev_register (struct frame_info *this_frame,
277 void **this_cache, int regnum)
6df5070e
MK
278{
279 struct sparc_frame_cache *cache =
94afd7a6 280 sparc64obsd_trapframe_cache (this_frame, this_cache);
6df5070e 281
94afd7a6 282 return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
6df5070e
MK
283}
284
94afd7a6
UW
285static int
286sparc64obsd_trapframe_sniffer (const struct frame_unwind *self,
287 struct frame_info *this_frame,
288 void **this_cache)
6df5070e 289{
93d42b30 290 CORE_ADDR pc;
6df5070e 291 ULONGEST pstate;
2c02bd72 292 const char *name;
6df5070e
MK
293
294 /* Check whether we are in privileged mode, and bail out if we're not. */
94afd7a6 295 pstate = get_frame_register_unsigned (this_frame, SPARC64_PSTATE_REGNUM);
6df5070e 296 if ((pstate & SPARC64_PSTATE_PRIV) == 0)
94afd7a6 297 return 0;
6df5070e 298
94afd7a6 299 pc = get_frame_address_in_block (this_frame);
93d42b30 300 find_pc_partial_function (pc, &name, NULL, NULL);
6df5070e 301 if (name && strcmp (name, "Lslowtrap_reenter") == 0)
94afd7a6 302 return 1;
6df5070e 303
94afd7a6 304 return 0;
6df5070e 305}
94afd7a6
UW
306
307static const struct frame_unwind sparc64obsd_trapframe_unwind =
308{
309 NORMAL_FRAME,
8fbca658 310 default_frame_unwind_stop_reason,
94afd7a6
UW
311 sparc64obsd_trapframe_this_id,
312 sparc64obsd_trapframe_prev_register,
313 NULL,
314 sparc64obsd_trapframe_sniffer
315};
6df5070e 316\f
1e067c66 317
585e38ed
MK
318/* Threads support. */
319
320/* Offset wthin the thread structure where we can find %fp and %i7. */
321#define SPARC64OBSD_UTHREAD_FP_OFFSET 232
322#define SPARC64OBSD_UTHREAD_PC_OFFSET 240
323
324static void
325sparc64obsd_supply_uthread (struct regcache *regcache,
326 int regnum, CORE_ADDR addr)
327{
e17a4113
UW
328 struct gdbarch *gdbarch = get_regcache_arch (regcache);
329 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
585e38ed
MK
330 CORE_ADDR fp, fp_addr = addr + SPARC64OBSD_UTHREAD_FP_OFFSET;
331 gdb_byte buf[8];
332
333 gdb_assert (regnum >= -1);
334
e17a4113 335 fp = read_memory_unsigned_integer (fp_addr, 8, byte_order);
585e38ed
MK
336 if (regnum == SPARC_SP_REGNUM || regnum == -1)
337 {
e17a4113 338 store_unsigned_integer (buf, 8, byte_order, fp);
585e38ed
MK
339 regcache_raw_supply (regcache, SPARC_SP_REGNUM, buf);
340
341 if (regnum == SPARC_SP_REGNUM)
342 return;
343 }
344
345 if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM
346 || regnum == -1)
347 {
348 CORE_ADDR i7, i7_addr = addr + SPARC64OBSD_UTHREAD_PC_OFFSET;
349
e17a4113 350 i7 = read_memory_unsigned_integer (i7_addr, 8, byte_order);
585e38ed
MK
351 if (regnum == SPARC64_PC_REGNUM || regnum == -1)
352 {
e17a4113 353 store_unsigned_integer (buf, 8, byte_order, i7 + 8);
585e38ed
MK
354 regcache_raw_supply (regcache, SPARC64_PC_REGNUM, buf);
355 }
356 if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
357 {
e17a4113 358 store_unsigned_integer (buf, 8, byte_order, i7 + 12);
585e38ed
MK
359 regcache_raw_supply (regcache, SPARC64_NPC_REGNUM, buf);
360 }
361
362 if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
363 return;
364 }
365
366 sparc_supply_rwindow (regcache, fp, regnum);
367}
368
369static void
370sparc64obsd_collect_uthread(const struct regcache *regcache,
371 int regnum, CORE_ADDR addr)
372{
e17a4113
UW
373 struct gdbarch *gdbarch = get_regcache_arch (regcache);
374 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
585e38ed
MK
375 CORE_ADDR sp;
376 gdb_byte buf[8];
377
378 gdb_assert (regnum >= -1);
379
380 if (regnum == SPARC_SP_REGNUM || regnum == -1)
381 {
382 CORE_ADDR fp_addr = addr + SPARC64OBSD_UTHREAD_FP_OFFSET;
383
384 regcache_raw_collect (regcache, SPARC_SP_REGNUM, buf);
385 write_memory (fp_addr,buf, 8);
386 }
387
388 if (regnum == SPARC64_PC_REGNUM || regnum == -1)
389 {
390 CORE_ADDR i7, i7_addr = addr + SPARC64OBSD_UTHREAD_PC_OFFSET;
391
392 regcache_raw_collect (regcache, SPARC64_PC_REGNUM, buf);
e17a4113
UW
393 i7 = extract_unsigned_integer (buf, 8, byte_order) - 8;
394 write_memory_unsigned_integer (i7_addr, 8, byte_order, i7);
585e38ed
MK
395
396 if (regnum == SPARC64_PC_REGNUM)
397 return;
398 }
399
400 regcache_raw_collect (regcache, SPARC_SP_REGNUM, buf);
e17a4113 401 sp = extract_unsigned_integer (buf, 8, byte_order);
585e38ed
MK
402 sparc_collect_rwindow (regcache, sp, regnum);
403}
404\f
405
1e067c66
MK
406static void
407sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
408{
409 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
410
9ea75c57 411 tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
26fd9228
MK
412 tdep->sizeof_gregset = 288;
413
414 tdep->fpregset = regset_alloc (gdbarch, sparc64obsd_supply_fpregset, NULL);
415 tdep->sizeof_fpregset = 272;
1e067c66 416
c893be75
MK
417 /* Make sure we can single-step "new" syscalls. */
418 tdep->step_trap = sparcnbsd_step_trap;
419
94afd7a6
UW
420 frame_unwind_append_unwinder (gdbarch, &sparc64obsd_frame_unwind);
421 frame_unwind_append_unwinder (gdbarch, &sparc64obsd_trapframe_unwind);
1e067c66
MK
422
423 sparc64_init_abi (info, gdbarch);
424
5b2d44a0 425 /* OpenBSD/sparc64 has SVR4-style shared libraries. */
1e067c66 426 set_solib_svr4_fetch_link_map_offsets
3510d1f2 427 (gdbarch, svr4_lp64_fetch_link_map_offsets);
4807909c 428 set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
585e38ed
MK
429
430 /* OpenBSD provides a user-level threads implementation. */
431 bsd_uthread_set_supply_uthread (gdbarch, sparc64obsd_supply_uthread);
432 bsd_uthread_set_collect_uthread (gdbarch, sparc64obsd_collect_uthread);
1e067c66 433}
1e067c66 434\f
5b2d44a0 435
1e067c66
MK
436/* Provide a prototype to silence -Wmissing-prototypes. */
437void _initialize_sparc64obsd_tdep (void);
438
439void
440_initialize_sparc64obsd_tdep (void)
441{
442 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
443 GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi);
444}