faf09f0119
This patch adjusts the native Linux target backend to tell the core whether a trap was caused by a breakpoint. It teaches the target to get that information out of the si_code of the SIGTRAP siginfo. Tested on x86-64 Fedora 20, s390 RHEL 7, and PPC64 Fedora 18. An earlier version was tested on ARM Fedora 21. gdb/ChangeLog: 2015-03-04 Pedro Alves <palves@redhat.com> * linux-nat.c (save_sigtrap): Check for breakpoints before checking watchpoints. (status_callback) [USE_SIGTRAP_SIGINFO]: Don't check whether a breakpoint is inserted if relying on SIGTRAP's siginfo.si_code. (check_stopped_by_breakpoint) [USE_SIGTRAP_SIGINFO]: Decide whether a breakpoint triggered based on the SIGTRAP's siginfo.si_code. (linux_nat_stopped_by_sw_breakpoint) (linux_nat_supports_stopped_by_sw_breakpoint) (linux_nat_stopped_by_hw_breakpoint) (linux_nat_supports_stopped_by_hw_breakpoint): New functions. (linux_nat_wait_1): Don't re-increment the PC if relying on SIGTRAP's siginfo->si_code. (linux_nat_add_target): Install new target methods. * linux-thread-db.c (check_event): Don't account for breakpoint PC offset if the target already adjusted the PC. * nat/linux-ptrace.h (USE_SIGTRAP_SIGINFO): New. (GDB_ARCH_TRAP_BRKPT): New. (TRAP_HWBKPT): Define if not already defined.
163 lines
6.1 KiB
C
163 lines
6.1 KiB
C
/* Copyright (C) 2011-2015 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifndef COMMON_LINUX_PTRACE_H
|
|
#define COMMON_LINUX_PTRACE_H
|
|
|
|
struct buffer;
|
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#ifdef __UCLIBC__
|
|
#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__))
|
|
/* PTRACE_TEXT_ADDR and friends. */
|
|
#include <asm/ptrace.h>
|
|
#define HAS_NOMMU
|
|
#endif
|
|
#endif
|
|
|
|
#if !defined(PTRACE_TYPE_ARG3)
|
|
#define PTRACE_TYPE_ARG3 void *
|
|
#endif
|
|
|
|
#if !defined(PTRACE_TYPE_ARG4)
|
|
#define PTRACE_TYPE_ARG4 void *
|
|
#endif
|
|
|
|
#ifndef PTRACE_GETSIGINFO
|
|
# define PTRACE_GETSIGINFO 0x4202
|
|
# define PTRACE_SETSIGINFO 0x4203
|
|
#endif /* PTRACE_GETSIGINF */
|
|
|
|
/* If the system headers did not provide the constants, hard-code the normal
|
|
values. */
|
|
#ifndef PTRACE_EVENT_FORK
|
|
|
|
#define PTRACE_SETOPTIONS 0x4200
|
|
#define PTRACE_GETEVENTMSG 0x4201
|
|
|
|
/* options set using PTRACE_SETOPTIONS */
|
|
#define PTRACE_O_TRACESYSGOOD 0x00000001
|
|
#define PTRACE_O_TRACEFORK 0x00000002
|
|
#define PTRACE_O_TRACEVFORK 0x00000004
|
|
#define PTRACE_O_TRACECLONE 0x00000008
|
|
#define PTRACE_O_TRACEEXEC 0x00000010
|
|
#define PTRACE_O_TRACEVFORKDONE 0x00000020
|
|
#define PTRACE_O_TRACEEXIT 0x00000040
|
|
|
|
/* Wait extended result codes for the above trace options. */
|
|
#define PTRACE_EVENT_FORK 1
|
|
#define PTRACE_EVENT_VFORK 2
|
|
#define PTRACE_EVENT_CLONE 3
|
|
#define PTRACE_EVENT_EXEC 4
|
|
#define PTRACE_EVENT_VFORK_DONE 5
|
|
#define PTRACE_EVENT_EXIT 6
|
|
|
|
#endif /* PTRACE_EVENT_FORK */
|
|
|
|
#ifndef PTRACE_O_EXITKILL
|
|
/* Only defined in Linux Kernel 3.8 or later. */
|
|
#define PTRACE_O_EXITKILL 0x00100000
|
|
#endif
|
|
|
|
#if (defined __bfin__ || defined __frv__ || defined __sh__) \
|
|
&& !defined PTRACE_GETFDPIC
|
|
#define PTRACE_GETFDPIC 31
|
|
#define PTRACE_GETFDPIC_EXEC 0
|
|
#define PTRACE_GETFDPIC_INTERP 1
|
|
#endif
|
|
|
|
/* We can't always assume that this flag is available, but all systems
|
|
with the ptrace event handlers also have __WALL, so it's safe to use
|
|
in some contexts. */
|
|
#ifndef __WALL
|
|
#define __WALL 0x40000000 /* Wait for any child. */
|
|
#endif
|
|
|
|
/* True if whether a breakpoint/watchpoint triggered can be determined
|
|
from the si_code of SIGTRAP's siginfo_t (TRAP_BRKPT/TRAP_HWBKPT).
|
|
That is, if the kernel can tell us whether the thread executed a
|
|
software breakpoint, we trust it. The kernel will be determining
|
|
that from the hardware (e.g., from which exception was raised in
|
|
the CPU). Relying on whether a breakpoint is planted in memory at
|
|
the time the SIGTRAP is processed to determine whether the thread
|
|
stopped for a software breakpoint can be too late. E.g., the
|
|
breakpoint could have been removed since. Or the thread could have
|
|
stepped an instruction the size of a breakpoint instruction, and
|
|
before the stop is processed a breakpoint is inserted at its
|
|
address. Getting these wrong is disastrous on decr_pc_after_break
|
|
architectures. The moribund location mechanism helps with that
|
|
somewhat but it is an heuristic, and can well fail. Getting that
|
|
information out of the kernel and ultimately out of the CPU is the
|
|
way to go. That said, some architecture may get the si_code wrong,
|
|
and as such we're leaving fallback code in place. We'll remove
|
|
this after a while if no problem is reported. */
|
|
#define USE_SIGTRAP_SIGINFO 1
|
|
|
|
/* The x86 kernel gets some of the si_code values backwards, like
|
|
this:
|
|
|
|
| what | si_code |
|
|
|------------------------------------------+------------|
|
|
| software breakpoints (int3) | SI_KERNEL |
|
|
| single-steps | TRAP_TRACE |
|
|
| single-stepping a syscall | TRAP_BRKPT |
|
|
| user sent SIGTRAP | 0 |
|
|
| exec SIGTRAP (when no PTRACE_EVENT_EXEC) | 0 |
|
|
| hardware breakpoints/watchpoints | TRAP_HWBPT |
|
|
|
|
That is, it reports SI_KERNEL for software breakpoints (and only
|
|
for those), and TRAP_BRKPT for single-stepping a syscall... If the
|
|
kernel is ever fixed, we'll just have to detect it like we detect
|
|
optional ptrace features: by forking and debugging ourselves,
|
|
running to a breakpoint and checking what comes out of
|
|
siginfo->si_code.
|
|
|
|
The generic Linux target code should use GDB_ARCH_TRAP_BRKPT
|
|
instead of TRAP_BRKPT to abstract out this x86 peculiarity. */
|
|
#if defined __i386__ || defined __x86_64__
|
|
# define GDB_ARCH_TRAP_BRKPT SI_KERNEL
|
|
#else
|
|
# define GDB_ARCH_TRAP_BRKPT TRAP_BRKPT
|
|
#endif
|
|
|
|
#ifndef TRAP_HWBKPT
|
|
# define TRAP_HWBKPT 4
|
|
#endif
|
|
|
|
extern void linux_ptrace_attach_fail_reason (pid_t pid, struct buffer *buffer);
|
|
|
|
/* Find all possible reasons we could have failed to attach to PTID
|
|
and return them as a string. ERR is the error PTRACE_ATTACH failed
|
|
with (an errno). The result is stored in a static buffer. This
|
|
string should be copied into a buffer by the client if the string
|
|
will not be immediately used, or if it must persist. */
|
|
extern char *linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err);
|
|
|
|
extern void linux_ptrace_init_warnings (void);
|
|
extern void linux_enable_event_reporting (pid_t pid, int attached);
|
|
extern void linux_disable_event_reporting (pid_t pid);
|
|
extern int linux_supports_tracefork (void);
|
|
extern int linux_supports_traceclone (void);
|
|
extern int linux_supports_tracevforkdone (void);
|
|
extern int linux_supports_tracesysgood (void);
|
|
extern void linux_ptrace_set_additional_flags (int);
|
|
extern int linux_ptrace_get_extended_event (int wstat);
|
|
extern int linux_is_extended_waitstatus (int wstat);
|
|
extern int linux_wstatus_maybe_breakpoint (int wstat);
|
|
|
|
#endif /* COMMON_LINUX_PTRACE_H */
|