xref: /openbsd-src/gnu/usr.bin/binutils/gdb/m68klinux-tdep.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
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