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