GDB (API)
|
00001 /* Motorola m68k target-dependent support for GNU/Linux. 00002 00003 Copyright (C) 1996-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "gdbcore.h" 00022 #include "doublest.h" 00023 #include "floatformat.h" 00024 #include "frame.h" 00025 #include "target.h" 00026 #include "gdb_string.h" 00027 #include "gdbtypes.h" 00028 #include "osabi.h" 00029 #include "regcache.h" 00030 #include "objfiles.h" 00031 #include "symtab.h" 00032 #include "m68k-tdep.h" 00033 #include "trad-frame.h" 00034 #include "frame-unwind.h" 00035 #include "glibc-tdep.h" 00036 #include "solib-svr4.h" 00037 #include "auxv.h" 00038 #include "observer.h" 00039 #include "elf/common.h" 00040 #include "linux-tdep.h" 00041 00042 /* Offsets (in target ints) into jmp_buf. */ 00043 00044 #define M68K_LINUX_JB_ELEMENT_SIZE 4 00045 #define M68K_LINUX_JB_PC 7 00046 00047 /* Check whether insn1 and insn2 are parts of a signal trampoline. */ 00048 00049 #define IS_SIGTRAMP(insn1, insn2) \ 00050 (/* addaw #20,sp; moveq #119,d0; trap #0 */ \ 00051 (insn1 == 0xdefc0014 && insn2 == 0x70774e40) \ 00052 /* moveq #119,d0; trap #0 */ \ 00053 || insn1 == 0x70774e40) 00054 00055 #define IS_RT_SIGTRAMP(insn1, insn2) \ 00056 (/* movel #173,d0; trap #0 */ \ 00057 (insn1 == 0x203c0000 && insn2 == 0x00ad4e40) \ 00058 /* moveq #82,d0; notb d0; trap #0 */ \ 00059 || (insn1 == 0x70524600 && (insn2 >> 16) == 0x4e40)) 00060 00061 /* Return non-zero if THIS_FRAME corresponds to a signal trampoline. For 00062 the sake of m68k_linux_get_sigtramp_info we also distinguish between 00063 non-RT and RT signal trampolines. */ 00064 00065 static int 00066 m68k_linux_pc_in_sigtramp (struct frame_info *this_frame) 00067 { 00068 struct gdbarch *gdbarch = get_frame_arch (this_frame); 00069 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 00070 gdb_byte buf[12]; 00071 unsigned long insn0, insn1, insn2; 00072 CORE_ADDR pc = get_frame_pc (this_frame); 00073 00074 if (!safe_frame_unwind_memory (this_frame, pc - 4, buf, sizeof (buf))) 00075 return 0; 00076 insn1 = extract_unsigned_integer (buf + 4, 4, byte_order); 00077 insn2 = extract_unsigned_integer (buf + 8, 4, byte_order); 00078 if (IS_SIGTRAMP (insn1, insn2)) 00079 return 1; 00080 if (IS_RT_SIGTRAMP (insn1, insn2)) 00081 return 2; 00082 00083 insn0 = extract_unsigned_integer (buf, 4, byte_order); 00084 if (IS_SIGTRAMP (insn0, insn1)) 00085 return 1; 00086 if (IS_RT_SIGTRAMP (insn0, insn1)) 00087 return 2; 00088 00089 insn0 = ((insn0 << 16) & 0xffffffff) | (insn1 >> 16); 00090 insn1 = ((insn1 << 16) & 0xffffffff) | (insn2 >> 16); 00091 if (IS_SIGTRAMP (insn0, insn1)) 00092 return 1; 00093 if (IS_RT_SIGTRAMP (insn0, insn1)) 00094 return 2; 00095 00096 return 0; 00097 } 00098 00099 /* From <asm/sigcontext.h>. */ 00100 static int m68k_linux_sigcontext_reg_offset[M68K_NUM_REGS] = 00101 { 00102 2 * 4, /* %d0 */ 00103 3 * 4, /* %d1 */ 00104 -1, /* %d2 */ 00105 -1, /* %d3 */ 00106 -1, /* %d4 */ 00107 -1, /* %d5 */ 00108 -1, /* %d6 */ 00109 -1, /* %d7 */ 00110 4 * 4, /* %a0 */ 00111 5 * 4, /* %a1 */ 00112 -1, /* %a2 */ 00113 -1, /* %a3 */ 00114 -1, /* %a4 */ 00115 -1, /* %a5 */ 00116 -1, /* %fp */ 00117 1 * 4, /* %sp */ 00118 6 * 4, /* %sr */ 00119 6 * 4 + 2, /* %pc */ 00120 8 * 4, /* %fp0 */ 00121 11 * 4, /* %fp1 */ 00122 -1, /* %fp2 */ 00123 -1, /* %fp3 */ 00124 -1, /* %fp4 */ 00125 -1, /* %fp5 */ 00126 -1, /* %fp6 */ 00127 -1, /* %fp7 */ 00128 14 * 4, /* %fpcr */ 00129 15 * 4, /* %fpsr */ 00130 16 * 4 /* %fpiaddr */ 00131 }; 00132 00133 static int m68k_uclinux_sigcontext_reg_offset[M68K_NUM_REGS] = 00134 { 00135 2 * 4, /* %d0 */ 00136 3 * 4, /* %d1 */ 00137 -1, /* %d2 */ 00138 -1, /* %d3 */ 00139 -1, /* %d4 */ 00140 -1, /* %d5 */ 00141 -1, /* %d6 */ 00142 -1, /* %d7 */ 00143 4 * 4, /* %a0 */ 00144 5 * 4, /* %a1 */ 00145 -1, /* %a2 */ 00146 -1, /* %a3 */ 00147 -1, /* %a4 */ 00148 6 * 4, /* %a5 */ 00149 -1, /* %fp */ 00150 1 * 4, /* %sp */ 00151 7 * 4, /* %sr */ 00152 7 * 4 + 2, /* %pc */ 00153 -1, /* %fp0 */ 00154 -1, /* %fp1 */ 00155 -1, /* %fp2 */ 00156 -1, /* %fp3 */ 00157 -1, /* %fp4 */ 00158 -1, /* %fp5 */ 00159 -1, /* %fp6 */ 00160 -1, /* %fp7 */ 00161 -1, /* %fpcr */ 00162 -1, /* %fpsr */ 00163 -1 /* %fpiaddr */ 00164 }; 00165 00166 /* From <asm/ucontext.h>. */ 00167 static int m68k_linux_ucontext_reg_offset[M68K_NUM_REGS] = 00168 { 00169 6 * 4, /* %d0 */ 00170 7 * 4, /* %d1 */ 00171 8 * 4, /* %d2 */ 00172 9 * 4, /* %d3 */ 00173 10 * 4, /* %d4 */ 00174 11 * 4, /* %d5 */ 00175 12 * 4, /* %d6 */ 00176 13 * 4, /* %d7 */ 00177 14 * 4, /* %a0 */ 00178 15 * 4, /* %a1 */ 00179 16 * 4, /* %a2 */ 00180 17 * 4, /* %a3 */ 00181 18 * 4, /* %a4 */ 00182 19 * 4, /* %a5 */ 00183 20 * 4, /* %fp */ 00184 21 * 4, /* %sp */ 00185 23 * 4, /* %sr */ 00186 22 * 4, /* %pc */ 00187 27 * 4, /* %fp0 */ 00188 30 * 4, /* %fp1 */ 00189 33 * 4, /* %fp2 */ 00190 36 * 4, /* %fp3 */ 00191 39 * 4, /* %fp4 */ 00192 42 * 4, /* %fp5 */ 00193 45 * 4, /* %fp6 */ 00194 48 * 4, /* %fp7 */ 00195 24 * 4, /* %fpcr */ 00196 25 * 4, /* %fpsr */ 00197 26 * 4 /* %fpiaddr */ 00198 }; 00199 00200 00201 /* Get info about saved registers in sigtramp. */ 00202 00203 struct m68k_linux_sigtramp_info 00204 { 00205 /* Address of sigcontext. */ 00206 CORE_ADDR sigcontext_addr; 00207 00208 /* Offset of registers in `struct sigcontext'. */ 00209 int *sc_reg_offset; 00210 }; 00211 00212 /* Nonzero if running on uClinux. */ 00213 static int target_is_uclinux; 00214 00215 static void 00216 m68k_linux_inferior_created (struct target_ops *objfile, int from_tty) 00217 { 00218 /* Record that we will need to re-evaluate whether we are running on a 00219 uClinux or normal GNU/Linux target (see m68k_linux_get_sigtramp_info). */ 00220 target_is_uclinux = -1; 00221 } 00222 00223 static struct m68k_linux_sigtramp_info 00224 m68k_linux_get_sigtramp_info (struct frame_info *this_frame) 00225 { 00226 struct gdbarch *gdbarch = get_frame_arch (this_frame); 00227 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 00228 CORE_ADDR sp; 00229 struct m68k_linux_sigtramp_info info; 00230 00231 /* Determine whether we are running on a uClinux or normal GNU/Linux 00232 target so we can use the correct sigcontext layouts. */ 00233 if (target_is_uclinux == -1) 00234 target_is_uclinux = linux_is_uclinux (); 00235 00236 sp = get_frame_register_unsigned (this_frame, M68K_SP_REGNUM); 00237 00238 /* Get sigcontext address, it is the third parameter on the stack. */ 00239 info.sigcontext_addr = read_memory_unsigned_integer (sp + 8, 4, byte_order); 00240 00241 if (m68k_linux_pc_in_sigtramp (this_frame) == 2) 00242 info.sc_reg_offset = m68k_linux_ucontext_reg_offset; 00243 else 00244 info.sc_reg_offset = (target_is_uclinux 00245 ? m68k_uclinux_sigcontext_reg_offset 00246 : m68k_linux_sigcontext_reg_offset); 00247 return info; 00248 } 00249 00250 /* Signal trampolines. */ 00251 00252 static struct trad_frame_cache * 00253 m68k_linux_sigtramp_frame_cache (struct frame_info *this_frame, 00254 void **this_cache) 00255 { 00256 struct frame_id this_id; 00257 struct trad_frame_cache *cache; 00258 struct gdbarch *gdbarch = get_frame_arch (this_frame); 00259 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00260 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 00261 struct m68k_linux_sigtramp_info info; 00262 gdb_byte buf[4]; 00263 int i; 00264 00265 if (*this_cache) 00266 return *this_cache; 00267 00268 cache = trad_frame_cache_zalloc (this_frame); 00269 00270 /* FIXME: cagney/2004-05-01: This is is long standing broken code. 00271 The frame ID's code address should be the start-address of the 00272 signal trampoline and not the current PC within that 00273 trampoline. */ 00274 get_frame_register (this_frame, M68K_SP_REGNUM, buf); 00275 /* See the end of m68k_push_dummy_call. */ 00276 this_id = frame_id_build (extract_unsigned_integer (buf, 4, byte_order) 00277 - 4 + 8, get_frame_pc (this_frame)); 00278 trad_frame_set_id (cache, this_id); 00279 00280 info = m68k_linux_get_sigtramp_info (this_frame); 00281 00282 for (i = 0; i < M68K_NUM_REGS; i++) 00283 if (info.sc_reg_offset[i] != -1) 00284 trad_frame_set_reg_addr (cache, i, 00285 info.sigcontext_addr + info.sc_reg_offset[i]); 00286 00287 *this_cache = cache; 00288 return cache; 00289 } 00290 00291 static void 00292 m68k_linux_sigtramp_frame_this_id (struct frame_info *this_frame, 00293 void **this_cache, 00294 struct frame_id *this_id) 00295 { 00296 struct trad_frame_cache *cache = 00297 m68k_linux_sigtramp_frame_cache (this_frame, this_cache); 00298 trad_frame_get_id (cache, this_id); 00299 } 00300 00301 static struct value * 00302 m68k_linux_sigtramp_frame_prev_register (struct frame_info *this_frame, 00303 void **this_cache, 00304 int regnum) 00305 { 00306 /* Make sure we've initialized the cache. */ 00307 struct trad_frame_cache *cache = 00308 m68k_linux_sigtramp_frame_cache (this_frame, this_cache); 00309 return trad_frame_get_register (cache, this_frame, regnum); 00310 } 00311 00312 static int 00313 m68k_linux_sigtramp_frame_sniffer (const struct frame_unwind *self, 00314 struct frame_info *this_frame, 00315 void **this_prologue_cache) 00316 { 00317 return m68k_linux_pc_in_sigtramp (this_frame); 00318 } 00319 00320 static const struct frame_unwind m68k_linux_sigtramp_frame_unwind = 00321 { 00322 SIGTRAMP_FRAME, 00323 default_frame_unwind_stop_reason, 00324 m68k_linux_sigtramp_frame_this_id, 00325 m68k_linux_sigtramp_frame_prev_register, 00326 NULL, 00327 m68k_linux_sigtramp_frame_sniffer 00328 }; 00329 00330 static void 00331 m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 00332 { 00333 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00334 00335 linux_init_abi (info, gdbarch); 00336 00337 tdep->jb_pc = M68K_LINUX_JB_PC; 00338 tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE; 00339 00340 /* GNU/Linux uses a calling convention that's similar to SVR4. It 00341 returns integer values in %d0/%d1, pointer values in %a0 and 00342 floating values in %fp0, just like SVR4, but uses %a1 to pass the 00343 address to store a structure value. It also returns small 00344 structures in registers instead of memory. */ 00345 m68k_svr4_init_abi (info, gdbarch); 00346 tdep->struct_value_regnum = M68K_A1_REGNUM; 00347 tdep->struct_return = reg_struct_return; 00348 00349 set_gdbarch_decr_pc_after_break (gdbarch, 2); 00350 00351 frame_unwind_append_unwinder (gdbarch, &m68k_linux_sigtramp_frame_unwind); 00352 00353 /* Shared library handling. */ 00354 00355 /* GNU/Linux uses SVR4-style shared libraries. */ 00356 set_solib_svr4_fetch_link_map_offsets (gdbarch, 00357 svr4_ilp32_fetch_link_map_offsets); 00358 00359 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ 00360 set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); 00361 00362 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); 00363 00364 /* Enable TLS support. */ 00365 set_gdbarch_fetch_tls_load_module_address (gdbarch, 00366 svr4_fetch_objfile_link_map); 00367 00368 set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); 00369 } 00370 00371 /* Provide a prototype to silence -Wmissing-prototypes. */ 00372 extern initialize_file_ftype _initialize_m68k_linux_tdep; 00373 00374 void 00375 _initialize_m68k_linux_tdep (void) 00376 { 00377 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_LINUX, 00378 m68k_linux_init_abi); 00379 observer_attach_inferior_created (m68k_linux_inferior_created); 00380 }