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