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

Subversion Repositories openrisc

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

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

Line No. Rev Author Line
1 24 jeremybenn
/* Target-dependent code for OpenBSD/amd64.
2
 
3
   Copyright (C) 2003, 2004, 2005, 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 "frame.h"
22
#include "frame-unwind.h"
23
#include "gdbcore.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 "trad-frame.h"
31
 
32
#include "gdb_assert.h"
33
#include "gdb_string.h"
34
 
35
#include "amd64-tdep.h"
36
#include "i387-tdep.h"
37
#include "solib-svr4.h"
38
#include "bsd-uthread.h"
39
 
40
/* Support for core dumps.  */
41
 
42
static void
43
amd64obsd_supply_regset (const struct regset *regset,
44
                         struct regcache *regcache, int regnum,
45
                         const void *regs, size_t len)
46
{
47
  const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
48
 
49
  gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
50
 
51
  i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
52
  amd64_supply_fxsave (regcache, regnum,
53
                       ((const gdb_byte *)regs) + tdep->sizeof_gregset);
54
}
55
 
56
static const struct regset *
57
amd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
58
                                    const char *sect_name, size_t sect_size)
59
{
60
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
61
 
62
  /* OpenBSD core dumps don't use seperate register sets for the
63
     general-purpose and floating-point registers.  */
64
 
65
  if (strcmp (sect_name, ".reg") == 0
66
      && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
67
    {
68
      if (tdep->gregset == NULL)
69
        tdep->gregset = regset_alloc (gdbarch, amd64obsd_supply_regset, NULL);
70
      return tdep->gregset;
71
    }
72
 
73
  return NULL;
74
}
75
 
76
 
77
/* Support for signal handlers.  */
78
 
79
/* Default page size.  */
80
static const int amd64obsd_page_size = 4096;
81
 
82
/* Return whether the frame preceding NEXT_FRAME corresponds to an
83
   OpenBSD sigtramp routine.  */
84
 
85
static int
86
amd64obsd_sigtramp_p (struct frame_info *next_frame)
87
{
88
  CORE_ADDR pc = frame_pc_unwind (next_frame);
89
  CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
90
  const gdb_byte sigreturn[] =
91
  {
92
    0x48, 0xc7, 0xc0,
93
    0x67, 0x00, 0x00, 0x00,     /* movq $SYS_sigreturn, %rax */
94
    0xcd, 0x80                  /* int $0x80 */
95
  };
96
  size_t buflen = (sizeof sigreturn) + 1;
97
  gdb_byte *buf;
98
  char *name;
99
 
100
  /* If the function has a valid symbol name, it isn't a
101
     trampoline.  */
102
  find_pc_partial_function (pc, &name, NULL, NULL);
103
  if (name != NULL)
104
    return 0;
105
 
106
  /* If the function lives in a valid section (even without a starting
107
     point) it isn't a trampoline.  */
108
  if (find_pc_section (pc) != NULL)
109
    return 0;
110
 
111
  /* If we can't read the instructions at START_PC, return zero.  */
112
  buf = alloca ((sizeof sigreturn) + 1);
113
  if (!safe_frame_unwind_memory (next_frame, start_pc + 6, buf, buflen))
114
    return 0;
115
 
116
  /* Check for sigreturn(2).  Depending on how the assembler encoded
117
     the `movq %rsp, %rdi' instruction, the code starts at offset 6 or
118
     7.  */
119
  if (memcmp (buf, sigreturn, sizeof sigreturn)
120
      && memcpy (buf + 1, sigreturn, sizeof sigreturn))
121
    return 0;
122
 
123
  return 1;
124
}
125
 
126
/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
127
   routine, return the address of the associated sigcontext structure.  */
128
 
129
static CORE_ADDR
130
amd64obsd_sigcontext_addr (struct frame_info *next_frame)
131
{
132
  CORE_ADDR pc = frame_pc_unwind (next_frame);
133
  ULONGEST offset = (pc & (amd64obsd_page_size - 1));
134
 
135
  /* The %rsp register points at `struct sigcontext' upon entry of a
136
     signal trampoline.  The relevant part of the trampoline is
137
 
138
        call    *%rax
139
        movq    %rsp, %rdi
140
        pushq   %rdi
141
        movq    $SYS_sigreturn,%rax
142
        int     $0x80
143
 
144
     (see /usr/src/sys/arch/amd64/amd64/locore.S).  The `pushq'
145
     instruction clobbers %rsp, but its value is saved in `%rdi'.  */
146
 
147
  if (offset > 5)
148
    return frame_unwind_register_unsigned (next_frame, AMD64_RDI_REGNUM);
149
  else
150
    return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
151
}
152
 
153
/* OpenBSD 3.5 or later.  */
154
 
155
/* Mapping between the general-purpose registers in `struct reg'
156
   format and GDB's register cache layout.  */
157
 
158
/* From <machine/reg.h>.  */
159
int amd64obsd_r_reg_offset[] =
160
{
161
  14 * 8,                       /* %rax */
162
  13 * 8,                       /* %rbx */
163
  3 * 8,                        /* %rcx */
164
  2 * 8,                        /* %rdx */
165
  1 * 8,                        /* %rsi */
166
 
167
  12 * 8,                       /* %rbp */
168
  15 * 8,                       /* %rsp */
169
  4 * 8,                        /* %r8 .. */
170
  5 * 8,
171
  6 * 8,
172
  7 * 8,
173
  8 * 8,
174
  9 * 8,
175
  10 * 8,
176
  11 * 8,                       /* ... %r15 */
177
  16 * 8,                       /* %rip */
178
  17 * 8,                       /* %eflags */
179
  18 * 8,                       /* %cs */
180
  19 * 8,                       /* %ss */
181
  20 * 8,                       /* %ds */
182
  21 * 8,                       /* %es */
183
  22 * 8,                       /* %fs */
184
  23 * 8                        /* %gs */
185
};
186
 
187
/* From <machine/signal.h>.  */
188
static int amd64obsd_sc_reg_offset[] =
189
{
190
  14 * 8,                       /* %rax */
191
  13 * 8,                       /* %rbx */
192
  3 * 8,                        /* %rcx */
193
  2 * 8,                        /* %rdx */
194
  1 * 8,                        /* %rsi */
195
 
196
  12 * 8,                       /* %rbp */
197
  24 * 8,                       /* %rsp */
198
  4 * 8,                        /* %r8 ... */
199
  5 * 8,
200
  6 * 8,
201
  7 * 8,
202
  8 * 8,
203
  9 * 8,
204
  10 * 8,
205
  11 * 8,                       /* ... %r15 */
206
  21 * 8,                       /* %rip */
207
  23 * 8,                       /* %eflags */
208
  22 * 8,                       /* %cs */
209
  25 * 8,                       /* %ss */
210
  18 * 8,                       /* %ds */
211
  17 * 8,                       /* %es */
212
  16 * 8,                       /* %fs */
213
  15 * 8                        /* %gs */
214
};
215
 
216
/* From /usr/src/lib/libpthread/arch/amd64/uthread_machdep.c.  */
217
static int amd64obsd_uthread_reg_offset[] =
218
{
219
  19 * 8,                       /* %rax */
220
  16 * 8,                       /* %rbx */
221
  18 * 8,                       /* %rcx */
222
  17 * 8,                       /* %rdx */
223
  14 * 8,                       /* %rsi */
224
  13 * 8,                       /* %rdi */
225
  15 * 8,                       /* %rbp */
226
  -1,                           /* %rsp */
227
  12 * 8,                       /* %r8 ... */
228
  11 * 8,
229
  10 * 8,
230
  9 * 8,
231
  8 * 8,
232
  7 * 8,
233
  6 * 8,
234
  5 * 8,                        /* ... %r15 */
235
  20 * 8,                       /* %rip */
236
  4 * 8,                        /* %eflags */
237
  21 * 8,                       /* %cs */
238
  -1,                           /* %ss */
239
  3 * 8,                        /* %ds */
240
  2 * 8,                        /* %es */
241
  1 * 8,                        /* %fs */
242
 
243
};
244
 
245
/* Offset within the thread structure where we can find the saved
246
   stack pointer (%esp).  */
247
#define AMD64OBSD_UTHREAD_RSP_OFFSET    400
248
 
249
static void
250
amd64obsd_supply_uthread (struct regcache *regcache,
251
                          int regnum, CORE_ADDR addr)
252
{
253
  CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
254
  CORE_ADDR sp = 0;
255
  gdb_byte buf[8];
256
  int i;
257
 
258
  gdb_assert (regnum >= -1);
259
 
260
  if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
261
    {
262
      int offset;
263
 
264
      /* Fetch stack pointer from thread structure.  */
265
      sp = read_memory_unsigned_integer (sp_addr, 8);
266
 
267
      /* Adjust the stack pointer such that it looks as if we just
268
         returned from _thread_machdep_switch.  */
269
      offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
270
      store_unsigned_integer (buf, 8, sp + offset);
271
      regcache_raw_supply (regcache, AMD64_RSP_REGNUM, buf);
272
    }
273
 
274
  for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
275
    {
276
      if (amd64obsd_uthread_reg_offset[i] != -1
277
          && (regnum == -1 || regnum == i))
278
        {
279
          /* Fetch stack pointer from thread structure (if we didn't
280
             do so already).  */
281
          if (sp == 0)
282
            sp = read_memory_unsigned_integer (sp_addr, 8);
283
 
284
          /* Read the saved register from the stack frame.  */
285
          read_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
286
          regcache_raw_supply (regcache, i, buf);
287
        }
288
    }
289
}
290
 
291
static void
292
amd64obsd_collect_uthread (const struct regcache *regcache,
293
                           int regnum, CORE_ADDR addr)
294
{
295
  CORE_ADDR sp_addr = addr + AMD64OBSD_UTHREAD_RSP_OFFSET;
296
  CORE_ADDR sp = 0;
297
  gdb_byte buf[8];
298
  int i;
299
 
300
  gdb_assert (regnum >= -1);
301
 
302
  if (regnum == -1 || regnum == AMD64_RSP_REGNUM)
303
    {
304
      int offset;
305
 
306
      /* Calculate the stack pointer (frame pointer) that will be
307
         stored into the thread structure.  */
308
      offset = amd64obsd_uthread_reg_offset[AMD64_RIP_REGNUM] + 8;
309
      regcache_raw_collect (regcache, AMD64_RSP_REGNUM, buf);
310
      sp = extract_unsigned_integer (buf, 8) - offset;
311
 
312
      /* Store the stack pointer.  */
313
      write_memory_unsigned_integer (sp_addr, 8, sp);
314
 
315
      /* The stack pointer was (potentially) modified.  Make sure we
316
         build a proper stack frame.  */
317
      regnum = -1;
318
    }
319
 
320
  for (i = 0; i < ARRAY_SIZE (amd64obsd_uthread_reg_offset); i++)
321
    {
322
      if (amd64obsd_uthread_reg_offset[i] != -1
323
          && (regnum == -1 || regnum == i))
324
        {
325
          /* Fetch stack pointer from thread structure (if we didn't
326
             calculate it already).  */
327
          if (sp == 0)
328
            sp = read_memory_unsigned_integer (sp_addr, 8);
329
 
330
          /* Write the register into the stack frame.  */
331
          regcache_raw_collect (regcache, i, buf);
332
          write_memory (sp + amd64obsd_uthread_reg_offset[i], buf, 8);
333
        }
334
    }
335
}
336
/* Kernel debugging support.  */
337
 
338
/* From <machine/frame.h>.  Easy since `struct trapframe' matches
339
   `struct sigcontext'.  */
340
#define amd64obsd_tf_reg_offset amd64obsd_sc_reg_offset
341
 
342
static struct trad_frame_cache *
343
amd64obsd_trapframe_cache(struct frame_info *next_frame, void **this_cache)
344
{
345
  struct trad_frame_cache *cache;
346
  CORE_ADDR func, sp, addr;
347
  ULONGEST cs;
348
  char *name;
349
  int i;
350
 
351
  if (*this_cache)
352
    return *this_cache;
353
 
354
  cache = trad_frame_cache_zalloc (next_frame);
355
  *this_cache = cache;
356
 
357
  /* NORMAL_FRAME matches the type in amd64obsd_trapframe_unwind, but
358
     SIGTRAMP_FRAME might be more appropriate.  */
359
  func = frame_func_unwind (next_frame, NORMAL_FRAME);
360
  sp = frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
361
 
362
  find_pc_partial_function (func, &name, NULL, NULL);
363
  if (name && strncmp (name, "Xintr", 5) == 0)
364
    addr = sp + 8;              /* It's an interrupt frame.  */
365
  else
366
    addr = sp;
367
 
368
  for (i = 0; i < ARRAY_SIZE (amd64obsd_tf_reg_offset); i++)
369
    if (amd64obsd_tf_reg_offset[i] != -1)
370
      trad_frame_set_reg_addr (cache, i, addr + amd64obsd_tf_reg_offset[i]);
371
 
372
  /* Read %cs from trap frame.  */
373
  addr += amd64obsd_tf_reg_offset[AMD64_CS_REGNUM];
374
  cs = read_memory_unsigned_integer (addr, 8);
375
  if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
376
    {
377
      /* Trap from user space; terminate backtrace.  */
378
      trad_frame_set_id (cache, null_frame_id);
379
    }
380
  else
381
    {
382
      /* Construct the frame ID using the function start.  */
383
      trad_frame_set_id (cache, frame_id_build (sp + 16, func));
384
    }
385
 
386
  return cache;
387
}
388
 
389
static void
390
amd64obsd_trapframe_this_id (struct frame_info *next_frame,
391
                             void **this_cache, struct frame_id *this_id)
392
{
393
  struct trad_frame_cache *cache =
394
    amd64obsd_trapframe_cache (next_frame, this_cache);
395
 
396
  trad_frame_get_id (cache, this_id);
397
}
398
 
399
static void
400
amd64obsd_trapframe_prev_register (struct frame_info *next_frame,
401
                                   void **this_cache, int regnum,
402
                                   int *optimizedp, enum lval_type *lvalp,
403
                                   CORE_ADDR *addrp, int *realnump,
404
                                   gdb_byte *valuep)
405
{
406
  struct trad_frame_cache *cache =
407
    amd64obsd_trapframe_cache (next_frame, this_cache);
408
 
409
  trad_frame_get_register (cache, next_frame, regnum,
410
                           optimizedp, lvalp, addrp, realnump, valuep);
411
}
412
 
413
static int
414
amd64obsd_trapframe_sniffer (const struct frame_unwind *self,
415
                             struct frame_info *next_frame,
416
                             void **this_prologue_cache)
417
{
418
  ULONGEST cs;
419
  char *name;
420
 
421
  /* Check Current Privilege Level and bail out if we're not executing
422
     in kernel space.  */
423
  cs = frame_unwind_register_unsigned (next_frame, AMD64_CS_REGNUM);
424
  if ((cs & I386_SEL_RPL) == I386_SEL_UPL)
425
    return 0;
426
 
427
  find_pc_partial_function (frame_pc_unwind (next_frame), &name, NULL, NULL);
428
  return (name && ((strcmp (name, "calltrap") == 0)
429
                   || (strcmp (name, "osyscall1") == 0)
430
                   || (strcmp (name, "Xsyscall") == 0)
431
                   || (strncmp (name, "Xintr", 5) == 0)));
432
}
433
 
434
static const struct frame_unwind amd64obsd_trapframe_unwind = {
435
  /* FIXME: kettenis/20051219: This really is more like an interrupt
436
     frame, but SIGTRAMP_FRAME would print <signal handler called>,
437
     which really is not what we want here.  */
438
  NORMAL_FRAME,
439
  amd64obsd_trapframe_this_id,
440
  amd64obsd_trapframe_prev_register,
441
  NULL,
442
  amd64obsd_trapframe_sniffer
443
};
444
 
445
 
446
static void
447
amd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
448
{
449
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
450
 
451
  amd64_init_abi (info, gdbarch);
452
 
453
  /* Initialize general-purpose register set details.  */
454
  tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
455
  tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
456
  tdep->sizeof_gregset = 24 * 8;
457
 
458
  set_gdbarch_regset_from_core_section (gdbarch,
459
                                        amd64obsd_regset_from_core_section);
460
 
461
  tdep->jb_pc_offset = 7 * 8;
462
 
463
  tdep->sigtramp_p = amd64obsd_sigtramp_p;
464
  tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
465
  tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
466
  tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
467
 
468
  /* OpenBSD provides a user-level threads implementation.  */
469
  bsd_uthread_set_supply_uthread (gdbarch, amd64obsd_supply_uthread);
470
  bsd_uthread_set_collect_uthread (gdbarch, amd64obsd_collect_uthread);
471
 
472
  /* OpenBSD uses SVR4-style shared libraries.  */
473
  set_solib_svr4_fetch_link_map_offsets
474
    (gdbarch, svr4_lp64_fetch_link_map_offsets);
475
 
476
  /* Unwind kernel trap frames correctly.  */
477
  frame_unwind_prepend_unwinder (gdbarch, &amd64obsd_trapframe_unwind);
478
}
479
 
480
 
481
/* Provide a prototype to silence -Wmissing-prototypes.  */
482
void _initialize_amd64obsd_tdep (void);
483
 
484
void
485
_initialize_amd64obsd_tdep (void)
486
{
487
  /* The OpenBSD/amd64 native dependent code makes this assumption.  */
488
  gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
489
 
490
  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
491
                          GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
492
 
493
  /* OpenBSD uses traditional (a.out) NetBSD-style core dumps.  */
494
  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
495
                          GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
496
}

powered by: WebSVN 2.1.0

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