]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/sparc64obsd-tdep.c
* breakpoint.c:
[thirdparty/binutils-gdb.git] / gdb / sparc64obsd-tdep.c
1 /* Target-dependent code for OpenBSD/sparc64.
2
3 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
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
19 Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
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"
28 #include "objfiles.h"
29 #include "solib-svr4.h"
30 #include "trad-frame.h"
31
32 #include "gdb_assert.h"
33
34 #include "sparc64-tdep.h"
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>. */
44 const 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
57 static void
58 sparc64obsd_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
64 sparc64_supply_gregset (&sparc64obsd_core_gregset, regcache, regnum, regs);
65 sparc64_supply_fpregset (regcache, regnum, regs + 288);
66 }
67 \f
68
69 /* Signal trampolines. */
70
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. */
83 static const int sparc64obsd_page_size = 8192;
84
85 /* Offset for sigreturn(2). */
86 static const int sparc64obsd_sigreturn_offset[] = {
87 0xf0, /* OpenBSD 3.8 */
88 0xec, /* OpenBSD 3.6 */
89 0xe8, /* OpenBSD 3.2 */
90 -1
91 };
92
93 static int
94 sparc64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
95 {
96 CORE_ADDR start_pc = (pc & ~(sparc64obsd_page_size - 1));
97 unsigned long insn;
98 const int *offset;
99
100 if (name)
101 return 0;
102
103 for (offset = sparc64obsd_sigreturn_offset; *offset != -1; offset++)
104 {
105 /* Check for "restore %g0, SYS_sigreturn, %g1". */
106 insn = sparc_fetch_instruction (start_pc + *offset);
107 if (insn != 0x83e82067)
108 continue;
109
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;
116 }
117
118 return 0;
119 }
120
121 static struct sparc_frame_cache *
122 sparc64obsd_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);
144 if (addr & 1)
145 addr += BIAS;
146 cache->base = addr;
147 }
148
149 /* We find the appropriate instance of `struct sigcontext' at a
150 fixed offset in the signal frame. */
151 addr = cache->base + 128 + 16;
152 cache->saved_regs = sparc64nbsd_sigcontext_saved_regs (addr, next_frame);
153
154 return cache;
155 }
156
157 static void
158 sparc64obsd_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
167 static void
168 sparc64obsd_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,
172 int *realnump, gdb_byte *valuep)
173 {
174 struct sparc_frame_cache *cache =
175 sparc64obsd_frame_cache (next_frame, this_cache);
176
177 trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
178 optimizedp, lvalp, addrp, realnump, valuep);
179 }
180
181 static const struct frame_unwind sparc64obsd_frame_unwind =
182 {
183 SIGTRAMP_FRAME,
184 sparc64obsd_frame_this_id,
185 sparc64obsd_frame_prev_register
186 };
187
188 static const struct frame_unwind *
189 sparc64obsd_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
202 static void
203 sparc64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
204 {
205 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
206
207 tdep->gregset = regset_alloc (gdbarch, sparc64obsd_supply_gregset, NULL);
208 tdep->sizeof_gregset = 832;
209
210 frame_unwind_append_sniffer (gdbarch, sparc64obsd_sigtramp_frame_sniffer);
211
212 sparc64_init_abi (info, gdbarch);
213
214 /* OpenBSD/sparc64 has SVR4-style shared libraries. */
215 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
216 set_solib_svr4_fetch_link_map_offsets
217 (gdbarch, svr4_lp64_fetch_link_map_offsets);
218 }
219 \f
220
221 /* Provide a prototype to silence -Wmissing-prototypes. */
222 void _initialize_sparc64obsd_tdep (void);
223
224 void
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 }