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