1b725ae77Skettenis /* Motorola m68k target-dependent support for GNU/Linux.
2b725ae77Skettenis
3*11efff7fSkettenis Copyright 1996, 1998, 2000, 2001, 2002, 2003, 2004
4*11efff7fSkettenis Free Software Foundation, Inc.
5b725ae77Skettenis
6b725ae77Skettenis This file is part of GDB.
7b725ae77Skettenis
8b725ae77Skettenis This program is free software; you can redistribute it and/or modify
9b725ae77Skettenis it under the terms of the GNU General Public License as published by
10b725ae77Skettenis the Free Software Foundation; either version 2 of the License, or
11b725ae77Skettenis (at your option) any later version.
12b725ae77Skettenis
13b725ae77Skettenis This program is distributed in the hope that it will be useful,
14b725ae77Skettenis but WITHOUT ANY WARRANTY; without even the implied warranty of
15b725ae77Skettenis MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16b725ae77Skettenis GNU General Public License for more details.
17b725ae77Skettenis
18b725ae77Skettenis You should have received a copy of the GNU General Public License
19b725ae77Skettenis along with this program; if not, write to the Free Software
20b725ae77Skettenis Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis Boston, MA 02111-1307, USA. */
22b725ae77Skettenis
23b725ae77Skettenis #include "defs.h"
24b725ae77Skettenis #include "gdbcore.h"
25b725ae77Skettenis #include "doublest.h"
26b725ae77Skettenis #include "floatformat.h"
27b725ae77Skettenis #include "frame.h"
28b725ae77Skettenis #include "target.h"
29b725ae77Skettenis #include "gdb_string.h"
30b725ae77Skettenis #include "gdbtypes.h"
31b725ae77Skettenis #include "osabi.h"
32b725ae77Skettenis #include "regcache.h"
33b725ae77Skettenis #include "objfiles.h"
34b725ae77Skettenis #include "symtab.h"
35b725ae77Skettenis #include "m68k-tdep.h"
36*11efff7fSkettenis #include "trad-frame.h"
37*11efff7fSkettenis #include "frame-unwind.h"
38b725ae77Skettenis
39b725ae77Skettenis /* Offsets (in target ints) into jmp_buf. */
40b725ae77Skettenis
41b725ae77Skettenis #define M68K_LINUX_JB_ELEMENT_SIZE 4
42b725ae77Skettenis #define M68K_LINUX_JB_PC 7
43b725ae77Skettenis
44b725ae77Skettenis /* Check whether insn1 and insn2 are parts of a signal trampoline. */
45b725ae77Skettenis
46b725ae77Skettenis #define IS_SIGTRAMP(insn1, insn2) \
47b725ae77Skettenis (/* addaw #20,sp; moveq #119,d0; trap #0 */ \
48b725ae77Skettenis (insn1 == 0xdefc0014 && insn2 == 0x70774e40) \
49b725ae77Skettenis /* moveq #119,d0; trap #0 */ \
50b725ae77Skettenis || insn1 == 0x70774e40)
51b725ae77Skettenis
52b725ae77Skettenis #define IS_RT_SIGTRAMP(insn1, insn2) \
53b725ae77Skettenis (/* movel #173,d0; trap #0 */ \
54b725ae77Skettenis (insn1 == 0x203c0000 && insn2 == 0x00ad4e40) \
55b725ae77Skettenis /* moveq #82,d0; notb d0; trap #0 */ \
56b725ae77Skettenis || (insn1 == 0x70524600 && (insn2 >> 16) == 0x4e40))
57b725ae77Skettenis
58b725ae77Skettenis /* Return non-zero if PC points into the signal trampoline. For the
59b725ae77Skettenis sake of m68k_linux_get_sigtramp_info we also distinguish between
60b725ae77Skettenis non-RT and RT signal trampolines. */
61b725ae77Skettenis
62b725ae77Skettenis static int
m68k_linux_pc_in_sigtramp(CORE_ADDR pc,char * name)63b725ae77Skettenis m68k_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
64b725ae77Skettenis {
65b725ae77Skettenis CORE_ADDR sp;
66b725ae77Skettenis char buf[12];
67b725ae77Skettenis unsigned long insn0, insn1, insn2;
68b725ae77Skettenis
69*11efff7fSkettenis if (deprecated_read_memory_nobpt (pc - 4, buf, sizeof (buf)))
70b725ae77Skettenis return 0;
71b725ae77Skettenis insn1 = extract_unsigned_integer (buf + 4, 4);
72b725ae77Skettenis insn2 = extract_unsigned_integer (buf + 8, 4);
73b725ae77Skettenis if (IS_SIGTRAMP (insn1, insn2))
74b725ae77Skettenis return 1;
75b725ae77Skettenis if (IS_RT_SIGTRAMP (insn1, insn2))
76b725ae77Skettenis return 2;
77b725ae77Skettenis
78b725ae77Skettenis insn0 = extract_unsigned_integer (buf, 4);
79b725ae77Skettenis if (IS_SIGTRAMP (insn0, insn1))
80b725ae77Skettenis return 1;
81b725ae77Skettenis if (IS_RT_SIGTRAMP (insn0, insn1))
82b725ae77Skettenis return 2;
83b725ae77Skettenis
84b725ae77Skettenis insn0 = ((insn0 << 16) & 0xffffffff) | (insn1 >> 16);
85b725ae77Skettenis insn1 = ((insn1 << 16) & 0xffffffff) | (insn2 >> 16);
86b725ae77Skettenis if (IS_SIGTRAMP (insn0, insn1))
87b725ae77Skettenis return 1;
88b725ae77Skettenis if (IS_RT_SIGTRAMP (insn0, insn1))
89b725ae77Skettenis return 2;
90b725ae77Skettenis
91b725ae77Skettenis return 0;
92b725ae77Skettenis }
93b725ae77Skettenis
94b725ae77Skettenis /* From <asm/sigcontext.h>. */
95b725ae77Skettenis static int m68k_linux_sigcontext_reg_offset[M68K_NUM_REGS] =
96b725ae77Skettenis {
97b725ae77Skettenis 2 * 4, /* %d0 */
98b725ae77Skettenis 3 * 4, /* %d1 */
99b725ae77Skettenis -1, /* %d2 */
100b725ae77Skettenis -1, /* %d3 */
101b725ae77Skettenis -1, /* %d4 */
102b725ae77Skettenis -1, /* %d5 */
103b725ae77Skettenis -1, /* %d6 */
104b725ae77Skettenis -1, /* %d7 */
105b725ae77Skettenis 4 * 4, /* %a0 */
106b725ae77Skettenis 5 * 4, /* %a1 */
107b725ae77Skettenis -1, /* %a2 */
108b725ae77Skettenis -1, /* %a3 */
109b725ae77Skettenis -1, /* %a4 */
110b725ae77Skettenis -1, /* %a5 */
111b725ae77Skettenis -1, /* %fp */
112b725ae77Skettenis 1 * 4, /* %sp */
113b725ae77Skettenis 5 * 4 + 2, /* %sr */
114b725ae77Skettenis 6 * 4 + 2, /* %pc */
115b725ae77Skettenis 8 * 4, /* %fp0 */
116b725ae77Skettenis 11 * 4, /* %fp1 */
117b725ae77Skettenis -1, /* %fp2 */
118b725ae77Skettenis -1, /* %fp3 */
119b725ae77Skettenis -1, /* %fp4 */
120b725ae77Skettenis -1, /* %fp5 */
121b725ae77Skettenis -1, /* %fp6 */
122b725ae77Skettenis -1, /* %fp7 */
123b725ae77Skettenis 14 * 4, /* %fpcr */
124b725ae77Skettenis 15 * 4, /* %fpsr */
125b725ae77Skettenis 16 * 4 /* %fpiaddr */
126b725ae77Skettenis };
127b725ae77Skettenis
128b725ae77Skettenis /* From <asm/ucontext.h>. */
129b725ae77Skettenis static int m68k_linux_ucontext_reg_offset[M68K_NUM_REGS] =
130b725ae77Skettenis {
131b725ae77Skettenis 6 * 4, /* %d0 */
132b725ae77Skettenis 7 * 4, /* %d1 */
133b725ae77Skettenis 8 * 4, /* %d2 */
134b725ae77Skettenis 9 * 4, /* %d3 */
135b725ae77Skettenis 10 * 4, /* %d4 */
136b725ae77Skettenis 11 * 4, /* %d5 */
137b725ae77Skettenis 12 * 4, /* %d6 */
138b725ae77Skettenis 13 * 4, /* %d7 */
139b725ae77Skettenis 14 * 4, /* %a0 */
140b725ae77Skettenis 15 * 4, /* %a1 */
141b725ae77Skettenis 16 * 4, /* %a2 */
142b725ae77Skettenis 17 * 4, /* %a3 */
143b725ae77Skettenis 18 * 4, /* %a4 */
144b725ae77Skettenis 19 * 4, /* %a5 */
145b725ae77Skettenis 20 * 4, /* %fp */
146b725ae77Skettenis 21 * 4, /* %sp */
147b725ae77Skettenis 23 * 4, /* %sr */
148b725ae77Skettenis 22 * 4, /* %pc */
149b725ae77Skettenis 27 * 4, /* %fp0 */
150b725ae77Skettenis 30 * 4, /* %fp1 */
151b725ae77Skettenis 33 * 4, /* %fp2 */
152b725ae77Skettenis 36 * 4, /* %fp3 */
153b725ae77Skettenis 39 * 4, /* %fp4 */
154b725ae77Skettenis 42 * 4, /* %fp5 */
155b725ae77Skettenis 45 * 4, /* %fp6 */
156b725ae77Skettenis 48 * 4, /* %fp7 */
157b725ae77Skettenis 24 * 4, /* %fpcr */
158b725ae77Skettenis 25 * 4, /* %fpsr */
159b725ae77Skettenis 26 * 4 /* %fpiaddr */
160b725ae77Skettenis };
161b725ae77Skettenis
162b725ae77Skettenis
163b725ae77Skettenis /* Get info about saved registers in sigtramp. */
164b725ae77Skettenis
165*11efff7fSkettenis struct m68k_linux_sigtramp_info
166*11efff7fSkettenis {
167*11efff7fSkettenis /* Address of sigcontext. */
168*11efff7fSkettenis CORE_ADDR sigcontext_addr;
169*11efff7fSkettenis
170*11efff7fSkettenis /* Offset of registers in `struct sigcontext'. */
171*11efff7fSkettenis int *sc_reg_offset;
172*11efff7fSkettenis };
173*11efff7fSkettenis
174*11efff7fSkettenis static struct m68k_linux_sigtramp_info
m68k_linux_get_sigtramp_info(struct frame_info * next_frame)175b725ae77Skettenis m68k_linux_get_sigtramp_info (struct frame_info *next_frame)
176b725ae77Skettenis {
177b725ae77Skettenis CORE_ADDR sp;
178b725ae77Skettenis char buf[4];
179*11efff7fSkettenis struct m68k_linux_sigtramp_info info;
180b725ae77Skettenis
181b725ae77Skettenis frame_unwind_register (next_frame, M68K_SP_REGNUM, buf);
182b725ae77Skettenis sp = extract_unsigned_integer (buf, 4);
183b725ae77Skettenis
184b725ae77Skettenis /* Get sigcontext address, it is the third parameter on the stack. */
185b725ae77Skettenis info.sigcontext_addr = read_memory_unsigned_integer (sp + 8, 4);
186b725ae77Skettenis
187b725ae77Skettenis if (m68k_linux_pc_in_sigtramp (frame_pc_unwind (next_frame), 0) == 2)
188b725ae77Skettenis info.sc_reg_offset = m68k_linux_ucontext_reg_offset;
189b725ae77Skettenis else
190b725ae77Skettenis info.sc_reg_offset = m68k_linux_sigcontext_reg_offset;
191b725ae77Skettenis return info;
192b725ae77Skettenis }
193b725ae77Skettenis
194*11efff7fSkettenis /* Signal trampolines. */
195b725ae77Skettenis
196*11efff7fSkettenis static struct trad_frame_cache *
m68k_linux_sigtramp_frame_cache(struct frame_info * next_frame,void ** this_cache)197*11efff7fSkettenis m68k_linux_sigtramp_frame_cache (struct frame_info *next_frame,
198*11efff7fSkettenis void **this_cache)
199b725ae77Skettenis {
200*11efff7fSkettenis struct frame_id this_id;
201*11efff7fSkettenis struct trad_frame_cache *cache;
202*11efff7fSkettenis struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
203*11efff7fSkettenis struct m68k_linux_sigtramp_info info;
204b725ae77Skettenis char buf[4];
205*11efff7fSkettenis int i;
206b725ae77Skettenis
207*11efff7fSkettenis if (*this_cache)
208*11efff7fSkettenis return *this_cache;
209*11efff7fSkettenis
210*11efff7fSkettenis cache = trad_frame_cache_zalloc (next_frame);
211*11efff7fSkettenis
212*11efff7fSkettenis /* FIXME: cagney/2004-05-01: This is is long standing broken code.
213*11efff7fSkettenis The frame ID's code address should be the start-address of the
214*11efff7fSkettenis signal trampoline and not the current PC within that
215*11efff7fSkettenis trampoline. */
216*11efff7fSkettenis frame_unwind_register (next_frame, M68K_SP_REGNUM, buf);
217*11efff7fSkettenis /* See the end of m68k_push_dummy_call. */
218*11efff7fSkettenis this_id = frame_id_build (extract_unsigned_integer (buf, 4) - 4 + 8,
219*11efff7fSkettenis frame_pc_unwind (next_frame));
220*11efff7fSkettenis trad_frame_set_id (cache, this_id);
221*11efff7fSkettenis
222*11efff7fSkettenis info = m68k_linux_get_sigtramp_info (next_frame);
223*11efff7fSkettenis
224*11efff7fSkettenis for (i = 0; i < M68K_NUM_REGS; i++)
225*11efff7fSkettenis if (info.sc_reg_offset[i] != -1)
226*11efff7fSkettenis trad_frame_set_reg_addr (cache, i,
227*11efff7fSkettenis info.sigcontext_addr + info.sc_reg_offset[i]);
228*11efff7fSkettenis
229*11efff7fSkettenis *this_cache = cache;
230*11efff7fSkettenis return cache;
231*11efff7fSkettenis }
232*11efff7fSkettenis
233*11efff7fSkettenis static void
m68k_linux_sigtramp_frame_this_id(struct frame_info * next_frame,void ** this_cache,struct frame_id * this_id)234*11efff7fSkettenis m68k_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
235*11efff7fSkettenis void **this_cache,
236*11efff7fSkettenis struct frame_id *this_id)
237*11efff7fSkettenis {
238*11efff7fSkettenis struct trad_frame_cache *cache =
239*11efff7fSkettenis m68k_linux_sigtramp_frame_cache (next_frame, this_cache);
240*11efff7fSkettenis trad_frame_get_id (cache, this_id);
241*11efff7fSkettenis }
242*11efff7fSkettenis
243*11efff7fSkettenis static void
m68k_linux_sigtramp_frame_prev_register(struct frame_info * next_frame,void ** this_cache,int regnum,int * optimizedp,enum lval_type * lvalp,CORE_ADDR * addrp,int * realnump,void * valuep)244*11efff7fSkettenis m68k_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
245*11efff7fSkettenis void **this_cache,
246*11efff7fSkettenis int regnum, int *optimizedp,
247*11efff7fSkettenis enum lval_type *lvalp,
248*11efff7fSkettenis CORE_ADDR *addrp,
249*11efff7fSkettenis int *realnump, void *valuep)
250*11efff7fSkettenis {
251*11efff7fSkettenis /* Make sure we've initialized the cache. */
252*11efff7fSkettenis struct trad_frame_cache *cache =
253*11efff7fSkettenis m68k_linux_sigtramp_frame_cache (next_frame, this_cache);
254*11efff7fSkettenis trad_frame_get_register (cache, next_frame, regnum, optimizedp, lvalp,
255*11efff7fSkettenis addrp, realnump, valuep);
256*11efff7fSkettenis }
257*11efff7fSkettenis
258*11efff7fSkettenis static const struct frame_unwind m68k_linux_sigtramp_frame_unwind =
259*11efff7fSkettenis {
260*11efff7fSkettenis SIGTRAMP_FRAME,
261*11efff7fSkettenis m68k_linux_sigtramp_frame_this_id,
262*11efff7fSkettenis m68k_linux_sigtramp_frame_prev_register
263*11efff7fSkettenis };
264*11efff7fSkettenis
265*11efff7fSkettenis static const struct frame_unwind *
m68k_linux_sigtramp_frame_sniffer(struct frame_info * next_frame)266*11efff7fSkettenis m68k_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
267*11efff7fSkettenis {
268*11efff7fSkettenis CORE_ADDR pc = frame_pc_unwind (next_frame);
269*11efff7fSkettenis char *name;
270*11efff7fSkettenis
271*11efff7fSkettenis find_pc_partial_function (pc, &name, NULL, NULL);
272*11efff7fSkettenis if (m68k_linux_pc_in_sigtramp (pc, name))
273*11efff7fSkettenis return &m68k_linux_sigtramp_frame_unwind;
274*11efff7fSkettenis
275*11efff7fSkettenis return NULL;
276b725ae77Skettenis }
277b725ae77Skettenis
278b725ae77Skettenis static void
m68k_linux_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)279b725ae77Skettenis m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
280b725ae77Skettenis {
281b725ae77Skettenis struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
282b725ae77Skettenis
283b725ae77Skettenis tdep->jb_pc = M68K_LINUX_JB_PC;
284b725ae77Skettenis tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
285*11efff7fSkettenis
286*11efff7fSkettenis /* GNU/Linux uses a calling convention that's similar to SVR4. It
287*11efff7fSkettenis returns integer values in %d0/%di, pointer values in %a0 and
288*11efff7fSkettenis floating values in %fp0, just like SVR4, but uses %a1 to pass the
289*11efff7fSkettenis address to store a structure value. It also returns small
290*11efff7fSkettenis structures in registers instead of memory. */
291*11efff7fSkettenis m68k_svr4_init_abi (info, gdbarch);
292*11efff7fSkettenis tdep->struct_value_regnum = M68K_A1_REGNUM;
293b725ae77Skettenis tdep->struct_return = reg_struct_return;
294b725ae77Skettenis
295*11efff7fSkettenis frame_unwind_append_sniffer (gdbarch, m68k_linux_sigtramp_frame_sniffer);
296b725ae77Skettenis
297b725ae77Skettenis /* Shared library handling. */
298b725ae77Skettenis set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
299b725ae77Skettenis set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
300b725ae77Skettenis }
301b725ae77Skettenis
302b725ae77Skettenis void
_initialize_m68k_linux_tdep(void)303b725ae77Skettenis _initialize_m68k_linux_tdep (void)
304b725ae77Skettenis {
305b725ae77Skettenis gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_LINUX,
306b725ae77Skettenis m68k_linux_init_abi);
307b725ae77Skettenis }
308