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