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