* avr-tdep.c, hppa-tdep.c, hppabsd-tdep.c, i386-tdep.c,
[platform/upstream/binutils.git] / gdb / hppabsd-tdep.c
1 /* Target-dependent code for HP PA-RISC BSD's.
2
3    Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, 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., 51 Franklin Street, Fifth Floor,
20    Boston, MA 02110-1301, USA.  */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "gdbtypes.h"
25 #include "symtab.h"
26 #include "objfiles.h"
27 #include "osabi.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "target.h"
31 #include "value.h"
32
33 #include "gdb_assert.h"
34 #include "gdb_string.h"
35
36 #include "elf/common.h"
37
38 #include "hppa-tdep.h"
39 #include "solib-svr4.h"
40
41 /* Core file support.  */
42
43 /* Sizeof `struct reg' in <machine/reg.h>.  */
44 #define HPPABSD_SIZEOF_GREGS    (34 * 4)
45
46 /* Supply register REGNUM from the buffer specified by GREGS and LEN
47    in the general-purpose register set REGSET to register cache
48    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
49
50 static void
51 hppabsd_supply_gregset (const struct regset *regset, struct regcache *regcache,
52                      int regnum, const void *gregs, size_t len)
53 {
54   const gdb_byte *regs = gregs;
55   size_t offset;
56   int i;
57
58   gdb_assert (len >= HPPABSD_SIZEOF_GREGS);
59
60   for (i = HPPA_R1_REGNUM, offset = 4; i <= HPPA_R31_REGNUM; i++, offset += 4)
61     {
62       if (regnum == -1 || regnum == i)
63         regcache_raw_supply (regcache, i, regs + offset);
64     }
65
66   if (regnum == -1 || regnum == HPPA_SAR_REGNUM)
67     regcache_raw_supply (regcache, HPPA_SAR_REGNUM, regs);
68   if (regnum == -1 || regnum == HPPA_PCOQ_HEAD_REGNUM)
69     regcache_raw_supply (regcache, HPPA_PCOQ_HEAD_REGNUM, regs + 32 * 4);
70   if (regnum == -1 || regnum == HPPA_PCOQ_TAIL_REGNUM)
71     regcache_raw_supply (regcache, HPPA_PCOQ_TAIL_REGNUM, regs + 33 * 4);
72 }
73
74 /* OpenBSD/hppa register set.  */
75
76 static struct regset hppabsd_gregset =
77 {
78   NULL,
79   hppabsd_supply_gregset
80 };
81
82 /* Return the appropriate register set for the core section identified
83    by SECT_NAME and SECT_SIZE.  */
84
85 static const struct regset *
86 hppabsd_regset_from_core_section (struct gdbarch *gdbarch,
87                                   const char *sect_name, size_t sect_size)
88 {
89   if (strcmp (sect_name, ".reg") == 0 && sect_size >= HPPABSD_SIZEOF_GREGS)
90     return &hppabsd_gregset;
91
92   return NULL;
93 }
94 \f
95
96 CORE_ADDR
97 hppabsd_find_global_pointer (struct value *function)
98 {
99   CORE_ADDR faddr = value_as_address (function);
100   struct obj_section *faddr_sec;
101   gdb_byte buf[4];
102
103   /* Is this a plabel? If so, dereference it to get the Global Pointer
104      value.  */
105   if (faddr & 2)
106     {
107       if (target_read_memory ((faddr & ~3) + 4, buf, sizeof buf) == 0)
108         return extract_unsigned_integer (buf, sizeof buf);
109     }
110
111   /* If the address is in the .plt section, then the real function
112      hasn't yet been fixed up by the linker so we cannot determine the
113      Global Pointer for that function.  */
114   if (in_plt_section (faddr, NULL))
115     return 0;
116
117   faddr_sec = find_pc_section (faddr);
118   if (faddr_sec != NULL)
119     {
120       struct obj_section *sec;
121
122       ALL_OBJFILE_OSECTIONS (faddr_sec->objfile, sec)
123         {
124           if (strcmp (sec->the_bfd_section->name, ".dynamic") == 0)
125             break;
126         }
127
128       if (sec < faddr_sec->objfile->sections_end)
129         {
130           CORE_ADDR addr = sec->addr;
131
132           while (addr < sec->endaddr)
133             {
134               gdb_byte buf[4];
135               LONGEST tag;
136
137               if (target_read_memory (addr, buf, sizeof buf) != 0)
138                 break;
139
140               tag = extract_signed_integer (buf, sizeof buf);
141               if (tag == DT_PLTGOT)
142                 {
143                   CORE_ADDR pltgot;
144
145                   if (target_read_memory (addr + 4, buf, sizeof buf) != 0)
146                     break;
147
148                   /* The OpenBSD ld.so doesn't relocate DT_PLTGOT, so
149                      we have to do it ourselves.  */
150                   pltgot = extract_unsigned_integer (buf, sizeof buf);
151                   pltgot += ANOFFSET (sec->objfile->section_offsets,
152                                       SECT_OFF_TEXT (sec->objfile));
153                   return pltgot;
154                 }
155
156               if (tag == DT_NULL)
157                 break;
158
159               addr += 8;
160             }
161         }
162     }
163
164   return 0;
165 }
166 \f
167
168 static void
169 hppabsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
170 {
171   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
172
173   /* OpenBSD and NetBSD have a 64-bit 'long double'.  */
174   set_gdbarch_long_double_bit (gdbarch, 64);
175   set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
176
177   /* Core file support.  */
178   set_gdbarch_regset_from_core_section
179     (gdbarch, hppabsd_regset_from_core_section);
180
181   /* OpenBSD and NetBSD use ELF.  */
182   tdep->is_elf = 1;
183   tdep->find_global_pointer = hppabsd_find_global_pointer;
184   tdep->in_solib_call_trampoline = hppa_in_solib_call_trampoline;
185   set_gdbarch_skip_trampoline_code (gdbarch, hppa_skip_trampoline_code);
186
187   /* OpenBSD and NetBSD use SVR4-style shared libraries.  */
188   set_solib_svr4_fetch_link_map_offsets
189     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
190 }
191 \f
192
193 /* OpenBSD uses uses the traditional NetBSD core file format, even for
194    ports that use ELF.  */
195 #define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
196
197 static enum gdb_osabi
198 hppabsd_core_osabi_sniffer (bfd *abfd)
199 {
200   if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
201     return GDB_OSABI_NETBSD_CORE;
202
203   return GDB_OSABI_UNKNOWN;
204 }
205 \f
206
207 /* Provide a prototype to silence -Wmissing-prototypes.  */
208 void _initialize_hppabsd_tdep (void);
209
210 void
211 _initialize_hppabsd_tdep (void)
212 {
213   /* BFD doesn't set a flavour for NetBSD style a.out core files.  */
214   gdbarch_register_osabi_sniffer (bfd_arch_hppa, bfd_target_unknown_flavour,
215                                   hppabsd_core_osabi_sniffer);
216
217   gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_NETBSD_ELF,
218                           hppabsd_init_abi);
219   gdbarch_register_osabi (bfd_arch_hppa, 0, GDB_OSABI_OPENBSD_ELF,
220                           hppabsd_init_abi);
221 }