Commit | Line | Data |
---|---|---|
9ce5c36a | 1 | /* Target-dependent code for SPARC systems running NetBSD. |
f6ad61e3 | 2 | Copyright 2002, 2003 Free Software Foundation, Inc. |
9ce5c36a JT |
3 | Contributed by Wasabi Systems, 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 "gdbcore.h" | |
24 | #include "regcache.h" | |
25 | #include "target.h" | |
26 | #include "value.h" | |
27 | #include "osabi.h" | |
28 | ||
f6ad61e3 MK |
29 | #include "gdb_string.h" |
30 | ||
9ce5c36a JT |
31 | #include "sparcnbsd-tdep.h" |
32 | #include "nbsd-tdep.h" | |
33 | ||
34 | #include "solib-svr4.h" | |
35 | ||
36 | #define REG32_OFFSET_PSR (0 * 4) | |
37 | #define REG32_OFFSET_PC (1 * 4) | |
38 | #define REG32_OFFSET_NPC (2 * 4) | |
39 | #define REG32_OFFSET_Y (3 * 4) | |
40 | #define REG32_OFFSET_GLOBAL (4 * 4) | |
41 | #define REG32_OFFSET_OUT (12 * 4) | |
42 | ||
43 | #define REG64_OFFSET_TSTATE (0 * 8) | |
44 | #define REG64_OFFSET_PC (1 * 8) | |
45 | #define REG64_OFFSET_NPC (2 * 8) | |
46 | #define REG64_OFFSET_Y (3 * 8) | |
47 | #define REG64_OFFSET_GLOBAL (4 * 8) | |
48 | #define REG64_OFFSET_OUT (12 * 8) | |
49 | ||
50 | void | |
51 | sparcnbsd_supply_reg32 (char *regs, int regno) | |
52 | { | |
53 | int i; | |
54 | ||
55 | if (regno == PS_REGNUM || regno == -1) | |
56 | supply_register (PS_REGNUM, regs + REG32_OFFSET_PSR); | |
57 | ||
58 | if (regno == PC_REGNUM || regno == -1) | |
59 | supply_register (PC_REGNUM, regs + REG32_OFFSET_PC); | |
60 | ||
61 | if (regno == NPC_REGNUM || regno == -1) | |
62 | supply_register (NPC_REGNUM, regs + REG32_OFFSET_NPC); | |
63 | ||
64 | if (regno == Y_REGNUM || regno == -1) | |
65 | supply_register (Y_REGNUM, regs + REG32_OFFSET_Y); | |
66 | ||
67 | if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1) | |
68 | { | |
69 | if (regno == G0_REGNUM || regno == -1) | |
70 | supply_register (G0_REGNUM, NULL); /* %g0 is always zero */ | |
71 | for (i = G1_REGNUM; i <= G7_REGNUM; i++) | |
72 | { | |
73 | if (regno == i || regno == -1) | |
74 | supply_register (i, regs + REG32_OFFSET_GLOBAL + | |
75 | ((i - G0_REGNUM) * 4)); | |
76 | } | |
77 | } | |
78 | ||
79 | if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1) | |
80 | { | |
81 | for (i = O0_REGNUM; i <= O7_REGNUM; i++) | |
82 | { | |
83 | if (regno == i || regno == -1) | |
84 | supply_register (i, regs + REG32_OFFSET_OUT + | |
85 | ((i - O0_REGNUM) * 4)); | |
86 | } | |
87 | } | |
88 | ||
89 | /* Inputs and Locals are stored onto the stack by by the kernel. */ | |
90 | if ((regno >= L0_REGNUM && regno <= I7_REGNUM) || regno == -1) | |
91 | { | |
92 | CORE_ADDR sp = read_register (SP_REGNUM); | |
93 | char buf[4]; | |
94 | ||
95 | for (i = L0_REGNUM; i <= I7_REGNUM; i++) | |
96 | { | |
97 | if (regno == i || regno == -1) | |
98 | { | |
99 | target_read_memory (sp + ((i - L0_REGNUM) * 4), | |
100 | buf, sizeof (buf)); | |
101 | supply_register (i, buf); | |
102 | } | |
103 | } | |
104 | } | |
105 | ||
106 | /* FIXME: If we don't set these valid, read_register_bytes() rereads | |
107 | all the regs every time it is called! */ | |
108 | if (regno == WIM_REGNUM || regno == -1) | |
109 | supply_register (WIM_REGNUM, NULL); | |
110 | if (regno == TBR_REGNUM || regno == -1) | |
111 | supply_register (TBR_REGNUM, NULL); | |
112 | if (regno == CPS_REGNUM || regno == -1) | |
113 | supply_register (CPS_REGNUM, NULL); | |
114 | } | |
115 | ||
116 | void | |
117 | sparcnbsd_supply_reg64 (char *regs, int regno) | |
118 | { | |
119 | int i; | |
120 | char buf[8]; | |
121 | ||
122 | if (regno == TSTATE_REGNUM || regno == -1) | |
123 | supply_register (PS_REGNUM, regs + REG64_OFFSET_TSTATE); | |
124 | ||
125 | if (regno == PC_REGNUM || regno == -1) | |
126 | supply_register (PC_REGNUM, regs + REG64_OFFSET_PC); | |
127 | ||
128 | if (regno == NPC_REGNUM || regno == -1) | |
129 | supply_register (NPC_REGNUM, regs + REG64_OFFSET_NPC); | |
130 | ||
131 | if (regno == Y_REGNUM || regno == -1) | |
132 | { | |
133 | memset (buf, 0, sizeof (buf)); | |
134 | memcpy (&buf[4], regs + REG64_OFFSET_Y, 4); | |
135 | supply_register (Y_REGNUM, buf); | |
136 | } | |
137 | ||
138 | if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1) | |
139 | { | |
140 | if (regno == G0_REGNUM || regno == -1) | |
141 | supply_register (G0_REGNUM, NULL); /* %g0 is always zero */ | |
142 | for (i = G1_REGNUM; i <= G7_REGNUM; i++) | |
143 | { | |
144 | if (regno == i || regno == -1) | |
145 | supply_register (i, regs + REG64_OFFSET_GLOBAL + | |
146 | ((i - G0_REGNUM) * 8)); | |
147 | } | |
148 | } | |
149 | ||
150 | if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1) | |
151 | { | |
152 | for (i = O0_REGNUM; i <= O7_REGNUM; i++) | |
153 | { | |
154 | if (regno == i || regno == -1) | |
155 | supply_register (i, regs + REG64_OFFSET_OUT + | |
156 | ((i - O0_REGNUM) * 8)); | |
157 | } | |
158 | } | |
159 | ||
160 | /* Inputs and Locals are stored onto the stack by by the kernel. */ | |
161 | if ((regno >= L0_REGNUM && regno <= I7_REGNUM) || regno == -1) | |
162 | { | |
163 | CORE_ADDR sp = read_register (SP_REGNUM); | |
164 | char buf[8]; | |
165 | ||
166 | if (sp & 1) | |
167 | { | |
168 | /* Registers are 64-bit. */ | |
169 | sp += 2047; | |
170 | ||
171 | for (i = L0_REGNUM; i <= I7_REGNUM; i++) | |
172 | { | |
173 | if (regno == i || regno == -1) | |
174 | { | |
175 | target_read_memory (sp + ((i - L0_REGNUM) * 8), | |
176 | buf, sizeof (buf)); | |
177 | supply_register (i, buf); | |
178 | } | |
179 | } | |
180 | } | |
181 | else | |
182 | { | |
183 | /* Registers are 32-bit. Toss any sign-extension of the stack | |
184 | pointer, clear out the top half of the temporary buffer, and | |
185 | put the register value in the bottom half. */ | |
186 | ||
187 | sp &= 0xffffffffUL; | |
188 | memset (buf, 0, sizeof (buf)); | |
189 | for (i = L0_REGNUM; i <= I7_REGNUM; i++) | |
190 | { | |
191 | if (regno == i || regno == -1) | |
192 | { | |
193 | target_read_memory (sp + ((i - L0_REGNUM) * 4), | |
194 | &buf[4], sizeof (buf)); | |
195 | supply_register (i, buf); | |
196 | } | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | /* FIXME: If we don't set these valid, read_register_bytes() rereads | |
202 | all the regs every time it is called! */ | |
203 | if (regno == WIM_REGNUM || regno == -1) | |
204 | supply_register (WIM_REGNUM, NULL); | |
205 | if (regno == TBR_REGNUM || regno == -1) | |
206 | supply_register (TBR_REGNUM, NULL); | |
207 | if (regno == CPS_REGNUM || regno == -1) | |
208 | supply_register (CPS_REGNUM, NULL); | |
209 | } | |
210 | ||
211 | void | |
212 | sparcnbsd_fill_reg32 (char *regs, int regno) | |
213 | { | |
214 | int i; | |
215 | ||
216 | if (regno == PS_REGNUM || regno == -1) | |
217 | regcache_collect (PS_REGNUM, regs + REG32_OFFSET_PSR); | |
218 | ||
219 | if (regno == PC_REGNUM || regno == -1) | |
220 | regcache_collect (PC_REGNUM, regs + REG32_OFFSET_PC); | |
221 | ||
222 | if (regno == NPC_REGNUM || regno == -1) | |
223 | regcache_collect (NPC_REGNUM, regs + REG32_OFFSET_NPC); | |
224 | ||
225 | if (regno == Y_REGNUM || regno == -1) | |
226 | regcache_collect (Y_REGNUM, regs + REG32_OFFSET_Y); | |
227 | ||
228 | if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1) | |
229 | { | |
230 | /* %g0 is always zero */ | |
231 | for (i = G1_REGNUM; i <= G7_REGNUM; i++) | |
232 | { | |
233 | if (regno == i || regno == -1) | |
234 | regcache_collect (i, regs + REG32_OFFSET_GLOBAL + | |
235 | ((i - G0_REGNUM) * 4)); | |
236 | } | |
237 | } | |
238 | ||
239 | if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1) | |
240 | { | |
241 | for (i = O0_REGNUM; i <= O7_REGNUM; i++) | |
242 | { | |
243 | if (regno == i || regno == -1) | |
244 | regcache_collect (i, regs + REG32_OFFSET_OUT + | |
245 | ((i - O0_REGNUM) * 4)); | |
246 | } | |
247 | } | |
248 | ||
249 | /* Responsibility for the stack regs is pushed off onto the caller. */ | |
250 | } | |
251 | ||
252 | void | |
253 | sparcnbsd_fill_reg64 (char *regs, int regno) | |
254 | { | |
255 | int i; | |
256 | ||
257 | if (regno == TSTATE_REGNUM || regno == -1) | |
258 | regcache_collect (TSTATE_REGNUM, regs + REG64_OFFSET_TSTATE); | |
259 | ||
260 | if (regno == PC_REGNUM || regno == -1) | |
261 | regcache_collect (PC_REGNUM, regs + REG64_OFFSET_PC); | |
262 | ||
263 | if (regno == NPC_REGNUM || regno == -1) | |
264 | regcache_collect (NPC_REGNUM, regs + REG64_OFFSET_NPC); | |
265 | ||
266 | if (regno == Y_REGNUM || regno == -1) | |
267 | regcache_collect (Y_REGNUM, regs + REG64_OFFSET_Y); | |
268 | ||
269 | if ((regno >= G0_REGNUM && regno <= G7_REGNUM) || regno == -1) | |
270 | { | |
271 | /* %g0 is always zero */ | |
272 | for (i = G1_REGNUM; i <= G7_REGNUM; i++) | |
273 | { | |
274 | if (regno == i || regno == -1) | |
275 | regcache_collect (i, regs + REG64_OFFSET_GLOBAL + | |
276 | ((i - G0_REGNUM) * 4)); | |
277 | } | |
278 | } | |
279 | ||
280 | if ((regno >= O0_REGNUM && regno <= O7_REGNUM) || regno == -1) | |
281 | { | |
282 | for (i = O0_REGNUM; i <= O7_REGNUM; i++) | |
283 | { | |
284 | if (regno == i || regno == -1) | |
285 | regcache_collect (i, regs + REG64_OFFSET_OUT + | |
286 | ((i - O0_REGNUM) * 4)); | |
287 | } | |
288 | } | |
289 | ||
290 | /* Responsibility for the stack regs is pushed off onto the caller. */ | |
291 | } | |
292 | ||
293 | void | |
294 | sparcnbsd_supply_fpreg32 (char *fpregs, int regno) | |
295 | { | |
296 | int i; | |
297 | ||
298 | for (i = 0; i <= 31; i++) | |
299 | { | |
300 | if (regno == (FP0_REGNUM + i) || regno == -1) | |
301 | supply_register (FP0_REGNUM + i, fpregs + (i * 4)); | |
302 | } | |
303 | ||
304 | if (regno == FPS_REGNUM || regno == -1) | |
305 | supply_register (FPS_REGNUM, fpregs + (32 * 4)); | |
306 | } | |
307 | ||
308 | void | |
309 | sparcnbsd_supply_fpreg64 (char *fpregs, int regno) | |
310 | { | |
311 | int i; | |
312 | ||
313 | for (i = 0; i <= 31; i++) | |
314 | { | |
315 | if (regno == (FP0_REGNUM + i) || regno == -1) | |
316 | supply_register (FP0_REGNUM + i, fpregs + (i * 4)); | |
317 | } | |
318 | ||
319 | for (; i <= 47; i++) | |
320 | { | |
321 | if (regno == (FP0_REGNUM + i) || regno == -1) | |
322 | supply_register (FP0_REGNUM + i, fpregs + (32 * 4) + (i * 8)); | |
323 | } | |
324 | ||
325 | if (regno == FPS_REGNUM || regno == -1) | |
326 | supply_register (FPS_REGNUM, fpregs + (32 * 4) + (16 * 8)); | |
327 | ||
328 | /* XXX %gsr */ | |
329 | } | |
330 | ||
331 | void | |
332 | sparcnbsd_fill_fpreg32 (char *fpregs, int regno) | |
333 | { | |
334 | int i; | |
335 | ||
336 | for (i = 0; i <= 31; i++) | |
337 | { | |
338 | if (regno == (FP0_REGNUM + i) || regno == -1) | |
339 | regcache_collect (FP0_REGNUM + i, fpregs + (i * 4)); | |
340 | } | |
341 | ||
342 | if (regno == FPS_REGNUM || regno == -1) | |
343 | regcache_collect (FPS_REGNUM, fpregs + (32 * 4)); | |
344 | } | |
345 | ||
346 | void | |
347 | sparcnbsd_fill_fpreg64 (char *fpregs, int regno) | |
348 | { | |
349 | int i; | |
350 | ||
351 | for (i = 0; i <= 31; i++) | |
352 | { | |
353 | if (regno == (FP0_REGNUM + i) || regno == -1) | |
354 | regcache_collect (FP0_REGNUM + i, fpregs + (i * 4)); | |
355 | } | |
356 | ||
357 | for (; i <= 47; i++) | |
358 | { | |
359 | if (regno == (FP0_REGNUM + i) || regno == -1) | |
360 | regcache_collect (FP0_REGNUM + i, fpregs + (32 * 4) + (i * 8)); | |
361 | } | |
362 | ||
363 | if (regno == FPS_REGNUM || regno == -1) | |
364 | regcache_collect (FPS_REGNUM, fpregs + (32 * 4) + (16 * 8)); | |
365 | ||
366 | /* XXX %gsr */ | |
367 | } | |
368 | ||
369 | /* Unlike other NetBSD implementations, the SPARC port historically used | |
370 | .reg and .reg2 (see bfd/netbsd-core.c), and as such, we can share one | |
371 | routine for a.out and ELF core files. */ | |
372 | static void | |
373 | fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, | |
374 | CORE_ADDR ignore) | |
375 | { | |
376 | int reg_size, fpreg_size; | |
377 | ||
378 | if (gdbarch_ptr_bit (current_gdbarch) == 32) | |
379 | { | |
380 | reg_size = (20 * 4); | |
381 | fpreg_size = (33 * 4); | |
382 | } | |
383 | else | |
384 | { | |
385 | reg_size = (20 * 8); | |
386 | fpreg_size = (64 * 4) | |
387 | + 8 /* fsr */ | |
388 | + 4 /* gsr */ | |
389 | + 4; /* pad */ | |
390 | } | |
391 | ||
392 | switch (which) | |
393 | { | |
394 | case 0: /* Integer registers */ | |
395 | if (core_reg_size != reg_size) | |
396 | warning ("Wrong size register set in core file."); | |
397 | else if (gdbarch_ptr_bit (current_gdbarch) == 32) | |
398 | sparcnbsd_supply_reg32 (core_reg_sect, -1); | |
399 | else | |
400 | sparcnbsd_supply_reg64 (core_reg_sect, -1); | |
401 | break; | |
402 | ||
403 | case 2: /* Floating pointer registers */ | |
404 | if (core_reg_size != fpreg_size) | |
405 | warning ("Wrong size FP register set in core file."); | |
406 | else if (gdbarch_ptr_bit (current_gdbarch) == 32) | |
407 | sparcnbsd_supply_fpreg32 (core_reg_sect, -1); | |
408 | else | |
409 | sparcnbsd_supply_fpreg64 (core_reg_sect, -1); | |
410 | break; | |
411 | ||
412 | default: | |
413 | /* Don't know what kind of register request this is; just ignore it. */ | |
414 | break; | |
415 | } | |
416 | } | |
417 | ||
418 | static struct core_fns sparcnbsd_core_fns = | |
419 | { | |
420 | bfd_target_unknown_flavour, /* core_flavour */ | |
421 | default_check_format, /* check_format */ | |
422 | default_core_sniffer, /* core_sniffer */ | |
423 | fetch_core_registers, /* core_read_registers */ | |
424 | NULL | |
425 | }; | |
426 | ||
427 | static struct core_fns sparcnbsd_elfcore_fns = | |
428 | { | |
429 | bfd_target_elf_flavour, /* core_flavour */ | |
430 | default_check_format, /* check_format */ | |
431 | default_core_sniffer, /* core_sniffer */ | |
432 | fetch_core_registers, /* core_read_registers */ | |
433 | NULL | |
434 | }; | |
435 | ||
436 | /* FIXME: Need PC_IN_SIGTRAMP() support, but NetBSD/sparc signal trampolines | |
437 | aren't easily identified. */ | |
438 | ||
439 | static int | |
440 | sparcnbsd_get_longjmp_target_32 (CORE_ADDR *pc) | |
441 | { | |
442 | CORE_ADDR jb_addr; | |
443 | char buf[4]; | |
444 | ||
445 | jb_addr = read_register (O0_REGNUM); | |
446 | ||
447 | if (target_read_memory (jb_addr + 12, buf, sizeof (buf))) | |
448 | return 0; | |
449 | ||
7c0b4a20 | 450 | *pc = extract_unsigned_integer (buf, sizeof (buf)); |
9ce5c36a JT |
451 | |
452 | return 1; | |
453 | } | |
454 | ||
455 | static int | |
456 | sparcnbsd_get_longjmp_target_64 (CORE_ADDR *pc) | |
457 | { | |
458 | CORE_ADDR jb_addr; | |
459 | char buf[8]; | |
460 | ||
461 | jb_addr = read_register (O0_REGNUM); | |
462 | ||
463 | if (target_read_memory (jb_addr + 16, buf, sizeof (buf))) | |
464 | return 0; | |
465 | ||
7c0b4a20 | 466 | *pc = extract_unsigned_integer (buf, sizeof (buf)); |
9ce5c36a JT |
467 | |
468 | return 1; | |
469 | } | |
470 | ||
471 | static int | |
472 | sparcnbsd_aout_in_solib_call_trampoline (CORE_ADDR pc, char *name) | |
473 | { | |
474 | if (strcmp (name, "_DYNAMIC") == 0) | |
475 | return 1; | |
476 | ||
477 | return 0; | |
478 | } | |
479 | ||
480 | static void | |
481 | sparcnbsd_init_abi_common (struct gdbarch_info info, | |
482 | struct gdbarch *gdbarch) | |
483 | { | |
484 | set_gdbarch_get_longjmp_target (gdbarch, gdbarch_ptr_bit (gdbarch) == 32 ? | |
485 | sparcnbsd_get_longjmp_target_32 : | |
486 | sparcnbsd_get_longjmp_target_64); | |
487 | } | |
488 | ||
489 | static void | |
490 | sparcnbsd_init_abi_aout (struct gdbarch_info info, | |
491 | struct gdbarch *gdbarch) | |
492 | { | |
493 | sparcnbsd_init_abi_common (info, gdbarch); | |
494 | ||
495 | set_gdbarch_in_solib_call_trampoline (gdbarch, | |
496 | sparcnbsd_aout_in_solib_call_trampoline); | |
497 | } | |
498 | ||
499 | static void | |
500 | sparcnbsd_init_abi_elf (struct gdbarch_info info, | |
501 | struct gdbarch *gdbarch) | |
502 | { | |
503 | sparcnbsd_init_abi_common (info, gdbarch); | |
504 | ||
3d9b49b0 JT |
505 | set_gdbarch_pc_in_sigtramp (gdbarch, nbsd_pc_in_sigtramp); |
506 | ||
9ce5c36a JT |
507 | set_solib_svr4_fetch_link_map_offsets (gdbarch, |
508 | gdbarch_ptr_bit (gdbarch) == 32 ? | |
509 | nbsd_ilp32_solib_svr4_fetch_link_map_offsets : | |
510 | nbsd_lp64_solib_svr4_fetch_link_map_offsets); | |
511 | } | |
512 | ||
513 | static enum gdb_osabi | |
514 | sparcnbsd_aout_osabi_sniffer (bfd *abfd) | |
515 | { | |
516 | if (strcmp (bfd_get_target (abfd), "a.out-sparc-netbsd") == 0) | |
517 | return GDB_OSABI_NETBSD_AOUT; | |
518 | ||
519 | return GDB_OSABI_UNKNOWN; | |
520 | } | |
521 | ||
522 | void | |
523 | _initialize_sparnbsd_tdep (void) | |
524 | { | |
525 | gdbarch_register_osabi_sniffer (bfd_arch_sparc, bfd_target_aout_flavour, | |
526 | sparcnbsd_aout_osabi_sniffer); | |
527 | ||
05816f70 | 528 | gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_NETBSD_AOUT, |
9ce5c36a | 529 | sparcnbsd_init_abi_aout); |
05816f70 | 530 | gdbarch_register_osabi (bfd_arch_sparc, 0, GDB_OSABI_NETBSD_ELF, |
9ce5c36a JT |
531 | sparcnbsd_init_abi_elf); |
532 | ||
533 | add_core_fns (&sparcnbsd_core_fns); | |
534 | add_core_fns (&sparcnbsd_elfcore_fns); | |
535 | } |