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