Move locator code to tui-stack.c
[external/binutils.git] / gdb / amd64-obsd-tdep.c
1 /* Target-dependent code for OpenBSD/amd64.
2
3    Copyright (C) 2003-2019 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 "frame.h"
22 #include "frame-unwind.h"
23 #include "gdbcore.h"
24 #include "symtab.h"
25 #include "objfiles.h"
26 #include "osabi.h"
27 #include "regcache.h"
28 #include "regset.h"
29 #include "target.h"
30 #include "trad-frame.h"
31
32 #include "obsd-tdep.h"
33 #include "amd64-tdep.h"
34 #include "i387-tdep.h"
35 #include "gdbsupport/x86-xstate.h"
36 #include "solib-svr4.h"
37 #include "bsd-uthread.h"
38
39 /* Support for signal handlers.  */
40
41 /* Default page size.  */
42 static const int amd64obsd_page_size = 4096;
43
44 /* Return whether THIS_FRAME corresponds to an OpenBSD sigtramp
45    routine.  */
46
47 static int
48 amd64obsd_sigtramp_p (struct frame_info *this_frame)
49 {
50   CORE_ADDR pc = get_frame_pc (this_frame);
51   CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
52   const gdb_byte osigreturn[] =
53   {
54     0x48, 0xc7, 0xc0,
55     0x67, 0x00, 0x00, 0x00,     /* movq $SYS_sigreturn, %rax */
56     0xcd, 0x80                  /* int $0x80 */
57   };
58   const gdb_byte sigreturn[] =
59   {
60     0x48, 0xc7, 0xc0,
61     0x67, 0x00, 0x00, 0x00,     /* movq $SYS_sigreturn, %rax */
62     0x0f, 0x05                  /* syscall */
63   };
64   size_t buflen = (sizeof sigreturn) + 1;
65   gdb_byte *buf;
66   const char *name;
67
68   /* If the function has a valid symbol name, it isn't a
69      trampoline.  */
70   find_pc_partial_function (pc, &name, NULL, NULL);
71   if (name != NULL)
72     return 0;
73
74   /* If the function lives in a valid section (even without a starting
75      point) it isn't a trampoline.  */
76   if (find_pc_section (pc) != NULL)
77     return 0;
78
79   /* If we can't read the instructions at START_PC, return zero.  */
80   buf = (gdb_byte *) alloca ((sizeof sigreturn) + 1);
81   if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen))
82     return 0;
83
84   /* Check for sigreturn(2).  Depending on how the assembler encoded
85      the `movq %rsp, %rdi' instruction, the code starts at offset 6 or
86      7.  OpenBSD 5.0 and later use the `syscall' instruction.  Older
87      versions use `int $0x80'.  Check for both.  */
88   if (memcmp (buf, sigreturn, sizeof sigreturn)
89       && memcmp (buf + 1, sigreturn, sizeof sigreturn)
90       && memcmp (buf, osigreturn, sizeof osigreturn)
91       && memcmp (buf + 1, osigreturn, sizeof osigreturn))
92     return 0;
93
94   return 1;
95 }
96
97 /* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
98    address of the associated sigcontext structure.  */
99
100 static CORE_ADDR
101 amd64obsd_sigcontext_addr (struct frame_info *this_frame)
102 {
103   CORE_ADDR pc = get_frame_pc (this_frame);
104   ULONGEST offset = (pc & (amd64obsd_page_size - 1));
105
106   /* The %rsp register points at `struct sigcontext' upon entry of a
107      signal trampoline.  The relevant part of the trampoline is
108
109         call    *%rax
110         movq    %rsp, %rdi
111         pushq   %rdi
112         movq    $SYS_sigreturn,%rax
113         int     $0x80
114
115      (see /usr/src/sys/arch/amd64/amd64/locore.S).  The `pushq'
116      instruction clobbers %rsp, but its value is saved in `%rdi'.  */
117
118   if (offset > 5)
119     return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM);
120   else
121     return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
122 }
123 \f
124 /* OpenBSD 3.5 or later.  */
125
126 /* Mapping between the general-purpose registers in `struct reg'
127    format and GDB's register cache layout.  */
128
129 /* From <machine/reg.h>.  */
130 int amd64obsd_r_reg_offset[] =
131 {
132   14 * 8,                       /* %rax */
133   13 * 8,                       /* %rbx */
134   3 * 8,                        /* %rcx */
135   2 * 8,                        /* %rdx */
136   1 * 8,                        /* %rsi */
137   0 * 8,                        /* %rdi */
138   12 * 8,                       /* %rbp */
139   15 * 8,                       /* %rsp */
140   4 * 8,                        /* %r8 ..  */
141   5 * 8,
142   6 * 8,
143   7 * 8,
144   8 * 8,
145   9 * 8,
146   10 * 8,
147   11 * 8,                       /* ... %r15 */
148   16 * 8,                       /* %rip */
149   17 * 8,                       /* %eflags */
150   18 * 8,                       /* %cs */
151   19 * 8,                       /* %ss */
152   20 * 8,                       /* %ds */
153   21 * 8,                       /* %es */
154   22 * 8,                       /* %fs */
155   23 * 8                        /* %gs */
156 };
157
158 /* From <machine/signal.h>.  */
159 static int amd64obsd_sc_reg_offset[] =
160 {
161   14 * 8,                       /* %rax */
162   13 * 8,                       /* %rbx */
163   3 * 8,                        /* %rcx */
164   2 * 8,                        /* %rdx */
165   1 * 8,                        /* %rsi */
166   0 * 8,                        /* %rdi */
167   12 * 8,                       /* %rbp */
168   24 * 8,                       /* %rsp */
169   4 * 8,                        /* %r8 ...  */
170   5 * 8,
171   6 * 8,
172   7 * 8,
173   8 * 8,
174   9 * 8,
175   10 * 8,
176   11 * 8,                       /* ... %r15 */
177   21 * 8,                       /* %rip */
178   23 * 8,                       /* %eflags */
179   22 * 8,                       /* %cs */
180   25 * 8,                       /* %ss */
181   18 * 8,                       /* %ds */
182   17 * 8,                       /* %es */
183   16 * 8,                       /* %fs */
184   15 * 8                        /* %gs */
185 };
186
187 /* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c.  */
188 static int amd64obsd_uthread_reg_offset[] =
189 {
190   19 * 8,                       /* %rax */
191   16 * 8,                       /* %rbx */
192   18 * 8,                       /* %rcx */
193   17 * 8,                       /* %rdx */
194   14 * 8,                       /* %rsi */
195   13 * 8,                       /* %rdi */
196   15 * 8,                       /* %rbp */
197   -1,                           /* %rsp */
198   12 * 8,                       /* %r8 ...  */
199   11 * 8,
200   10 * 8,
201   9 * 8,
202   8 * 8,
203   7 * 8,
204   6 * 8,
205   5 * 8,                        /* ... %r15 */
206   20 * 8,                       /* %rip */
207   4 * 8,                        /* %eflags */
208   21 * 8,                       /* %cs */
209   -1,                           /* %ss */
210   3 * 8,                        /* %ds */
211   2 * 8,                        /* %es */
212   1 * 8,                        /* %fs */
213   0 * 8                         /* %gs */
214 };
215
216 /* Offset within the thread structure where we can find the saved
217    stack pointer (%esp).  */
218 #define AMD64OBSD_UTHREAD_RSP_OFFSET    400
219
220 static void
221 amd64obsd_supply_uthread (struct regcache *regcache,
222                           int regnum, CORE_ADDR addr)
223 {
224   struct gdbarch *gdbarch = regcache->arch ();
225   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
226   CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
227   CORE_ADDR sp = 0;
228   gdb_byte buf[8];
229   int i;
230
231   gdb_assert (regnum >= -1);
232
233   if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
234     {
235       int offset;
236
237       /* Fetch stack pointer from thread structure.  */
238       sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
239
240       /* Adjust the stack pointer such that it looks as if we just
241          returned from _thread_machdep_switch.  */
242       offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
243       store_unsigned_integer (buf, 8, byte_order, sp + offset);
244       regcache->raw_supply (AMD64_RSP_REGNUM, buf);
245     }
246
247   for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
248     {
249       if (amd64obsd_uthread_reg_offset[i] != -1
250           && (regnum == -1 || regnum == i))
251         {
252           /* Fetch stack pointer from thread structure (if we didn't
253              do so already).  */
254           if (sp == 0)
255             sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
256
257           /* Read the saved register from the stack frame.  */
258           read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
259           regcache->raw_supply (i, buf);
260         }
261     }
262 }
263
264 static void
265 amd64obsd_collect_uthread (const struct regcache *regcache,
266                            int regnum, CORE_ADDR addr)
267 {
268   struct gdbarch *gdbarch = regcache->arch ();
269   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
270   CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
271   CORE_ADDR sp = 0;
272   gdb_byte buf[8];
273   int i;
274
275   gdb_assert (regnum >= -1);
276
277   if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
278     {
279       int offset;
280
281       /* Calculate the stack pointer (frame pointer) that will be
282          stored into the thread structure.  */
283       offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
284       regcache->raw_collect (AMD64_RSP_REGNUM, buf);
285       sp = extract_unsigned_integer (buf, 8, byte_order) - offset;
286
287       /* Store the stack pointer.  */
288       write_memory_unsigned_integer (sp_addr, 8, byte_order, sp);
289
290       /* The stack pointer was (potentially) modified.  Make sure we
291          build a proper stack frame.  */
292       regnum = -1;
293     }
294
295   for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
296     {
297       if (amd64obsd_uthread_reg_offset[i] != -1
298           && (regnum == -1 || regnum == i))
299         {
300           /* Fetch stack pointer from thread structure (if we didn't
301              calculate it already).  */
302           if (sp == 0)
303             sp = read_memory_unsigned_integer (sp_addr, 8, byte_order);
304
305           /* Write the register into the stack frame.  */
306           regcache->raw_collect (i, buf);
307           write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
308         }
309     }
310 }
311 /* Kernel debugging support.  */
312
313 /* From <machine/frame.h>.  Easy since `struct trapframe' matches
314    `struct sigcontext'.  */
315 #define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
316
317 static struct trad_frame_cache *
318 amd64obsd_trapframe_cache (struct frame_info *this_frame, void **this_cache)
319 {
320   struct gdbarch *gdbarch = get_frame_arch (this_frame);
321   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
322   struct trad_frame_cache *cache;
323   CORE_ADDR func, sp, addr;
324   ULONGEST cs;
325   const char *name;
326   int i;
327
328   if (*this_cache)
329     return (struct trad_frame_cache *) *this_cache;
330
331   cache = trad_frame_cache_zalloc (this_frame);
332   *this_cache = cache;
333
334   func = get_frame_func (this_frame);
335   sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
336
337   find_pc_partial_function (func, &name, NULL, NULL);
338   if (name && startswith (name, "Xintr"))
339     addr = sp + 8;              /* It's an interrupt frame.  */
340   else
341     addr = sp;
342
343   for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
344     if (amd64obsd_tf_reg_offset[i] != -1)
345       trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
346
347   /* Read %cs from trap frame.  */
348   addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
349   cs = read_memory_unsigned_integer (addr, 8, byte_order);
350   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
351     {
352       /* Trap from user space; terminate backtrace.  */
353       trad_frame_set_id (cache, outer_frame_id);
354     }
355   else
356     {
357       /* Construct the frame ID using the function start.  */
358       trad_frame_set_id (cache, frame_id_build (sp + 16, func));
359     }
360
361   return cache;
362 }
363
364 static void
365 amd64obsd_trapframe_this_id (struct frame_info *this_frame,
366                              void **this_cache, struct frame_id *this_id)
367 {
368   struct trad_frame_cache *cache =
369     amd64obsd_trapframe_cache (this_frame, this_cache);
370   
371   trad_frame_get_id (cache, this_id);
372 }
373
374 static struct value *
375 amd64obsd_trapframe_prev_register (struct frame_info *this_frame,
376                                    void **this_cache, int regnum)
377 {
378   struct trad_frame_cache *cache =
379     amd64obsd_trapframe_cache (this_frame, this_cache);
380
381   return trad_frame_get_register (cache, this_frame, regnum);
382 }
383
384 static int
385 amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
386                              struct frame_info *this_frame,
387                              void **this_prologue_cache)
388 {
389   ULONGEST cs;
390   const char *name;
391
392   /* Check Current Privilege Level and bail out if we're not executing
393      in kernel space.  */
394   cs = get_frame_register_unsigned (this_frame, AMD64_CS_REGNUM);
395   if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
396     return 0;
397
398   find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL);
399   return (name && ((strcmp (name, "calltrap") == 0)
400                    || (strcmp (name, "osyscall1") == 0)
401                    || (strcmp (name, "Xsyscall") == 0)
402                    || (startswith (name, "Xintr"))));
403 }
404
405 static const struct frame_unwind amd64obsd_trapframe_unwind = {
406   /* FIXME: kettenis/20051219: This really is more like an interrupt
407      frame, but SIGTRAMP_FRAME would print <signal handler called>,
408      which really is not what we want here.  */
409   NORMAL_FRAME,
410   default_frame_unwind_stop_reason,
411   amd64obsd_trapframe_this_id,
412   amd64obsd_trapframe_prev_register,
413   NULL,
414   amd64obsd_trapframe_sniffer
415 };
416 \f
417
418 static void
419 amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
420 {
421   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
422
423   amd64_init_abi (info, gdbarch,
424                   amd64_target_description (X86_XSTATE_SSE_MASK, true));
425   obsd_init_abi (info, gdbarch);
426
427   /* Initialize general-purpose register set details.  */
428   tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
429   tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
430   tdep->sizeof_gregset = 24 * 8;
431
432   tdep->jb_pc_offset = 7 * 8;
433
434   tdep->sigtramp_p = amd64obsd_sigtramp_p;
435   tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
436   tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
437   tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
438
439   /* OpenBSD provides a user-level threads implementation.  */
440   bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
441   bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
442
443   /* OpenBSD uses SVR4-style shared libraries.  */
444   set_solib_svr4_fetch_link_map_offsets
445     (gdbarch, svr4_lp64_fetch_link_map_offsets);
446
447   /* Unwind kernel trap frames correctly.  */
448   frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
449 }
450
451 void
452 _initialize_amd64obsd_tdep (void)
453 {
454   /* The OpenBSD/amd64 native dependent code makes this assumption.  */
455   gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
456
457   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
458                           GDB_OSABI_OPENBSD, amd64obsd_init_abi);
459 }