GDB (xrefs)
Loading...
Searching...
No Matches
i386-obsd-tdep.c
Go to the documentation of this file.
1/* Target-dependent code for OpenBSD/i386.
2
3 Copyright (C) 1988-2023 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 3 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, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "arch-utils.h"
22#include "frame.h"
23#include "frame-unwind.h"
24#include "gdbcore.h"
25#include "regcache.h"
26#include "regset.h"
27#include "symtab.h"
28#include "objfiles.h"
29#include "osabi.h"
30#include "target.h"
31#include "trad-frame.h"
32
33#include "obsd-tdep.h"
34#include "i386-tdep.h"
35#include "i387-tdep.h"
36#include "solib-svr4.h"
37#include "bsd-uthread.h"
38
39/* Support for signal handlers. */
40
41/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
42 in virtual memory. The randomness makes it somewhat tricky to
43 detect it, but fortunately we can rely on the fact that the start
44 of the sigtramp routine is page-aligned. We recognize the
45 trampoline by looking for the code that invokes the sigreturn
46 system call. The offset where we can find that code varies from
47 release to release.
48
49 By the way, the mapping mentioned above is read-only, so you cannot
50 place a breakpoint in the signal trampoline. */
51
52/* Default page size. */
53static const int i386obsd_page_size = 4096;
54
55/* Offset for sigreturn(2). */
56static const int i386obsd_sigreturn_offset[] = {
57 0x0a, /* OpenBSD 3.2 */
58 0x14, /* OpenBSD 3.6 */
59 0x3a, /* OpenBSD 3.8 */
60 -1
61};
62
63/* Return whether THIS_FRAME corresponds to an OpenBSD sigtramp
64 routine. */
65
66static int
68{
69 CORE_ADDR pc = get_frame_pc (this_frame);
70 CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
71 /* The call sequence invoking sigreturn(2). */
72 const gdb_byte sigreturn[] =
73 {
74 0xb8,
75 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
76 0xcd, 0x80 /* int $0x80 */
77 };
78 size_t buflen = sizeof sigreturn;
79 const int *offset;
80 gdb_byte *buf;
81 const char *name;
82
83 /* If the function has a valid symbol name, it isn't a
84 trampoline. */
85 find_pc_partial_function (pc, &name, NULL, NULL);
86 if (name != NULL)
87 return 0;
88
89 /* If the function lives in a valid section (even without a starting
90 point) it isn't a trampoline. */
91 if (find_pc_section (pc) != NULL)
92 return 0;
93
94 /* Allocate buffer. */
95 buf = (gdb_byte *) alloca (buflen);
96
97 /* Loop over all offsets. */
98 for (offset = i386obsd_sigreturn_offset; *offset != -1; offset++)
99 {
100 /* If we can't read the instructions, return zero. */
101 if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
102 {buf, buflen}))
103 return 0;
104
105 /* Check for sigreturn(2). */
106 if (memcmp (buf, sigreturn, buflen) == 0)
107 return 1;
108 }
109
110 return 0;
111}
112
113/* Mapping between the general-purpose registers in `struct reg'
114 format and GDB's register cache layout. */
115
116/* From <machine/reg.h>. */
118{
119 0 * 4, /* %eax */
120 1 * 4, /* %ecx */
121 2 * 4, /* %edx */
122 3 * 4, /* %ebx */
123 4 * 4, /* %esp */
124 5 * 4, /* %ebp */
125 6 * 4, /* %esi */
126 7 * 4, /* %edi */
127 8 * 4, /* %eip */
128 9 * 4, /* %eflags */
129 10 * 4, /* %cs */
130 11 * 4, /* %ss */
131 12 * 4, /* %ds */
132 13 * 4, /* %es */
133 14 * 4, /* %fs */
134 15 * 4 /* %gs */
135};
136
137
138
139/* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
140CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
141CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
142
143/* From <machine/signal.h>. */
145{
146 10 * 4, /* %eax */
147 9 * 4, /* %ecx */
148 8 * 4, /* %edx */
149 7 * 4, /* %ebx */
150 14 * 4, /* %esp */
151 6 * 4, /* %ebp */
152 5 * 4, /* %esi */
153 4 * 4, /* %edi */
154 11 * 4, /* %eip */
155 13 * 4, /* %eflags */
156 12 * 4, /* %cs */
157 15 * 4, /* %ss */
158 3 * 4, /* %ds */
159 2 * 4, /* %es */
160 1 * 4, /* %fs */
161 0 * 4 /* %gs */
162};
163
164/* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c. */
166{
167 11 * 4, /* %eax */
168 10 * 4, /* %ecx */
169 9 * 4, /* %edx */
170 8 * 4, /* %ebx */
171 -1, /* %esp */
172 6 * 4, /* %ebp */
173 5 * 4, /* %esi */
174 4 * 4, /* %edi */
175 12 * 4, /* %eip */
176 -1, /* %eflags */
177 13 * 4, /* %cs */
178 -1, /* %ss */
179 3 * 4, /* %ds */
180 2 * 4, /* %es */
181 1 * 4, /* %fs */
182 0 * 4 /* %gs */
183};
184
185/* Offset within the thread structure where we can find the saved
186 stack pointer (%esp). */
187#define I386OBSD_UTHREAD_ESP_OFFSET 176
188
189static void
191 int regnum, CORE_ADDR addr)
192{
193 struct gdbarch *gdbarch = regcache->arch ();
194 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
195 CORE_ADDR sp_addr = addr + I386OBSD_UTHREAD_ESP_OFFSET;
196 CORE_ADDR sp = 0;
197 gdb_byte buf[4];
198 int i;
199
200 gdb_assert (regnum >= -1);
201
202 if (regnum == -1 || regnum == I386_ESP_REGNUM)
203 {
204 int offset;
205
206 /* Fetch stack pointer from thread structure. */
207 sp = read_memory_unsigned_integer (sp_addr, 4, byte_order);
208
209 /* Adjust the stack pointer such that it looks as if we just
210 returned from _thread_machdep_switch. */
212 store_unsigned_integer (buf, 4, byte_order, sp + offset);
214 }
215
216 for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
217 {
218 if (i386obsd_uthread_reg_offset[i] != -1
219 && (regnum == -1 || regnum == i))
220 {
221 /* Fetch stack pointer from thread structure (if we didn't
222 do so already). */
223 if (sp == 0)
224 sp = read_memory_unsigned_integer (sp_addr, 4, byte_order);
225
226 /* Read the saved register from the stack frame. */
228 regcache->raw_supply (i, buf);
229 }
230 }
231}
232
233static void
235 int regnum, CORE_ADDR addr)
236{
237 struct gdbarch *gdbarch = regcache->arch ();
238 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
239 CORE_ADDR sp_addr = addr + I386OBSD_UTHREAD_ESP_OFFSET;
240 CORE_ADDR sp = 0;
241 gdb_byte buf[4];
242 int i;
243
244 gdb_assert (regnum >= -1);
245
246 if (regnum == -1 || regnum == I386_ESP_REGNUM)
247 {
248 int offset;
249
250 /* Calculate the stack pointer (frame pointer) that will be
251 stored into the thread structure. */
254 sp = extract_unsigned_integer (buf, 4, byte_order) - offset;
255
256 /* Store the stack pointer. */
257 write_memory_unsigned_integer (sp_addr, 4, byte_order, sp);
258
259 /* The stack pointer was (potentially) modified. Make sure we
260 build a proper stack frame. */
261 regnum = -1;
262 }
263
264 for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
265 {
266 if (i386obsd_uthread_reg_offset[i] != -1
267 && (regnum == -1 || regnum == i))
268 {
269 /* Fetch stack pointer from thread structure (if we didn't
270 calculate it already). */
271 if (sp == 0)
272 sp = read_memory_unsigned_integer (sp_addr, 4, byte_order);
273
274 /* Write the register into the stack frame. */
275 regcache->raw_collect (i, buf);
277 }
278 }
279}
280
281/* Kernel debugging support. */
282
283/* From <machine/frame.h>. Note that %esp and %ess are only saved in
284 a trap frame when entering the kernel from user space. */
286{
287 10 * 4, /* %eax */
288 9 * 4, /* %ecx */
289 8 * 4, /* %edx */
290 7 * 4, /* %ebx */
291 -1, /* %esp */
292 6 * 4, /* %ebp */
293 5 * 4, /* %esi */
294 4 * 4, /* %edi */
295 13 * 4, /* %eip */
296 15 * 4, /* %eflags */
297 14 * 4, /* %cs */
298 -1, /* %ss */
299 3 * 4, /* %ds */
300 2 * 4, /* %es */
301 0 * 4, /* %fs */
302 1 * 4 /* %gs */
303};
304
305static struct trad_frame_cache *
307{
308 struct gdbarch *gdbarch = get_frame_arch (this_frame);
309 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
310 struct trad_frame_cache *cache;
311 CORE_ADDR func, sp, addr;
312 ULONGEST cs;
313 const char *name;
314 int i;
315
316 if (*this_cache)
317 return (struct trad_frame_cache *) *this_cache;
318
320 *this_cache = cache;
321
324
325 find_pc_partial_function (func, &name, NULL, NULL);
326 if (name && startswith (name, "Xintr"))
327 addr = sp + 8; /* It's an interrupt frame. */
328 else
329 addr = sp;
330
331 for (i = 0; i < ARRAY_SIZE (i386obsd_tf_reg_offset); i++)
332 if (i386obsd_tf_reg_offset[i] != -1)
334
335 /* Read %cs from trap frame. */
337 cs = read_memory_unsigned_integer (addr, 4, byte_order);
338 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
339 {
340 /* Trap from user space; terminate backtrace. */
342 }
343 else
344 {
345 /* Construct the frame ID using the function start. */
346 trad_frame_set_id (cache, frame_id_build (sp + 8, func));
347 }
348
349 return cache;
350}
351
352static void
354 void **this_cache, struct frame_id *this_id)
355{
356 struct trad_frame_cache *cache =
358
359 trad_frame_get_id (cache, this_id);
360}
361
362static struct value *
364 void **this_cache, int regnum)
365{
366 struct trad_frame_cache *cache =
368
370}
371
372static int
375 void **this_prologue_cache)
376{
377 ULONGEST cs;
378 const char *name;
379
380 /* Check Current Privilege Level and bail out if we're not executing
381 in kernel space. */
383 if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
384 return 0;
385
387 return (name && (strcmp (name, "calltrap") == 0
388 || strcmp (name, "syscall1") == 0
389 || startswith (name, "Xintr")
390 || startswith (name, "Xsoft")));
391}
392
394 "i386 openbsd trap",
395 /* FIXME: kettenis/20051219: This really is more like an interrupt
396 frame, but SIGTRAMP_FRAME would print <signal handler called>,
397 which really is not what we want here. */
402 NULL,
404};
405
406
407static void
409{
410 i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
411
412 /* Obviously OpenBSD is BSD-based. */
414 obsd_init_abi (info, gdbarch);
416
417 /* OpenBSD has a different `struct reg'. */
419 tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
420 tdep->sizeof_gregset = 16 * 4;
421
422 /* OpenBSD uses -freg-struct-return by default. */
423 tdep->struct_return = reg_struct_return;
424
425 /* OpenBSD uses a different memory layout. */
429
430 /* OpenBSD has a `struct sigcontext' that's different from the
431 original 4.3 BSD. */
433 tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
434
435 /* OpenBSD provides a user-level threads implementation. */
438
439 /* Unwind kernel trap frames correctly. */
441
442 /* OpenBSD ELF uses SVR4-style shared libraries. */
445}
446
448void
int regnum
const char *const name
@ reg_struct_return
Definition arm-tdep.h:86
bool find_pc_partial_function(CORE_ADDR pc, const char **name, CORE_ADDR *address, CORE_ADDR *endaddr, const struct block **block)
Definition blockframe.c:373
void bsd_uthread_set_collect_uthread(struct gdbarch *gdbarch, void(*collect_uthread)(const struct regcache *, int, CORE_ADDR))
void bsd_uthread_set_supply_uthread(struct gdbarch *gdbarch, void(*supply_uthread)(struct regcache *, int, CORE_ADDR))
Definition bsd-uthread.c:98
gdbarch * arch() const
Definition regcache.c:231
void raw_collect(int regnum, void *buf) const override
Definition regcache.c:1127
void raw_supply(int regnum, const void *buf) override
Definition regcache.c:1062
void write_memory(CORE_ADDR memaddr, const bfd_byte *myaddr, ssize_t len)
Definition corefile.c:347
ULONGEST read_memory_unsigned_integer(CORE_ADDR memaddr, int len, enum bfd_endian byte_order)
Definition corefile.c:306
void write_memory_unsigned_integer(CORE_ADDR addr, int len, enum bfd_endian byte_order, ULONGEST value)
Definition corefile.c:380
void read_memory(CORE_ADDR memaddr, gdb_byte *myaddr, ssize_t len)
Definition corefile.c:238
static void store_unsigned_integer(gdb_byte *addr, int len, enum bfd_endian byte_order, ULONGEST val)
Definition defs.h:515
static ULONGEST extract_unsigned_integer(gdb::array_view< const gdb_byte > buf, enum bfd_endian byte_order)
Definition defs.h:480
const struct frame_id outer_frame_id
Definition frame.c:689
void frame_unwind_prepend_unwinder(struct gdbarch *gdbarch, const struct frame_unwind *unwinder)
enum unwind_stop_reason default_frame_unwind_stop_reason(frame_info_ptr this_frame, void **this_cache)
ULONGEST get_frame_register_unsigned(frame_info_ptr frame, int regnum)
Definition frame.c:1399
CORE_ADDR get_frame_pc(frame_info_ptr frame)
Definition frame.c:2712
struct frame_id frame_id_build(CORE_ADDR stack_addr, CORE_ADDR code_addr)
Definition frame.c:736
struct gdbarch * get_frame_arch(frame_info_ptr this_frame)
Definition frame.c:3027
CORE_ADDR get_frame_func(frame_info_ptr this_frame)
Definition frame.c:1098
bool safe_frame_unwind_memory(frame_info_ptr this_frame, CORE_ADDR addr, gdb::array_view< gdb_byte > buffer)
Definition frame.c:3017
@ NORMAL_FRAME
Definition frame.h:187
enum bfd_endian gdbarch_byte_order(struct gdbarch *gdbarch)
Definition gdbarch.c:1396
void i386bsd_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
int i386obsd_sc_reg_offset[I386_NUM_GREGS]
static void i386obsd_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
CORE_ADDR i386obsd_sigtramp_end_addr
static const int i386obsd_page_size
static void i386obsd_supply_uthread(struct regcache *regcache, int regnum, CORE_ADDR addr)
static const struct frame_unwind i386obsd_trapframe_unwind
static int i386obsd_tf_reg_offset[]
CORE_ADDR i386obsd_sigtramp_start_addr
#define I386OBSD_UTHREAD_ESP_OFFSET
static struct value * i386obsd_trapframe_prev_register(frame_info_ptr this_frame, void **this_cache, int regnum)
static int i386obsd_sigtramp_p(frame_info_ptr this_frame)
static void i386obsd_collect_uthread(const struct regcache *regcache, int regnum, CORE_ADDR addr)
static int i386obsd_r_reg_offset[]
static struct trad_frame_cache * i386obsd_trapframe_cache(frame_info_ptr this_frame, void **this_cache)
static void i386obsd_trapframe_this_id(frame_info_ptr this_frame, void **this_cache, struct frame_id *this_id)
static int i386obsd_uthread_reg_offset[]
void _initialize_i386obsd_tdep()
static const int i386obsd_sigreturn_offset[]
static int i386obsd_trapframe_sniffer(const struct frame_unwind *self, frame_info_ptr this_frame, void **this_prologue_cache)
void i386_elf_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
Definition i386-tdep.c:4530
#define I386_SEL_UPL
Definition i386-tdep.h:394
@ I386_EIP_REGNUM
Definition i386-tdep.h:289
@ I386_CS_REGNUM
Definition i386-tdep.h:291
@ I386_ESP_REGNUM
Definition i386-tdep.h:285
#define I386_SEL_RPL
Definition i386-tdep.h:393
#define I386_NUM_GREGS
Definition i386-tdep.h:344
struct obj_section * find_pc_section(CORE_ADDR pc)
Definition objfiles.c:1128
void obsd_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch)
Definition obsd-tdep.c:294
void gdbarch_register_osabi(enum bfd_architecture arch, unsigned long machine, enum gdb_osabi osabi, void(*init_osabi)(struct gdbarch_info, struct gdbarch *))
Definition osabi.c:146
@ GDB_OSABI_OPENBSD
Definition osabi.h:35
void(* func)(remote_target *remote, char *)
void set_solib_svr4_fetch_link_map_offsets(struct gdbarch *gdbarch, struct link_map_offsets *(*flmo)(void))
struct link_map_offsets * svr4_ilp32_fetch_link_map_offsets(void)
int * gregset_reg_offset
Definition i386-tdep.h:64
int(* sigtramp_p)(frame_info_ptr)
Definition i386-tdep.h:230
CORE_ADDR sigtramp_end
Definition i386-tdep.h:227
CORE_ADDR sigtramp_start
Definition i386-tdep.h:226
size_t sizeof_gregset
Definition i386-tdep.h:66
struct frame_id this_id
Definition trad-frame.c:35
frame_info_ptr this_frame
Definition trad-frame.c:32
Definition value.h:130
struct trad_frame_cache * trad_frame_cache_zalloc(frame_info_ptr this_frame)
Definition trad-frame.c:39
void trad_frame_set_reg_addr(struct trad_frame_cache *this_trad_cache, int regnum, CORE_ADDR addr)
Definition trad-frame.c:110
void trad_frame_get_id(struct trad_frame_cache *this_trad_cache, struct frame_id *this_id)
Definition trad-frame.c:227
void trad_frame_set_id(struct trad_frame_cache *this_trad_cache, struct frame_id this_id)
Definition trad-frame.c:220
struct value * trad_frame_get_register(struct trad_frame_cache *this_trad_cache, frame_info_ptr this_frame, int regnum)
Definition trad-frame.c:211