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