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