* sparcobsd-tdep.c: Include "obsd-tdep.h".
[deliverable/binutils-gdb.git] / gdb / sparc64obsd-tdep.c
CommitLineData
1e067c66
MK
1/* Target-dependent code for OpenBSD/sparc64.
2
197e01b6 3 Copyright (C) 2004, 2005 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
9 the Free Software Foundation; either version 2 of the License, or
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
18 along with this program; if not, write to the Free Software
197e01b6
EZ
19 Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
1e067c66
MK
21
22#include "defs.h"
23#include "frame.h"
24#include "frame-unwind.h"
25#include "osabi.h"
26#include "regset.h"
27#include "symtab.h"
3510d1f2 28#include "objfiles.h"
1e067c66
MK
29#include "solib-svr4.h"
30#include "trad-frame.h"
31
32#include "gdb_assert.h"
33
34#include "sparc64-tdep.h"
1e067c66
MK
35
36/* OpenBSD uses the traditional NetBSD core file format, even for
37 ports that use ELF. The core files don't use multiple register
38 sets. Instead, the general-purpose and floating-point registers
39 are lumped together in a single section. Unlike on NetBSD, OpenBSD
40 uses a different layout for its general-purpose registers than the
41 layout used for ptrace(2). */
42
43/* From <machine/reg.h>. */
44const struct sparc_gregset sparc64obsd_core_gregset =
45{
46 0 * 8, /* "tstate" */
47 1 * 8, /* %pc */
48 2 * 8, /* %npc */
49 3 * 8, /* %y */
50 -1, /* %fprs */
51 -1,
52 7 * 8, /* %g1 */
53 22 * 8, /* %l0 */
54 4 /* sizeof (%y) */
55};
56
57static void
58sparc64obsd_supply_gregset (const struct regset *regset,
59 struct regcache *regcache,
60 int regnum, const void *gregs, size_t len)
61{
62 const char *regs = gregs;
63
9ea75c57 64 sparc64_supply_gregset (&sparc64obsd_core_gregset, regcache, regnum, regs);
1e067c66
MK
65 sparc64_supply_fpregset (regcache, regnum, regs + 288);
66}
67\f
68
69/* Signal trampolines. */
70
47b4f830
MK
71/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
72 in virtual memory. The randomness makes it somewhat tricky to
73 detect it, but fortunately we can rely on the fact that the start
74 of the sigtramp routine is page-aligned. We recognize the
75 trampoline by looking for the code that invokes the sigreturn
76 system call. The offset where we can find that code varies from
77 release to release.
78
79 By the way, the mapping mentioned above is read-only, so you cannot
80 place a breakpoint in the signal trampoline. */
81
82/* Default page size. */
1e067c66 83static const int sparc64obsd_page_size = 8192;
47b4f830
MK
84
85/* Offset for sigreturn(2). */
86static const int sparc64obsd_sigreturn_offset[] = {
87 0xf0, /* OpenBSD 3.8 */
88 0xec, /* OpenBSD 3.6 */
89 0xe8, /* OpenBSD 3.2 */
90 -1
91};
1e067c66
MK
92
93static int
94sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
95{
96 CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
97 unsigned long insn;
dc856692 98 const int *offset;
1e067c66
MK
99
100 if (name)
101 return 0;
102
dc856692 103 for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
24f033e8 104 {
dc856692
MK
105 /* Check for "restore %g0, SYS_sigreturn, %g1". */
106 insn = sparc_fetch_instruction (start_pc + *offset);
107 if (insn != 0x83e82067)
108 continue;
1e067c66 109
dc856692
MK
110 /* Check for "t ST_SYSCALL". */
111 insn = sparc_fetch_instruction (start_pc + *offset + 8);
112 if (insn != 0x91d02000)
113 continue;
114
115 return 1;
5a5effe1 116 }
1e067c66 117
dc856692 118 return 0;
1e067c66
MK
119}
120
121static struct sparc_frame_cache *
122sparc64obsd_frame_cache (struct frame_info *next_frame, void **this_cache)
123{
124 struct sparc_frame_cache *cache;
125 CORE_ADDR addr;
126
127 if (*this_cache)
128 return *this_cache;
129
130 cache = sparc_frame_cache (next_frame, this_cache);
131 gdb_assert (cache == *this_cache);
132
133 /* If we couldn't find the frame's function, we're probably dealing
134 with an on-stack signal trampoline. */
135 if (cache->pc == 0)
136 {
137 cache->pc = frame_pc_unwind (next_frame);
138 cache->pc &= ~(sparc64obsd_page_size - 1);
139
140 /* Since we couldn't find the frame's function, the cache was
141 initialized under the assumption that we're frameless. */
142 cache->frameless_p = 0;
143 addr = frame_unwind_register_unsigned (next_frame, SPARC_FP_REGNUM);
5b2d44a0
MK
144 if (addr & 1)
145 addr += BIAS;
1e067c66
MK
146 cache->base = addr;
147 }
148
149 /* We find the appropriate instance of `struct sigcontext' at a
150 fixed offset in the signal frame. */
5b2d44a0 151 addr = cache->base + 128 + 16;
1e067c66
MK
152 cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
153
154 return cache;
155}
156
157static void
158sparc64obsd_frame_this_id (struct frame_info *next_frame, void **this_cache,
159 struct frame_id *this_id)
160{
161 struct sparc_frame_cache *cache =
162 sparc64obsd_frame_cache (next_frame, this_cache);
163
164 (*this_id) = frame_id_build (cache->base, cache->pc);
165}
166
167static void
168sparc64obsd_frame_prev_register (struct frame_info *next_frame,
169 void **this_cache,
170 int regnum, int *optimizedp,
171 enum lval_type *lvalp, CORE_ADDR *addrp,
47ef841b 172 int *realnump, gdb_byte *valuep)
1e067c66
MK
173{
174 struct sparc_frame_cache *cache =
175 sparc64obsd_frame_cache (next_frame, this_cache);
176
1f67027d
AC
177 trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
178 optimizedp, lvalp, addrp, realnump, valuep);
1e067c66
MK
179}
180
181static const struct frame_unwind sparc64obsd_frame_unwind =
182{
183 SIGTRAMP_FRAME,
184 sparc64obsd_frame_this_id,
185 sparc64obsd_frame_prev_register
186};
187
188static const struct frame_unwind *
189sparc64obsd_sigtramp_frame_sniffer (struct frame_info *next_frame)
190{
191 CORE_ADDR pc = frame_pc_unwind (next_frame);
192 char *name;
193
194 find_pc_partial_function (pc, &name, NULL, NULL);
195 if (sparc64obsd_pc_in_sigtramp (pc, name))
196 return &sparc64obsd_frame_unwind;
197
198 return NULL;
199}
200\f
201
202static void
203sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
204{
205 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
206
9ea75c57 207 tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
1e067c66
MK
208 tdep->sizeof_gregset = 832;
209
1e067c66
MK
210 frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
211
212 sparc64_init_abi (info, gdbarch);
213
5b2d44a0 214 /* OpenBSD/sparc64 has SVR4-style shared libraries. */
3510d1f2 215 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
1e067c66 216 set_solib_svr4_fetch_link_map_offsets
3510d1f2 217 (gdbarch, svr4_lp64_fetch_link_map_offsets);
1e067c66 218}
1e067c66 219\f
5b2d44a0 220
1e067c66
MK
221/* Provide a prototype to silence -Wmissing-prototypes. */
222void _initialize_sparc64obsd_tdep (void);
223
224void
225_initialize_sparc64obsd_tdep (void)
226{
227 gdbarch_register_osabi (bfd_arch_sparc, bfd_mach_sparc_v9,
228 GDB_OSABI_OPENBSD_ELF, sparc64obsd_init_abi);
229}
This page took 0.291585 seconds and 4 git commands to generate.