xref: /openbsd-src/gnu/usr.bin/binutils/gdb/amd64-linux-tdep.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* Target-dependent code for GNU/Linux x86-64.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 2001, 2003, 2004 Free Software Foundation, Inc.
4b725ae77Skettenis    Contributed by Jiri Smid, SuSE Labs.
5b725ae77Skettenis 
6b725ae77Skettenis    This file is part of GDB.
7b725ae77Skettenis 
8b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
9b725ae77Skettenis    it under the terms of the GNU General Public License as published by
10b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
11b725ae77Skettenis    (at your option) any later version.
12b725ae77Skettenis 
13b725ae77Skettenis    This program is distributed in the hope that it will be useful,
14b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
15b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16b725ae77Skettenis    GNU General Public License for more details.
17b725ae77Skettenis 
18b725ae77Skettenis    You should have received a copy of the GNU General Public License
19b725ae77Skettenis    along with this program; if not, write to the Free Software
20b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
22b725ae77Skettenis 
23b725ae77Skettenis #include "defs.h"
24*11efff7fSkettenis #include "frame.h"
25b725ae77Skettenis #include "gdbcore.h"
26b725ae77Skettenis #include "regcache.h"
27b725ae77Skettenis #include "osabi.h"
28*11efff7fSkettenis #include "symtab.h"
29b725ae77Skettenis 
30b725ae77Skettenis #include "gdb_string.h"
31b725ae77Skettenis 
32b725ae77Skettenis #include "amd64-tdep.h"
33*11efff7fSkettenis #include "solib-svr4.h"
34b725ae77Skettenis 
35b725ae77Skettenis /* Mapping between the general-purpose registers in `struct user'
36*11efff7fSkettenis    format and GDB's register cache layout.  */
37b725ae77Skettenis 
38*11efff7fSkettenis /* From <sys/reg.h>.  */
39*11efff7fSkettenis static int amd64_linux_gregset_reg_offset[] =
40b725ae77Skettenis {
41*11efff7fSkettenis   10 * 8,			/* %rax */
42*11efff7fSkettenis   5 * 8,			/* %rbx */
43*11efff7fSkettenis   11 * 8,			/* %rcx */
44*11efff7fSkettenis   12 * 8,			/* %rdx */
45*11efff7fSkettenis   13 * 8,			/* %rsi */
46*11efff7fSkettenis   14 * 8,			/* %rdi */
47*11efff7fSkettenis   4 * 8,			/* %rbp */
48*11efff7fSkettenis   19 * 8,			/* %rsp */
49*11efff7fSkettenis   9 * 8,			/* %r8 ... */
50*11efff7fSkettenis   8 * 8,
51*11efff7fSkettenis   7 * 8,
52*11efff7fSkettenis   6 * 8,
53*11efff7fSkettenis   3 * 8,
54*11efff7fSkettenis   2 * 8,
55*11efff7fSkettenis   1 * 8,
56*11efff7fSkettenis   0 * 8,			/* ... %r15 */
57*11efff7fSkettenis   16 * 8,			/* %rip */
58*11efff7fSkettenis   18 * 8,			/* %eflags */
59*11efff7fSkettenis   17 * 8,			/* %cs */
60*11efff7fSkettenis   20 * 8,			/* %ss */
61*11efff7fSkettenis   23 * 8,			/* %ds */
62*11efff7fSkettenis   24 * 8,			/* %es */
63*11efff7fSkettenis   25 * 8,			/* %fs */
64*11efff7fSkettenis   26 * 8			/* %gs */
65b725ae77Skettenis };
66*11efff7fSkettenis 
67b725ae77Skettenis 
68*11efff7fSkettenis /* Support for signal handlers.  */
69b725ae77Skettenis 
70b725ae77Skettenis #define LINUX_SIGTRAMP_INSN0	0x48	/* mov $NNNNNNNN, %rax */
71b725ae77Skettenis #define LINUX_SIGTRAMP_OFFSET0	0
72b725ae77Skettenis #define LINUX_SIGTRAMP_INSN1	0x0f	/* syscall */
73b725ae77Skettenis #define LINUX_SIGTRAMP_OFFSET1	7
74b725ae77Skettenis 
75b725ae77Skettenis static const unsigned char linux_sigtramp_code[] =
76b725ae77Skettenis {
77b725ae77Skettenis   /* mov $__NR_rt_sigreturn, %rax */
78b725ae77Skettenis   LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
79b725ae77Skettenis   /* syscall */
80b725ae77Skettenis   LINUX_SIGTRAMP_INSN1, 0x05
81b725ae77Skettenis };
82b725ae77Skettenis 
83b725ae77Skettenis #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
84b725ae77Skettenis 
85b725ae77Skettenis /* If PC is in a sigtramp routine, return the address of the start of
86b725ae77Skettenis    the routine.  Otherwise, return 0.  */
87b725ae77Skettenis 
88b725ae77Skettenis static CORE_ADDR
amd64_linux_sigtramp_start(struct frame_info * next_frame)89*11efff7fSkettenis amd64_linux_sigtramp_start (struct frame_info *next_frame)
90b725ae77Skettenis {
91*11efff7fSkettenis   CORE_ADDR pc = frame_pc_unwind (next_frame);
92b725ae77Skettenis   unsigned char buf[LINUX_SIGTRAMP_LEN];
93b725ae77Skettenis 
94b725ae77Skettenis   /* We only recognize a signal trampoline if PC is at the start of
95b725ae77Skettenis      one of the two instructions.  We optimize for finding the PC at
96b725ae77Skettenis      the start, as will be the case when the trampoline is not the
97b725ae77Skettenis      first frame on the stack.  We assume that in the case where the
98b725ae77Skettenis      PC is not at the start of the instruction sequence, there will be
99b725ae77Skettenis      a few trailing readable bytes on the stack.  */
100b725ae77Skettenis 
101*11efff7fSkettenis   if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN))
102b725ae77Skettenis     return 0;
103b725ae77Skettenis 
104b725ae77Skettenis   if (buf[0] != LINUX_SIGTRAMP_INSN0)
105b725ae77Skettenis     {
106b725ae77Skettenis       if (buf[0] != LINUX_SIGTRAMP_INSN1)
107b725ae77Skettenis 	return 0;
108b725ae77Skettenis 
109b725ae77Skettenis       pc -= LINUX_SIGTRAMP_OFFSET1;
110b725ae77Skettenis 
111*11efff7fSkettenis       if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN))
112b725ae77Skettenis 	return 0;
113b725ae77Skettenis     }
114b725ae77Skettenis 
115b725ae77Skettenis   if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
116b725ae77Skettenis     return 0;
117b725ae77Skettenis 
118b725ae77Skettenis   return pc;
119b725ae77Skettenis }
120b725ae77Skettenis 
121*11efff7fSkettenis /* Return whether the frame preceding NEXT_FRAME corresponds to a
122*11efff7fSkettenis    GNU/Linux sigtramp routine.  */
123b725ae77Skettenis 
124b725ae77Skettenis static int
amd64_linux_sigtramp_p(struct frame_info * next_frame)125*11efff7fSkettenis amd64_linux_sigtramp_p (struct frame_info *next_frame)
126b725ae77Skettenis {
127*11efff7fSkettenis   CORE_ADDR pc = frame_pc_unwind (next_frame);
128*11efff7fSkettenis   char *name;
129*11efff7fSkettenis 
130*11efff7fSkettenis   find_pc_partial_function (pc, &name, NULL, NULL);
131*11efff7fSkettenis 
132b725ae77Skettenis   /* If we have NAME, we can optimize the search.  The trampoline is
133b725ae77Skettenis      named __restore_rt.  However, it isn't dynamically exported from
134b725ae77Skettenis      the shared C library, so the trampoline may appear to be part of
135b725ae77Skettenis      the preceding function.  This should always be sigaction,
136b725ae77Skettenis      __sigaction, or __libc_sigaction (all aliases to the same
137b725ae77Skettenis      function).  */
138b725ae77Skettenis   if (name == NULL || strstr (name, "sigaction") != NULL)
139*11efff7fSkettenis     return (amd64_linux_sigtramp_start (next_frame) != 0);
140b725ae77Skettenis 
141b725ae77Skettenis   return (strcmp ("__restore_rt", name) == 0);
142b725ae77Skettenis }
143b725ae77Skettenis 
144b725ae77Skettenis /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
145b725ae77Skettenis #define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
146b725ae77Skettenis 
147b725ae77Skettenis /* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
148b725ae77Skettenis    routine, return the address of the associated sigcontext structure.  */
149b725ae77Skettenis 
150b725ae77Skettenis static CORE_ADDR
amd64_linux_sigcontext_addr(struct frame_info * next_frame)151b725ae77Skettenis amd64_linux_sigcontext_addr (struct frame_info *next_frame)
152b725ae77Skettenis {
153b725ae77Skettenis   CORE_ADDR sp;
154b725ae77Skettenis   char buf[8];
155b725ae77Skettenis 
156b725ae77Skettenis   frame_unwind_register (next_frame, SP_REGNUM, buf);
157b725ae77Skettenis   sp = extract_unsigned_integer (buf, 8);
158b725ae77Skettenis 
159b725ae77Skettenis   /* The sigcontext structure is part of the user context.  A pointer
160b725ae77Skettenis      to the user context is passed as the third argument to the signal
161b725ae77Skettenis      handler, i.e. in %rdx.  Unfortunately %rdx isn't preserved across
162b725ae77Skettenis      function calls so we can't use it.  Fortunately the user context
163b725ae77Skettenis      is part of the signal frame and the unwound %rsp directly points
164b725ae77Skettenis      at it.  */
165b725ae77Skettenis   return sp + AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
166b725ae77Skettenis }
167b725ae77Skettenis 
168b725ae77Skettenis 
169b725ae77Skettenis /* From <asm/sigcontext.h>.  */
170b725ae77Skettenis static int amd64_linux_sc_reg_offset[] =
171b725ae77Skettenis {
172b725ae77Skettenis   13 * 8,			/* %rax */
173b725ae77Skettenis   11 * 8,			/* %rbx */
174b725ae77Skettenis   14 * 8,			/* %rcx */
175b725ae77Skettenis   12 * 8,			/* %rdx */
176b725ae77Skettenis   9 * 8,			/* %rsi */
177b725ae77Skettenis   8 * 8,			/* %rdi */
178b725ae77Skettenis   10 * 8,			/* %rbp */
179b725ae77Skettenis   15 * 8,			/* %rsp */
180b725ae77Skettenis   0 * 8,			/* %r8 */
181b725ae77Skettenis   1 * 8,			/* %r9 */
182b725ae77Skettenis   2 * 8,			/* %r10 */
183b725ae77Skettenis   3 * 8,			/* %r11 */
184b725ae77Skettenis   4 * 8,			/* %r12 */
185b725ae77Skettenis   5 * 8,			/* %r13 */
186b725ae77Skettenis   6 * 8,			/* %r14 */
187b725ae77Skettenis   7 * 8,			/* %r15 */
188b725ae77Skettenis   16 * 8,			/* %rip */
189b725ae77Skettenis   17 * 8,			/* %eflags */
190b725ae77Skettenis 
191b725ae77Skettenis   /* FIXME: kettenis/2002030531: The registers %cs, %fs and %gs are
192b725ae77Skettenis      available in `struct sigcontext'.  However, they only occupy two
193b725ae77Skettenis      bytes instead of four, which makes using them here rather
194b725ae77Skettenis      difficult.  Leave them out for now.  */
195b725ae77Skettenis   -1,				/* %cs */
196b725ae77Skettenis   -1,				/* %ss */
197b725ae77Skettenis   -1,				/* %ds */
198b725ae77Skettenis   -1,				/* %es */
199b725ae77Skettenis   -1,				/* %fs */
200b725ae77Skettenis   -1				/* %gs */
201b725ae77Skettenis };
202b725ae77Skettenis 
203b725ae77Skettenis static void
amd64_linux_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)204b725ae77Skettenis amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
205b725ae77Skettenis {
206b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
207*11efff7fSkettenis 
208*11efff7fSkettenis   tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
209*11efff7fSkettenis   tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
210*11efff7fSkettenis   tdep->sizeof_gregset = 27 * 8;
211*11efff7fSkettenis 
212b725ae77Skettenis   amd64_init_abi (info, gdbarch);
213b725ae77Skettenis 
214*11efff7fSkettenis   tdep->sigtramp_p = amd64_linux_sigtramp_p;
215b725ae77Skettenis   tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
216b725ae77Skettenis   tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
217b725ae77Skettenis   tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
218*11efff7fSkettenis 
219*11efff7fSkettenis   /* GNU/Linux uses SVR4-style shared libraries.  */
220*11efff7fSkettenis   set_solib_svr4_fetch_link_map_offsets
221*11efff7fSkettenis     (gdbarch, svr4_lp64_fetch_link_map_offsets);
222b725ae77Skettenis }
223b725ae77Skettenis 
224b725ae77Skettenis 
225b725ae77Skettenis /* Provide a prototype to silence -Wmissing-prototypes.  */
226b725ae77Skettenis extern void _initialize_amd64_linux_tdep (void);
227b725ae77Skettenis 
228b725ae77Skettenis void
_initialize_amd64_linux_tdep(void)229b725ae77Skettenis _initialize_amd64_linux_tdep (void)
230b725ae77Skettenis {
231b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
232b725ae77Skettenis 			  GDB_OSABI_LINUX, amd64_linux_init_abi);
233b725ae77Skettenis }
234