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