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