]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/m68k-linux-tdep.c
sim: bfin: initial bf60x support
[thirdparty/binutils-gdb.git] / gdb / m68k-linux-tdep.c
CommitLineData
0a595803
AS
1/* Motorola m68k target-dependent support for GNU/Linux.
2
213516ef 3 Copyright (C) 1996-2023 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"
22#include "frame.h"
23#include "target.h"
d0b45d99 24#include "gdbtypes.h"
55809acb 25#include "osabi.h"
eb2e12d7
AS
26#include "regcache.h"
27#include "objfiles.h"
28#include "symtab.h"
d0b45d99 29#include "m68k-tdep.h"
17e20bce
AC
30#include "trad-frame.h"
31#include "frame-unwind.h"
fefa1888
AS
32#include "glibc-tdep.h"
33#include "solib-svr4.h"
0ebdb728 34#include "auxv.h"
76727919 35#include "observable.h"
0ebdb728 36#include "elf/common.h"
a5ee0f0c 37#include "linux-tdep.h"
08f9f542 38#include "regset.h"
0a595803 39\f
eb2e12d7
AS
40/* Offsets (in target ints) into jmp_buf. */
41
42#define M68K_LINUX_JB_ELEMENT_SIZE 4
43#define M68K_LINUX_JB_PC 7
44
0a595803
AS
45/* Check whether insn1 and insn2 are parts of a signal trampoline. */
46
47#define IS_SIGTRAMP(insn1, insn2) \
48 (/* addaw #20,sp; moveq #119,d0; trap #0 */ \
49 (insn1 == 0xdefc0014 && insn2 == 0x70774e40) \
50 /* moveq #119,d0; trap #0 */ \
51 || insn1 == 0x70774e40)
52
53#define IS_RT_SIGTRAMP(insn1, insn2) \
54 (/* movel #173,d0; trap #0 */ \
55 (insn1 == 0x203c0000 && insn2 == 0x00ad4e40) \
56 /* moveq #82,d0; notb d0; trap #0 */ \
57 || (insn1 == 0x70524600 && (insn2 >> 16) == 0x4e40))
58
f36bf22c
AS
59/* Return non-zero if THIS_FRAME corresponds to a signal trampoline. For
60 the sake of m68k_linux_get_sigtramp_info we also distinguish between
8de307e0 61 non-RT and RT signal trampolines. */
0a595803 62
eb2e12d7 63static int
bd2b40ac 64m68k_linux_pc_in_sigtramp (frame_info_ptr this_frame)
0a595803 65{
e17a4113
UW
66 struct gdbarch *gdbarch = get_frame_arch (this_frame);
67 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
f36bf22c 68 gdb_byte buf[12];
0a595803 69 unsigned long insn0, insn1, insn2;
f36bf22c 70 CORE_ADDR pc = get_frame_pc (this_frame);
0a595803 71
bdec2917 72 if (!safe_frame_unwind_memory (this_frame, pc - 4, {buf, sizeof (buf)}))
0a595803 73 return 0;
e17a4113
UW
74 insn1 = extract_unsigned_integer (buf + 4, 4, byte_order);
75 insn2 = extract_unsigned_integer (buf + 8, 4, byte_order);
0a595803
AS
76 if (IS_SIGTRAMP (insn1, insn2))
77 return 1;
78 if (IS_RT_SIGTRAMP (insn1, insn2))
79 return 2;
80
e17a4113 81 insn0 = extract_unsigned_integer (buf, 4, byte_order);
0a595803
AS
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
a0ff652f 214m68k_linux_inferior_created (inferior *inf)
0ebdb728 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
bd2b40ac 222m68k_linux_get_sigtramp_info (frame_info_ptr this_frame)
8de307e0 223{
e17a4113
UW
224 struct gdbarch *gdbarch = get_frame_arch (this_frame);
225 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
8de307e0 226 CORE_ADDR sp;
17e20bce 227 struct m68k_linux_sigtramp_info info;
8de307e0 228
c01cbb3d
YQ
229 /* Determine whether we are running on a uClinux or normal GNU/Linux
230 target so we can use the correct sigcontext layouts. */
0ebdb728 231 if (target_is_uclinux == -1)
c01cbb3d 232 target_is_uclinux = linux_is_uclinux ();
0ebdb728 233
f36bf22c 234 sp = get_frame_register_unsigned (this_frame, M68K_SP_REGNUM);
0a595803
AS
235
236 /* Get sigcontext address, it is the third parameter on the stack. */
e17a4113 237 info.sigcontext_addr = read_memory_unsigned_integer (sp + 8, 4, byte_order);
8de307e0 238
f36bf22c 239 if (m68k_linux_pc_in_sigtramp (this_frame) == 2)
8de307e0 240 info.sc_reg_offset = m68k_linux_ucontext_reg_offset;
0a595803 241 else
f36bf22c
AS
242 info.sc_reg_offset = (target_is_uclinux
243 ? m68k_uclinux_sigcontext_reg_offset
244 : m68k_linux_sigcontext_reg_offset);
8de307e0 245 return info;
0a595803
AS
246}
247
17e20bce
AC
248/* Signal trampolines. */
249
250static struct trad_frame_cache *
bd2b40ac 251m68k_linux_sigtramp_frame_cache (frame_info_ptr this_frame,
17e20bce
AC
252 void **this_cache)
253{
254 struct frame_id this_id;
255 struct trad_frame_cache *cache;
e17a4113 256 struct gdbarch *gdbarch = get_frame_arch (this_frame);
e17a4113 257 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
17e20bce 258 struct m68k_linux_sigtramp_info info;
f36bf22c 259 gdb_byte buf[4];
17e20bce
AC
260 int i;
261
262 if (*this_cache)
9a3c8263 263 return (struct trad_frame_cache *) *this_cache;
17e20bce 264
f36bf22c 265 cache = trad_frame_cache_zalloc (this_frame);
17e20bce
AC
266
267 /* FIXME: cagney/2004-05-01: This is is long standing broken code.
268 The frame ID's code address should be the start-address of the
269 signal trampoline and not the current PC within that
270 trampoline. */
f36bf22c 271 get_frame_register (this_frame, M68K_SP_REGNUM, buf);
17e20bce 272 /* See the end of m68k_push_dummy_call. */
e17a4113
UW
273 this_id = frame_id_build (extract_unsigned_integer (buf, 4, byte_order)
274 - 4 + 8, get_frame_pc (this_frame));
17e20bce
AC
275 trad_frame_set_id (cache, this_id);
276
f36bf22c 277 info = m68k_linux_get_sigtramp_info (this_frame);
17e20bce
AC
278
279 for (i = 0; i < M68K_NUM_REGS; i++)
280 if (info.sc_reg_offset[i] != -1)
281 trad_frame_set_reg_addr (cache, i,
282 info.sigcontext_addr + info.sc_reg_offset[i]);
283
284 *this_cache = cache;
285 return cache;
286}
287
288static void
bd2b40ac 289m68k_linux_sigtramp_frame_this_id (frame_info_ptr this_frame,
17e20bce
AC
290 void **this_cache,
291 struct frame_id *this_id)
292{
293 struct trad_frame_cache *cache =
f36bf22c 294 m68k_linux_sigtramp_frame_cache (this_frame, this_cache);
17e20bce
AC
295 trad_frame_get_id (cache, this_id);
296}
297
f36bf22c 298static struct value *
bd2b40ac 299m68k_linux_sigtramp_frame_prev_register (frame_info_ptr this_frame,
17e20bce 300 void **this_cache,
f36bf22c 301 int regnum)
17e20bce
AC
302{
303 /* Make sure we've initialized the cache. */
304 struct trad_frame_cache *cache =
f36bf22c
AS
305 m68k_linux_sigtramp_frame_cache (this_frame, this_cache);
306 return trad_frame_get_register (cache, this_frame, regnum);
307}
308
309static int
310m68k_linux_sigtramp_frame_sniffer (const struct frame_unwind *self,
bd2b40ac 311 frame_info_ptr this_frame,
f36bf22c
AS
312 void **this_prologue_cache)
313{
314 return m68k_linux_pc_in_sigtramp (this_frame);
17e20bce
AC
315}
316
317static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
318{
a154d838 319 "m68k linux sigtramp",
17e20bce 320 SIGTRAMP_FRAME,
8fbca658 321 default_frame_unwind_stop_reason,
17e20bce 322 m68k_linux_sigtramp_frame_this_id,
f36bf22c
AS
323 m68k_linux_sigtramp_frame_prev_register,
324 NULL,
325 m68k_linux_sigtramp_frame_sniffer
17e20bce
AC
326};
327
08f9f542
AA
328/* Register maps for supply/collect regset functions. */
329
330static const struct regcache_map_entry m68k_linux_gregmap[] =
331 {
332 { 7, M68K_D1_REGNUM, 4 }, /* d1 ... d7 */
333 { 7, M68K_A0_REGNUM, 4 }, /* a0 ... a6 */
334 { 1, M68K_D0_REGNUM, 4 },
335 { 1, M68K_SP_REGNUM, 4 },
336 { 1, REGCACHE_MAP_SKIP, 4 }, /* orig_d0 (skip) */
337 { 1, M68K_PS_REGNUM, 4 },
338 { 1, M68K_PC_REGNUM, 4 },
339 /* Ignore 16-bit fields 'fmtvec' and '__fill'. */
340 { 0 }
341 };
342
343#define M68K_LINUX_GREGS_SIZE (20 * 4)
344
345static const struct regcache_map_entry m68k_linux_fpregmap[] =
346 {
347 { 8, M68K_FP0_REGNUM, 12 }, /* fp0 ... fp7 */
348 { 1, M68K_FPC_REGNUM, 4 },
349 { 1, M68K_FPS_REGNUM, 4 },
350 { 1, M68K_FPI_REGNUM, 4 },
351 { 0 }
352 };
353
354#define M68K_LINUX_FPREGS_SIZE (27 * 4)
355
356/* Register sets. */
357
358static const struct regset m68k_linux_gregset =
359 {
360 m68k_linux_gregmap,
361 regcache_supply_regset, regcache_collect_regset
362 };
363
364static const struct regset m68k_linux_fpregset =
365 {
366 m68k_linux_fpregmap,
367 regcache_supply_regset, regcache_collect_regset
368 };
369
022c98ab 370/* Iterate over core file register note sections. */
08f9f542 371
022c98ab
AA
372static void
373m68k_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
374 iterate_over_regset_sections_cb *cb,
375 void *cb_data,
376 const struct regcache *regcache)
08f9f542 377{
a616bb94
AH
378 cb (".reg", M68K_LINUX_GREGS_SIZE, M68K_LINUX_GREGS_SIZE, &m68k_linux_gregset,
379 NULL, cb_data);
380 cb (".reg2", M68K_LINUX_FPREGS_SIZE, M68K_LINUX_FPREGS_SIZE,
381 &m68k_linux_fpregset, NULL, cb_data);
08f9f542
AA
382}
383
55809acb
AS
384static void
385m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
386{
08106042 387 m68k_gdbarch_tdep *tdep = gdbarch_tdep<m68k_gdbarch_tdep> (gdbarch);
eb2e12d7 388
480af54c 389 linux_init_abi (info, gdbarch, 0);
a5ee0f0c 390
eb2e12d7
AS
391 tdep->jb_pc = M68K_LINUX_JB_PC;
392 tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
393
f595cb19 394 /* GNU/Linux uses a calling convention that's similar to SVR4. It
8d3239d5 395 returns integer values in %d0/%d1, pointer values in %a0 and
f595cb19
MK
396 floating values in %fp0, just like SVR4, but uses %a1 to pass the
397 address to store a structure value. It also returns small
398 structures in registers instead of memory. */
399 m68k_svr4_init_abi (info, gdbarch);
400 tdep->struct_value_regnum = M68K_A1_REGNUM;
401 tdep->struct_return = reg_struct_return;
eb2e12d7 402
9418f048
UW
403 set_gdbarch_decr_pc_after_break (gdbarch, 2);
404
f36bf22c 405 frame_unwind_append_unwinder (gdbarch, &m68k_linux_sigtramp_frame_unwind);
eb2e12d7
AS
406
407 /* Shared library handling. */
fefa1888
AS
408
409 /* GNU/Linux uses SVR4-style shared libraries. */
410 set_solib_svr4_fetch_link_map_offsets (gdbarch,
c0154a4a 411 linux_ilp32_fetch_link_map_offsets);
fefa1888
AS
412
413 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
414 set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
415
eb2e12d7 416 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
b2756930 417
08f9f542 418 /* Core file support. */
022c98ab
AA
419 set_gdbarch_iterate_over_regset_sections
420 (gdbarch, m68k_linux_iterate_over_regset_sections);
08f9f542 421
b2756930
KB
422 /* Enable TLS support. */
423 set_gdbarch_fetch_tls_load_module_address (gdbarch,
dda83cd7 424 svr4_fetch_objfile_link_map);
55809acb
AS
425}
426
6c265988 427void _initialize_m68k_linux_tdep ();
55809acb 428void
6c265988 429_initialize_m68k_linux_tdep ()
55809acb
AS
430{
431 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_LINUX,
432 m68k_linux_init_abi);
c90e7d63
SM
433 gdb::observers::inferior_created.attach (m68k_linux_inferior_created,
434 "m68k-linux-tdep");
55809acb 435}