Add "set print finish"
[deliverable/binutils-gdb.git] / gdb / m68k-linux-tdep.c
CommitLineData
0a595803
AS
1/* Motorola m68k target-dependent support for GNU/Linux.
2
42a4f53d 3 Copyright (C) 1996-2019 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
f36bf22c 64m68k_linux_pc_in_sigtramp (struct frame_info *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
c95f5026 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
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
f36bf22c 222m68k_linux_get_sigtramp_info (struct frame_info *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 *
f36bf22c 251m68k_linux_sigtramp_frame_cache (struct frame_info *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
f36bf22c 289m68k_linux_sigtramp_frame_this_id (struct frame_info *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
AS
298static struct value *
299m68k_linux_sigtramp_frame_prev_register (struct frame_info *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,
311 struct frame_info *this_frame,
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{
319 SIGTRAMP_FRAME,
8fbca658 320 default_frame_unwind_stop_reason,
17e20bce 321 m68k_linux_sigtramp_frame_this_id,
f36bf22c
AS
322 m68k_linux_sigtramp_frame_prev_register,
323 NULL,
324 m68k_linux_sigtramp_frame_sniffer
17e20bce
AC
325};
326
08f9f542
AA
327/* Register maps for supply/collect regset functions. */
328
329static const struct regcache_map_entry m68k_linux_gregmap[] =
330 {
331 { 7, M68K_D1_REGNUM, 4 }, /* d1 ... d7 */
332 { 7, M68K_A0_REGNUM, 4 }, /* a0 ... a6 */
333 { 1, M68K_D0_REGNUM, 4 },
334 { 1, M68K_SP_REGNUM, 4 },
335 { 1, REGCACHE_MAP_SKIP, 4 }, /* orig_d0 (skip) */
336 { 1, M68K_PS_REGNUM, 4 },
337 { 1, M68K_PC_REGNUM, 4 },
338 /* Ignore 16-bit fields 'fmtvec' and '__fill'. */
339 { 0 }
340 };
341
342#define M68K_LINUX_GREGS_SIZE (20 * 4)
343
344static const struct regcache_map_entry m68k_linux_fpregmap[] =
345 {
346 { 8, M68K_FP0_REGNUM, 12 }, /* fp0 ... fp7 */
347 { 1, M68K_FPC_REGNUM, 4 },
348 { 1, M68K_FPS_REGNUM, 4 },
349 { 1, M68K_FPI_REGNUM, 4 },
350 { 0 }
351 };
352
353#define M68K_LINUX_FPREGS_SIZE (27 * 4)
354
355/* Register sets. */
356
357static const struct regset m68k_linux_gregset =
358 {
359 m68k_linux_gregmap,
360 regcache_supply_regset, regcache_collect_regset
361 };
362
363static const struct regset m68k_linux_fpregset =
364 {
365 m68k_linux_fpregmap,
366 regcache_supply_regset, regcache_collect_regset
367 };
368
022c98ab 369/* Iterate over core file register note sections. */
08f9f542 370
022c98ab
AA
371static void
372m68k_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
373 iterate_over_regset_sections_cb *cb,
374 void *cb_data,
375 const struct regcache *regcache)
08f9f542 376{
a616bb94
AH
377 cb (".reg", M68K_LINUX_GREGS_SIZE, M68K_LINUX_GREGS_SIZE, &m68k_linux_gregset,
378 NULL, cb_data);
379 cb (".reg2", M68K_LINUX_FPREGS_SIZE, M68K_LINUX_FPREGS_SIZE,
380 &m68k_linux_fpregset, NULL, cb_data);
08f9f542
AA
381}
382
55809acb
AS
383static void
384m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
385{
eb2e12d7
AS
386 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
387
a5ee0f0c
PA
388 linux_init_abi (info, gdbarch);
389
eb2e12d7
AS
390 tdep->jb_pc = M68K_LINUX_JB_PC;
391 tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
392
f595cb19 393 /* GNU/Linux uses a calling convention that's similar to SVR4. It
8d3239d5 394 returns integer values in %d0/%d1, pointer values in %a0 and
f595cb19
MK
395 floating values in %fp0, just like SVR4, but uses %a1 to pass the
396 address to store a structure value. It also returns small
397 structures in registers instead of memory. */
398 m68k_svr4_init_abi (info, gdbarch);
399 tdep->struct_value_regnum = M68K_A1_REGNUM;
400 tdep->struct_return = reg_struct_return;
eb2e12d7 401
9418f048
UW
402 set_gdbarch_decr_pc_after_break (gdbarch, 2);
403
f36bf22c 404 frame_unwind_append_unwinder (gdbarch, &m68k_linux_sigtramp_frame_unwind);
eb2e12d7
AS
405
406 /* Shared library handling. */
fefa1888
AS
407
408 /* GNU/Linux uses SVR4-style shared libraries. */
409 set_solib_svr4_fetch_link_map_offsets (gdbarch,
410 svr4_ilp32_fetch_link_map_offsets);
411
412 /* GNU/Linux uses the dynamic linker included in the GNU C Library. */
413 set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
414
eb2e12d7 415 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
b2756930 416
08f9f542 417 /* Core file support. */
022c98ab
AA
418 set_gdbarch_iterate_over_regset_sections
419 (gdbarch, m68k_linux_iterate_over_regset_sections);
08f9f542 420
b2756930
KB
421 /* Enable TLS support. */
422 set_gdbarch_fetch_tls_load_module_address (gdbarch,
423 svr4_fetch_objfile_link_map);
55809acb
AS
424}
425
426void
427_initialize_m68k_linux_tdep (void)
428{
429 gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_LINUX,
430 m68k_linux_init_abi);
76727919 431 gdb::observers::inferior_created.attach (m68k_linux_inferior_created);
55809acb 432}
This page took 1.567602 seconds and 4 git commands to generate.