gdb
[deliverable/binutils-gdb.git] / gdb / m68klinux-tdep.c
CommitLineData
0a595803
AS
1/* Motorola m68k target-dependent support for GNU/Linux.
2
0fb0cc75 3 Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2007, 2008, 2009
f595cb19 4 Free Software Foundation, Inc.
0a595803
AS
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
a9762ec7 10 the Free Software Foundation; either version 3 of the License, or
0a595803
AS
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
a9762ec7 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
0a595803
AS
20
21#include "defs.h"
22#include "gdbcore.h"
8de307e0
AS
23#include "doublest.h"
24#include "floatformat.h"
0a595803
AS
25#include "frame.h"
26#include "target.h"
d0b45d99
AS
27#include "gdb_string.h"
28#include "gdbtypes.h"
55809acb 29#include "osabi.h"
eb2e12d7
AS
30#include "regcache.h"
31#include "objfiles.h"
32#include "symtab.h"
d0b45d99 33#include "m68k-tdep.h"
17e20bce
AC
34#include "trad-frame.h"
35#include "frame-unwind.h"
fefa1888
AS
36#include "glibc-tdep.h"
37#include "solib-svr4.h"
0ebdb728
MS
38#include "auxv.h"
39#include "observer.h"
40#include "elf/common.h"
0a595803 41\f
eb2e12d7
AS
42/* Offsets (in target ints) into jmp_buf. */
43
44#define M68K_LINUX_JB_ELEMENT_SIZE 4
45#define M68K_LINUX_JB_PC 7
46
0a595803
AS
47/* Check whether insn1 and insn2 are parts of a signal trampoline. */
48
49#define IS_SIGTRAMP(insn1, insn2) \
50 (/* addaw #20,sp; moveq #119,d0; trap #0 */ \
51 (insn1 == 0xdefc0014 && insn2 == 0x70774e40) \
52 /* moveq #119,d0; trap #0 */ \
53 || insn1 == 0x70774e40)
54
55#define IS_RT_SIGTRAMP(insn1, insn2) \
56 (/* movel #173,d0; trap #0 */ \
57 (insn1 == 0x203c0000 && insn2 == 0x00ad4e40) \
58 /* moveq #82,d0; notb d0; trap #0 */ \
59 || (insn1 == 0x70524600 && (insn2 >> 16) == 0x4e40))
60
f36bf22c
AS
61/* Return non-zero if THIS_FRAME corresponds to a signal trampoline. For
62 the sake of m68k_linux_get_sigtramp_info we also distinguish between
8de307e0 63 non-RT and RT signal trampolines. */
0a595803 64
eb2e12d7 65static int
f36bf22c 66m68k_linux_pc_in_sigtramp (struct frame_info *this_frame)
0a595803
AS
67{
68 CORE_ADDR sp;
f36bf22c 69 gdb_byte buf[12];
0a595803 70 unsigned long insn0, insn1, insn2;
f36bf22c 71 CORE_ADDR pc = get_frame_pc (this_frame);
0a595803 72
c95f5026 73 if (!safe_frame_unwind_memory (this_frame, pc - 4, buf, sizeof (buf)))
0a595803
AS
74 return 0;
75 insn1 = extract_unsigned_integer (buf + 4, 4);
76 insn2 = extract_unsigned_integer (buf + 8, 4);
77 if (IS_SIGTRAMP (insn1, insn2))
78 return 1;
79 if (IS_RT_SIGTRAMP (insn1, insn2))
80 return 2;
81
82 insn0 = extract_unsigned_integer (buf, 4);
83 if (IS_SIGTRAMP (insn0, insn1))
84 return 1;
85 if (IS_RT_SIGTRAMP (insn0, insn1))
86 return 2;
87
55809acb
AS
88 insn0 = ((insn0 << 16) & 0xffffffff) | (insn1 >> 16);
89 insn1 = ((insn1 << 16) & 0xffffffff) | (insn2 >> 16);
0a595803
AS
90 if (IS_SIGTRAMP (insn0, insn1))
91 return 1;
92 if (IS_RT_SIGTRAMP (insn0, insn1))
93 return 2;
94
95 return 0;
96}
97
8de307e0
AS
98/* From <asm/sigcontext.h>. */
99static int m68k_linux_sigcontext_reg_offset[M68K_NUM_REGS] =
0a595803 100{
8de307e0
AS
101 2 * 4, /* %d0 */
102 3 * 4, /* %d1 */
103 -1, /* %d2 */
104 -1, /* %d3 */
105 -1, /* %d4 */
106 -1, /* %d5 */
107 -1, /* %d6 */
108 -1, /* %d7 */
109 4 * 4, /* %a0 */
110 5 * 4, /* %a1 */
111 -1, /* %a2 */
112 -1, /* %a3 */
113 -1, /* %a4 */
114 -1, /* %a5 */
115 -1, /* %fp */
116 1 * 4, /* %sp */
0ebdb728 117 6 * 4, /* %sr */
8de307e0
AS
118 6 * 4 + 2, /* %pc */
119 8 * 4, /* %fp0 */
120 11 * 4, /* %fp1 */
121 -1, /* %fp2 */
122 -1, /* %fp3 */
123 -1, /* %fp4 */
124 -1, /* %fp5 */
125 -1, /* %fp6 */
126 -1, /* %fp7 */
127 14 * 4, /* %fpcr */
128 15 * 4, /* %fpsr */
129 16 * 4 /* %fpiaddr */
130};
131
0ebdb728
MS
132static int m68k_uclinux_sigcontext_reg_offset[M68K_NUM_REGS] =
133{
134 2 * 4, /* %d0 */
135 3 * 4, /* %d1 */
136 -1, /* %d2 */
137 -1, /* %d3 */
138 -1, /* %d4 */
139 -1, /* %d5 */
140 -1, /* %d6 */
141 -1, /* %d7 */
142 4 * 4, /* %a0 */
143 5 * 4, /* %a1 */
144 -1, /* %a2 */
145 -1, /* %a3 */
146 -1, /* %a4 */
147 6 * 4, /* %a5 */
148 -1, /* %fp */
149 1 * 4, /* %sp */
150 7 * 4, /* %sr */
151 7 * 4 + 2, /* %pc */
152 -1, /* %fp0 */
153 -1, /* %fp1 */
154 -1, /* %fp2 */
155 -1, /* %fp3 */
156 -1, /* %fp4 */
157 -1, /* %fp5 */
158 -1, /* %fp6 */
159 -1, /* %fp7 */
160 -1, /* %fpcr */
161 -1, /* %fpsr */
162 -1 /* %fpiaddr */
163};
164
8de307e0
AS
165/* From <asm/ucontext.h>. */
166static int m68k_linux_ucontext_reg_offset[M68K_NUM_REGS] =
167{
168 6 * 4, /* %d0 */
169 7 * 4, /* %d1 */
170 8 * 4, /* %d2 */
171 9 * 4, /* %d3 */
172 10 * 4, /* %d4 */
173 11 * 4, /* %d5 */
174 12 * 4, /* %d6 */
175 13 * 4, /* %d7 */
176 14 * 4, /* %a0 */
177 15 * 4, /* %a1 */
178 16 * 4, /* %a2 */
179 17 * 4, /* %a3 */
180 18 * 4, /* %a4 */
181 19 * 4, /* %a5 */
182 20 * 4, /* %fp */
183 21 * 4, /* %sp */
184 23 * 4, /* %sr */
185 22 * 4, /* %pc */
186 27 * 4, /* %fp0 */
187 30 * 4, /* %fp1 */
188 33 * 4, /* %fp2 */
189 36 * 4, /* %fp3 */
190 39 * 4, /* %fp4 */
191 42 * 4, /* %fp5 */
192 45 * 4, /* %fp6 */
193 48 * 4, /* %fp7 */
194 24 * 4, /* %fpcr */
195 25 * 4, /* %fpsr */
196 26 * 4 /* %fpiaddr */
197};
198
199
200/* Get info about saved registers in sigtramp. */
201
17e20bce
AC
202struct m68k_linux_sigtramp_info
203{
204 /* Address of sigcontext. */
205 CORE_ADDR sigcontext_addr;
206
207 /* Offset of registers in `struct sigcontext'. */
208 int *sc_reg_offset;
209};
210
0ebdb728
MS
211/* Nonzero if running on uClinux. */
212static int target_is_uclinux;
213
214static void
215m68k_linux_inferior_created (struct target_ops *objfile, int from_tty)
216{
e9efe249
UW
217 /* Record that we will need to re-evaluate whether we are running on a
218 uClinux or normal GNU/Linux target (see m68k_linux_get_sigtramp_info). */
0ebdb728
MS
219 target_is_uclinux = -1;
220}
221
17e20bce 222static struct m68k_linux_sigtramp_info
f36bf22c 223m68k_linux_get_sigtramp_info (struct frame_info *this_frame)
8de307e0
AS
224{
225 CORE_ADDR sp;
17e20bce 226 struct m68k_linux_sigtramp_info info;
8de307e0 227
0ebdb728
MS
228 if (target_is_uclinux == -1)
229 {
e9efe249 230 /* Determine whether we are running on a uClinux or normal GNU/Linux
0ebdb728 231 target so we can use the correct sigcontext layouts. */
0ebdb728 232 CORE_ADDR dummy;
f36bf22c 233
0ebdb728 234 target_is_uclinux
f36bf22c
AS
235 = (target_auxv_search (&current_target, AT_NULL, &dummy) > 0
236 && target_auxv_search (&current_target, AT_PAGESZ, &dummy) == 0);
0ebdb728
MS
237 }
238
f36bf22c 239 sp = get_frame_register_unsigned (this_frame, M68K_SP_REGNUM);
0a595803
AS
240
241 /* Get sigcontext address, it is the third parameter on the stack. */
8de307e0
AS
242 info.sigcontext_addr = read_memory_unsigned_integer (sp + 8, 4);
243
f36bf22c 244 if (m68k_linux_pc_in_sigtramp (this_frame) == 2)
8de307e0 245 info.sc_reg_offset = m68k_linux_ucontext_reg_offset;
0a595803 246 else
f36bf22c
AS
247 info.sc_reg_offset = (target_is_uclinux
248 ? m68k_uclinux_sigcontext_reg_offset
249 : m68k_linux_sigcontext_reg_offset);
8de307e0 250 return info;
0a595803
AS
251}
252
17e20bce
AC
253/* Signal trampolines. */
254
255static struct trad_frame_cache *
f36bf22c 256m68k_linux_sigtramp_frame_cache (struct frame_info *this_frame,
17e20bce
AC
257 void **this_cache)
258{
259 struct frame_id this_id;
260 struct trad_frame_cache *cache;
f36bf22c 261 struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame));
17e20bce 262 struct m68k_linux_sigtramp_info info;
f36bf22c 263 gdb_byte buf[4];
17e20bce
AC
264 int i;
265
266 if (*this_cache)
267 return *this_cache;
268
f36bf22c 269 cache = trad_frame_cache_zalloc (this_frame);
17e20bce
AC
270
271 /* FIXME: cagney/2004-05-01: This is is long standing broken code.
272 The frame ID's code address should be the start-address of the
273 signal trampoline and not the current PC within that
274 trampoline. */
f36bf22c 275 get_frame_register (this_frame, M68K_SP_REGNUM, buf);
17e20bce
AC
276 /* See the end of m68k_push_dummy_call. */
277 this_id = frame_id_build (extract_unsigned_integer (buf, 4) - 4 + 8,
f36bf22c 278 get_frame_pc (this_frame));
17e20bce
AC
279 trad_frame_set_id (cache, this_id);
280
f36bf22c 281 info = m68k_linux_get_sigtramp_info (this_frame);
17e20bce
AC
282
283 for (i = 0; i < M68K_NUM_REGS; i++)
284 if (info.sc_reg_offset[i] != -1)
285 trad_frame_set_reg_addr (cache, i,
286 info.sigcontext_addr + info.sc_reg_offset[i]);
287
288 *this_cache = cache;
289 return cache;
290}
291
292static void
f36bf22c 293m68k_linux_sigtramp_frame_this_id (struct frame_info *this_frame,
17e20bce
AC
294 void **this_cache,
295 struct frame_id *this_id)
296{
297 struct trad_frame_cache *cache =
f36bf22c 298 m68k_linux_sigtramp_frame_cache (this_frame, this_cache);
17e20bce
AC
299 trad_frame_get_id (cache, this_id);
300}
301
f36bf22c
AS
302static struct value *
303m68k_linux_sigtramp_frame_prev_register (struct frame_info *this_frame,
17e20bce 304 void **this_cache,
f36bf22c 305 int regnum)
17e20bce
AC
306{
307 /* Make sure we've initialized the cache. */
308 struct trad_frame_cache *cache =
f36bf22c
AS
309 m68k_linux_sigtramp_frame_cache (this_frame, this_cache);
310 return trad_frame_get_register (cache, this_frame, regnum);
311}
312
313static int
314m68k_linux_sigtramp_frame_sniffer (const struct frame_unwind *self,
315 struct frame_info *this_frame,
316 void **this_prologue_cache)
317{
318 return m68k_linux_pc_in_sigtramp (this_frame);
17e20bce
AC
319}
320
321static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
322{
323 SIGTRAMP_FRAME,
324 m68k_linux_sigtramp_frame_this_id,
f36bf22c
AS
325 m68k_linux_sigtramp_frame_prev_register,
326 NULL,
327 m68k_linux_sigtramp_frame_sniffer
17e20bce
AC
328};
329
55809acb
AS
330static void
331m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
332{
eb2e12d7
AS
333 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
334
335 tdep->jb_pc = M68K_LINUX_JB_PC;
336 tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
337
f595cb19 338 /* GNU/Linux uses a calling convention that's similar to SVR4. It
8d3239d5 339 returns integer values in %d0/%d1, pointer values in %a0 and
f595cb19
MK
340 floating values in %fp0, just like SVR4, but uses %a1 to pass the
341 address to store a structure value. It also returns small
342 structures in registers instead of memory. */
343 m68k_svr4_init_abi (info, gdbarch);
344 tdep->struct_value_regnum = M68K_A1_REGNUM;
345 tdep->struct_return = reg_struct_return;
eb2e12d7 346
9418f048
UW
347 set_gdbarch_decr_pc_after_break (gdbarch, 2);
348
f36bf22c 349 frame_unwind_append_unwinder (gdbarch, &m68k_linux_sigtramp_frame_unwind);
eb2e12d7
AS
350
351 /* Shared library handling. */
fefa1888
AS
352
353 /* GNU/Linux uses SVR4-style shared libraries. */
354 set_solib_svr4_fetch_link_map_offsets (gdbarch,
355 svr4_ilp32_fetch_link_map_offsets);
356
357 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
358 set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
359
eb2e12d7 360 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
b2756930
KB
361
362 /* Enable TLS support. */
363 set_gdbarch_fetch_tls_load_module_address (gdbarch,
364 svr4_fetch_objfile_link_map);
55809acb
AS
365}
366
63807e1d
PA
367/* Provide a prototype to silence -Wmissing-prototypes. */
368extern initialize_file_ftype _initialize_m68k_linux_tdep;
369
55809acb
AS
370void
371_initialize_m68k_linux_tdep (void)
372{
373 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_LINUX,
374 m68k_linux_init_abi);
0ebdb728 375 observer_attach_inferior_created (m68k_linux_inferior_created);
55809acb 376}
This page took 0.581778 seconds and 4 git commands to generate.