xref: /openbsd-src/gnu/usr.bin/binutils/gdb/sparc-linux-tdep.c (revision 11efff7f3ac2b3cfeff0c0cddc14294d9b3aca4f)
1b725ae77Skettenis /* Target-dependent code for GNU/Linux SPARC.
2b725ae77Skettenis 
3*11efff7fSkettenis    Copyright 2003, 2004 Free Software Foundation, Inc.
4b725ae77Skettenis 
5b725ae77Skettenis    This file is part of GDB.
6b725ae77Skettenis 
7b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
8b725ae77Skettenis    it under the terms of the GNU General Public License as published by
9b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
10b725ae77Skettenis    (at your option) any later version.
11b725ae77Skettenis 
12b725ae77Skettenis    This program is distributed in the hope that it will be useful,
13b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
14b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15b725ae77Skettenis    GNU General Public License for more details.
16b725ae77Skettenis 
17b725ae77Skettenis    You should have received a copy of the GNU General Public License
18b725ae77Skettenis    along with this program; if not, write to the Free Software
19b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
20b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
21b725ae77Skettenis 
22b725ae77Skettenis #include "defs.h"
23b725ae77Skettenis #include "floatformat.h"
24b725ae77Skettenis #include "frame.h"
25b725ae77Skettenis #include "frame-unwind.h"
26b725ae77Skettenis #include "gdbarch.h"
27b725ae77Skettenis #include "gdbcore.h"
28b725ae77Skettenis #include "osabi.h"
29b725ae77Skettenis #include "regcache.h"
30b725ae77Skettenis #include "solib-svr4.h"
31b725ae77Skettenis #include "symtab.h"
32b725ae77Skettenis #include "trad-frame.h"
33b725ae77Skettenis 
34b725ae77Skettenis #include "gdb_assert.h"
35b725ae77Skettenis #include "gdb_string.h"
36b725ae77Skettenis 
37b725ae77Skettenis #include "sparc-tdep.h"
38b725ae77Skettenis 
39b725ae77Skettenis /* Recognizing signal handler frames.  */
40b725ae77Skettenis 
41b725ae77Skettenis /* GNU/Linux has two flavors of signals.  Normal signal handlers, and
42b725ae77Skettenis    "realtime" (RT) signals.  The RT signals can provide additional
43b725ae77Skettenis    information to the signal handler if the SA_SIGINFO flag is set
44b725ae77Skettenis    when establishing a signal handler using `sigaction'.  It is not
45b725ae77Skettenis    unlikely that future versions of GNU/Linux will support SA_SIGINFO
46b725ae77Skettenis    for normal signals too.  */
47b725ae77Skettenis 
48b725ae77Skettenis /* When the sparc Linux kernel calls a signal handler and the
49b725ae77Skettenis    SA_RESTORER flag isn't set, the return address points to a bit of
50b725ae77Skettenis    code on the stack.  This function returns whether the PC appears to
51b725ae77Skettenis    be within this bit of code.
52b725ae77Skettenis 
53b725ae77Skettenis    The instruction sequence for normal signals is
54b725ae77Skettenis 	mov __NR_sigreturn, %g1		! hex: 0x821020d8
55b725ae77Skettenis 	ta  0x10			! hex: 0x91d02010
56b725ae77Skettenis 
57b725ae77Skettenis    Checking for the code sequence should be somewhat reliable, because
58b725ae77Skettenis    the effect is to call the system call sigreturn.  This is unlikely
59b725ae77Skettenis    to occur anywhere other than a signal trampoline.
60b725ae77Skettenis 
61b725ae77Skettenis    It kind of sucks that we have to read memory from the process in
62b725ae77Skettenis    order to identify a signal trampoline, but there doesn't seem to be
63b725ae77Skettenis    any other way.  However, sparc32_linux_pc_in_sigtramp arranges to
64b725ae77Skettenis    only call us if no function name could be identified, which should
65b725ae77Skettenis    be the case since the code is on the stack.  */
66b725ae77Skettenis 
67b725ae77Skettenis #define LINUX32_SIGTRAMP_INSN0	0x821020d8	/* mov __NR_sigreturn, %g1 */
68b725ae77Skettenis #define LINUX32_SIGTRAMP_INSN1	0x91d02010	/* ta  0x10 */
69b725ae77Skettenis 
70b725ae77Skettenis /* The instruction sequence for RT signals is
71b725ae77Skettenis        mov __NR_rt_sigreturn, %g1	! hex: 0x82102065
72b725ae77Skettenis        ta  {0x10,0x6d}			! hex: 0x91d02010 or 0x91d0206d
73b725ae77Skettenis 
74b725ae77Skettenis    The effect is to call the system call rt_sigreturn.  The trap number
75b725ae77Skettenis    is variable based upon whether this is a 32-bit or 64-bit sparc binary.
76b725ae77Skettenis    Note that 64-bit binaries only use this RT signal return method.  */
77b725ae77Skettenis 
78b725ae77Skettenis #define LINUX32_RT_SIGTRAMP_INSN0	0x82102065
79b725ae77Skettenis #define LINUX32_RT_SIGTRAMP_INSN1	0x91d02010
80b725ae77Skettenis 
81b725ae77Skettenis /* If PC is in a sigtramp routine consisting of the instructions INSN0
82b725ae77Skettenis    and INSN1, return the address of the start of the routine.
83b725ae77Skettenis    Otherwise, return 0.  */
84b725ae77Skettenis 
85b725ae77Skettenis CORE_ADDR
sparc_linux_sigtramp_start(struct frame_info * next_frame,ULONGEST insn0,ULONGEST insn1)86*11efff7fSkettenis sparc_linux_sigtramp_start (struct frame_info *next_frame,
87*11efff7fSkettenis 			    ULONGEST insn0, ULONGEST insn1)
88b725ae77Skettenis {
89*11efff7fSkettenis   CORE_ADDR pc = frame_pc_unwind (next_frame);
90b725ae77Skettenis   ULONGEST word0, word1;
91*11efff7fSkettenis   unsigned char buf[8];		/* Two instructions.  */
92b725ae77Skettenis 
93b725ae77Skettenis   /* We only recognize a signal trampoline if PC is at the start of
94b725ae77Skettenis      one of the instructions.  We optimize for finding the PC at the
95b725ae77Skettenis      start of the instruction sequence, as will be the case when the
96b725ae77Skettenis      trampoline is not the first frame on the stack.  We assume that
97b725ae77Skettenis      in the case where the PC is not at the start of the instruction
98b725ae77Skettenis      sequence, there will be a few trailing readable bytes on the
99b725ae77Skettenis      stack.  */
100b725ae77Skettenis 
101*11efff7fSkettenis   if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
102b725ae77Skettenis     return 0;
103b725ae77Skettenis 
104b725ae77Skettenis   word0 = extract_unsigned_integer (buf, 4);
105b725ae77Skettenis   if (word0 != insn0)
106b725ae77Skettenis     {
107b725ae77Skettenis       if (word0 != insn1)
108b725ae77Skettenis 	return 0;
109b725ae77Skettenis 
110b725ae77Skettenis       pc -= 4;
111*11efff7fSkettenis       if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
112b725ae77Skettenis 	return 0;
113b725ae77Skettenis 
114b725ae77Skettenis       word0 = extract_unsigned_integer (buf, 4);
115b725ae77Skettenis     }
116b725ae77Skettenis 
117b725ae77Skettenis   word1 = extract_unsigned_integer (buf + 4, 4);
118b725ae77Skettenis   if (word0 != insn0 || word1 != insn1)
119b725ae77Skettenis     return 0;
120b725ae77Skettenis 
121b725ae77Skettenis   return pc;
122b725ae77Skettenis }
123b725ae77Skettenis 
124b725ae77Skettenis static CORE_ADDR
sparc32_linux_sigtramp_start(struct frame_info * next_frame)125*11efff7fSkettenis sparc32_linux_sigtramp_start (struct frame_info *next_frame)
126b725ae77Skettenis {
127*11efff7fSkettenis   return sparc_linux_sigtramp_start (next_frame, LINUX32_SIGTRAMP_INSN0,
128b725ae77Skettenis 				     LINUX32_SIGTRAMP_INSN1);
129b725ae77Skettenis }
130b725ae77Skettenis 
131b725ae77Skettenis static CORE_ADDR
sparc32_linux_rt_sigtramp_start(struct frame_info * next_frame)132*11efff7fSkettenis sparc32_linux_rt_sigtramp_start (struct frame_info *next_frame)
133b725ae77Skettenis {
134*11efff7fSkettenis   return sparc_linux_sigtramp_start (next_frame, LINUX32_RT_SIGTRAMP_INSN0,
135b725ae77Skettenis 				     LINUX32_RT_SIGTRAMP_INSN1);
136b725ae77Skettenis }
137b725ae77Skettenis 
138b725ae77Skettenis static int
sparc32_linux_sigtramp_p(struct frame_info * next_frame)139*11efff7fSkettenis sparc32_linux_sigtramp_p (struct frame_info *next_frame)
140b725ae77Skettenis {
141*11efff7fSkettenis   CORE_ADDR pc = frame_pc_unwind (next_frame);
142*11efff7fSkettenis   char *name;
143*11efff7fSkettenis 
144*11efff7fSkettenis   find_pc_partial_function (pc, &name, NULL, NULL);
145*11efff7fSkettenis 
146b725ae77Skettenis   /* If we have NAME, we can optimize the search.  The trampolines are
147b725ae77Skettenis      named __restore and __restore_rt.  However, they aren't dynamically
148b725ae77Skettenis      exported from the shared C library, so the trampoline may appear to
149b725ae77Skettenis      be part of the preceding function.  This should always be sigaction,
150b725ae77Skettenis      __sigaction, or __libc_sigaction (all aliases to the same function).  */
151b725ae77Skettenis   if (name == NULL || strstr (name, "sigaction") != NULL)
152*11efff7fSkettenis     return (sparc32_linux_sigtramp_start (next_frame) != 0
153*11efff7fSkettenis 	    || sparc32_linux_rt_sigtramp_start (next_frame) != 0);
154b725ae77Skettenis 
155b725ae77Skettenis   return (strcmp ("__restore", name) == 0
156b725ae77Skettenis 	  || strcmp ("__restore_rt", name) == 0);
157b725ae77Skettenis }
158b725ae77Skettenis 
159b725ae77Skettenis static struct sparc_frame_cache *
sparc32_linux_sigtramp_frame_cache(struct frame_info * next_frame,void ** this_cache)160b725ae77Skettenis sparc32_linux_sigtramp_frame_cache (struct frame_info *next_frame,
161b725ae77Skettenis 				    void **this_cache)
162b725ae77Skettenis {
163b725ae77Skettenis   struct sparc_frame_cache *cache;
164b725ae77Skettenis   CORE_ADDR sigcontext_addr, addr;
165b725ae77Skettenis   int regnum;
166b725ae77Skettenis 
167b725ae77Skettenis   if (*this_cache)
168b725ae77Skettenis     return *this_cache;
169b725ae77Skettenis 
170b725ae77Skettenis   cache = sparc32_frame_cache (next_frame, this_cache);
171b725ae77Skettenis   gdb_assert (cache == *this_cache);
172b725ae77Skettenis 
173b725ae77Skettenis   /* ??? What about signal trampolines that aren't frameless?  */
174b725ae77Skettenis   regnum = SPARC_SP_REGNUM;
175b725ae77Skettenis   cache->base = frame_unwind_register_unsigned (next_frame, regnum);
176b725ae77Skettenis 
177b725ae77Skettenis   regnum = SPARC_O1_REGNUM;
178b725ae77Skettenis   sigcontext_addr = frame_unwind_register_unsigned (next_frame, regnum);
179b725ae77Skettenis 
180*11efff7fSkettenis   addr = sparc32_linux_sigtramp_start (next_frame);
181b725ae77Skettenis   if (addr == 0)
182b725ae77Skettenis     {
183b725ae77Skettenis       /* If this is a RT signal trampoline, adjust SIGCONTEXT_ADDR
184b725ae77Skettenis          accordingly.  */
185*11efff7fSkettenis       addr = sparc32_linux_rt_sigtramp_start (next_frame);
186b725ae77Skettenis       if (addr)
187b725ae77Skettenis 	sigcontext_addr += 128;
188b725ae77Skettenis       else
189b725ae77Skettenis 	addr = frame_func_unwind (next_frame);
190b725ae77Skettenis     }
191b725ae77Skettenis   cache->pc = addr;
192b725ae77Skettenis 
193b725ae77Skettenis   cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
194b725ae77Skettenis 
195b725ae77Skettenis   cache->saved_regs[SPARC32_PSR_REGNUM].addr = sigcontext_addr + 0;
196b725ae77Skettenis   cache->saved_regs[SPARC32_PC_REGNUM].addr = sigcontext_addr + 4;
197b725ae77Skettenis   cache->saved_regs[SPARC32_NPC_REGNUM].addr = sigcontext_addr + 8;
198b725ae77Skettenis   cache->saved_regs[SPARC32_Y_REGNUM].addr = sigcontext_addr + 12;
199b725ae77Skettenis 
200b725ae77Skettenis   /* Since %g0 is always zero, keep the identity encoding.  */
201b725ae77Skettenis   for (regnum = SPARC_G1_REGNUM, addr = sigcontext_addr + 20;
202b725ae77Skettenis        regnum <= SPARC_O7_REGNUM; regnum++, addr += 4)
203b725ae77Skettenis     cache->saved_regs[regnum].addr = addr;
204b725ae77Skettenis 
205b725ae77Skettenis   for (regnum = SPARC_L0_REGNUM, addr = cache->base;
206b725ae77Skettenis        regnum <= SPARC_I7_REGNUM; regnum++, addr += 4)
207b725ae77Skettenis     cache->saved_regs[regnum].addr = addr;
208b725ae77Skettenis 
209b725ae77Skettenis   return cache;
210b725ae77Skettenis }
211b725ae77Skettenis 
212b725ae77Skettenis static void
sparc32_linux_sigtramp_frame_this_id(struct frame_info * next_frame,void ** this_cache,struct frame_id * this_id)213b725ae77Skettenis sparc32_linux_sigtramp_frame_this_id (struct frame_info *next_frame,
214b725ae77Skettenis 				      void **this_cache,
215b725ae77Skettenis 				      struct frame_id *this_id)
216b725ae77Skettenis {
217b725ae77Skettenis   struct sparc_frame_cache *cache =
218b725ae77Skettenis     sparc32_linux_sigtramp_frame_cache (next_frame, this_cache);
219b725ae77Skettenis 
220b725ae77Skettenis   (*this_id) = frame_id_build (cache->base, cache->pc);
221b725ae77Skettenis }
222b725ae77Skettenis 
223b725ae77Skettenis static void
sparc32_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)224b725ae77Skettenis sparc32_linux_sigtramp_frame_prev_register (struct frame_info *next_frame,
225b725ae77Skettenis 					    void **this_cache,
226b725ae77Skettenis 					    int regnum, int *optimizedp,
227b725ae77Skettenis 					    enum lval_type *lvalp,
228b725ae77Skettenis 					    CORE_ADDR *addrp,
229b725ae77Skettenis 					    int *realnump, void *valuep)
230b725ae77Skettenis {
231b725ae77Skettenis   struct sparc_frame_cache *cache =
232b725ae77Skettenis     sparc32_linux_sigtramp_frame_cache (next_frame, this_cache);
233b725ae77Skettenis 
234*11efff7fSkettenis   trad_frame_get_prev_register (next_frame, cache->saved_regs, regnum,
235b725ae77Skettenis 				optimizedp, lvalp, addrp, realnump, valuep);
236b725ae77Skettenis }
237b725ae77Skettenis 
238b725ae77Skettenis static const struct frame_unwind sparc32_linux_sigtramp_frame_unwind =
239b725ae77Skettenis {
240b725ae77Skettenis   SIGTRAMP_FRAME,
241b725ae77Skettenis   sparc32_linux_sigtramp_frame_this_id,
242b725ae77Skettenis   sparc32_linux_sigtramp_frame_prev_register
243b725ae77Skettenis };
244b725ae77Skettenis 
245b725ae77Skettenis static const struct frame_unwind *
sparc32_linux_sigtramp_frame_sniffer(struct frame_info * next_frame)246b725ae77Skettenis sparc32_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
247b725ae77Skettenis {
248*11efff7fSkettenis   if (sparc32_linux_sigtramp_p (next_frame))
249b725ae77Skettenis     return &sparc32_linux_sigtramp_frame_unwind;
250b725ae77Skettenis 
251b725ae77Skettenis   return NULL;
252b725ae77Skettenis }
253b725ae77Skettenis 
254b725ae77Skettenis 
255b725ae77Skettenis static void
sparc32_linux_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)256b725ae77Skettenis sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
257b725ae77Skettenis {
258b725ae77Skettenis   /* GNU/Linux is very similar to Solaris ...  */
259b725ae77Skettenis   sparc32_sol2_init_abi (info, gdbarch);
260b725ae77Skettenis 
261b725ae77Skettenis   /* ... but doesn't have kernel-assisted single-stepping support.  */
262b725ae77Skettenis   set_gdbarch_software_single_step (gdbarch, sparc_software_single_step);
263b725ae77Skettenis 
264b725ae77Skettenis   /* GNU/Linux doesn't support the 128-bit `long double' from the psABI.  */
265b725ae77Skettenis   set_gdbarch_long_double_bit (gdbarch, 64);
266b725ae77Skettenis   set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
267b725ae77Skettenis 
268b725ae77Skettenis   frame_unwind_append_sniffer (gdbarch, sparc32_linux_sigtramp_frame_sniffer);
269b725ae77Skettenis }
270b725ae77Skettenis 
271b725ae77Skettenis /* Provide a prototype to silence -Wmissing-prototypes.  */
272b725ae77Skettenis extern void _initialize_sparc_linux_tdep (void);
273b725ae77Skettenis 
274b725ae77Skettenis void
_initialize_sparc_linux_tdep(void)275b725ae77Skettenis _initialize_sparc_linux_tdep (void)
276b725ae77Skettenis {
277b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_LINUX,
278b725ae77Skettenis 			  sparc32_linux_init_abi);
279b725ae77Skettenis }
280