]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gdb/gdb/mipsnbsd-tdep.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gdb / gdb / mipsnbsd-tdep.c
1 /* Target-dependent code for MIPS systems running NetBSD.
2    Copyright 2002, 2003 Free Software Foundation, Inc.
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
29 #include "nbsd-tdep.h"
30 #include "mipsnbsd-tdep.h"
31
32 #include "solib-svr4.h"
33
34 /* Conveniently, GDB uses the same register numbering as the
35    ptrace register structure used by NetBSD/mips.  */
36
37 void
38 mipsnbsd_supply_reg (char *regs, int regno)
39 {
40   int i;
41
42   for (i = 0; i <= PC_REGNUM; i++)
43     {
44       if (regno == i || regno == -1)
45         {
46           if (CANNOT_FETCH_REGISTER (i))
47             supply_register (i, NULL);
48           else
49             supply_register (i, regs + (i * mips_regsize (current_gdbarch)));
50         }
51     }
52 }
53
54 void
55 mipsnbsd_fill_reg (char *regs, int regno)
56 {
57   int i;
58
59   for (i = 0; i <= PC_REGNUM; i++)
60     if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
61       regcache_collect (i, regs + (i * mips_regsize (current_gdbarch)));
62 }
63
64 void
65 mipsnbsd_supply_fpreg (char *fpregs, int regno)
66 {
67   int i;
68
69   for (i = FP0_REGNUM;
70        i <= mips_regnum (current_gdbarch)->fp_implementation_revision;
71        i++)
72     {
73       if (regno == i || regno == -1)
74         {
75           if (CANNOT_FETCH_REGISTER (i))
76             supply_register (i, NULL);
77           else
78             supply_register (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
79         }
80     }
81 }
82
83 void
84 mipsnbsd_fill_fpreg (char *fpregs, int regno)
85 {
86   int i;
87
88   for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status;
89        i++)
90     if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
91       regcache_collect (i, fpregs + ((i - FP0_REGNUM) * mips_regsize (current_gdbarch)));
92 }
93
94 static void
95 fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
96                       CORE_ADDR ignore)
97 {
98   char *regs, *fpregs;
99
100   /* We get everything from one section.  */
101   if (which != 0)
102     return;
103
104   regs = core_reg_sect;
105   fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
106
107   /* Integer registers.  */
108   mipsnbsd_supply_reg (regs, -1);
109
110   /* Floating point registers.  */
111   mipsnbsd_supply_fpreg (fpregs, -1);
112 }
113
114 static void
115 fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
116                          CORE_ADDR ignore)
117 {
118   switch (which)
119     {
120     case 0:  /* Integer registers.  */
121       if (core_reg_size != SIZEOF_STRUCT_REG)
122         warning ("Wrong size register set in core file.");
123       else
124         mipsnbsd_supply_reg (core_reg_sect, -1);
125       break;
126
127     case 2:  /* Floating point registers.  */
128       if (core_reg_size != SIZEOF_STRUCT_FPREG)
129         warning ("Wrong size register set in core file.");
130       else
131         mipsnbsd_supply_fpreg (core_reg_sect, -1);
132       break;
133
134     default:
135       /* Don't know what kind of register request this is; just ignore it.  */
136       break;
137     }
138 }
139
140 static struct core_fns mipsnbsd_core_fns =
141 {
142   bfd_target_unknown_flavour,           /* core_flavour */
143   default_check_format,                 /* check_format */
144   default_core_sniffer,                 /* core_sniffer */
145   fetch_core_registers,                 /* core_read_registers */
146   NULL                                  /* next */
147 };
148
149 static struct core_fns mipsnbsd_elfcore_fns =
150 {
151   bfd_target_elf_flavour,               /* core_flavour */
152   default_check_format,                 /* check_format */
153   default_core_sniffer,                 /* core_sniffer */
154   fetch_elfcore_registers,              /* core_read_registers */
155   NULL                                  /* next */
156 };
157
158 /* Under NetBSD/mips, signal handler invocations can be identified by the
159    designated code sequence that is used to return from a signal handler.
160    In particular, the return address of a signal handler points to the
161    following code sequence:
162
163         addu    a0, sp, 16
164         li      v0, 295                 # __sigreturn14
165         syscall
166    
167    Each instruction has a unique encoding, so we simply attempt to match
168    the instruction the PC is pointing to with any of the above instructions.
169    If there is a hit, we know the offset to the start of the designated
170    sequence and can then check whether we really are executing in the
171    signal trampoline.  If not, -1 is returned, otherwise the offset from the
172    start of the return sequence is returned.  */
173
174 #define RETCODE_NWORDS  3
175 #define RETCODE_SIZE    (RETCODE_NWORDS * 4)
176
177 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
178 {
179   0x10, 0x00, 0xa4, 0x27,       /* addu a0, sp, 16 */
180   0x27, 0x01, 0x02, 0x24,       /* li v0, 295 */
181   0x0c, 0x00, 0x00, 0x00,       /* syscall */
182 };
183
184 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
185 {
186   0x27, 0xa4, 0x00, 0x10,       /* addu a0, sp, 16 */
187   0x24, 0x02, 0x01, 0x27,       /* li v0, 295 */
188   0x00, 0x00, 0x00, 0x0c,       /* syscall */
189 };
190
191 static LONGEST
192 mipsnbsd_sigtramp_offset (CORE_ADDR pc)
193 {
194   const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
195         ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel;
196   unsigned char ret[RETCODE_SIZE], w[4];
197   LONGEST off;
198   int i;
199
200   if (read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0)
201     return -1;
202
203   for (i = 0; i < RETCODE_NWORDS; i++)
204     {
205       if (memcmp (w, retcode + (i * 4), 4) == 0)
206         break;
207     }
208   if (i == RETCODE_NWORDS)
209     return -1;
210
211   off = i * 4;
212   pc -= off;
213
214   if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
215     return -1;
216
217   if (memcmp (ret, retcode, RETCODE_SIZE) == 0)
218     return off;
219
220   return -1;
221 }
222
223 static int
224 mipsnbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
225 {
226   return (nbsd_pc_in_sigtramp (pc, func_name)
227           || mipsnbsd_sigtramp_offset (pc) >= 0);
228 }
229
230 /* Figure out where the longjmp will land.  We expect that we have
231    just entered longjmp and haven't yet setup the stack frame, so
232    the args are still in the argument regs.  A0_REGNUM points at the
233    jmp_buf structure from which we extract the PC that we will land
234    at.  The PC is copied into *pc.  This routine returns true on
235    success.  */
236
237 #define NBSD_MIPS_JB_PC                 (2 * 4)
238 #define NBSD_MIPS_JB_ELEMENT_SIZE       mips_regsize (current_gdbarch)
239 #define NBSD_MIPS_JB_OFFSET             (NBSD_MIPS_JB_PC * \
240                                          NBSD_MIPS_JB_ELEMENT_SIZE)
241
242 static int
243 mipsnbsd_get_longjmp_target (CORE_ADDR *pc)
244 {
245   CORE_ADDR jb_addr;
246   char *buf;
247
248   buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE);
249
250   jb_addr = read_register (A0_REGNUM);
251
252   if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf,
253                           NBSD_MIPS_JB_ELEMENT_SIZE))
254     return 0;
255
256   *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE);
257
258   return 1;
259 }
260
261 static int
262 mipsnbsd_cannot_fetch_register (int regno)
263 {
264   return (regno == ZERO_REGNUM
265           || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
266 }
267
268 static int
269 mipsnbsd_cannot_store_register (int regno)
270 {
271   return (regno == ZERO_REGNUM
272           || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
273 }
274
275 /* NetBSD/mips uses a slightly different link_map structure from the
276    other NetBSD platforms.  */
277 static struct link_map_offsets *
278 mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
279 {
280   static struct link_map_offsets lmo;
281   static struct link_map_offsets *lmp = NULL;
282
283   if (lmp == NULL) 
284     {
285       lmp = &lmo;
286
287       lmo.r_debug_size = 16;
288
289       lmo.r_map_offset = 4;
290       lmo.r_map_size   = 4;
291
292       lmo.link_map_size = 24;
293
294       lmo.l_addr_offset = 0;
295       lmo.l_addr_size   = 4;
296
297       lmo.l_name_offset = 8;
298       lmo.l_name_size   = 4;
299
300       lmo.l_next_offset = 16;
301       lmo.l_next_size   = 4;
302
303       lmo.l_prev_offset = 20;
304       lmo.l_prev_size   = 4;
305     }
306
307   return lmp;
308 }
309
310 static struct link_map_offsets *
311 mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void)
312 {
313   static struct link_map_offsets lmo;
314   static struct link_map_offsets *lmp = NULL;
315
316   if (lmp == NULL)
317     {
318       lmp = &lmo;
319
320       lmo.r_debug_size = 32;
321
322       lmo.r_map_offset = 8;  
323       lmo.r_map_size   = 8;
324
325       lmo.link_map_size = 48;
326
327       lmo.l_addr_offset = 0;
328       lmo.l_addr_size   = 8;
329
330       lmo.l_name_offset = 16; 
331       lmo.l_name_size   = 8;
332
333       lmo.l_next_offset = 32;
334       lmo.l_next_size   = 8;
335
336       lmo.l_prev_offset = 40;
337       lmo.l_prev_size   = 8;
338     }
339
340   return lmp;
341 }
342
343 static void
344 mipsnbsd_init_abi (struct gdbarch_info info,
345                    struct gdbarch *gdbarch)
346 {
347   set_gdbarch_pc_in_sigtramp (gdbarch, mipsnbsd_pc_in_sigtramp);
348
349   set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
350
351   set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
352   set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
353
354   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
355
356   set_solib_svr4_fetch_link_map_offsets (gdbarch,
357                                          gdbarch_ptr_bit (gdbarch) == 32 ?
358                             mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets :
359                             mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets);
360 }
361
362 void
363 _initialize_mipsnbsd_tdep (void)
364 {
365   gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF,
366                           mipsnbsd_init_abi);
367
368   add_core_fns (&mipsnbsd_core_fns);
369   add_core_fns (&mipsnbsd_elfcore_fns);
370 }