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