*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / amd64-linux-nat.c
CommitLineData
a4b6fc86 1/* Native-dependent code for GNU/Linux x86-64.
0a65a603 2
f973ed9c
DJ
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
4 Free Software Foundation, Inc.
53e95fcf
JS
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 2 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, write to the Free Software
197e01b6
EZ
21 Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
53e95fcf
JS
23
24#include "defs.h"
25#include "inferior.h"
26#include "gdbcore.h"
27#include "regcache.h"
4056d258 28#include "linux-nat.h"
c4f35dd8 29
53e95fcf 30#include "gdb_assert.h"
30d52491 31#include "gdb_string.h"
53e95fcf
JS
32#include <sys/ptrace.h>
33#include <sys/debugreg.h>
34#include <sys/syscall.h>
35#include <sys/procfs.h>
c43af07c
EZ
36#include <asm/prctl.h>
37/* FIXME ezannoni-2003-07-09: we need <sys/reg.h> to be included after
38 <asm/ptrace.h> because the latter redefines FS and GS for no apparent
39 reason, and those definitions don't match the ones that libpthread_db
40 uses, which come from <sys/reg.h>. */
41/* ezannoni-2003-07-09: I think this is fixed. The extraneous defs have
42 been removed from ptrace.h in the kernel. However, better safe than
43 sorry. */
44#include <asm/ptrace.h>
33a0a2ac 45#include <sys/reg.h>
c43af07c 46#include "gdb_proc_service.h"
33a0a2ac 47
c4f35dd8
MK
48/* Prototypes for supply_gregset etc. */
49#include "gregset.h"
50
9c1488cb 51#include "amd64-tdep.h"
60fac5b8
MK
52#include "i386-linux-tdep.h"
53#include "amd64-nat.h"
54
55/* Mapping between the general-purpose registers in GNU/Linux x86-64
56 `struct user' format and GDB's register cache layout. */
57
430eaf2e 58static int amd64_linux_gregset64_reg_offset[] =
60fac5b8
MK
59{
60 RAX * 8, RBX * 8, /* %rax, %rbx */
61 RCX * 8, RDX * 8, /* %rcx, %rdx */
62 RSI * 8, RDI * 8, /* %rsi, %rdi */
63 RBP * 8, RSP * 8, /* %rbp, %rsp */
64 R8 * 8, R9 * 8, /* %r8 ... */
65 R10 * 8, R11 * 8,
66 R12 * 8, R13 * 8,
67 R14 * 8, R15 * 8, /* ... %r15 */
68 RIP * 8, EFLAGS * 8, /* %rip, %eflags */
af233647 69 CS * 8, SS * 8, /* %cs, %ss */
60fac5b8
MK
70 DS * 8, ES * 8, /* %ds, %es */
71 FS * 8, GS * 8 /* %fs, %gs */
72};
73\f
74
75/* Mapping between the general-purpose registers in GNU/Linux x86-64
76 `struct user' format and GDB's register cache layout for GNU/Linux
77 i386.
78
79 Note that most GNU/Linux x86-64 registers are 64-bit, while the
80 GNU/Linux i386 registers are all 32-bit, but since we're
81 little-endian we get away with that. */
82
83/* From <sys/reg.h> on GNU/Linux i386. */
430eaf2e 84static int amd64_linux_gregset32_reg_offset[] =
60fac5b8 85{
f5859b4d
MK
86 RAX * 8, RCX * 8, /* %eax, %ecx */
87 RDX * 8, RBX * 8, /* %edx, %ebx */
88 RSP * 8, RBP * 8, /* %esp, %ebp */
89 RSI * 8, RDI * 8, /* %esi, %edi */
90 RIP * 8, EFLAGS * 8, /* %eip, %eflags */
91 CS * 8, SS * 8, /* %cs, %ss */
92 DS * 8, ES * 8, /* %ds, %es */
93 FS * 8, GS * 8, /* %fs, %gs */
60fac5b8
MK
94 -1, -1, -1, -1, -1, -1, -1, -1,
95 -1, -1, -1, -1, -1, -1, -1, -1,
96 -1, -1, -1, -1, -1, -1, -1, -1, -1,
f5859b4d 97 ORIG_RAX * 8 /* "orig_eax" */
60fac5b8 98};
53e95fcf
JS
99\f
100
101/* Transfering the general-purpose registers between GDB, inferiors
102 and core files. */
103
60fac5b8 104/* Fill GDB's register cache with the general-purpose register values
53e95fcf
JS
105 in *GREGSETP. */
106
107void
c4f35dd8 108supply_gregset (elf_gregset_t *gregsetp)
53e95fcf 109{
60fac5b8 110 amd64_supply_native_gregset (current_regcache, gregsetp, -1);
53e95fcf
JS
111}
112
60fac5b8
MK
113/* Fill register REGNUM (if it is a general-purpose register) in
114 *GREGSETP with the value in GDB's register cache. If REGNUM is -1,
53e95fcf
JS
115 do this for all registers. */
116
117void
60fac5b8 118fill_gregset (elf_gregset_t *gregsetp, int regnum)
53e95fcf 119{
60fac5b8 120 amd64_collect_native_gregset (current_regcache, gregsetp, regnum);
53e95fcf
JS
121}
122
53e95fcf
JS
123/* Transfering floating-point registers between GDB, inferiors and cores. */
124
60fac5b8 125/* Fill GDB's register cache with the floating-point and SSE register
c4f35dd8 126 values in *FPREGSETP. */
53e95fcf
JS
127
128void
c4f35dd8 129supply_fpregset (elf_fpregset_t *fpregsetp)
53e95fcf 130{
90f90721 131 amd64_supply_fxsave (current_regcache, -1, fpregsetp);
53e95fcf
JS
132}
133
8dda9770 134/* Fill register REGNUM (if it is a floating-point or SSE register) in
60fac5b8 135 *FPREGSETP with the value in GDB's register cache. If REGNUM is
c4f35dd8 136 -1, do this for all registers. */
53e95fcf
JS
137
138void
c4f35dd8 139fill_fpregset (elf_fpregset_t *fpregsetp, int regnum)
53e95fcf 140{
722d18c2 141 amd64_collect_fxsave (current_regcache, regnum, fpregsetp);
53e95fcf 142}
53e95fcf
JS
143\f
144
145/* Transferring arbitrary registers between GDB and inferior. */
146
60fac5b8 147/* Fetch register REGNUM from the child process. If REGNUM is -1, do
53e95fcf
JS
148 this for all registers (including the floating point and SSE
149 registers). */
150
10d6c8cd
DJ
151static void
152amd64_linux_fetch_inferior_registers (int regnum)
53e95fcf
JS
153{
154 int tid;
155
a4b6fc86 156 /* GNU/Linux LWP ID's are process ID's. */
c4f35dd8
MK
157 tid = TIDGET (inferior_ptid);
158 if (tid == 0)
159 tid = PIDGET (inferior_ptid); /* Not a threaded program. */
53e95fcf 160
60fac5b8 161 if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
53e95fcf 162 {
99679982
MK
163 elf_gregset_t regs;
164
165 if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
edefbb7c 166 perror_with_name (_("Couldn't get registers"));
99679982
MK
167
168 amd64_supply_native_gregset (current_regcache, &regs, -1);
60fac5b8
MK
169 if (regnum != -1)
170 return;
53e95fcf
JS
171 }
172
18bbbd9e 173 if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
53e95fcf 174 {
99679982 175 elf_fpregset_t fpregs;
53e95fcf 176
99679982 177 if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
edefbb7c 178 perror_with_name (_("Couldn't get floating point status"));
99679982
MK
179
180 amd64_supply_fxsave (current_regcache, -1, &fpregs);
181 }
53e95fcf
JS
182}
183
60fac5b8
MK
184/* Store register REGNUM back into the child process. If REGNUM is
185 -1, do this for all registers (including the floating-point and SSE
53e95fcf 186 registers). */
c4f35dd8 187
10d6c8cd
DJ
188static void
189amd64_linux_store_inferior_registers (int regnum)
53e95fcf
JS
190{
191 int tid;
192
a4b6fc86 193 /* GNU/Linux LWP ID's are process ID's. */
c4f35dd8
MK
194 tid = TIDGET (inferior_ptid);
195 if (tid == 0)
196 tid = PIDGET (inferior_ptid); /* Not a threaded program. */
53e95fcf 197
60fac5b8 198 if (regnum == -1 || amd64_native_gregset_supplies_p (regnum))
53e95fcf 199 {
99679982
MK
200 elf_gregset_t regs;
201
202 if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
edefbb7c 203 perror_with_name (_("Couldn't get registers"));
99679982
MK
204
205 amd64_collect_native_gregset (current_regcache, &regs, regnum);
206
207 if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
edefbb7c 208 perror_with_name (_("Couldn't write registers"));
99679982 209
60fac5b8
MK
210 if (regnum != -1)
211 return;
53e95fcf
JS
212 }
213
18bbbd9e 214 if (regnum == -1 || !amd64_native_gregset_supplies_p (regnum))
53e95fcf 215 {
99679982
MK
216 elf_fpregset_t fpregs;
217
218 if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
edefbb7c 219 perror_with_name (_("Couldn't get floating point status"));
99679982
MK
220
221 amd64_collect_fxsave (current_regcache, regnum, &fpregs);
222
223 if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
edefbb7c 224 perror_with_name (_("Couldn't write floating point status"));
99679982 225
53e95fcf
JS
226 return;
227 }
53e95fcf
JS
228}
229\f
230
c4f35dd8 231static unsigned long
430eaf2e 232amd64_linux_dr_get (int regnum)
c4f35dd8
MK
233{
234 int tid;
235 unsigned long value;
53e95fcf 236
c4f35dd8
MK
237 /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
238 multi-threaded processes here. For now, pretend there is just
239 one thread. */
240 tid = PIDGET (inferior_ptid);
53e95fcf 241
c4f35dd8
MK
242 /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
243 ptrace call fails breaks debugging remote targets. The correct
244 way to fix this is to add the hardware breakpoint and watchpoint
245 stuff to the target vectore. For now, just return zero if the
246 ptrace call fails. */
247 errno = 0;
248 value = ptrace (PT_READ_U, tid,
249 offsetof (struct user, u_debugreg[regnum]), 0);
250 if (errno != 0)
251#if 0
edefbb7c 252 perror_with_name (_("Couldn't read debug register"));
c4f35dd8
MK
253#else
254 return 0;
53e95fcf
JS
255#endif
256
c4f35dd8
MK
257 return value;
258}
53e95fcf
JS
259
260static void
430eaf2e 261amd64_linux_dr_set (int regnum, unsigned long value)
53e95fcf 262{
c4f35dd8 263 int tid;
53e95fcf 264
c4f35dd8
MK
265 /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
266 multi-threaded processes here. For now, pretend there is just
267 one thread. */
268 tid = PIDGET (inferior_ptid);
53e95fcf 269
c4f35dd8
MK
270 errno = 0;
271 ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
272 if (errno != 0)
edefbb7c 273 perror_with_name (_("Couldn't write debug register"));
c4f35dd8 274}
53e95fcf 275
c4f35dd8 276void
430eaf2e 277amd64_linux_dr_set_control (unsigned long control)
c4f35dd8 278{
430eaf2e 279 amd64_linux_dr_set (DR_CONTROL, control);
c4f35dd8 280}
53e95fcf 281
c4f35dd8 282void
430eaf2e 283amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
b7c4cbf8 284{
c4f35dd8
MK
285 gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
286
430eaf2e 287 amd64_linux_dr_set (DR_FIRSTADDR + regnum, addr);
b7c4cbf8
AJ
288}
289
53e95fcf 290void
430eaf2e 291amd64_linux_dr_reset_addr (int regnum)
53e95fcf 292{
c4f35dd8
MK
293 gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
294
430eaf2e 295 amd64_linux_dr_set (DR_FIRSTADDR + regnum, 0L);
53e95fcf 296}
8cfda98c 297
c4f35dd8 298unsigned long
430eaf2e 299amd64_linux_dr_get_status (void)
8cfda98c 300{
430eaf2e 301 return amd64_linux_dr_get (DR_STATUS);
8cfda98c 302}
5bca7895 303\f
c43af07c 304
50d71875
AC
305/* This function is called by libthread_db as part of its handling of
306 a request for a thread's local storage address. */
307
5bca7895 308ps_err_e
c43af07c
EZ
309ps_get_thread_area (const struct ps_prochandle *ph,
310 lwpid_t lwpid, int idx, void **base)
311{
50d71875
AC
312 if (gdbarch_ptr_bit (current_gdbarch) == 32)
313 {
314 /* The full structure is found in <asm-i386/ldt.h>. The second
315 integer is the LDT's base_address and that is used to locate
316 the thread's local storage. See i386-linux-nat.c more
317 info. */
318 unsigned int desc[4];
319
320 /* This code assumes that "int" is 32 bits and that
321 GET_THREAD_AREA returns no more than 4 int values. */
322 gdb_assert (sizeof (int) == 4);
323#ifndef PTRACE_GET_THREAD_AREA
324#define PTRACE_GET_THREAD_AREA 25
325#endif
326 if (ptrace (PTRACE_GET_THREAD_AREA,
327 lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
328 return PS_ERR;
329
330 /* Extend the value to 64 bits. Here it's assumed that a "long"
331 and a "void *" are the same. */
332 (*base) = (void *) (long) desc[1];
333 return PS_OK;
334 }
335 else
336 {
337 /* This definition comes from prctl.h, but some kernels may not
338 have it. */
c43af07c
EZ
339#ifndef PTRACE_ARCH_PRCTL
340#define PTRACE_ARCH_PRCTL 30
341#endif
50d71875
AC
342 /* FIXME: ezannoni-2003-07-09 see comment above about include
343 file order. We could be getting bogus values for these two. */
344 gdb_assert (FS < ELF_NGREG);
345 gdb_assert (GS < ELF_NGREG);
346 switch (idx)
347 {
348 case FS:
349 if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
350 return PS_OK;
351 break;
352 case GS:
353 if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
354 return PS_OK;
355 break;
356 default: /* Should not happen. */
357 return PS_BADADDR;
358 }
c43af07c 359 }
b6d42148 360 return PS_ERR; /* ptrace failed. */
c43af07c 361}
5bca7895 362\f
c43af07c 363
10d6c8cd
DJ
364static void (*super_post_startup_inferior) (ptid_t ptid);
365
366static void
367amd64_linux_child_post_startup_inferior (ptid_t ptid)
4056d258
ML
368{
369 i386_cleanup_dregs ();
10d6c8cd 370 super_post_startup_inferior (ptid);
4056d258 371}
60fac5b8
MK
372\f
373
374/* Provide a prototype to silence -Wmissing-prototypes. */
430eaf2e 375void _initialize_amd64_linux_nat (void);
60fac5b8
MK
376
377void
430eaf2e 378_initialize_amd64_linux_nat (void)
60fac5b8 379{
10d6c8cd
DJ
380 struct target_ops *t;
381
430eaf2e 382 amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
60fac5b8 383 amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
430eaf2e 384 amd64_native_gregset64_reg_offset = amd64_linux_gregset64_reg_offset;
60fac5b8 385
430eaf2e 386 gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
60fac5b8 387 == amd64_native_gregset32_num_regs);
430eaf2e 388 gdb_assert (ARRAY_SIZE (amd64_linux_gregset64_reg_offset)
60fac5b8 389 == amd64_native_gregset64_num_regs);
10d6c8cd
DJ
390
391 /* Fill in the generic GNU/Linux methods. */
392 t = linux_target ();
393
394 /* Override the GNU/Linux inferior startup hook. */
395 super_post_startup_inferior = t->to_post_startup_inferior;
396 t->to_post_startup_inferior = amd64_linux_child_post_startup_inferior;
397
398 /* Add our register access methods. */
399 t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
400 t->to_store_registers = amd64_linux_store_inferior_registers;
401
402 /* Register the target. */
f973ed9c 403 linux_nat_add_target (t);
60fac5b8 404}
This page took 0.410122 seconds and 4 git commands to generate.