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