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