OSDN Git Service

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