OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [ppcobsd-tdep.c] - Blame information for rev 853

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 227 jeremybenn
/* Target-dependent code for OpenBSD/powerpc.
2
 
3
   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
4
   Free Software Foundation, Inc.
5
 
6
   This file is part of GDB.
7
 
8
   This program is free software; you can redistribute it and/or modify
9
   it under the terms of the GNU General Public License as published by
10
   the Free Software Foundation; either version 3 of the License, or
11
   (at your option) any later version.
12
 
13
   This program is distributed in the hope that it will be useful,
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
   GNU General Public License for more details.
17
 
18
   You should have received a copy of the GNU General Public License
19
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
 
21
#include "defs.h"
22
#include "arch-utils.h"
23
#include "frame.h"
24
#include "frame-unwind.h"
25
#include "gdbtypes.h"
26
#include "osabi.h"
27
#include "regcache.h"
28
#include "regset.h"
29
#include "symtab.h"
30
#include "trad-frame.h"
31
 
32
#include "gdb_assert.h"
33
#include "gdb_string.h"
34
 
35
#include "ppc-tdep.h"
36
#include "ppcobsd-tdep.h"
37
#include "solib-svr4.h"
38
 
39
/* Register offsets from <machine/reg.h>.  */
40
struct ppc_reg_offsets ppcobsd_reg_offsets;
41
struct ppc_reg_offsets ppcobsd_fpreg_offsets;
42
 
43
 
44
/* Core file support.  */
45
 
46
/* Supply register REGNUM in the general-purpose register set REGSET
47
   from the buffer specified by GREGS and LEN to register cache
48
   REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
49
 
50
void
51
ppcobsd_supply_gregset (const struct regset *regset,
52
                        struct regcache *regcache, int regnum,
53
                        const void *gregs, size_t len)
54
{
55
  ppc_supply_gregset (regset, regcache, regnum, gregs, len);
56
  ppc_supply_fpregset (regset, regcache, regnum, gregs, len);
57
}
58
 
59
/* Collect register REGNUM in the general-purpose register set
60
   REGSET. from register cache REGCACHE into the buffer specified by
61
   GREGS and LEN.  If REGNUM is -1, do this for all registers in
62
   REGSET.  */
63
 
64
void
65
ppcobsd_collect_gregset (const struct regset *regset,
66
                         const struct regcache *regcache, int regnum,
67
                         void *gregs, size_t len)
68
{
69
  ppc_collect_gregset (regset, regcache, regnum, gregs, len);
70
  ppc_collect_fpregset (regset, regcache, regnum, gregs, len);
71
}
72
 
73
/* OpenBSD/powerpc register set.  */
74
 
75
struct regset ppcobsd_gregset =
76
{
77
  &ppcobsd_reg_offsets,
78
  ppcobsd_supply_gregset
79
};
80
 
81
struct regset ppcobsd_fpregset =
82
{
83
  &ppcobsd_fpreg_offsets,
84
  ppc_supply_fpregset
85
};
86
 
87
/* Return the appropriate register set for the core section identified
88
   by SECT_NAME and SECT_SIZE.  */
89
 
90
static const struct regset *
91
ppcobsd_regset_from_core_section (struct gdbarch *gdbarch,
92
                                  const char *sect_name, size_t sect_size)
93
{
94
  if (strcmp (sect_name, ".reg") == 0 && sect_size >= 412)
95
    return &ppcobsd_gregset;
96
 
97
  return NULL;
98
}
99
 
100
 
101
/* Signal trampolines.  */
102
 
103
/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
104
   in virtual memory.  The randomness makes it somewhat tricky to
105
   detect it, but fortunately we can rely on the fact that the start
106
   of the sigtramp routine is page-aligned.  We recognize the
107
   trampoline by looking for the code that invokes the sigreturn
108
   system call.  The offset where we can find that code varies from
109
   release to release.
110
 
111
   By the way, the mapping mentioned above is read-only, so you cannot
112
   place a breakpoint in the signal trampoline.  */
113
 
114
/* Default page size.  */
115
static const int ppcobsd_page_size = 4096;
116
 
117
/* Offset for sigreturn(2).  */
118
static const int ppcobsd_sigreturn_offset[] = {
119
  0x98,                         /* OpenBSD 3.8 */
120
  0x0c,                         /* OpenBSD 3.2 */
121
  -1
122
};
123
 
124
static int
125
ppcobsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
126
                                struct frame_info *this_frame,
127
                                void **this_cache)
128
{
129
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
130
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
131
  CORE_ADDR pc = get_frame_pc (this_frame);
132
  CORE_ADDR start_pc = (pc & ~(ppcobsd_page_size - 1));
133
  const int *offset;
134
  char *name;
135
 
136
  find_pc_partial_function (pc, &name, NULL, NULL);
137
  if (name)
138
    return 0;
139
 
140
  for (offset = ppcobsd_sigreturn_offset; *offset != -1; offset++)
141
    {
142
      gdb_byte buf[2 * PPC_INSN_SIZE];
143
      unsigned long insn;
144
 
145
      if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
146
                                     buf, sizeof buf))
147
        continue;
148
 
149
      /* Check for "li r0,SYS_sigreturn".  */
150
      insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
151
      if (insn != 0x38000067)
152
        continue;
153
 
154
      /* Check for "sc".  */
155
      insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
156
                                       PPC_INSN_SIZE, byte_order);
157
      if (insn != 0x44000002)
158
        continue;
159
 
160
      return 1;
161
    }
162
 
163
  return 0;
164
}
165
 
166
static struct trad_frame_cache *
167
ppcobsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
168
{
169
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
170
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
171
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
172
  struct trad_frame_cache *cache;
173
  CORE_ADDR addr, base, func;
174
  gdb_byte buf[PPC_INSN_SIZE];
175
  unsigned long insn, sigcontext_offset;
176
  int i;
177
 
178
  if (*this_cache)
179
    return *this_cache;
180
 
181
  cache = trad_frame_cache_zalloc (this_frame);
182
  *this_cache = cache;
183
 
184
  func = get_frame_pc (this_frame);
185
  func &= ~(ppcobsd_page_size - 1);
186
  if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
187
    return cache;
188
 
189
  /* Calculate the offset where we can find `struct sigcontext'.  We
190
     base our calculation on the amount of stack space reserved by the
191
     first instruction of the signal trampoline.  */
192
  insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
193
  sigcontext_offset = (0x10000 - (insn & 0x0000ffff)) + 8;
194
 
195
  base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
196
  addr = base + sigcontext_offset + 2 * tdep->wordsize;
197
  for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
198
    {
199
      int regnum = i + tdep->ppc_gp0_regnum;
200
      trad_frame_set_reg_addr (cache, regnum, addr);
201
    }
202
  trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
203
  addr += tdep->wordsize;
204
  trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
205
  addr += tdep->wordsize;
206
  trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
207
  addr += tdep->wordsize;
208
  trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
209
  addr += tdep->wordsize;
210
  trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
211
  /* SRR0? */
212
  addr += tdep->wordsize;
213
 
214
  /* Construct the frame ID using the function start.  */
215
  trad_frame_set_id (cache, frame_id_build (base, func));
216
 
217
  return cache;
218
}
219
 
220
static void
221
ppcobsd_sigtramp_frame_this_id (struct frame_info *this_frame,
222
                                void **this_cache, struct frame_id *this_id)
223
{
224
  struct trad_frame_cache *cache =
225
    ppcobsd_sigtramp_frame_cache (this_frame, this_cache);
226
 
227
  trad_frame_get_id (cache, this_id);
228
}
229
 
230
static struct value *
231
ppcobsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
232
                                      void **this_cache, int regnum)
233
{
234
  struct trad_frame_cache *cache =
235
    ppcobsd_sigtramp_frame_cache (this_frame, this_cache);
236
 
237
  return trad_frame_get_register (cache, this_frame, regnum);
238
}
239
 
240
static const struct frame_unwind ppcobsd_sigtramp_frame_unwind = {
241
  SIGTRAMP_FRAME,
242
  ppcobsd_sigtramp_frame_this_id,
243
  ppcobsd_sigtramp_frame_prev_register,
244
  NULL,
245
  ppcobsd_sigtramp_frame_sniffer
246
};
247
 
248
 
249
static void
250
ppcobsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
251
{
252
  /* OpenBSD doesn't support the 128-bit `long double' from the psABI.  */
253
  set_gdbarch_long_double_bit (gdbarch, 64);
254
  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
255
 
256
  /* OpenBSD currently uses a broken GCC.  */
257
  set_gdbarch_return_value (gdbarch, ppc_sysv_abi_broken_return_value);
258
 
259
  /* OpenBSD uses SVR4-style shared libraries.  */
260
  set_solib_svr4_fetch_link_map_offsets
261
    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
262
 
263
  set_gdbarch_regset_from_core_section
264
    (gdbarch, ppcobsd_regset_from_core_section);
265
 
266
  frame_unwind_append_unwinder (gdbarch, &ppcobsd_sigtramp_frame_unwind);
267
}
268
 
269
 
270
/* OpenBSD uses uses the traditional NetBSD core file format, even for
271
   ports that use ELF.  */
272
#define GDB_OSABI_NETBSD_CORE GDB_OSABI_OPENBSD_ELF
273
 
274
static enum gdb_osabi
275
ppcobsd_core_osabi_sniffer (bfd *abfd)
276
{
277
  if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
278
    return GDB_OSABI_NETBSD_CORE;
279
 
280
  return GDB_OSABI_UNKNOWN;
281
}
282
 
283
 
284
/* Provide a prototype to silence -Wmissing-prototypes.  */
285
void _initialize_ppcobsd_tdep (void);
286
 
287
void
288
_initialize_ppcobsd_tdep (void)
289
{
290
  /* BFD doesn't set a flavour for NetBSD style a.out core files.  */
291
  gdbarch_register_osabi_sniffer (bfd_arch_powerpc, bfd_target_unknown_flavour,
292
                                  ppcobsd_core_osabi_sniffer);
293
 
294
  gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_OPENBSD_ELF,
295
                          ppcobsd_init_abi);
296
  gdbarch_register_osabi (bfd_arch_powerpc, 0, GDB_OSABI_OPENBSD_ELF,
297
                          ppcobsd_init_abi);
298
 
299
  /* Avoid initializing the register offsets again if they were
300
     already initailized by ppcobsd-nat.c.  */
301
  if (ppcobsd_reg_offsets.pc_offset == 0)
302
    {
303
      /* General-purpose registers.  */
304
      ppcobsd_reg_offsets.r0_offset = 0;
305
      ppcobsd_reg_offsets.gpr_size = 4;
306
      ppcobsd_reg_offsets.xr_size = 4;
307
      ppcobsd_reg_offsets.pc_offset = 384;
308
      ppcobsd_reg_offsets.ps_offset = 388;
309
      ppcobsd_reg_offsets.cr_offset = 392;
310
      ppcobsd_reg_offsets.lr_offset = 396;
311
      ppcobsd_reg_offsets.ctr_offset = 400;
312
      ppcobsd_reg_offsets.xer_offset = 404;
313
      ppcobsd_reg_offsets.mq_offset = 408;
314
 
315
      /* Floating-point registers.  */
316
      ppcobsd_reg_offsets.f0_offset = 128;
317
      ppcobsd_reg_offsets.fpscr_offset = -1;
318
 
319
      /* AltiVec registers.  */
320
      ppcobsd_reg_offsets.vr0_offset = 0;
321
      ppcobsd_reg_offsets.vscr_offset = 512;
322
      ppcobsd_reg_offsets.vrsave_offset = 520;
323
    }
324
 
325
  if (ppcobsd_fpreg_offsets.fpscr_offset == 0)
326
    {
327
      /* Floating-point registers.  */
328
      ppcobsd_reg_offsets.f0_offset = 0;
329
      ppcobsd_reg_offsets.fpscr_offset = 256;
330
      ppcobsd_reg_offsets.fpscr_size = 4;
331
    }
332
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.