* osabi.c: Include "gdb_assert.h" and "gdb_string.h".
[platform/upstream/binutils.git] / gdb / alphanbsd-tdep.c
1 /* Target-dependent code for NetBSD/Alpha.
2    Copyright 2002 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 "frame.h"
25 #include "regcache.h"
26 #include "value.h"
27
28 #include "solib-svr4.h"
29
30 #include "alpha-tdep.h"
31 #include "alphabsd-tdep.h"
32 #include "nbsd-tdep.h"
33
34 static void
35 fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
36                       CORE_ADDR ignore)
37 {
38   char *regs, *fpregs;
39   int regno;
40
41   /* Table to map a gdb register number to a trapframe register index.  */
42   static const int regmap[] =
43   {
44      0,   1,   2,   3,
45      4,   5,   6,   7,
46      8,   9,  10,  11,
47     12,  13,  14,  15, 
48     30,  31,  32,  16, 
49     17,  18,  19,  20,
50     21,  22,  23,  24,
51     25,  29,  26
52   };
53 #define SIZEOF_TRAPFRAME (33 * 8)
54
55   /* We get everything from one section.  */
56   if (which != 0)
57     return;
58
59   regs = core_reg_sect;
60   fpregs = core_reg_sect + SIZEOF_TRAPFRAME;
61
62   if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG))
63     {
64       warning ("Wrong size register set in core file.");
65       return;
66     }
67
68   /* Integer registers.  */
69   for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++)
70     supply_register (regno, regs + (regmap[regno] * 8));
71   supply_register (ALPHA_ZERO_REGNUM, NULL);
72   supply_register (FP_REGNUM, NULL);
73   supply_register (PC_REGNUM, regs + (28 * 8));
74
75   /* Floating point registers.  */
76   alphabsd_supply_fpreg (fpregs, -1);
77 }
78
79 static void
80 fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
81                          CORE_ADDR ignore)
82 {
83   switch (which)
84     {
85     case 0:  /* Integer registers.  */
86       if (core_reg_size != SIZEOF_STRUCT_REG)
87         warning ("Wrong size register set in core file.");
88       else
89         alphabsd_supply_reg (core_reg_sect, -1);
90       break;
91
92     case 2:  /* Floating point registers.  */
93       if (core_reg_size != SIZEOF_STRUCT_FPREG)
94         warning ("Wrong size FP register set in core file.");
95       else
96         alphabsd_supply_fpreg (core_reg_sect, -1);
97       break;
98
99     default:
100       /* Don't know what kind of register request this is; just ignore it.  */
101       break;
102     }
103 }
104
105 static struct core_fns alphanbsd_core_fns =
106 {
107   bfd_target_unknown_flavour,           /* core_flavour */
108   default_check_format,                 /* check_format */
109   default_core_sniffer,                 /* core_sniffer */
110   fetch_core_registers,                 /* core_read_registers */
111   NULL                                  /* next */
112 };
113
114 static struct core_fns alphanbsd_elfcore_fns =
115 {
116   bfd_target_elf_flavour,               /* core_flavour */
117   default_check_format,                 /* check_format */
118   default_core_sniffer,                 /* core_sniffer */
119   fetch_elfcore_registers,              /* core_read_registers */
120   NULL                                  /* next */
121 };
122
123 /* Under NetBSD/alpha, signal handler invocations can be identified by the
124    designated code sequence that is used to return from a signal handler.
125    In particular, the return address of a signal handler points to the
126    following code sequence:
127
128         ldq     a0, 0(sp)
129         lda     sp, 16(sp)
130         lda     v0, 295(zero)   # __sigreturn14
131         call_pal callsys
132
133    Each instruction has a unique encoding, so we simply attempt to match
134    the instruction the PC is pointing to with any of the above instructions.
135    If there is a hit, we know the offset to the start of the designated
136    sequence and can then check whether we really are executing in the
137    signal trampoline.  If not, -1 is returned, otherwise the offset from the
138    start of the return sequence is returned.  */
139 static const unsigned char sigtramp_retcode[] =
140 {
141   0x00, 0x00, 0x1e, 0xa6,       /* ldq a0, 0(sp) */
142   0x10, 0x00, 0xde, 0x23,       /* lda sp, 16(sp) */
143   0x27, 0x01, 0x1f, 0x20,       /* lda v0, 295(zero) */
144   0x83, 0x00, 0x00, 0x00,       /* call_pal callsys */
145 };
146 #define RETCODE_NWORDS          4
147 #define RETCODE_SIZE            (RETCODE_NWORDS * 4)
148
149 LONGEST
150 alphanbsd_sigtramp_offset (CORE_ADDR pc)
151 {
152   unsigned char ret[RETCODE_SIZE], w[4];
153   LONGEST off;
154   int i;
155
156   if (read_memory_nobpt (pc, (char *) w, 4) != 0)
157     return -1;
158
159   for (i = 0; i < RETCODE_NWORDS; i++)
160     {
161       if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
162         break;
163     }
164   if (i == RETCODE_NWORDS)
165     return (-1);
166
167   off = i * 4;
168   pc -= off;
169
170   if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
171     return -1;
172
173   if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
174     return off;
175
176   return -1;
177 }
178
179 static int
180 alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
181 {
182   return (nbsd_pc_in_sigtramp (pc, func_name)
183           || alphanbsd_sigtramp_offset (pc) >= 0);
184 }
185
186 static CORE_ADDR
187 alphanbsd_sigcontext_addr (struct frame_info *frame)
188 {
189   /* FIXME: This is not correct for all versions of NetBSD/alpha.
190      We will probably need to disassemble the trampoline to figure
191      out which trampoline frame type we have.  */
192   return frame->frame;
193 }
194
195 static CORE_ADDR
196 alphanbsd_skip_sigtramp_frame (struct frame_info *frame, CORE_ADDR pc)
197 {
198   char *name;
199
200   /* FIXME: This is not correct for all versions of NetBSD/alpha.
201      We will probably need to disassemble the trampoline to figure
202      out which trampoline frame type we have.  */
203   find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
204   if (PC_IN_SIGTRAMP (pc, name))
205     return frame->frame;
206   return 0;
207 }
208
209 static void
210 alphanbsd_init_abi (struct gdbarch_info info,
211                     struct gdbarch *gdbarch)
212 {
213   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
214
215   set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp);
216
217   /* NetBSD/alpha does not provide single step support via ptrace(2); we
218      must use software single-stepping.  */
219   set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
220
221   set_solib_svr4_fetch_link_map_offsets (gdbarch,
222                                  nbsd_lp64_solib_svr4_fetch_link_map_offsets);
223
224   tdep->skip_sigtramp_frame = alphanbsd_skip_sigtramp_frame;
225   tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
226   tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
227
228   tdep->jb_pc = 2;
229   tdep->jb_elt_size = 8;
230 }
231
232 void
233 _initialize_alphanbsd_tdep (void)
234 {
235   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
236                           alphanbsd_init_abi);
237
238   add_core_fns (&alphanbsd_core_fns);
239   add_core_fns (&alphanbsd_elfcore_fns);
240 }