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

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gdb/] [gdb-6.8/] [gdb/] [amd64-linux-tdep.c] - Blame information for rev 25

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 25 jlechner
/* Target-dependent code for GNU/Linux x86-64.
2
 
3
   Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008
4
   Free Software Foundation, Inc.
5
   Contributed by Jiri Smid, SuSE Labs.
6
 
7
   This file is part of GDB.
8
 
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
 
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
 
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
 
22
#include "defs.h"
23
#include "frame.h"
24
#include "gdbcore.h"
25
#include "regcache.h"
26
#include "osabi.h"
27
#include "symtab.h"
28
#include "gdbtypes.h"
29
#include "reggroups.h"
30
#include "amd64-linux-tdep.h"
31
 
32
#include "gdb_string.h"
33
 
34
#include "amd64-tdep.h"
35
#include "solib-svr4.h"
36
 
37
/* Mapping between the general-purpose registers in `struct user'
38
   format and GDB's register cache layout.  */
39
 
40
/* From <sys/reg.h>.  */
41
static int amd64_linux_gregset_reg_offset[] =
42
{
43
  10 * 8,                       /* %rax */
44
  5 * 8,                        /* %rbx */
45
  11 * 8,                       /* %rcx */
46
  12 * 8,                       /* %rdx */
47
  13 * 8,                       /* %rsi */
48
  14 * 8,                       /* %rdi */
49
  4 * 8,                        /* %rbp */
50
  19 * 8,                       /* %rsp */
51
  9 * 8,                        /* %r8 ... */
52
  8 * 8,
53
  7 * 8,
54
  6 * 8,
55
  3 * 8,
56
  2 * 8,
57
  1 * 8,
58
 
59
  16 * 8,                       /* %rip */
60
  18 * 8,                       /* %eflags */
61
  17 * 8,                       /* %cs */
62
  20 * 8,                       /* %ss */
63
  23 * 8,                       /* %ds */
64
  24 * 8,                       /* %es */
65
  25 * 8,                       /* %fs */
66
  26 * 8                        /* %gs */
67
};
68
 
69
 
70
/* Support for signal handlers.  */
71
 
72
#define LINUX_SIGTRAMP_INSN0    0x48    /* mov $NNNNNNNN, %rax */
73
#define LINUX_SIGTRAMP_OFFSET0  0
74
#define LINUX_SIGTRAMP_INSN1    0x0f    /* syscall */
75
#define LINUX_SIGTRAMP_OFFSET1  7
76
 
77
static const gdb_byte linux_sigtramp_code[] =
78
{
79
  /* mov $__NR_rt_sigreturn, %rax */
80
  LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00,
81
  /* syscall */
82
  LINUX_SIGTRAMP_INSN1, 0x05
83
};
84
 
85
#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
86
 
87
/* If PC is in a sigtramp routine, return the address of the start of
88
   the routine.  Otherwise, return 0.  */
89
 
90
static CORE_ADDR
91
amd64_linux_sigtramp_start (struct frame_info *next_frame)
92
{
93
  CORE_ADDR pc = frame_pc_unwind (next_frame);
94
  gdb_byte buf[LINUX_SIGTRAMP_LEN];
95
 
96
  /* We only recognize a signal trampoline if PC is at the start of
97
     one of the two instructions.  We optimize for finding the PC at
98
     the start, as will be the case when the trampoline is not the
99
     first frame on the stack.  We assume that in the case where the
100
     PC is not at the start of the instruction sequence, there will be
101
     a few trailing readable bytes on the stack.  */
102
 
103
  if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
104
    return 0;
105
 
106
  if (buf[0] != LINUX_SIGTRAMP_INSN0)
107
    {
108
      if (buf[0] != LINUX_SIGTRAMP_INSN1)
109
        return 0;
110
 
111
      pc -= LINUX_SIGTRAMP_OFFSET1;
112
      if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf))
113
        return 0;
114
    }
115
 
116
  if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
117
    return 0;
118
 
119
  return pc;
120
}
121
 
122
/* Return whether the frame preceding NEXT_FRAME corresponds to a
123
   GNU/Linux sigtramp routine.  */
124
 
125
static int
126
amd64_linux_sigtramp_p (struct frame_info *next_frame)
127
{
128
  CORE_ADDR pc = frame_pc_unwind (next_frame);
129
  char *name;
130
 
131
  find_pc_partial_function (pc, &name, NULL, NULL);
132
 
133
  /* If we have NAME, we can optimize the search.  The trampoline is
134
     named __restore_rt.  However, it isn't dynamically exported from
135
     the shared C library, so the trampoline may appear to be part of
136
     the preceding function.  This should always be sigaction,
137
     __sigaction, or __libc_sigaction (all aliases to the same
138
     function).  */
139
  if (name == NULL || strstr (name, "sigaction") != NULL)
140
    return (amd64_linux_sigtramp_start (next_frame) != 0);
141
 
142
  return (strcmp ("__restore_rt", name) == 0);
143
}
144
 
145
/* Offset to struct sigcontext in ucontext, from <asm/ucontext.h>.  */
146
#define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40
147
 
148
/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp
149
   routine, return the address of the associated sigcontext structure.  */
150
 
151
static CORE_ADDR
152
amd64_linux_sigcontext_addr (struct frame_info *next_frame)
153
{
154
  CORE_ADDR sp;
155
  gdb_byte buf[8];
156
 
157
  frame_unwind_register (next_frame,
158
                         gdbarch_sp_regnum (get_frame_arch (next_frame)), buf);
159
  sp = extract_unsigned_integer (buf, 8);
160
 
161
  /* The sigcontext structure is part of the user context.  A pointer
162
     to the user context is passed as the third argument to the signal
163
     handler, i.e. in %rdx.  Unfortunately %rdx isn't preserved across
164
     function calls so we can't use it.  Fortunately the user context
165
     is part of the signal frame and the unwound %rsp directly points
166
     at it.  */
167
  return sp + AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET;
168
}
169
 
170
 
171
/* From <asm/sigcontext.h>.  */
172
static int amd64_linux_sc_reg_offset[] =
173
{
174
  13 * 8,                       /* %rax */
175
  11 * 8,                       /* %rbx */
176
  14 * 8,                       /* %rcx */
177
  12 * 8,                       /* %rdx */
178
  9 * 8,                        /* %rsi */
179
  8 * 8,                        /* %rdi */
180
  10 * 8,                       /* %rbp */
181
  15 * 8,                       /* %rsp */
182
 
183
  1 * 8,                        /* %r9 */
184
  2 * 8,                        /* %r10 */
185
  3 * 8,                        /* %r11 */
186
  4 * 8,                        /* %r12 */
187
  5 * 8,                        /* %r13 */
188
  6 * 8,                        /* %r14 */
189
  7 * 8,                        /* %r15 */
190
  16 * 8,                       /* %rip */
191
  17 * 8,                       /* %eflags */
192
 
193
  /* FIXME: kettenis/2002030531: The registers %cs, %fs and %gs are
194
     available in `struct sigcontext'.  However, they only occupy two
195
     bytes instead of four, which makes using them here rather
196
     difficult.  Leave them out for now.  */
197
  -1,                           /* %cs */
198
  -1,                           /* %ss */
199
  -1,                           /* %ds */
200
  -1,                           /* %es */
201
  -1,                           /* %fs */
202
  -1                            /* %gs */
203
};
204
 
205
/* Replacement register functions which know about %orig_rax.  */
206
 
207
static const char *
208
amd64_linux_register_name (struct gdbarch *gdbarch, int reg)
209
{
210
  if (reg == AMD64_LINUX_ORIG_RAX_REGNUM)
211
    return "orig_rax";
212
 
213
  return amd64_register_name (gdbarch, reg);
214
}
215
 
216
static struct type *
217
amd64_linux_register_type (struct gdbarch *gdbarch, int reg)
218
{
219
  if (reg == AMD64_LINUX_ORIG_RAX_REGNUM)
220
    return builtin_type_int64;
221
 
222
  return amd64_register_type (gdbarch, reg);
223
}
224
 
225
static int
226
amd64_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
227
                                 struct reggroup *group)
228
{
229
  if (regnum == AMD64_LINUX_ORIG_RAX_REGNUM)
230
    return (group == system_reggroup
231
            || group == save_reggroup
232
            || group == restore_reggroup);
233
  return default_register_reggroup_p (gdbarch, regnum, group);
234
}
235
 
236
/* Set the program counter for process PTID to PC.  */
237
 
238
static void
239
amd64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
240
{
241
  regcache_cooked_write_unsigned (regcache, AMD64_RIP_REGNUM, pc);
242
 
243
  /* We must be careful with modifying the program counter.  If we
244
     just interrupted a system call, the kernel might try to restart
245
     it when we resume the inferior.  On restarting the system call,
246
     the kernel will try backing up the program counter even though it
247
     no longer points at the system call.  This typically results in a
248
     SIGSEGV or SIGILL.  We can prevent this by writing `-1' in the
249
     "orig_rax" pseudo-register.
250
 
251
     Note that "orig_rax" is saved when setting up a dummy call frame.
252
     This means that it is properly restored when that frame is
253
     popped, and that the interrupted system call will be restarted
254
     when we resume the inferior on return from a function call from
255
     within GDB.  In all other cases the system call will not be
256
     restarted.  */
257
  regcache_cooked_write_unsigned (regcache, AMD64_LINUX_ORIG_RAX_REGNUM, -1);
258
}
259
 
260
static void
261
amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
262
{
263
  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
264
 
265
  tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset;
266
  tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset);
267
  tdep->sizeof_gregset = 27 * 8;
268
 
269
  amd64_init_abi (info, gdbarch);
270
 
271
  tdep->sigtramp_p = amd64_linux_sigtramp_p;
272
  tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
273
  tdep->sc_reg_offset = amd64_linux_sc_reg_offset;
274
  tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset);
275
 
276
  /* GNU/Linux uses SVR4-style shared libraries.  */
277
  set_solib_svr4_fetch_link_map_offsets
278
    (gdbarch, svr4_lp64_fetch_link_map_offsets);
279
 
280
  /* Add the %orig_rax register used for syscall restarting.  */
281
  set_gdbarch_write_pc (gdbarch, amd64_linux_write_pc);
282
  set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS);
283
  set_gdbarch_register_name (gdbarch, amd64_linux_register_name);
284
  set_gdbarch_register_type (gdbarch, amd64_linux_register_type);
285
  set_gdbarch_register_reggroup_p (gdbarch, amd64_linux_register_reggroup_p);
286
 
287
  /* Enable TLS support.  */
288
  set_gdbarch_fetch_tls_load_module_address (gdbarch,
289
                                             svr4_fetch_objfile_link_map);
290
}
291
 
292
 
293
/* Provide a prototype to silence -Wmissing-prototypes.  */
294
extern void _initialize_amd64_linux_tdep (void);
295
 
296
void
297
_initialize_amd64_linux_tdep (void)
298
{
299
  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
300
                          GDB_OSABI_LINUX, amd64_linux_init_abi);
301
}

powered by: WebSVN 2.1.0

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