]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/m68klinux-tdep.c
M32R: Migrate from 'regset_from_core_section' to 'iterate_over_regset_sections'
[thirdparty/binutils-gdb.git] / gdb / m68klinux-tdep.c
CommitLineData
0a595803
AS
1/* Motorola m68k target-dependent support for GNU/Linux.
2
ecd75fc8 3 Copyright (C) 1996-2014 Free Software Foundation, Inc.
0a595803
AS
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
0a595803
AS
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
0a595803
AS
19
20#include "defs.h"
21#include "gdbcore.h"
8de307e0
AS
22#include "doublest.h"
23#include "floatformat.h"
0a595803
AS
24#include "frame.h"
25#include "target.h"
d0b45d99 26#include "gdbtypes.h"
55809acb 27#include "osabi.h"
eb2e12d7
AS
28#include "regcache.h"
29#include "objfiles.h"
30#include "symtab.h"
d0b45d99 31#include "m68k-tdep.h"
17e20bce
AC
32#include "trad-frame.h"
33#include "frame-unwind.h"
fefa1888
AS
34#include "glibc-tdep.h"
35#include "solib-svr4.h"
0ebdb728
MS
36#include "auxv.h"
37#include "observer.h"
38#include "elf/common.h"
a5ee0f0c 39#include "linux-tdep.h"
08f9f542 40#include "regset.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);
f36bf22c 70 gdb_byte buf[12];
0a595803 71 unsigned long insn0, insn1, insn2;
f36bf22c 72 CORE_ADDR pc = get_frame_pc (this_frame);
0a595803 73
c95f5026 74 if (!safe_frame_unwind_memory (this_frame, pc - 4, buf, sizeof (buf)))
0a595803 75 return 0;
e17a4113
UW
76 insn1 = extract_unsigned_integer (buf + 4, 4, byte_order);
77 insn2 = extract_unsigned_integer (buf + 8, 4, byte_order);
0a595803
AS
78 if (IS_SIGTRAMP (insn1, insn2))
79 return 1;
80 if (IS_RT_SIGTRAMP (insn1, insn2))
81 return 2;
82
e17a4113 83 insn0 = extract_unsigned_integer (buf, 4, byte_order);
0a595803
AS
84 if (IS_SIGTRAMP (insn0, insn1))
85 return 1;
86 if (IS_RT_SIGTRAMP (insn0, insn1))
87 return 2;
88
55809acb
AS
89 insn0 = ((insn0 << 16) & 0xffffffff) | (insn1 >> 16);
90 insn1 = ((insn1 << 16) & 0xffffffff) | (insn2 >> 16);
0a595803
AS
91 if (IS_SIGTRAMP (insn0, insn1))
92 return 1;
93 if (IS_RT_SIGTRAMP (insn0, insn1))
94 return 2;
95
96 return 0;
97}
98
8de307e0
AS
99/* From <asm/sigcontext.h>. */
100static int m68k_linux_sigcontext_reg_offset[M68K_NUM_REGS] =
0a595803 101{
8de307e0
AS
102 2 * 4, /* %d0 */
103 3 * 4, /* %d1 */
104 -1, /* %d2 */
105 -1, /* %d3 */
106 -1, /* %d4 */
107 -1, /* %d5 */
108 -1, /* %d6 */
109 -1, /* %d7 */
110 4 * 4, /* %a0 */
111 5 * 4, /* %a1 */
112 -1, /* %a2 */
113 -1, /* %a3 */
114 -1, /* %a4 */
115 -1, /* %a5 */
116 -1, /* %fp */
117 1 * 4, /* %sp */
0ebdb728 118 6 * 4, /* %sr */
8de307e0
AS
119 6 * 4 + 2, /* %pc */
120 8 * 4, /* %fp0 */
121 11 * 4, /* %fp1 */
122 -1, /* %fp2 */
123 -1, /* %fp3 */
124 -1, /* %fp4 */
125 -1, /* %fp5 */
126 -1, /* %fp6 */
127 -1, /* %fp7 */
128 14 * 4, /* %fpcr */
129 15 * 4, /* %fpsr */
130 16 * 4 /* %fpiaddr */
131};
132
0ebdb728
MS
133static int m68k_uclinux_sigcontext_reg_offset[M68K_NUM_REGS] =
134{
135 2 * 4, /* %d0 */
136 3 * 4, /* %d1 */
137 -1, /* %d2 */
138 -1, /* %d3 */
139 -1, /* %d4 */
140 -1, /* %d5 */
141 -1, /* %d6 */
142 -1, /* %d7 */
143 4 * 4, /* %a0 */
144 5 * 4, /* %a1 */
145 -1, /* %a2 */
146 -1, /* %a3 */
147 -1, /* %a4 */
148 6 * 4, /* %a5 */
149 -1, /* %fp */
150 1 * 4, /* %sp */
151 7 * 4, /* %sr */
152 7 * 4 + 2, /* %pc */
153 -1, /* %fp0 */
154 -1, /* %fp1 */
155 -1, /* %fp2 */
156 -1, /* %fp3 */
157 -1, /* %fp4 */
158 -1, /* %fp5 */
159 -1, /* %fp6 */
160 -1, /* %fp7 */
161 -1, /* %fpcr */
162 -1, /* %fpsr */
163 -1 /* %fpiaddr */
164};
165
8de307e0
AS
166/* From <asm/ucontext.h>. */
167static int m68k_linux_ucontext_reg_offset[M68K_NUM_REGS] =
168{
169 6 * 4, /* %d0 */
170 7 * 4, /* %d1 */
171 8 * 4, /* %d2 */
172 9 * 4, /* %d3 */
173 10 * 4, /* %d4 */
174 11 * 4, /* %d5 */
175 12 * 4, /* %d6 */
176 13 * 4, /* %d7 */
177 14 * 4, /* %a0 */
178 15 * 4, /* %a1 */
179 16 * 4, /* %a2 */
180 17 * 4, /* %a3 */
181 18 * 4, /* %a4 */
182 19 * 4, /* %a5 */
183 20 * 4, /* %fp */
184 21 * 4, /* %sp */
185 23 * 4, /* %sr */
186 22 * 4, /* %pc */
187 27 * 4, /* %fp0 */
188 30 * 4, /* %fp1 */
189 33 * 4, /* %fp2 */
190 36 * 4, /* %fp3 */
191 39 * 4, /* %fp4 */
192 42 * 4, /* %fp5 */
193 45 * 4, /* %fp6 */
194 48 * 4, /* %fp7 */
195 24 * 4, /* %fpcr */
196 25 * 4, /* %fpsr */
197 26 * 4 /* %fpiaddr */
198};
199
200
201/* Get info about saved registers in sigtramp. */
202
17e20bce
AC
203struct m68k_linux_sigtramp_info
204{
205 /* Address of sigcontext. */
206 CORE_ADDR sigcontext_addr;
207
208 /* Offset of registers in `struct sigcontext'. */
209 int *sc_reg_offset;
210};
211
0ebdb728
MS
212/* Nonzero if running on uClinux. */
213static int target_is_uclinux;
214
215static void
216m68k_linux_inferior_created (struct target_ops *objfile, int from_tty)
217{
e9efe249
UW
218 /* Record that we will need to re-evaluate whether we are running on a
219 uClinux or normal GNU/Linux target (see m68k_linux_get_sigtramp_info). */
0ebdb728
MS
220 target_is_uclinux = -1;
221}
222
17e20bce 223static struct m68k_linux_sigtramp_info
f36bf22c 224m68k_linux_get_sigtramp_info (struct frame_info *this_frame)
8de307e0 225{
e17a4113
UW
226 struct gdbarch *gdbarch = get_frame_arch (this_frame);
227 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
8de307e0 228 CORE_ADDR sp;
17e20bce 229 struct m68k_linux_sigtramp_info info;
8de307e0 230
c01cbb3d
YQ
231 /* Determine whether we are running on a uClinux or normal GNU/Linux
232 target so we can use the correct sigcontext layouts. */
0ebdb728 233 if (target_is_uclinux == -1)
c01cbb3d 234 target_is_uclinux = linux_is_uclinux ();
0ebdb728 235
f36bf22c 236 sp = get_frame_register_unsigned (this_frame, M68K_SP_REGNUM);
0a595803
AS
237
238 /* Get sigcontext address, it is the third parameter on the stack. */
e17a4113 239 info.sigcontext_addr = read_memory_unsigned_integer (sp + 8, 4, byte_order);
8de307e0 240
f36bf22c 241 if (m68k_linux_pc_in_sigtramp (this_frame) == 2)
8de307e0 242 info.sc_reg_offset = m68k_linux_ucontext_reg_offset;
0a595803 243 else
f36bf22c
AS
244 info.sc_reg_offset = (target_is_uclinux
245 ? m68k_uclinux_sigcontext_reg_offset
246 : m68k_linux_sigcontext_reg_offset);
8de307e0 247 return info;
0a595803
AS
248}
249
17e20bce
AC
250/* Signal trampolines. */
251
252static struct trad_frame_cache *
f36bf22c 253m68k_linux_sigtramp_frame_cache (struct frame_info *this_frame,
17e20bce
AC
254 void **this_cache)
255{
256 struct frame_id this_id;
257 struct trad_frame_cache *cache;
e17a4113
UW
258 struct gdbarch *gdbarch = get_frame_arch (this_frame);
259 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
260 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
17e20bce 261 struct m68k_linux_sigtramp_info info;
f36bf22c 262 gdb_byte buf[4];
17e20bce
AC
263 int i;
264
265 if (*this_cache)
266 return *this_cache;
267
f36bf22c 268 cache = trad_frame_cache_zalloc (this_frame);
17e20bce
AC
269
270 /* FIXME: cagney/2004-05-01: This is is long standing broken code.
271 The frame ID's code address should be the start-address of the
272 signal trampoline and not the current PC within that
273 trampoline. */
f36bf22c 274 get_frame_register (this_frame, M68K_SP_REGNUM, buf);
17e20bce 275 /* See the end of m68k_push_dummy_call. */
e17a4113
UW
276 this_id = frame_id_build (extract_unsigned_integer (buf, 4, byte_order)
277 - 4 + 8, get_frame_pc (this_frame));
17e20bce
AC
278 trad_frame_set_id (cache, this_id);
279
f36bf22c 280 info = m68k_linux_get_sigtramp_info (this_frame);
17e20bce
AC
281
282 for (i = 0; i < M68K_NUM_REGS; i++)
283 if (info.sc_reg_offset[i] != -1)
284 trad_frame_set_reg_addr (cache, i,
285 info.sigcontext_addr + info.sc_reg_offset[i]);
286
287 *this_cache = cache;
288 return cache;
289}
290
291static void
f36bf22c 292m68k_linux_sigtramp_frame_this_id (struct frame_info *this_frame,
17e20bce
AC
293 void **this_cache,
294 struct frame_id *this_id)
295{
296 struct trad_frame_cache *cache =
f36bf22c 297 m68k_linux_sigtramp_frame_cache (this_frame, this_cache);
17e20bce
AC
298 trad_frame_get_id (cache, this_id);
299}
300
f36bf22c
AS
301static struct value *
302m68k_linux_sigtramp_frame_prev_register (struct frame_info *this_frame,
17e20bce 303 void **this_cache,
f36bf22c 304 int regnum)
17e20bce
AC
305{
306 /* Make sure we've initialized the cache. */
307 struct trad_frame_cache *cache =
f36bf22c
AS
308 m68k_linux_sigtramp_frame_cache (this_frame, this_cache);
309 return trad_frame_get_register (cache, this_frame, regnum);
310}
311
312static int
313m68k_linux_sigtramp_frame_sniffer (const struct frame_unwind *self,
314 struct frame_info *this_frame,
315 void **this_prologue_cache)
316{
317 return m68k_linux_pc_in_sigtramp (this_frame);
17e20bce
AC
318}
319
320static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
321{
322 SIGTRAMP_FRAME,
8fbca658 323 default_frame_unwind_stop_reason,
17e20bce 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
08f9f542
AA
330/* Register maps for supply/collect regset functions. */
331
332static const struct regcache_map_entry m68k_linux_gregmap[] =
333 {
334 { 7, M68K_D1_REGNUM, 4 }, /* d1 ... d7 */
335 { 7, M68K_A0_REGNUM, 4 }, /* a0 ... a6 */
336 { 1, M68K_D0_REGNUM, 4 },
337 { 1, M68K_SP_REGNUM, 4 },
338 { 1, REGCACHE_MAP_SKIP, 4 }, /* orig_d0 (skip) */
339 { 1, M68K_PS_REGNUM, 4 },
340 { 1, M68K_PC_REGNUM, 4 },
341 /* Ignore 16-bit fields 'fmtvec' and '__fill'. */
342 { 0 }
343 };
344
345#define M68K_LINUX_GREGS_SIZE (20 * 4)
346
347static const struct regcache_map_entry m68k_linux_fpregmap[] =
348 {
349 { 8, M68K_FP0_REGNUM, 12 }, /* fp0 ... fp7 */
350 { 1, M68K_FPC_REGNUM, 4 },
351 { 1, M68K_FPS_REGNUM, 4 },
352 { 1, M68K_FPI_REGNUM, 4 },
353 { 0 }
354 };
355
356#define M68K_LINUX_FPREGS_SIZE (27 * 4)
357
358/* Register sets. */
359
360static const struct regset m68k_linux_gregset =
361 {
362 m68k_linux_gregmap,
363 regcache_supply_regset, regcache_collect_regset
364 };
365
366static const struct regset m68k_linux_fpregset =
367 {
368 m68k_linux_fpregmap,
369 regcache_supply_regset, regcache_collect_regset
370 };
371
372/* Return the appropriate register set for the core section identified
373 by SECT_NAME and SECT_SIZE. */
374
375static const struct regset *
376m68k_linux_regset_from_core_section (struct gdbarch *gdbarch,
377 const char *sect_name,
378 size_t sect_size)
379{
380 if (strcmp (sect_name, ".reg") == 0
381 && sect_size >= M68K_LINUX_GREGS_SIZE)
382 return &m68k_linux_gregset;
383
384 if (strcmp (sect_name, ".reg2") == 0
385 && sect_size >= M68K_LINUX_FPREGS_SIZE)
386 return &m68k_linux_fpregset;
387
388 return NULL;
389}
390
55809acb
AS
391static void
392m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
393{
eb2e12d7
AS
394 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
395
a5ee0f0c
PA
396 linux_init_abi (info, gdbarch);
397
eb2e12d7
AS
398 tdep->jb_pc = M68K_LINUX_JB_PC;
399 tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
400
f595cb19 401 /* GNU/Linux uses a calling convention that's similar to SVR4. It
8d3239d5 402 returns integer values in %d0/%d1, pointer values in %a0 and
f595cb19
MK
403 floating values in %fp0, just like SVR4, but uses %a1 to pass the
404 address to store a structure value. It also returns small
405 structures in registers instead of memory. */
406 m68k_svr4_init_abi (info, gdbarch);
407 tdep->struct_value_regnum = M68K_A1_REGNUM;
408 tdep->struct_return = reg_struct_return;
eb2e12d7 409
9418f048
UW
410 set_gdbarch_decr_pc_after_break (gdbarch, 2);
411
f36bf22c 412 frame_unwind_append_unwinder (gdbarch, &m68k_linux_sigtramp_frame_unwind);
eb2e12d7
AS
413
414 /* Shared library handling. */
fefa1888
AS
415
416 /* GNU/Linux uses SVR4-style shared libraries. */
417 set_solib_svr4_fetch_link_map_offsets (gdbarch,
418 svr4_ilp32_fetch_link_map_offsets);
419
420 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
421 set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
422
eb2e12d7 423 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
b2756930 424
08f9f542
AA
425 /* Core file support. */
426 set_gdbarch_regset_from_core_section
427 (gdbarch, m68k_linux_regset_from_core_section);
428
b2756930
KB
429 /* Enable TLS support. */
430 set_gdbarch_fetch_tls_load_module_address (gdbarch,
431 svr4_fetch_objfile_link_map);
007cafee
AS
432
433 set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
55809acb
AS
434}
435
63807e1d
PA
436/* Provide a prototype to silence -Wmissing-prototypes. */
437extern initialize_file_ftype _initialize_m68k_linux_tdep;
438
55809acb
AS
439void
440_initialize_m68k_linux_tdep (void)
441{
442 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_LINUX,
443 m68k_linux_init_abi);
0ebdb728 444 observer_attach_inferior_created (m68k_linux_inferior_created);
55809acb 445}