]>
Commit | Line | Data |
---|---|---|
a4b6fc86 AC |
1 | /* Target-dependent code for GNU/Linux running on x86-64, for GDB. |
2 | ||
1bac305b | 3 | Copyright 2001, 2003 Free Software Foundation, Inc. |
a4b6fc86 | 4 | |
53e95fcf JS |
5 | Contributed by Jiri Smid, SuSE Labs. |
6 | ||
7 | This file is part of GDB. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
11 | the Free Software Foundation; either version 2 of the License, or | |
12 | (at your option) any later version. | |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
21 | Foundation, Inc., 59 Temple Place - Suite 330, | |
22 | Boston, MA 02111-1307, USA. */ | |
23 | ||
24 | #include "defs.h" | |
25 | #include "inferior.h" | |
26 | #include "gdbcore.h" | |
27 | #include "regcache.h" | |
84dc46cb | 28 | #include "osabi.h" |
53e95fcf | 29 | |
c4f35dd8 | 30 | #include "gdb_string.h" |
53e95fcf | 31 | |
c4f35dd8 | 32 | #include "x86-64-tdep.h" |
eba29c8c ML |
33 | #include "x86-64-linux-tdep.h" |
34 | ||
35 | /* Register indexes to 'struct user' come from <sys/reg.h>. */ | |
36 | ||
37 | #define USER_R15 0 | |
38 | #define USER_R14 1 | |
39 | #define USER_R13 2 | |
40 | #define USER_R12 3 | |
41 | #define USER_RBP 4 | |
42 | #define USER_RBX 5 | |
43 | #define USER_R11 6 | |
44 | #define USER_R10 7 | |
45 | #define USER_R9 8 | |
46 | #define USER_R8 9 | |
47 | #define USER_RAX 10 | |
48 | #define USER_RCX 11 | |
49 | #define USER_RDX 12 | |
50 | #define USER_RSI 13 | |
51 | #define USER_RDI 14 | |
52 | #define USER_RIP 16 | |
53 | #define USER_CS 17 | |
54 | #define USER_EFLAGS 18 | |
55 | #define USER_RSP 19 | |
56 | #define USER_SS 20 | |
57 | #define USER_DS 23 | |
58 | #define USER_ES 24 | |
59 | #define USER_FS 25 | |
60 | #define USER_GS 26 | |
61 | ||
62 | /* Mapping between the general-purpose registers in `struct user' | |
63 | format and GDB's register array layout. */ | |
64 | ||
65 | static int user_to_gdb_regmap[] = | |
66 | { | |
67 | USER_RAX, USER_RBX, USER_RCX, USER_RDX, | |
68 | USER_RSI, USER_RDI, USER_RBP, USER_RSP, | |
69 | USER_R8, USER_R9, USER_R10, USER_R11, | |
70 | USER_R12, USER_R13, USER_R14, USER_R15, | |
b0f5c6f2 | 71 | USER_RIP, USER_EFLAGS, |
eba29c8c ML |
72 | USER_DS, USER_ES, USER_FS, USER_GS |
73 | }; | |
74 | ||
75 | /* Fill GDB's register array with the general-purpose register values | |
76 | in *GREGSETP. */ | |
77 | ||
78 | void | |
79 | x86_64_linux_supply_gregset (char *regp) | |
80 | { | |
81 | int i; | |
82 | ||
83 | for (i = 0; i < X86_64_NUM_GREGS; i++) | |
84 | supply_register (i, regp + (user_to_gdb_regmap[i] * 8)); | |
85 | } | |
86 | ||
87 | /* Fill register REGNO (if it is a general-purpose register) in | |
88 | *GREGSETPS with the value in GDB's register array. If REGNO is -1, | |
89 | do this for all registers. */ | |
90 | ||
91 | void | |
92 | x86_64_linux_fill_gregset (char *regp, int regno) | |
93 | { | |
94 | int i; | |
95 | ||
96 | for (i = 0; i < X86_64_NUM_GREGS; i++) | |
97 | if (regno == -1 || regno == i) | |
98 | regcache_collect (i, regp + (user_to_gdb_regmap[i] * 8)); | |
99 | } | |
100 | ||
101 | /* The register sets used in GNU/Linux ELF core-dumps are identical to | |
102 | the register sets used by `ptrace'. The corresponding types are | |
103 | `elf_gregset_t' for the general-purpose registers (with | |
104 | `elf_greg_t' the type of a single GP register) and `elf_fpregset_t' | |
105 | for the floating-point registers. */ | |
106 | ||
107 | static void | |
108 | fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, | |
109 | int which, CORE_ADDR ignore) | |
110 | { | |
111 | switch (which) | |
112 | { | |
113 | case 0: /* Integer registers. */ | |
114 | if (core_reg_size != 216) | |
115 | warning ("Wrong size register set in core file."); | |
116 | else | |
117 | x86_64_linux_supply_gregset (core_reg_sect); | |
118 | break; | |
119 | ||
120 | case 2: /* Floating point registers. */ | |
121 | case 3: /* "Extended" floating point registers. This is gdb-speak | |
122 | for SSE/SSE2. */ | |
123 | if (core_reg_size != 512) | |
124 | warning ("Wrong size XMM register set in core file."); | |
125 | else | |
41d041d6 | 126 | x86_64_supply_fxsave (current_regcache, -1, core_reg_sect); |
eba29c8c ML |
127 | break; |
128 | ||
129 | default: | |
130 | /* Don't know what kind of register request this is; just ignore it. */ | |
131 | break; | |
132 | } | |
133 | } | |
134 | ||
135 | static struct core_fns x86_64_core_fns = | |
136 | { | |
137 | bfd_target_elf_flavour, /* core_flavour */ | |
138 | default_check_format, /* check_format */ | |
139 | default_core_sniffer, /* core_sniffer */ | |
140 | fetch_core_registers, /* core_read_registers */ | |
141 | NULL /* next */ | |
142 | }; | |
c4f35dd8 MK |
143 | |
144 | #define LINUX_SIGTRAMP_INSN0 0x48 /* mov $NNNNNNNN, %rax */ | |
145 | #define LINUX_SIGTRAMP_OFFSET0 0 | |
146 | #define LINUX_SIGTRAMP_INSN1 0x0f /* syscall */ | |
147 | #define LINUX_SIGTRAMP_OFFSET1 7 | |
148 | ||
149 | static const unsigned char linux_sigtramp_code[] = | |
150 | { | |
151 | /* mov $__NR_rt_sigreturn, %rax */ | |
baed091b ML |
152 | LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00, |
153 | /* syscall */ | |
154 | LINUX_SIGTRAMP_INSN1, 0x05 | |
53e95fcf JS |
155 | }; |
156 | ||
157 | #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code) | |
158 | ||
159 | /* If PC is in a sigtramp routine, return the address of the start of | |
160 | the routine. Otherwise, return 0. */ | |
161 | ||
162 | static CORE_ADDR | |
163 | x86_64_linux_sigtramp_start (CORE_ADDR pc) | |
164 | { | |
165 | unsigned char buf[LINUX_SIGTRAMP_LEN]; | |
c4f35dd8 MK |
166 | |
167 | /* We only recognize a signal trampoline if PC is at the start of | |
168 | one of the two instructions. We optimize for finding the PC at | |
169 | the start, as will be the case when the trampoline is not the | |
170 | first frame on the stack. We assume that in the case where the | |
171 | PC is not at the start of the instruction sequence, there will be | |
172 | a few trailing readable bytes on the stack. */ | |
173 | ||
53e95fcf JS |
174 | if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0) |
175 | return 0; | |
176 | ||
177 | if (buf[0] != LINUX_SIGTRAMP_INSN0) | |
178 | { | |
179 | if (buf[0] != LINUX_SIGTRAMP_INSN1) | |
180 | return 0; | |
181 | ||
182 | pc -= LINUX_SIGTRAMP_OFFSET1; | |
183 | ||
184 | if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0) | |
185 | return 0; | |
186 | } | |
187 | ||
188 | if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) | |
189 | return 0; | |
190 | ||
191 | return pc; | |
192 | } | |
193 | ||
baed091b ML |
194 | /* Return whether PC is in a GNU/Linux sigtramp routine. */ |
195 | ||
c4f35dd8 MK |
196 | static int |
197 | x86_64_linux_pc_in_sigtramp (CORE_ADDR pc, char *name) | |
baed091b | 198 | { |
c4f35dd8 MK |
199 | /* If we have NAME, we can optimize the search. The trampoline is |
200 | named __restore_rt. However, it isn't dynamically exported from | |
201 | the shared C library, so the trampoline may appear to be part of | |
202 | the preceding function. This should always be sigaction, | |
203 | __sigaction, or __libc_sigaction (all aliases to the same | |
204 | function). */ | |
205 | if (name == NULL || strstr (name, "sigaction") != NULL) | |
206 | return (x86_64_linux_sigtramp_start (pc) != 0); | |
207 | ||
208 | return (strcmp ("__restore_rt", name) == 0); | |
baed091b ML |
209 | } |
210 | ||
c4f35dd8 MK |
211 | /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>. */ |
212 | #define X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40 | |
b64bbf8c | 213 | |
c4f35dd8 MK |
214 | /* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp |
215 | routine, return the address of the associated sigcontext structure. */ | |
baed091b | 216 | |
c4f35dd8 MK |
217 | static CORE_ADDR |
218 | x86_64_linux_sigcontext_addr (struct frame_info *next_frame) | |
baed091b | 219 | { |
c4f35dd8 MK |
220 | CORE_ADDR sp; |
221 | char buf[8]; | |
222 | ||
223 | frame_unwind_register (next_frame, SP_REGNUM, buf); | |
224 | sp = extract_unsigned_integer (buf, 8); | |
225 | ||
226 | /* The sigcontext structure is part of the user context. A pointer | |
227 | to the user context is passed as the third argument to the signal | |
228 | handler, i.e. in %rdx. Unfortunately %rdx isn't preserved across | |
229 | function calls so we can't use it. Fortunately the user context | |
230 | is part of the signal frame and the unwound %rsp directly points | |
231 | at it. */ | |
232 | return sp + X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; | |
baed091b | 233 | } |
2213a65d MK |
234 | \f |
235 | ||
2b5e0749 | 236 | /* From <asm/sigcontext.h>. */ |
4c05fe53 | 237 | static int x86_64_linux_sc_reg_offset[] = |
2b5e0749 MK |
238 | { |
239 | 13 * 8, /* %rax */ | |
240 | 11 * 8, /* %rbx */ | |
241 | 14 * 8, /* %rcx */ | |
242 | 12 * 8, /* %rdx */ | |
243 | 9 * 8, /* %rsi */ | |
244 | 8 * 8, /* %rdi */ | |
245 | 10 * 8, /* %rbp */ | |
246 | 15 * 8, /* %rsp */ | |
247 | 0 * 8, /* %r8 */ | |
248 | 1 * 8, /* %r9 */ | |
249 | 2 * 8, /* %r10 */ | |
250 | 3 * 8, /* %r11 */ | |
251 | 4 * 8, /* %r12 */ | |
252 | 5 * 8, /* %r13 */ | |
253 | 6 * 8, /* %r14 */ | |
254 | 7 * 8, /* %r15 */ | |
255 | 16 * 8, /* %rip */ | |
256 | 17 * 8, /* %eflags */ | |
257 | -1, /* %ds */ | |
258 | -1, /* %es */ | |
259 | ||
260 | /* FIXME: kettenis/2002030531: The registers %fs and %gs are | |
261 | available in `struct sigcontext'. However, they only occupy two | |
262 | bytes instead of four, which makes using them here rather | |
263 | difficult. Leave them out for now. */ | |
264 | -1, /* %fs */ | |
265 | -1 /* %gs */ | |
266 | }; | |
267 | ||
2213a65d MK |
268 | static void |
269 | x86_64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
270 | { | |
c4f35dd8 | 271 | struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); |
2213a65d | 272 | x86_64_init_abi (info, gdbarch); |
c4f35dd8 MK |
273 | |
274 | set_gdbarch_pc_in_sigtramp (gdbarch, x86_64_linux_pc_in_sigtramp); | |
275 | ||
276 | tdep->sigcontext_addr = x86_64_linux_sigcontext_addr; | |
2b5e0749 | 277 | tdep->sc_reg_offset = x86_64_linux_sc_reg_offset; |
4c05fe53 | 278 | tdep->sc_num_regs = ARRAY_SIZE (x86_64_linux_sc_reg_offset); |
2213a65d | 279 | } |
c4f35dd8 | 280 | \f |
2213a65d MK |
281 | |
282 | /* Provide a prototype to silence -Wmissing-prototypes. */ | |
283 | extern void _initialize_x86_64_linux_tdep (void); | |
284 | ||
285 | void | |
286 | _initialize_x86_64_linux_tdep (void) | |
287 | { | |
eba29c8c ML |
288 | add_core_fns (&x86_64_core_fns); |
289 | ||
2213a65d MK |
290 | gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_LINUX, |
291 | x86_64_linux_init_abi); | |
292 | } |