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