Updated copyright notices for most files.
[deliverable/binutils-gdb.git] / gdb / m68klinux-tdep.c
CommitLineData
0a595803
AS
1/* Motorola m68k target-dependent support for GNU/Linux.
2
9b254dd1 3 Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2007, 2008
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
8de307e0
AS
61/* Return non-zero if PC points into the signal trampoline. For the
62 sake of m68k_linux_get_sigtramp_info we also distinguish between
63 non-RT and RT signal trampolines. */
0a595803 64
eb2e12d7
AS
65static int
66m68k_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
0a595803
AS
67{
68 CORE_ADDR sp;
69 char buf[12];
70 unsigned long insn0, insn1, insn2;
71
359a9262 72 if (read_memory_nobpt (pc - 4, buf, sizeof (buf)))
0a595803
AS
73 return 0;
74 insn1 = extract_unsigned_integer (buf + 4, 4);
75 insn2 = extract_unsigned_integer (buf + 8, 4);
76 if (IS_SIGTRAMP (insn1, insn2))
77 return 1;
78 if (IS_RT_SIGTRAMP (insn1, insn2))
79 return 2;
80
81 insn0 = extract_unsigned_integer (buf, 4);
82 if (IS_SIGTRAMP (insn0, insn1))
83 return 1;
84 if (IS_RT_SIGTRAMP (insn0, insn1))
85 return 2;
86
55809acb
AS
87 insn0 = ((insn0 << 16) & 0xffffffff) | (insn1 >> 16);
88 insn1 = ((insn1 << 16) & 0xffffffff) | (insn2 >> 16);
0a595803
AS
89 if (IS_SIGTRAMP (insn0, insn1))
90 return 1;
91 if (IS_RT_SIGTRAMP (insn0, insn1))
92 return 2;
93
94 return 0;
95}
96
8de307e0
AS
97/* From <asm/sigcontext.h>. */
98static int m68k_linux_sigcontext_reg_offset[M68K_NUM_REGS] =
0a595803 99{
8de307e0
AS
100 2 * 4, /* %d0 */
101 3 * 4, /* %d1 */
102 -1, /* %d2 */
103 -1, /* %d3 */
104 -1, /* %d4 */
105 -1, /* %d5 */
106 -1, /* %d6 */
107 -1, /* %d7 */
108 4 * 4, /* %a0 */
109 5 * 4, /* %a1 */
110 -1, /* %a2 */
111 -1, /* %a3 */
112 -1, /* %a4 */
113 -1, /* %a5 */
114 -1, /* %fp */
115 1 * 4, /* %sp */
0ebdb728 116 6 * 4, /* %sr */
8de307e0
AS
117 6 * 4 + 2, /* %pc */
118 8 * 4, /* %fp0 */
119 11 * 4, /* %fp1 */
120 -1, /* %fp2 */
121 -1, /* %fp3 */
122 -1, /* %fp4 */
123 -1, /* %fp5 */
124 -1, /* %fp6 */
125 -1, /* %fp7 */
126 14 * 4, /* %fpcr */
127 15 * 4, /* %fpsr */
128 16 * 4 /* %fpiaddr */
129};
130
0ebdb728
MS
131static int m68k_uclinux_sigcontext_reg_offset[M68K_NUM_REGS] =
132{
133 2 * 4, /* %d0 */
134 3 * 4, /* %d1 */
135 -1, /* %d2 */
136 -1, /* %d3 */
137 -1, /* %d4 */
138 -1, /* %d5 */
139 -1, /* %d6 */
140 -1, /* %d7 */
141 4 * 4, /* %a0 */
142 5 * 4, /* %a1 */
143 -1, /* %a2 */
144 -1, /* %a3 */
145 -1, /* %a4 */
146 6 * 4, /* %a5 */
147 -1, /* %fp */
148 1 * 4, /* %sp */
149 7 * 4, /* %sr */
150 7 * 4 + 2, /* %pc */
151 -1, /* %fp0 */
152 -1, /* %fp1 */
153 -1, /* %fp2 */
154 -1, /* %fp3 */
155 -1, /* %fp4 */
156 -1, /* %fp5 */
157 -1, /* %fp6 */
158 -1, /* %fp7 */
159 -1, /* %fpcr */
160 -1, /* %fpsr */
161 -1 /* %fpiaddr */
162};
163
8de307e0
AS
164/* From <asm/ucontext.h>. */
165static int m68k_linux_ucontext_reg_offset[M68K_NUM_REGS] =
166{
167 6 * 4, /* %d0 */
168 7 * 4, /* %d1 */
169 8 * 4, /* %d2 */
170 9 * 4, /* %d3 */
171 10 * 4, /* %d4 */
172 11 * 4, /* %d5 */
173 12 * 4, /* %d6 */
174 13 * 4, /* %d7 */
175 14 * 4, /* %a0 */
176 15 * 4, /* %a1 */
177 16 * 4, /* %a2 */
178 17 * 4, /* %a3 */
179 18 * 4, /* %a4 */
180 19 * 4, /* %a5 */
181 20 * 4, /* %fp */
182 21 * 4, /* %sp */
183 23 * 4, /* %sr */
184 22 * 4, /* %pc */
185 27 * 4, /* %fp0 */
186 30 * 4, /* %fp1 */
187 33 * 4, /* %fp2 */
188 36 * 4, /* %fp3 */
189 39 * 4, /* %fp4 */
190 42 * 4, /* %fp5 */
191 45 * 4, /* %fp6 */
192 48 * 4, /* %fp7 */
193 24 * 4, /* %fpcr */
194 25 * 4, /* %fpsr */
195 26 * 4 /* %fpiaddr */
196};
197
198
199/* Get info about saved registers in sigtramp. */
200
17e20bce
AC
201struct m68k_linux_sigtramp_info
202{
203 /* Address of sigcontext. */
204 CORE_ADDR sigcontext_addr;
205
206 /* Offset of registers in `struct sigcontext'. */
207 int *sc_reg_offset;
208};
209
0ebdb728
MS
210/* Nonzero if running on uClinux. */
211static int target_is_uclinux;
212
213static void
214m68k_linux_inferior_created (struct target_ops *objfile, int from_tty)
215{
e9efe249
UW
216 /* Record that we will need to re-evaluate whether we are running on a
217 uClinux or normal GNU/Linux target (see m68k_linux_get_sigtramp_info). */
0ebdb728
MS
218 target_is_uclinux = -1;
219}
220
17e20bce 221static struct m68k_linux_sigtramp_info
8de307e0
AS
222m68k_linux_get_sigtramp_info (struct frame_info *next_frame)
223{
224 CORE_ADDR sp;
225 char buf[4];
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
MS
231 target so we can use the correct sigcontext layouts. */
232
233 CORE_ADDR dummy;
234
235 target_is_uclinux
236 = target_auxv_search (&current_target, AT_NULL, &dummy) > 0
237 && target_auxv_search (&current_target, AT_PAGESZ, &dummy) == 0;
238 }
239
8de307e0
AS
240 frame_unwind_register (next_frame, M68K_SP_REGNUM, buf);
241 sp = extract_unsigned_integer (buf, 4);
0a595803
AS
242
243 /* Get sigcontext address, it is the third parameter on the stack. */
8de307e0
AS
244 info.sigcontext_addr = read_memory_unsigned_integer (sp + 8, 4);
245
246 if (m68k_linux_pc_in_sigtramp (frame_pc_unwind (next_frame), 0) == 2)
247 info.sc_reg_offset = m68k_linux_ucontext_reg_offset;
0a595803 248 else
0ebdb728
MS
249 info.sc_reg_offset
250 = target_is_uclinux ? m68k_uclinux_sigcontext_reg_offset
251 : m68k_linux_sigcontext_reg_offset;
8de307e0 252 return info;
0a595803
AS
253}
254
17e20bce
AC
255/* Signal trampolines. */
256
257static struct trad_frame_cache *
258m68k_linux_sigtramp_frame_cache (struct frame_info *next_frame,
259 void **this_cache)
260{
261 struct frame_id this_id;
262 struct trad_frame_cache *cache;
c984b7ff 263 struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
17e20bce
AC
264 struct m68k_linux_sigtramp_info info;
265 char buf[4];
266 int i;
267
268 if (*this_cache)
269 return *this_cache;
270
271 cache = trad_frame_cache_zalloc (next_frame);
272
273 /* FIXME: cagney/2004-05-01: This is is long standing broken code.
274 The frame ID's code address should be the start-address of the
275 signal trampoline and not the current PC within that
276 trampoline. */
277 frame_unwind_register (next_frame, M68K_SP_REGNUM, buf);
278 /* See the end of m68k_push_dummy_call. */
279 this_id = frame_id_build (extract_unsigned_integer (buf, 4) - 4 + 8,
280 frame_pc_unwind (next_frame));
281 trad_frame_set_id (cache, this_id);
282
283 info = m68k_linux_get_sigtramp_info (next_frame);
284
285 for (i = 0; i < M68K_NUM_REGS; i++)
286 if (info.sc_reg_offset[i] != -1)
287 trad_frame_set_reg_addr (cache, i,
288 info.sigcontext_addr + info.sc_reg_offset[i]);
289
290 *this_cache = cache;
291 return cache;
292}
293
294static void
295m68k_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
296 void **this_cache,
297 struct frame_id *this_id)
298{
299 struct trad_frame_cache *cache =
300 m68k_linux_sigtramp_frame_cache (next_frame, this_cache);
301 trad_frame_get_id (cache, this_id);
302}
303
304static void
305m68k_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
306 void **this_cache,
307 int regnum, int *optimizedp,
308 enum lval_type *lvalp,
309 CORE_ADDR *addrp,
cba5fab9 310 int *realnump, gdb_byte *valuep)
17e20bce
AC
311{
312 /* Make sure we've initialized the cache. */
313 struct trad_frame_cache *cache =
314 m68k_linux_sigtramp_frame_cache (next_frame, this_cache);
315 trad_frame_get_register (cache, next_frame, regnum, optimizedp, lvalp,
316 addrp, realnump, valuep);
317}
318
319static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
320{
321 SIGTRAMP_FRAME,
322 m68k_linux_sigtramp_frame_this_id,
323 m68k_linux_sigtramp_frame_prev_register
324};
325
326static const struct frame_unwind *
327m68k_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
328{
329 CORE_ADDR pc = frame_pc_unwind (next_frame);
330 char *name;
331
332 find_pc_partial_function (pc, &name, NULL, NULL);
333 if (m68k_linux_pc_in_sigtramp (pc, name))
334 return &m68k_linux_sigtramp_frame_unwind;
335
336 return NULL;
337}
338
55809acb
AS
339static void
340m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
341{
eb2e12d7
AS
342 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
343
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
17e20bce 358 frame_unwind_append_sniffer (gdbarch, m68k_linux_sigtramp_frame_sniffer);
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
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.405929 seconds and 4 git commands to generate.