* infrun.c (handle_inferior_event): Fixed typos in printf.
[platform/upstream/binutils.git] / gdb / alphanbsd-tdep.c
1 /* Target-dependent code for NetBSD/alpha.
2
3    Copyright (C) 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
4
5    Contributed by Wasabi Systems, Inc.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor,
22    Boston, MA 02110-1301, USA.  */
23
24 #include "defs.h"
25 #include "frame.h"
26 #include "gdbcore.h"
27 #include "osabi.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "value.h"
31
32 #include "gdb_assert.h"
33 #include "gdb_string.h"
34
35 #include "alpha-tdep.h"
36 #include "alphabsd-tdep.h"
37 #include "nbsd-tdep.h"
38 #include "solib-svr4.h"
39
40 /* Core file support.  */
41
42 /* Even though NetBSD/alpha used ELF since day one, it used the
43    traditional a.out-style core dump format before NetBSD 1.6.  */
44
45 /* Sizeof `struct reg' in <machine/reg.h>.  */
46 #define ALPHANBSD_SIZEOF_GREGS  (32 * 8)
47
48 /* Sizeof `struct fpreg' in <machine/reg.h.  */
49 #define ALPHANBSD_SIZEOF_FPREGS ((32 * 8) + 8)
50
51 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
52    in the floating-point register set REGSET to register cache
53    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
54
55 static void
56 alphanbsd_supply_fpregset (const struct regset *regset,
57                            struct regcache *regcache,
58                            int regnum, const void *fpregs, size_t len)
59 {
60   const gdb_byte *regs = fpregs;
61   int i;
62
63   gdb_assert (len >= ALPHANBSD_SIZEOF_FPREGS);
64
65   for (i = ALPHA_FP0_REGNUM; i < ALPHA_FP0_REGNUM + 31; i++)
66     {
67       if (regnum == i || regnum == -1)
68         regcache_raw_supply (regcache, i, regs + (i - ALPHA_FP0_REGNUM) * 8);
69     }
70
71   if (regnum == ALPHA_FPCR_REGNUM || regnum == -1)
72     regcache_raw_supply (regcache, ALPHA_FPCR_REGNUM, regs + 32 * 8);
73 }
74
75 /* Supply register REGNUM from the buffer specified by GREGS and LEN
76    in the general-purpose register set REGSET to register cache
77    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
78
79 static void
80 alphanbsd_supply_gregset (const struct regset *regset,
81                           struct regcache *regcache,
82                           int regnum, const void *gregs, size_t len)
83 {
84   const gdb_byte *regs = gregs;
85   int i;
86
87   gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
88
89   for (i = 0; i < ALPHA_ZERO_REGNUM; i++)
90     {
91       if (regnum == i || regnum == -1)
92         regcache_raw_supply (regcache, i, regs + i * 8);
93     }
94
95   if (regnum == ALPHA_PC_REGNUM || regnum == -1)
96     regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
97 }
98
99 /* Supply register REGNUM from the buffer specified by GREGS and LEN
100    in the general-purpose register set REGSET to register cache
101    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
102
103 static void
104 alphanbsd_aout_supply_gregset (const struct regset *regset,
105                                struct regcache *regcache,
106                                int regnum, const void *gregs, size_t len)
107 {
108   const gdb_byte *regs = gregs;
109   int i;
110
111   /* Table to map a GDB register number to a trapframe register index.  */
112   static const int regmap[] =
113   {
114      0,   1,   2,   3,
115      4,   5,   6,   7,
116      8,   9,  10,  11,
117     12,  13,  14,  15, 
118     30,  31,  32,  16, 
119     17,  18,  19,  20,
120     21,  22,  23,  24,
121     25,  29,  26
122   };
123
124   gdb_assert (len >= ALPHANBSD_SIZEOF_GREGS);
125
126   for (i = 0; i < ARRAY_SIZE(regmap); i++)
127     {
128       if (regnum == i || regnum == -1)
129         regcache_raw_supply (regcache, i, regs + regmap[i] * 8);
130     }
131
132   if (regnum == ALPHA_PC_REGNUM || regnum == -1)
133     regcache_raw_supply (regcache, ALPHA_PC_REGNUM, regs + 31 * 8);
134
135   if (len >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
136     {
137       regs += ALPHANBSD_SIZEOF_GREGS;
138       len -= ALPHANBSD_SIZEOF_GREGS;
139       alphanbsd_supply_fpregset (regset, regcache, regnum, regs, len);
140     }
141 }
142
143 /* NetBSD/alpha register sets.  */
144
145 static struct regset alphanbsd_gregset =
146 {
147   NULL,
148   alphanbsd_supply_gregset
149 };
150
151 static struct regset alphanbsd_fpregset =
152 {
153   NULL,
154   alphanbsd_supply_fpregset
155 };
156
157 static struct regset alphanbsd_aout_gregset =
158 {
159   NULL,
160   alphanbsd_aout_supply_gregset
161 };
162
163 /* Return the appropriate register set for the core section identified
164    by SECT_NAME and SECT_SIZE.  */
165
166 const struct regset *
167 alphanbsd_regset_from_core_section (struct gdbarch *gdbarch,
168                                     const char *sect_name, size_t sect_size)
169 {
170   if (strcmp (sect_name, ".reg") == 0 && sect_size >= ALPHANBSD_SIZEOF_GREGS)
171     {
172       if (sect_size >= ALPHANBSD_SIZEOF_GREGS + ALPHANBSD_SIZEOF_FPREGS)
173         return &alphanbsd_aout_gregset;
174       else
175         return &alphanbsd_gregset;
176     }
177
178   if (strcmp (sect_name, ".reg2") == 0 && sect_size >= ALPHANBSD_SIZEOF_FPREGS)
179     return &alphanbsd_fpregset;
180
181   return NULL;
182 }
183 \f
184
185 /* Signal trampolines.  */
186
187 /* Under NetBSD/alpha, signal handler invocations can be identified by the
188    designated code sequence that is used to return from a signal handler.
189    In particular, the return address of a signal handler points to the
190    following code sequence:
191
192         ldq     a0, 0(sp)
193         lda     sp, 16(sp)
194         lda     v0, 295(zero)   # __sigreturn14
195         call_pal callsys
196
197    Each instruction has a unique encoding, so we simply attempt to match
198    the instruction the PC is pointing to with any of the above instructions.
199    If there is a hit, we know the offset to the start of the designated
200    sequence and can then check whether we really are executing in the
201    signal trampoline.  If not, -1 is returned, otherwise the offset from the
202    start of the return sequence is returned.  */
203 static const unsigned char sigtramp_retcode[] =
204 {
205   0x00, 0x00, 0x1e, 0xa6,       /* ldq a0, 0(sp) */
206   0x10, 0x00, 0xde, 0x23,       /* lda sp, 16(sp) */
207   0x27, 0x01, 0x1f, 0x20,       /* lda v0, 295(zero) */
208   0x83, 0x00, 0x00, 0x00,       /* call_pal callsys */
209 };
210 #define RETCODE_NWORDS          4
211 #define RETCODE_SIZE            (RETCODE_NWORDS * 4)
212
213 static LONGEST
214 alphanbsd_sigtramp_offset (CORE_ADDR pc)
215 {
216   unsigned char ret[RETCODE_SIZE], w[4];
217   LONGEST off;
218   int i;
219
220   if (deprecated_read_memory_nobpt (pc, (char *) w, 4) != 0)
221     return -1;
222
223   for (i = 0; i < RETCODE_NWORDS; i++)
224     {
225       if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
226         break;
227     }
228   if (i == RETCODE_NWORDS)
229     return (-1);
230
231   off = i * 4;
232   pc -= off;
233
234   if (deprecated_read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
235     return -1;
236
237   if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
238     return off;
239
240   return -1;
241 }
242
243 static int
244 alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
245 {
246   return (nbsd_pc_in_sigtramp (pc, func_name)
247           || alphanbsd_sigtramp_offset (pc) >= 0);
248 }
249
250 static CORE_ADDR
251 alphanbsd_sigcontext_addr (struct frame_info *frame)
252 {
253   /* FIXME: This is not correct for all versions of NetBSD/alpha.
254      We will probably need to disassemble the trampoline to figure
255      out which trampoline frame type we have.  */
256   return get_frame_base (frame);
257 }
258 \f
259
260 static void
261 alphanbsd_init_abi (struct gdbarch_info info,
262                     struct gdbarch *gdbarch)
263 {
264   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
265
266   /* Hook into the DWARF CFI frame unwinder.  */
267   alpha_dwarf2_init_abi (info, gdbarch);
268
269   /* Hook into the MDEBUG frame unwinder.  */
270   alpha_mdebug_init_abi (info, gdbarch);
271
272   /* NetBSD/alpha does not provide single step support via ptrace(2); we
273      must use software single-stepping.  */
274   set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
275
276   /* NetBSD/alpha has SVR4-style shared libraries.  */
277   set_solib_svr4_fetch_link_map_offsets
278     (gdbarch, svr4_lp64_fetch_link_map_offsets);
279
280   tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
281   tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
282   tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
283
284   tdep->jb_pc = 2;
285   tdep->jb_elt_size = 8;
286
287   set_gdbarch_regset_from_core_section
288     (gdbarch, alphanbsd_regset_from_core_section);
289 }
290 \f
291
292 static enum gdb_osabi
293 alphanbsd_core_osabi_sniffer (bfd *abfd)
294 {
295   if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
296     return GDB_OSABI_NETBSD_ELF;
297
298   return GDB_OSABI_UNKNOWN;
299 }
300 \f
301
302 /* Provide a prototype to silence -Wmissing-prototypes.  */
303 void _initialize_alphanbsd_tdep (void);
304
305 void
306 _initialize_alphanbsd_tdep (void)
307 {
308   /* BFD doesn't set a flavour for NetBSD style a.out core files.  */
309   gdbarch_register_osabi_sniffer (bfd_arch_alpha, bfd_target_unknown_flavour,
310                                   alphanbsd_core_osabi_sniffer);
311
312   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
313                           alphanbsd_init_abi);
314 }