1 /* Target-dependent code for GNU/Linux x86-64. 2 3 Copyright 2001, 2003, 2004 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 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 unsigned char 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 unsigned char 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, LINUX_SIGTRAMP_LEN)) 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 111 if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN)) 112 return 0; 113 } 114 115 if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) 116 return 0; 117 118 return pc; 119 } 120 121 /* Return whether the frame preceding NEXT_FRAME corresponds to a 122 GNU/Linux sigtramp routine. */ 123 124 static int 125 amd64_linux_sigtramp_p (struct frame_info *next_frame) 126 { 127 CORE_ADDR pc = frame_pc_unwind (next_frame); 128 char *name; 129 130 find_pc_partial_function (pc, &name, NULL, NULL); 131 132 /* If we have NAME, we can optimize the search. The trampoline is 133 named __restore_rt. However, it isn't dynamically exported from 134 the shared C library, so the trampoline may appear to be part of 135 the preceding function. This should always be sigaction, 136 __sigaction, or __libc_sigaction (all aliases to the same 137 function). */ 138 if (name == NULL || strstr (name, "sigaction") != NULL) 139 return (amd64_linux_sigtramp_start (next_frame) != 0); 140 141 return (strcmp ("__restore_rt", name) == 0); 142 } 143 144 /* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>. */ 145 #define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40 146 147 /* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp 148 routine, return the address of the associated sigcontext structure. */ 149 150 static CORE_ADDR 151 amd64_linux_sigcontext_addr (struct frame_info *next_frame) 152 { 153 CORE_ADDR sp; 154 char buf[8]; 155 156 frame_unwind_register (next_frame, SP_REGNUM, buf); 157 sp = extract_unsigned_integer (buf, 8); 158 159 /* The sigcontext structure is part of the user context. A pointer 160 to the user context is passed as the third argument to the signal 161 handler, i.e. in %rdx. Unfortunately %rdx isn't preserved across 162 function calls so we can't use it. Fortunately the user context 163 is part of the signal frame and the unwound %rsp directly points 164 at it. */ 165 return sp + AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; 166 } 167 168 169 /* From <asm/sigcontext.h>. */ 170 static int amd64_linux_sc_reg_offset[] = 171 { 172 13 * 8, /* %rax */ 173 11 * 8, /* %rbx */ 174 14 * 8, /* %rcx */ 175 12 * 8, /* %rdx */ 176 9 * 8, /* %rsi */ 177 8 * 8, /* %rdi */ 178 10 * 8, /* %rbp */ 179 15 * 8, /* %rsp */ 180 0 * 8, /* %r8 */ 181 1 * 8, /* %r9 */ 182 2 * 8, /* %r10 */ 183 3 * 8, /* %r11 */ 184 4 * 8, /* %r12 */ 185 5 * 8, /* %r13 */ 186 6 * 8, /* %r14 */ 187 7 * 8, /* %r15 */ 188 16 * 8, /* %rip */ 189 17 * 8, /* %eflags */ 190 191 /* FIXME: kettenis/2002030531: The registers %cs, %fs and %gs are 192 available in `struct sigcontext'. However, they only occupy two 193 bytes instead of four, which makes using them here rather 194 difficult. Leave them out for now. */ 195 -1, /* %cs */ 196 -1, /* %ss */ 197 -1, /* %ds */ 198 -1, /* %es */ 199 -1, /* %fs */ 200 -1 /* %gs */ 201 }; 202 203 static void 204 amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 205 { 206 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 207 208 tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset; 209 tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset); 210 tdep->sizeof_gregset = 27 * 8; 211 212 amd64_init_abi (info, gdbarch); 213 214 tdep->sigtramp_p = amd64_linux_sigtramp_p; 215 tdep->sigcontext_addr = amd64_linux_sigcontext_addr; 216 tdep->sc_reg_offset = amd64_linux_sc_reg_offset; 217 tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset); 218 219 /* GNU/Linux uses SVR4-style shared libraries. */ 220 set_solib_svr4_fetch_link_map_offsets 221 (gdbarch, svr4_lp64_fetch_link_map_offsets); 222 } 223 224 225 /* Provide a prototype to silence -Wmissing-prototypes. */ 226 extern void _initialize_amd64_linux_tdep (void); 227 228 void 229 _initialize_amd64_linux_tdep (void) 230 { 231 gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, 232 GDB_OSABI_LINUX, amd64_linux_init_abi); 233 } 234