| Index: gdb/amd64-linux-nat.c
|
| diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
|
| index 01982acf17c26fd840eeafcc281db0ec9a429c5c..b1676ac32ea676bd0d046ce35c05decf6687968c 100644
|
| --- a/gdb/amd64-linux-nat.c
|
| +++ b/gdb/amd64-linux-nat.c
|
| @@ -1,6 +1,6 @@
|
| /* Native-dependent code for GNU/Linux x86-64.
|
|
|
| - Copyright (C) 2001-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2001-2013 Free Software Foundation, Inc.
|
| Contributed by Jiri Smid, SuSE Labs.
|
|
|
| This file is part of GDB.
|
| @@ -25,9 +25,11 @@
|
| #include "regset.h"
|
| #include "linux-nat.h"
|
| #include "amd64-linux-tdep.h"
|
| +#include "linux-btrace.h"
|
| +#include "btrace.h"
|
|
|
| #include "gdb_assert.h"
|
| -#include "gdb_string.h"
|
| +#include <string.h>
|
| #include "elf/common.h"
|
| #include <sys/uio.h>
|
| #include <sys/ptrace.h>
|
| @@ -98,7 +100,9 @@ static int amd64_linux_gregset32_reg_offset[] =
|
| -1, -1, -1, -1, -1, -1, -1, -1,
|
| -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
| -1, -1, -1, -1, -1, -1, -1, -1,
|
| - ORIG_RAX * 8 /* "orig_eax" */
|
| + -1, -1, -1, -1, /* MPX registers BND0 ... BND3. */
|
| + -1, -1, /* MPX registers BNDCFGU, BNDSTATUS. */
|
| + ORIG_RAX * 8, /* "orig_eax" */
|
| };
|
|
|
|
|
| @@ -162,9 +166,9 @@ amd64_linux_fetch_inferior_registers (struct target_ops *ops,
|
| int tid;
|
|
|
| /* GNU/Linux LWP ID's are process ID's. */
|
| - tid = TIDGET (inferior_ptid);
|
| + tid = ptid_get_lwp (inferior_ptid);
|
| if (tid == 0)
|
| - tid = PIDGET (inferior_ptid); /* Not a threaded program. */
|
| + tid = ptid_get_pid (inferior_ptid); /* Not a threaded program. */
|
|
|
| if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
|
| {
|
| @@ -217,9 +221,9 @@ amd64_linux_store_inferior_registers (struct target_ops *ops,
|
| int tid;
|
|
|
| /* GNU/Linux LWP ID's are process ID's. */
|
| - tid = TIDGET (inferior_ptid);
|
| + tid = ptid_get_lwp (inferior_ptid);
|
| if (tid == 0)
|
| - tid = PIDGET (inferior_ptid); /* Not a threaded program. */
|
| + tid = ptid_get_pid (inferior_ptid); /* Not a threaded program. */
|
|
|
| if (regnum == -1 || amd64_native_gregset_supplies_p (gdbarch, regnum))
|
| {
|
| @@ -279,9 +283,9 @@ amd64_linux_dr_get (ptid_t ptid, int regnum)
|
| int tid;
|
| unsigned long value;
|
|
|
| - tid = TIDGET (ptid);
|
| + tid = ptid_get_lwp (ptid);
|
| if (tid == 0)
|
| - tid = PIDGET (ptid);
|
| + tid = ptid_get_pid (ptid);
|
|
|
| errno = 0;
|
| value = ptrace (PTRACE_PEEKUSER, tid,
|
| @@ -299,9 +303,9 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
|
| {
|
| int tid;
|
|
|
| - tid = TIDGET (ptid);
|
| + tid = ptid_get_lwp (ptid);
|
| if (tid == 0)
|
| - tid = PIDGET (ptid);
|
| + tid = ptid_get_pid (ptid);
|
|
|
| errno = 0;
|
| ptrace (PTRACE_POKEUSER, tid,
|
| @@ -337,8 +341,8 @@ amd64_linux_dr_get_status (void)
|
| return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
|
| }
|
|
|
| -/* Callback for linux_nat_iterate_watchpoint_lwps. Update the debug registers
|
| - of LWP. */
|
| +/* Callback for iterate_over_lwps. Update the debug registers of
|
| + LWP. */
|
|
|
| static int
|
| update_debug_registers_callback (struct lwp_info *lwp, void *arg)
|
| @@ -364,7 +368,9 @@ update_debug_registers_callback (struct lwp_info *lwp, void *arg)
|
| static void
|
| amd64_linux_dr_set_control (unsigned long control)
|
| {
|
| - linux_nat_iterate_watchpoint_lwps (update_debug_registers_callback, NULL);
|
| + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
|
| +
|
| + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
|
| }
|
|
|
| /* Set address REGNUM (zero based) to ADDR in all LWPs of the current
|
| @@ -373,9 +379,11 @@ amd64_linux_dr_set_control (unsigned long control)
|
| static void
|
| amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
|
| {
|
| + ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
|
| +
|
| gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
|
|
|
| - linux_nat_iterate_watchpoint_lwps (update_debug_registers_callback, NULL);
|
| + iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
|
| }
|
|
|
| /* Called when resuming a thread.
|
| @@ -394,7 +402,8 @@ amd64_linux_prepare_to_resume (struct lwp_info *lwp)
|
|
|
| if (lwp->arch_private->debug_registers_changed)
|
| {
|
| - struct i386_debug_reg_state *state = i386_debug_reg_state ();
|
| + struct i386_debug_reg_state *state
|
| + = i386_debug_reg_state (ptid_get_pid (lwp->ptid));
|
| int i;
|
|
|
| /* On Linux kernel before 2.6.33 commit
|
| @@ -434,6 +443,41 @@ amd64_linux_new_thread (struct lwp_info *lp)
|
|
|
| lp->arch_private = info;
|
| }
|
| +
|
| +/* linux_nat_new_fork hook. */
|
| +
|
| +static void
|
| +amd64_linux_new_fork (struct lwp_info *parent, pid_t child_pid)
|
| +{
|
| + pid_t parent_pid;
|
| + struct i386_debug_reg_state *parent_state;
|
| + struct i386_debug_reg_state *child_state;
|
| +
|
| + /* NULL means no watchpoint has ever been set in the parent. In
|
| + that case, there's nothing to do. */
|
| + if (parent->arch_private == NULL)
|
| + return;
|
| +
|
| + /* Linux kernel before 2.6.33 commit
|
| + 72f674d203cd230426437cdcf7dd6f681dad8b0d
|
| + will inherit hardware debug registers from parent
|
| + on fork/vfork/clone. Newer Linux kernels create such tasks with
|
| + zeroed debug registers.
|
| +
|
| + GDB core assumes the child inherits the watchpoints/hw
|
| + breakpoints of the parent, and will remove them all from the
|
| + forked off process. Copy the debug registers mirrors into the
|
| + new process so that all breakpoints and watchpoints can be
|
| + removed together. The debug registers mirror will become zeroed
|
| + in the end before detaching the forked off process, thus making
|
| + this compatible with older Linux kernels too. */
|
| +
|
| + parent_pid = ptid_get_pid (parent->ptid);
|
| + parent_state = i386_debug_reg_state (parent_pid);
|
| + child_state = i386_debug_reg_state (child_pid);
|
| + *child_state = *parent_state;
|
| +}
|
| +
|
|
|
|
|
| /* This function is called by libthread_db as part of its handling of
|
| @@ -443,7 +487,7 @@ ps_err_e
|
| ps_get_thread_area (const struct ps_prochandle *ph,
|
| lwpid_t lwpid, int idx, void **base)
|
| {
|
| - if (gdbarch_bfd_arch_info (target_gdbarch)->bits_per_word == 32)
|
| + if (gdbarch_bfd_arch_info (target_gdbarch ())->bits_per_word == 32)
|
| {
|
| /* The full structure is found in <asm-i386/ldt.h>. The second
|
| integer is the LDT's base_address and that is used to locate
|
| @@ -1004,9 +1048,9 @@ amd64_linux_read_description (struct target_ops *ops)
|
| static uint64_t xcr0;
|
|
|
| /* GNU/Linux LWP ID's are process ID's. */
|
| - tid = TIDGET (inferior_ptid);
|
| + tid = ptid_get_lwp (inferior_ptid);
|
| if (tid == 0)
|
| - tid = PIDGET (inferior_ptid); /* Not a threaded program. */
|
| + tid = ptid_get_pid (inferior_ptid); /* Not a threaded program. */
|
|
|
| /* Get CS register. */
|
| errno = 0;
|
| @@ -1052,18 +1096,41 @@ amd64_linux_read_description (struct target_ops *ops)
|
| }
|
|
|
| /* Check the native XCR0 only if PTRACE_GETREGSET is available. */
|
| - if (have_ptrace_getregset
|
| - && (xcr0 & I386_XSTATE_AVX_MASK) == I386_XSTATE_AVX_MASK)
|
| + if (have_ptrace_getregset && (xcr0 & I386_XSTATE_ALL_MASK))
|
| {
|
| - if (is_64bit)
|
| + switch (xcr0 & I386_XSTATE_ALL_MASK)
|
| {
|
| - if (is_x32)
|
| - return tdesc_x32_avx_linux;
|
| + case I386_XSTATE_MPX_MASK:
|
| + if (is_64bit)
|
| + {
|
| + if (is_x32)
|
| + return tdesc_x32_avx_linux; /* No MPX on x32 using AVX. */
|
| + else
|
| + return tdesc_amd64_mpx_linux;
|
| + }
|
| + else
|
| + return tdesc_i386_mpx_linux;
|
| + case I386_XSTATE_AVX_MASK:
|
| + if (is_64bit)
|
| + {
|
| + if (is_x32)
|
| + return tdesc_x32_avx_linux;
|
| + else
|
| + return tdesc_amd64_avx_linux;
|
| + }
|
| + else
|
| + return tdesc_i386_avx_linux;
|
| + default:
|
| + if (is_64bit)
|
| + {
|
| + if (is_x32)
|
| + return tdesc_x32_linux;
|
| + else
|
| + return tdesc_amd64_linux;
|
| + }
|
| else
|
| - return tdesc_amd64_avx_linux;
|
| + return tdesc_i386_linux;
|
| }
|
| - else
|
| - return tdesc_i386_avx_linux;
|
| }
|
| else
|
| {
|
| @@ -1079,6 +1146,48 @@ amd64_linux_read_description (struct target_ops *ops)
|
| }
|
| }
|
|
|
| +/* Enable branch tracing. */
|
| +
|
| +static struct btrace_target_info *
|
| +amd64_linux_enable_btrace (ptid_t ptid)
|
| +{
|
| + struct btrace_target_info *tinfo;
|
| + struct gdbarch *gdbarch;
|
| +
|
| + errno = 0;
|
| + tinfo = linux_enable_btrace (ptid);
|
| +
|
| + if (tinfo == NULL)
|
| + error (_("Could not enable branch tracing for %s: %s."),
|
| + target_pid_to_str (ptid), safe_strerror (errno));
|
| +
|
| + /* Fill in the size of a pointer in bits. */
|
| + gdbarch = target_thread_architecture (ptid);
|
| + tinfo->ptr_bits = gdbarch_ptr_bit (gdbarch);
|
| +
|
| + return tinfo;
|
| +}
|
| +
|
| +/* Disable branch tracing. */
|
| +
|
| +static void
|
| +amd64_linux_disable_btrace (struct btrace_target_info *tinfo)
|
| +{
|
| + int errcode = linux_disable_btrace (tinfo);
|
| +
|
| + if (errcode != 0)
|
| + error (_("Could not disable branch tracing: %s."), safe_strerror (errcode));
|
| +}
|
| +
|
| +/* Teardown branch tracing. */
|
| +
|
| +static void
|
| +amd64_linux_teardown_btrace (struct btrace_target_info *tinfo)
|
| +{
|
| + /* Ignore errors. */
|
| + linux_disable_btrace (tinfo);
|
| +}
|
| +
|
| /* Provide a prototype to silence -Wmissing-prototypes. */
|
| void _initialize_amd64_linux_nat (void);
|
|
|
| @@ -1117,9 +1226,18 @@ _initialize_amd64_linux_nat (void)
|
|
|
| t->to_read_description = amd64_linux_read_description;
|
|
|
| + /* Add btrace methods. */
|
| + t->to_supports_btrace = linux_supports_btrace;
|
| + t->to_enable_btrace = amd64_linux_enable_btrace;
|
| + t->to_disable_btrace = amd64_linux_disable_btrace;
|
| + t->to_teardown_btrace = amd64_linux_teardown_btrace;
|
| + t->to_read_btrace = linux_read_btrace;
|
| +
|
| /* Register the target. */
|
| linux_nat_add_target (t);
|
| linux_nat_set_new_thread (t, amd64_linux_new_thread);
|
| + linux_nat_set_new_fork (t, amd64_linux_new_fork);
|
| + linux_nat_set_forget_process (t, i386_forget_process);
|
| linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup);
|
| linux_nat_set_prepare_to_resume (t, amd64_linux_prepare_to_resume);
|
| }
|
|
|