configure clean up patch from Steve Ellcey.
[external/binutils.git] / gdb / amd64-linux-tdep.c
1 /* Target-dependent code for GNU/Linux x86-64.
2
3    Copyright 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
4    Contributed by Jiri Smid, SuSE Labs.
5
6    This file is part of GDB.
7
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.
12
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.
17
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., 59 Temple Place - Suite 330,
21    Boston, MA 02111-1307, USA.  */
22
23 #include "defs.h"
24 #include "frame.h"
25 #include "gdbcore.h"
26 #include "regcache.h"
27 #include "osabi.h"
28 #include "symtab.h"
29
30 #include "gdb_string.h"
31
32 #include "amd64-tdep.h"
33 #include "solib-svr4.h"
34
35 /* Mapping between the general-purpose registers in `struct user'
36    format and GDB's register cache layout.  */
37
38 /* From <sys/reg.h>.  */
39 static int amd64_linux_gregset_reg_offset[] =
40 {
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 */
65 };
66 \f
67
68 /* Support for signal handlers.  */
69
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
74
75 static const gdb_byte linux_sigtramp_code[] =
76 {
77   /* mov $__NR_rt_sigreturn, %rax */
78   LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
79   /* syscall */
80   LINUX_SIGTRAMP_INSN1, 0x05
81 };
82
83 #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
84
85 /* If PC is in a sigtramp routine, return the address of the start of
86    the routine.  Otherwise, return 0.  */
87
88 static CORE_ADDR
89 amd64_linux_sigtramp_start (struct frame_info *next_frame)
90 {
91   CORE_ADDR pc = frame_pc_unwind (next_frame);
92   gdb_byte buf[LINUX_SIGTRAMP_LEN];
93
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.  */
100
101   if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
102     return 0;
103
104   if (buf[0] != LINUX_SIGTRAMP_INSN0)
105     {
106       if (buf[0] != LINUX_SIGTRAMP_INSN1)
107         return 0;
108
109       pc -= LINUX_SIGTRAMP_OFFSET1;
110       if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
111         return 0;
112     }
113
114   if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
115     return 0;
116
117   return pc;
118 }
119
120 /* Return whether the frame preceding NEXT_FRAME corresponds to a
121    GNU/Linux sigtramp routine.  */
122
123 static int
124 amd64_linux_sigtramp_p (struct frame_info *next_frame)
125 {
126   CORE_ADDR pc = frame_pc_unwind (next_frame);
127   char *name;
128
129   find_pc_partial_function (pc, &name, NULL, NULL);
130
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);
139
140   return (strcmp ("__restore_rt", name) == 0);
141 }
142
143 /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
144 #define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
145
146 /* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
147    routine, return the address of the associated sigcontext structure.  */
148
149 static CORE_ADDR
150 amd64_linux_sigcontext_addr (struct frame_info *next_frame)
151 {
152   CORE_ADDR sp;
153   gdb_byte buf[8];
154
155   frame_unwind_register (next_frame, SP_REGNUM, buf);
156   sp = extract_unsigned_integer (buf, 8);
157
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;
165 }
166 \f
167
168 /* From <asm/sigcontext.h>.  */
169 static int amd64_linux_sc_reg_offset[] =
170 {
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 */
189
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 */
200 };
201
202 static void
203 amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
204 {
205   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
206
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;
210
211   amd64_init_abi (info, gdbarch);
212
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);
217
218   /* GNU/Linux uses SVR4-style shared libraries.  */
219   set_solib_svr4_fetch_link_map_offsets
220     (gdbarch, svr4_lp64_fetch_link_map_offsets);
221
222   /* Enable TLS support.  */
223   set_gdbarch_fetch_tls_load_module_address (gdbarch,
224                                              svr4_fetch_objfile_link_map);
225 }
226 \f
227
228 /* Provide a prototype to silence -Wmissing-prototypes.  */
229 extern void _initialize_amd64_linux_tdep (void);
230
231 void
232 _initialize_amd64_linux_tdep (void)
233 {
234   gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
235                           GDB_OSABI_LINUX, amd64_linux_init_abi);
236 }