* avr-tdep.c, hppa-tdep.c, hppabsd-tdep.c, i386-tdep.c,
[external/binutils.git] / gdb / sparc-linux-tdep.c
1 /* Target-dependent code for GNU/Linux SPARC.
2
3    Copyright (C) 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
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
9    the Free Software Foundation; either version 2 of the License, or
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
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "defs.h"
23 #include "dwarf2-frame.h"
24 #include "frame.h"
25 #include "frame-unwind.h"
26 #include "gdbtypes.h"
27 #include "regset.h"
28 #include "gdbarch.h"
29 #include "gdbcore.h"
30 #include "osabi.h"
31 #include "regcache.h"
32 #include "solib-svr4.h"
33 #include "symtab.h"
34 #include "trad-frame.h"
35 #include "tramp-frame.h"
36
37 #include "sparc-tdep.h"
38
39 /* Signal trampoline support.  */
40
41 static void sparc32_linux_sigframe_init (const struct tramp_frame *self,
42                                          struct frame_info *next_frame,
43                                          struct trad_frame_cache *this_cache,
44                                          CORE_ADDR func);
45
46 /* GNU/Linux has two flavors of signals.  Normal signal handlers, and
47    "realtime" (RT) signals.  The RT signals can provide additional
48    information to the signal handler if the SA_SIGINFO flag is set
49    when establishing a signal handler using `sigaction'.  It is not
50    unlikely that future versions of GNU/Linux will support SA_SIGINFO
51    for normal signals too.  */
52
53 /* When the sparc Linux kernel calls a signal handler and the
54    SA_RESTORER flag isn't set, the return address points to a bit of
55    code on the stack.  This code checks whether the PC appears to be
56    within this bit of code.
57
58    The instruction sequence for normal signals is encoded below.
59    Checking for the code sequence should be somewhat reliable, because
60    the effect is to call the system call sigreturn.  This is unlikely
61    to occur anywhere other than a signal trampoline.  */
62
63 static const struct tramp_frame sparc32_linux_sigframe =
64 {
65   SIGTRAMP_FRAME,
66   4,
67   {
68     { 0x821020d8, -1 },         /* mov __NR_sugreturn, %g1 */
69     { 0x91d02010, -1 },         /* ta  0x10 */
70     { TRAMP_SENTINEL_INSN, -1 }
71   },
72   sparc32_linux_sigframe_init
73 };
74
75 /* The instruction sequence for RT signals is slightly different.  The
76    effect is to call the system call rt_sigreturn.  */
77
78 static const struct tramp_frame sparc32_linux_rt_sigframe =
79 {
80   SIGTRAMP_FRAME,
81   4,
82   {
83     { 0x82102065, -1 },         /* mov __NR_rt_sigreturn, %g1 */
84     { 0x91d02010, -1 },         /* ta  0x10 */
85     { TRAMP_SENTINEL_INSN, -1 }
86   },
87   sparc32_linux_sigframe_init
88 };
89
90 static void
91 sparc32_linux_sigframe_init (const struct tramp_frame *self,
92                              struct frame_info *next_frame,
93                              struct trad_frame_cache *this_cache,
94                              CORE_ADDR func)
95 {
96   CORE_ADDR base, addr, sp_addr;
97   int regnum;
98
99   base = frame_unwind_register_unsigned (next_frame, SPARC_O1_REGNUM);
100   if (self == &sparc32_linux_rt_sigframe)
101     base += 128;
102
103   /* Offsets from <bits/sigcontext.h>.  */
104
105   trad_frame_set_reg_addr (this_cache, SPARC32_PSR_REGNUM, base + 0);
106   trad_frame_set_reg_addr (this_cache, SPARC32_PC_REGNUM, base + 4);
107   trad_frame_set_reg_addr (this_cache, SPARC32_NPC_REGNUM, base + 8);
108   trad_frame_set_reg_addr (this_cache, SPARC32_Y_REGNUM, base + 12);
109
110   /* Since %g0 is always zero, keep the identity encoding.  */
111   addr = base + 20;
112   sp_addr = base + 16 + ((SPARC_SP_REGNUM - SPARC_G0_REGNUM) * 4);
113   for (regnum = SPARC_G1_REGNUM; regnum <= SPARC_O7_REGNUM; regnum++)
114     {
115       trad_frame_set_reg_addr (this_cache, regnum, addr);
116       addr += 4;
117     }
118
119   base = frame_unwind_register_unsigned (next_frame, SPARC_SP_REGNUM);
120   addr = get_frame_memory_unsigned (next_frame, sp_addr, 4);
121
122   for (regnum = SPARC_L0_REGNUM; regnum <= SPARC_I7_REGNUM; regnum++)
123     {
124       trad_frame_set_reg_addr (this_cache, regnum, addr);
125       addr += 4;
126     }
127   trad_frame_set_id (this_cache, frame_id_build (base, func));
128 }
129 \f
130 /* Return the address of a system call's alternative return
131    address.  */
132
133 static CORE_ADDR
134 sparc32_linux_step_trap (unsigned long insn)
135 {
136   if (insn == 0x91d02010)
137     {
138       ULONGEST sc_num;
139
140       regcache_cooked_read_unsigned (current_regcache,
141                                      SPARC_G1_REGNUM, &sc_num);
142
143       /* __NR_rt_sigreturn is 101 and __NR_sigreturn is 216  */
144       if (sc_num == 101 || sc_num == 216)
145         {
146           ULONGEST sp, pc_offset;
147
148           regcache_cooked_read_unsigned (current_regcache,
149                                          SPARC_SP_REGNUM, &sp);
150
151           /* The kernel puts the sigreturn registers on the stack,
152              and this is where the signal unwinding state is take from
153              when returning from a signal.
154
155              For __NR_sigreturn, this register area sits 96 bytes from
156              the base of the stack.  The saved PC sits 4 bytes into the
157              sigreturn register save area.
158
159              For __NR_rt_sigreturn a siginfo_t, which is 128 bytes, sits
160              right before the sigreturn register save area.  */
161
162           pc_offset = 96 + 4;
163           if (sc_num == 101)
164             pc_offset += 128;
165
166           return read_memory_unsigned_integer (sp + pc_offset, 4);
167         }
168     }
169
170   return 0;
171 }
172 \f
173
174 const struct sparc_gregset sparc32_linux_core_gregset =
175 {
176   32 * 4,                       /* %psr */
177   33 * 4,                       /* %pc */
178   34 * 4,                       /* %npc */
179   35 * 4,                       /* %y */
180   -1,                           /* %wim */
181   -1,                           /* %tbr */
182   1 * 4,                        /* %g1 */
183   16 * 4,                       /* %l0 */
184   4,                            /* y size */
185 };
186 \f
187
188 static void
189 sparc32_linux_supply_core_gregset (const struct regset *regset,
190                                    struct regcache *regcache,
191                                    int regnum, const void *gregs, size_t len)
192 {
193   sparc32_supply_gregset (&sparc32_linux_core_gregset, regcache, regnum, gregs);
194 }
195
196 static void
197 sparc32_linux_collect_core_gregset (const struct regset *regset,
198                                     const struct regcache *regcache,
199                                     int regnum, void *gregs, size_t len)
200 {
201   sparc32_collect_gregset (&sparc32_linux_core_gregset, regcache, regnum, gregs);
202 }
203
204 static void
205 sparc32_linux_supply_core_fpregset (const struct regset *regset,
206                                     struct regcache *regcache,
207                                     int regnum, const void *fpregs, size_t len)
208 {
209   sparc32_supply_fpregset (regcache, regnum, fpregs);
210 }
211
212 static void
213 sparc32_linux_collect_core_fpregset (const struct regset *regset,
214                                      const struct regcache *regcache,
215                                      int regnum, void *fpregs, size_t len)
216 {
217   sparc32_collect_fpregset (regcache, regnum, fpregs);
218 }
219
220 \f
221
222 static void
223 sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
224 {
225   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
226
227   tdep->gregset = regset_alloc (gdbarch, sparc32_linux_supply_core_gregset,
228                                 sparc32_linux_collect_core_gregset);
229   tdep->sizeof_gregset = 152;
230
231   tdep->fpregset = regset_alloc (gdbarch, sparc32_linux_supply_core_fpregset,
232                                  sparc32_linux_collect_core_fpregset);
233   tdep->sizeof_fpregset = 396;
234
235   tramp_frame_prepend_unwinder (gdbarch, &sparc32_linux_sigframe);
236   tramp_frame_prepend_unwinder (gdbarch, &sparc32_linux_rt_sigframe);
237
238   /* GNU/Linux has SVR4-style shared libraries...  */
239   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
240   set_solib_svr4_fetch_link_map_offsets
241     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
242
243   /* ...which means that we need some special handling when doing
244      prologue analysis.  */
245   tdep->plt_entry_size = 12;
246
247   /* GNU/Linux doesn't support the 128-bit `long double' from the psABI.  */
248   set_gdbarch_long_double_bit (gdbarch, 64);
249   set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
250
251   /* Enable TLS support.  */
252   set_gdbarch_fetch_tls_load_module_address (gdbarch,
253                                              svr4_fetch_objfile_link_map);
254
255   /* Make sure we can single-step over signal return system calls.  */
256   tdep->step_trap = sparc32_linux_step_trap;
257
258   /* Hook in the DWARF CFI frame unwinder.  */
259   frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer);
260 }
261
262 /* Provide a prototype to silence -Wmissing-prototypes.  */
263 extern void _initialize_sparc_linux_tdep (void);
264
265 void
266 _initialize_sparc_linux_tdep (void)
267 {
268   gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_LINUX,
269                           sparc32_linux_init_abi);
270 }