]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/sparc64-obsd-tdep.c
Automatic Copyright Year update after running gdb/copyright.py
[thirdparty/binutils-gdb.git] / gdb / sparc64-obsd-tdep.c
CommitLineData
1e067c66
MK
1/* Target-dependent code for OpenBSD/sparc64.
2
4a94e368 3 Copyright (C) 2004-2022 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 29#include "trad-frame.h"
d1e93af6 30#include "inferior.h"
1e067c66 31
4807909c 32#include "obsd-tdep.h"
1e067c66 33#include "sparc64-tdep.h"
585e38ed
MK
34#include "solib-svr4.h"
35#include "bsd-uthread.h"
1e067c66 36
26fd9228
MK
37/* Older OpenBSD versions used the traditional NetBSD core file
38 format, even for ports that use ELF. These core files don't use
39 multiple register sets. Instead, the general-purpose and
40 floating-point registers are lumped together in a single section.
41 Unlike on NetBSD, OpenBSD uses a different layout for its
42 general-purpose registers than the layout used for ptrace(2).
43
44 Newer OpenBSD versions use ELF core files. Here the register sets
45 match the ptrace(2) layout. */
1e067c66
MK
46
47/* From <machine/reg.h>. */
b4fd25c9 48const struct sparc_gregmap sparc64obsd_gregmap =
26fd9228
MK
49{
50 0 * 8, /* "tstate" */
51 1 * 8, /* %pc */
52 2 * 8, /* %npc */
53 3 * 8, /* %y */
54 -1, /* %fprs */
55 -1,
56 5 * 8, /* %g1 */
57 20 * 8, /* %l0 */
58 4 /* sizeof (%y) */
59};
60
b4fd25c9 61const struct sparc_gregmap sparc64obsd_core_gregmap =
1e067c66
MK
62{
63 0 * 8, /* "tstate" */
64 1 * 8, /* %pc */
65 2 * 8, /* %npc */
66 3 * 8, /* %y */
67 -1, /* %fprs */
68 -1,
69 7 * 8, /* %g1 */
70 22 * 8, /* %l0 */
71 4 /* sizeof (%y) */
72};
73
74static void
75sparc64obsd_supply_gregset (const struct regset *regset,
76 struct regcache *regcache,
77 int regnum, const void *gregs, size_t len)
78{
26fd9228 79 const void *fpregs = (char *)gregs + 288;
1e067c66 80
26fd9228
MK
81 if (len < 832)
82 {
b4fd25c9 83 sparc64_supply_gregset (&sparc64obsd_gregmap, regcache, regnum, gregs);
26fd9228
MK
84 return;
85 }
86
b4fd25c9
AA
87 sparc64_supply_gregset (&sparc64obsd_core_gregmap, regcache, regnum, gregs);
88 sparc64_supply_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
26fd9228
MK
89}
90
91static void
92sparc64obsd_supply_fpregset (const struct regset *regset,
93 struct regcache *regcache,
94 int regnum, const void *fpregs, size_t len)
95{
b4fd25c9 96 sparc64_supply_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
1e067c66
MK
97}
98\f
99
100/* Signal trampolines. */
101
47b4f830
MK
102/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
103 in virtual memory. The randomness makes it somewhat tricky to
104 detect it, but fortunately we can rely on the fact that the start
105 of the sigtramp routine is page-aligned. We recognize the
106 trampoline by looking for the code that invokes the sigreturn
107 system call. The offset where we can find that code varies from
108 release to release.
109
110 By the way, the mapping mentioned above is read-only, so you cannot
111 place a breakpoint in the signal trampoline. */
112
113/* Default page size. */
1e067c66 114static const int sparc64obsd_page_size = 8192;
47b4f830
MK
115
116/* Offset for sigreturn(2). */
117static const int sparc64obsd_sigreturn_offset[] = {
118 0xf0, /* OpenBSD 3.8 */
119 0xec, /* OpenBSD 3.6 */
120 0xe8, /* OpenBSD 3.2 */
121 -1
122};
1e067c66
MK
123
124static int
2c02bd72 125sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, const char *name)
1e067c66
MK
126{
127 CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
128 unsigned long insn;
dc856692 129 const int *offset;
1e067c66
MK
130
131 if (name)
132 return 0;
133
dc856692 134 for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
24f033e8 135 {
dc856692
MK
136 /* Check for "restore %g0, SYS_sigreturn, %g1". */
137 insn = sparc_fetch_instruction (start_pc + *offset);
138 if (insn != 0x83e82067)
139 continue;
1e067c66 140
dc856692
MK
141 /* Check for "t ST_SYSCALL". */
142 insn = sparc_fetch_instruction (start_pc + *offset + 8);
143 if (insn != 0x91d02000)
144 continue;
145
146 return 1;
5a5effe1 147 }
1e067c66 148
dc856692 149 return 0;
1e067c66
MK
150}
151
152static struct sparc_frame_cache *
94afd7a6 153sparc64obsd_frame_cache (struct frame_info *this_frame, void **this_cache)
1e067c66
MK
154{
155 struct sparc_frame_cache *cache;
156 CORE_ADDR addr;
157
158 if (*this_cache)
19ba03f4 159 return (struct sparc_frame_cache *) *this_cache;
1e067c66 160
94afd7a6 161 cache = sparc_frame_cache (this_frame, this_cache);
1e067c66
MK
162 gdb_assert (cache == *this_cache);
163
164 /* If we couldn't find the frame's function, we're probably dealing
165 with an on-stack signal trampoline. */
166 if (cache->pc == 0)
167 {
94afd7a6 168 cache->pc = get_frame_pc (this_frame);
1e067c66
MK
169 cache->pc &= ~(sparc64obsd_page_size - 1);
170
171 /* Since we couldn't find the frame's function, the cache was
dda83cd7 172 initialized under the assumption that we're frameless. */
369c397b 173 sparc_record_save_insn (cache);
94afd7a6 174 addr = get_frame_register_unsigned (this_frame, SPARC_FP_REGNUM);
5b2d44a0
MK
175 if (addr & 1)
176 addr += BIAS;
1e067c66
MK
177 cache->base = addr;
178 }
179
180 /* We find the appropriate instance of `struct sigcontext' at a
181 fixed offset in the signal frame. */
5b2d44a0 182 addr = cache->base + 128 + 16;
94afd7a6 183 cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, this_frame);
1e067c66
MK
184
185 return cache;
186}
187
188static void
94afd7a6 189sparc64obsd_frame_this_id (struct frame_info *this_frame, void **this_cache,
1e067c66
MK
190 struct frame_id *this_id)
191{
192 struct sparc_frame_cache *cache =
94afd7a6 193 sparc64obsd_frame_cache (this_frame, this_cache);
1e067c66
MK
194
195 (*this_id) = frame_id_build (cache->base, cache->pc);
196}
197
94afd7a6
UW
198static struct value *
199sparc64obsd_frame_prev_register (struct frame_info *this_frame,
200 void **this_cache, int regnum)
1e067c66
MK
201{
202 struct sparc_frame_cache *cache =
94afd7a6 203 sparc64obsd_frame_cache (this_frame, this_cache);
1e067c66 204
94afd7a6 205 return trad_frame_get_prev_register (this_frame, cache->saved_regs, regnum);
1e067c66
MK
206}
207
94afd7a6
UW
208static int
209sparc64obsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
210 struct frame_info *this_frame,
211 void **this_cache)
1e067c66 212{
94afd7a6 213 CORE_ADDR pc = get_frame_pc (this_frame);
2c02bd72 214 const char *name;
1e067c66
MK
215
216 find_pc_partial_function (pc, &name, NULL, NULL);
217 if (sparc64obsd_pc_in_sigtramp (pc, name))
94afd7a6 218 return 1;
1e067c66 219
94afd7a6 220 return 0;
1e067c66 221}
94afd7a6
UW
222
223static const struct frame_unwind sparc64obsd_frame_unwind =
224{
a154d838 225 "sparc64 openbsd sigtramp",
94afd7a6 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)
19ba03f4 244 return (struct sparc_frame_cache *) *this_cache;
6df5070e 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 253
098caef4
LM
254 cache->saved_regs[SPARC64_STATE_REGNUM].set_addr (trapframe_addr);
255 cache->saved_regs[SPARC64_PC_REGNUM].set_addr (trapframe_addr + 8);
256 cache->saved_regs[SPARC64_NPC_REGNUM].set_addr (trapframe_addr + 16);
6df5070e
MK
257
258 for (regnum = SPARC_G0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
098caef4
LM
259 cache->saved_regs[regnum].set_addr (trapframe_addr + 48
260 + (regnum - SPARC_G0_REGNUM) * 8);
6df5070e
MK
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{
a154d838 309 "sparc64 openbsd trap",
94afd7a6 310 NORMAL_FRAME,
8fbca658 311 default_frame_unwind_stop_reason,
94afd7a6
UW
312 sparc64obsd_trapframe_this_id,
313 sparc64obsd_trapframe_prev_register,
314 NULL,
315 sparc64obsd_trapframe_sniffer
316};
6df5070e 317\f
1e067c66 318
585e38ed
MK
319/* Threads support. */
320
321/* Offset wthin the thread structure where we can find %fp and %i7. */
322#define SPARC64OBSD_UTHREAD_FP_OFFSET 232
323#define SPARC64OBSD_UTHREAD_PC_OFFSET 240
324
325static void
326sparc64obsd_supply_uthread (struct regcache *regcache,
327 int regnum, CORE_ADDR addr)
328{
ac7936df 329 struct gdbarch *gdbarch = regcache->arch ();
e17a4113 330 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
585e38ed
MK
331 CORE_ADDR fp, fp_addr = addr + SPARC64OBSD_UTHREAD_FP_OFFSET;
332 gdb_byte buf[8];
333
d1e93af6
SM
334 /* This function calls functions that depend on the global current thread. */
335 gdb_assert (regcache->ptid () == inferior_ptid);
336
585e38ed
MK
337 gdb_assert (regnum >= -1);
338
e17a4113 339 fp = read_memory_unsigned_integer (fp_addr, 8, byte_order);
585e38ed
MK
340 if (regnum == SPARC_SP_REGNUM || regnum == -1)
341 {
e17a4113 342 store_unsigned_integer (buf, 8, byte_order, fp);
73e1c03f 343 regcache->raw_supply (SPARC_SP_REGNUM, buf);
585e38ed
MK
344
345 if (regnum == SPARC_SP_REGNUM)
346 return;
347 }
348
349 if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM
350 || regnum == -1)
351 {
352 CORE_ADDR i7, i7_addr = addr + SPARC64OBSD_UTHREAD_PC_OFFSET;
353
e17a4113 354 i7 = read_memory_unsigned_integer (i7_addr, 8, byte_order);
585e38ed
MK
355 if (regnum == SPARC64_PC_REGNUM || regnum == -1)
356 {
e17a4113 357 store_unsigned_integer (buf, 8, byte_order, i7 + 8);
73e1c03f 358 regcache->raw_supply (SPARC64_PC_REGNUM, buf);
585e38ed
MK
359 }
360 if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
361 {
e17a4113 362 store_unsigned_integer (buf, 8, byte_order, i7 + 12);
73e1c03f 363 regcache->raw_supply (SPARC64_NPC_REGNUM, buf);
585e38ed
MK
364 }
365
366 if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
367 return;
368 }
369
370 sparc_supply_rwindow (regcache, fp, regnum);
371}
372
373static void
374sparc64obsd_collect_uthread(const struct regcache *regcache,
375 int regnum, CORE_ADDR addr)
376{
ac7936df 377 struct gdbarch *gdbarch = regcache->arch ();
e17a4113 378 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
585e38ed
MK
379 CORE_ADDR sp;
380 gdb_byte buf[8];
381
d1e93af6
SM
382 /* This function calls functions that depend on the global current thread. */
383 gdb_assert (regcache->ptid () == inferior_ptid);
384
585e38ed
MK
385 gdb_assert (regnum >= -1);
386
387 if (regnum == SPARC_SP_REGNUM || regnum == -1)
388 {
389 CORE_ADDR fp_addr = addr + SPARC64OBSD_UTHREAD_FP_OFFSET;
390
34a79281 391 regcache->raw_collect (SPARC_SP_REGNUM, buf);
585e38ed
MK
392 write_memory (fp_addr,buf, 8);
393 }
394
395 if (regnum == SPARC64_PC_REGNUM || regnum == -1)
396 {
397 CORE_ADDR i7, i7_addr = addr + SPARC64OBSD_UTHREAD_PC_OFFSET;
398
34a79281 399 regcache->raw_collect (SPARC64_PC_REGNUM, buf);
e17a4113
UW
400 i7 = extract_unsigned_integer (buf, 8, byte_order) - 8;
401 write_memory_unsigned_integer (i7_addr, 8, byte_order, i7);
585e38ed
MK
402
403 if (regnum == SPARC64_PC_REGNUM)
404 return;
405 }
406
34a79281 407 regcache->raw_collect (SPARC_SP_REGNUM, buf);
e17a4113 408 sp = extract_unsigned_integer (buf, 8, byte_order);
585e38ed
MK
409 sparc_collect_rwindow (regcache, sp, regnum);
410}
411\f
412
b13feb94
AA
413static const struct regset sparc64obsd_gregset =
414 {
415 NULL, sparc64obsd_supply_gregset, NULL
416 };
417
418static const struct regset sparc64obsd_fpregset =
419 {
420 NULL, sparc64obsd_supply_fpregset, NULL
421 };
422
1e067c66
MK
423static void
424sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
425{
345bd07c 426 sparc_gdbarch_tdep *tdep = (sparc_gdbarch_tdep *) gdbarch_tdep (gdbarch);
1e067c66 427
b13feb94 428 tdep->gregset = &sparc64obsd_gregset;
26fd9228 429 tdep->sizeof_gregset = 288;
b13feb94 430 tdep->fpregset = &sparc64obsd_fpregset;
26fd9228 431 tdep->sizeof_fpregset = 272;
1e067c66 432
c893be75
MK
433 /* Make sure we can single-step "new" syscalls. */
434 tdep->step_trap = sparcnbsd_step_trap;
435
94afd7a6
UW
436 frame_unwind_append_unwinder (gdbarch, &sparc64obsd_frame_unwind);
437 frame_unwind_append_unwinder (gdbarch, &sparc64obsd_trapframe_unwind);
1e067c66
MK
438
439 sparc64_init_abi (info, gdbarch);
0548b5db 440 obsd_init_abi (info, gdbarch);
1e067c66 441
5b2d44a0 442 /* OpenBSD/sparc64 has SVR4-style shared libraries. */
1e067c66 443 set_solib_svr4_fetch_link_map_offsets
3510d1f2 444 (gdbarch, svr4_lp64_fetch_link_map_offsets);
4807909c 445 set_gdbarch_skip_solib_resolver (gdbarch, obsd_skip_solib_resolver);
585e38ed
MK
446
447 /* OpenBSD provides a user-level threads implementation. */
448 bsd_uthread_set_supply_uthread (gdbarch, sparc64obsd_supply_uthread);
449 bsd_uthread_set_collect_uthread (gdbarch, sparc64obsd_collect_uthread);
1e067c66 450}
1e067c66 451
6c265988 452void _initialize_sparc64obsd_tdep ();
1e067c66 453void
6c265988 454_initialize_sparc64obsd_tdep ()
1e067c66
MK
455{
456 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
1736a7bd 457 GDB_OSABI_OPENBSD, sparc64obsd_init_abi);
1e067c66 458}