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

Subversion Repositories scarts

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 25 jlechner
/* Native-dependent code for GNU/Linux x86-64.
2
 
3
   Copyright (C) 2001, 2002, 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 "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
 
57
static 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.  */
88
static 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
 
111
void
112
supply_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
 
121
void
122
fill_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
 
133
void
134
supply_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
 
143
void
144
fill_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
 
157
static void
158
amd64_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
159
{
160
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
161
  int tid;
162
 
163
  /* GNU/Linux LWP ID's are process ID's.  */
164
  tid = TIDGET (inferior_ptid);
165
  if (tid == 0)
166
    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
167
 
168
  if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
169
    {
170
      elf_gregset_t regs;
171
 
172
      if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
173
        perror_with_name (_("Couldn't get registers"));
174
 
175
      amd64_supply_native_gregset (regcache, &regs, -1);
176
      if (regnum != -1)
177
        return;
178
    }
179
 
180
  if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
181
    {
182
      elf_fpregset_t fpregs;
183
 
184
      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
185
        perror_with_name (_("Couldn't get floating point status"));
186
 
187
      amd64_supply_fxsave (regcache, -1, &fpregs);
188
    }
189
}
190
 
191
/* Store register REGNUM back into the child process.  If REGNUM is
192
   -1, do this for all registers (including the floating-point and SSE
193
   registers).  */
194
 
195
static void
196
amd64_linux_store_inferior_registers (struct regcache *regcache, int regnum)
197
{
198
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
199
  int tid;
200
 
201
  /* GNU/Linux LWP ID's are process ID's.  */
202
  tid = TIDGET (inferior_ptid);
203
  if (tid == 0)
204
    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
205
 
206
  if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
207
    {
208
      elf_gregset_t regs;
209
 
210
      if (ptrace (PTRACE_GETREGS, tid, 0, (long) &regs) < 0)
211
        perror_with_name (_("Couldn't get registers"));
212
 
213
      amd64_collect_native_gregset (regcache, &regs, regnum);
214
 
215
      if (ptrace (PTRACE_SETREGS, tid, 0, (long) &regs) < 0)
216
        perror_with_name (_("Couldn't write registers"));
217
 
218
      if (regnum != -1)
219
        return;
220
    }
221
 
222
  if (regnum == -1 || !amd64_native_gregset_supplies_p (gdbarch, regnum))
223
    {
224
      elf_fpregset_t fpregs;
225
 
226
      if (ptrace (PTRACE_GETFPREGS, tid, 0, (long) &fpregs) < 0)
227
        perror_with_name (_("Couldn't get floating point status"));
228
 
229
      amd64_collect_fxsave (regcache, regnum, &fpregs);
230
 
231
      if (ptrace (PTRACE_SETFPREGS, tid, 0, (long) &fpregs) < 0)
232
        perror_with_name (_("Couldn't write floating point status"));
233
 
234
      return;
235
    }
236
}
237
 
238
/* Support for debug registers.  */
239
 
240
static unsigned long amd64_linux_dr[DR_CONTROL + 1];
241
 
242
static unsigned long
243
amd64_linux_dr_get (ptid_t ptid, int regnum)
244
{
245
  int tid;
246
  unsigned long value;
247
 
248
  tid = TIDGET (ptid);
249
  if (tid == 0)
250
    tid = PIDGET (ptid);
251
 
252
  /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
253
     ptrace call fails breaks debugging remote targets.  The correct
254
     way to fix this is to add the hardware breakpoint and watchpoint
255
     stuff to the target vector.  For now, just return zero if the
256
     ptrace call fails.  */
257
  errno = 0;
258
  value = ptrace (PTRACE_PEEKUSER, tid,
259
                  offsetof (struct user, u_debugreg[regnum]), 0);
260
  if (errno != 0)
261
#if 0
262
    perror_with_name (_("Couldn't read debug register"));
263
#else
264
    return 0;
265
#endif
266
 
267
  return value;
268
}
269
 
270
static void
271
amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
272
{
273
  int tid;
274
 
275
  tid = TIDGET (ptid);
276
  if (tid == 0)
277
    tid = PIDGET (ptid);
278
 
279
  errno = 0;
280
  ptrace (PTRACE_POKEUSER, tid,
281
          offsetof (struct user, u_debugreg[regnum]), value);
282
  if (errno != 0)
283
    perror_with_name (_("Couldn't write debug register"));
284
}
285
 
286
void
287
amd64_linux_dr_set_control (unsigned long control)
288
{
289
  struct lwp_info *lp;
290
  ptid_t ptid;
291
 
292
  amd64_linux_dr[DR_CONTROL] = control;
293
  ALL_LWPS (lp, ptid)
294
    amd64_linux_dr_set (ptid, DR_CONTROL, control);
295
}
296
 
297
void
298
amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
299
{
300
  struct lwp_info *lp;
301
  ptid_t ptid;
302
 
303
  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
304
 
305
  amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
306
  ALL_LWPS (lp, ptid)
307
    amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
308
}
309
 
310
void
311
amd64_linux_dr_reset_addr (int regnum)
312
{
313
  amd64_linux_dr_set_addr (regnum, 0);
314
}
315
 
316
unsigned long
317
amd64_linux_dr_get_status (void)
318
{
319
  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
320
}
321
 
322
static void
323
amd64_linux_new_thread (ptid_t ptid)
324
{
325
  int i;
326
 
327
  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
328
    amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
329
 
330
  amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
331
}
332
 
333
 
334
/* This function is called by libthread_db as part of its handling of
335
   a request for a thread's local storage address.  */
336
 
337
ps_err_e
338
ps_get_thread_area (const struct ps_prochandle *ph,
339
                    lwpid_t lwpid, int idx, void **base)
340
{
341
  if (gdbarch_ptr_bit (current_gdbarch) == 32)
342
    {
343
      /* The full structure is found in <asm-i386/ldt.h>.  The second
344
         integer is the LDT's base_address and that is used to locate
345
         the thread's local storage.  See i386-linux-nat.c more
346
         info.  */
347
      unsigned int desc[4];
348
 
349
      /* This code assumes that "int" is 32 bits and that
350
         GET_THREAD_AREA returns no more than 4 int values.  */
351
      gdb_assert (sizeof (int) == 4);
352
#ifndef PTRACE_GET_THREAD_AREA
353
#define PTRACE_GET_THREAD_AREA 25
354
#endif
355
      if  (ptrace (PTRACE_GET_THREAD_AREA,
356
                   lwpid, (void *) (long) idx, (unsigned long) &desc) < 0)
357
        return PS_ERR;
358
 
359
      /* Extend the value to 64 bits.  Here it's assumed that a "long"
360
         and a "void *" are the same.  */
361
      (*base) = (void *) (long) desc[1];
362
      return PS_OK;
363
    }
364
  else
365
    {
366
      /* This definition comes from prctl.h, but some kernels may not
367
         have it.  */
368
#ifndef PTRACE_ARCH_PRCTL
369
#define PTRACE_ARCH_PRCTL      30
370
#endif
371
      /* FIXME: ezannoni-2003-07-09 see comment above about include
372
         file order.  We could be getting bogus values for these two.  */
373
      gdb_assert (FS < ELF_NGREG);
374
      gdb_assert (GS < ELF_NGREG);
375
      switch (idx)
376
        {
377
        case FS:
378
          if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0)
379
            return PS_OK;
380
          break;
381
        case GS:
382
          if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0)
383
            return PS_OK;
384
          break;
385
        default:                   /* Should not happen.  */
386
          return PS_BADADDR;
387
        }
388
    }
389
  return PS_ERR;               /* ptrace failed.  */
390
}
391
 
392
 
393
static void (*super_post_startup_inferior) (ptid_t ptid);
394
 
395
static void
396
amd64_linux_child_post_startup_inferior (ptid_t ptid)
397
{
398
  i386_cleanup_dregs ();
399
  super_post_startup_inferior (ptid);
400
}
401
 
402
 
403
/* Provide a prototype to silence -Wmissing-prototypes.  */
404
void _initialize_amd64_linux_nat (void);
405
 
406
void
407
_initialize_amd64_linux_nat (void)
408
{
409
  struct target_ops *t;
410
 
411
  amd64_native_gregset32_reg_offset = amd64_linux_gregset32_reg_offset;
412
  amd64_native_gregset32_num_regs = I386_LINUX_NUM_REGS;
413
  amd64_native_gregset64_reg_offset = amd64_linux_gregset64_reg_offset;
414
  amd64_native_gregset64_num_regs = AMD64_LINUX_NUM_REGS;
415
 
416
  gdb_assert (ARRAY_SIZE (amd64_linux_gregset32_reg_offset)
417
              == amd64_native_gregset32_num_regs);
418
  gdb_assert (ARRAY_SIZE (amd64_linux_gregset64_reg_offset)
419
              == amd64_native_gregset64_num_regs);
420
 
421
  /* Fill in the generic GNU/Linux methods.  */
422
  t = linux_target ();
423
 
424
  /* Override the GNU/Linux inferior startup hook.  */
425
  super_post_startup_inferior = t->to_post_startup_inferior;
426
  t->to_post_startup_inferior = amd64_linux_child_post_startup_inferior;
427
 
428
  /* Add our register access methods.  */
429
  t->to_fetch_registers = amd64_linux_fetch_inferior_registers;
430
  t->to_store_registers = amd64_linux_store_inferior_registers;
431
 
432
  /* Register the target.  */
433
  linux_nat_add_target (t);
434
  linux_nat_set_new_thread (t, amd64_linux_new_thread);
435
}

powered by: WebSVN 2.1.0

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