mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-03 04:12:10 +08:00
94585166df
This patch implements support for exec events on extended-remote Linux targets. Follow-exec-mode and rerun behave as expected. Catchpoints and test updates are implemented in subsequent patches. This patch was derived from a patch posted last October: https://sourceware.org/ml/gdb-patches/2014-10/msg00877.html. It was originally based on some work done by Luis Machado in 2013. IMPLEMENTATION ---------------- Exec events are enabled via ptrace options. When an exec event is detected by gdbserver, the existing process data, along with all its associated lwp and thread data, is deleted and replaced by data for a new single-threaded process. The new process data is initialized with the appropriate parts of the state of the execing process. This approach takes care of several potential pitfalls, including: * deleting the data for an execing non-leader thread before any wait/sigsuspend occurs * correctly initializing the architecture of the execed process We then report the exec event using a new RSP stop reason, "exec". When GDB receives an "exec" event, it saves the status in the event structure's target_waitstatus field, like what is done for remote fork events. Because the original and execed programs may have different architectures, we skip parsing the section of the stop reply packet that contains register data. The register data will be retrieved later after the inferior's architecture has been set up by infrun.c:follow_exec. At that point the exec event is handled by the existing event handling in GDB. However, a few changes were necessary so that infrun.c:follow_exec could accommodate the remote target. * Where follow-exec-mode "new" is handled, we now call add_inferior_with_spaces instead of add_inferior with separate calls to set up the program and address spaces. The motivation for this is that add_inferior_with_spaces also sets up the initial architecture for the inferior, which is needed later by target_find_description when it calls target_gdbarch. * We call a new target function, target_follow_exec. This function allows us to store the execd_pathname in the inferior, instead of using the static string remote_exec_file from remote.c. The static string didn't work for follow-exec-mode "new", since once you switched to the execed program, the original remote exec-file was lost. The execd_pathname is now stored in the inferior's program space as a REGISTRY field. All of the requisite mechanisms for this are defined in remote.c. gdb/gdbserver/ChangeLog: * linux-low.c (linux_mourn): Static declaration. (linux_arch_setup): Move in front of handle_extended_wait. (linux_arch_setup_thread): New function. (handle_extended_wait): Handle exec events. Call linux_arch_setup_thread. Make event_lwp argument a pointer-to-a-pointer. (check_zombie_leaders): Do not check stopped threads. (linux_low_ptrace_options): Add PTRACE_O_TRACEEXEC. (linux_low_filter_event): Add lwp and thread for exec'ing non-leader thread if leader thread has been deleted. Refactor code into linux_arch_setup_thread and call it. Pass child lwp pointer by reference to handle_extended_wait. (linux_wait_for_event_filtered): Update comment. (linux_wait_1): Prevent clobbering exec event status. (linux_supports_exec_events): New function. (linux_target_ops) <supports_exec_events>: Initialize new member. * lynx-low.c (lynx_target_ops) <supports_exec_events>: Initialize new member. * remote-utils.c (prepare_resume_reply): New stop reason 'exec'. * server.c (report_exec_events): New global variable. (handle_query): Handle qSupported query for exec-events feature. (captured_main): Initialize report_exec_events. * server.h (report_exec_events): Declare new global variable. * target.h (struct target_ops) <supports_exec_events>: New member. (target_supports_exec_events): New macro. * win32-low.c (win32_target_ops) <supports_exec_events>: Initialize new member. gdb/ChangeLog: * infrun.c (follow_exec): Use process-style ptid for exec message. Call add_inferior_with_spaces and target_follow_exec. * nat/linux-ptrace.c (linux_supports_traceexec): New function. * nat/linux-ptrace.h (linux_supports_traceexec): Declare. * remote.c (remote_pspace_data): New static variable. (remote_pspace_data_cleanup): New function. (get_remote_exec_file): New function. (set_remote_exec_file_1): New function. (set_remote_exec_file): New function. (show_remote_exec_file): New function. (remote_exec_file): Delete static variable. (anonymous enum) <PACKET_exec_event_feature> New enumeration constant. (remote_protocol_features): Add entry for exec-events feature. (remote_query_supported): Add client side of qSupported query for exec-events feature. (remote_follow_exec): New function. (remote_parse_stop_reply): Handle 'exec' stop reason. (extended_remote_run, extended_remote_create_inferior): Call get_remote_exec_file and set_remote_exec_file_1. (init_extended_remote_ops) <to_follow_exec>: Initialize new member. (_initialize_remote): Call register_program_space_data_with_cleanup. Call add_packet_config_cmd for remote exec-events feature. Modify call to add_setshow_string_noescape_cmd for exec-file to use new functions set_remote_exec_file and show_remote_exec_file. * target-debug.h, target-delegates.c: Regenerated. * target.c (target_follow_exec): New function. * target.h (struct target_ops) <to_follow_exec>: New member. (target_follow_exec): Declare new function.
180 lines
6.6 KiB
C
180 lines
6.6 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 "nat/gdb_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 */
|
|
|
|
#ifndef PTRACE_GETREGSET
|
|
#define PTRACE_GETREGSET 0x4204
|
|
#endif
|
|
|
|
#ifndef PTRACE_SETREGSET
|
|
#define PTRACE_SETREGSET 0x4205
|
|
#endif
|
|
|
|
/* 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 ppc kernel does use TRAP_BRKPT for software breakpoints
|
|
in PowerPC code, but it uses SI_KERNEL for software breakpoints
|
|
in SPU code on a Cell/B.E. However, SI_KERNEL is never seen
|
|
on a SIGTRAP for any other reason.
|
|
|
|
The generic Linux target code should use GDB_ARCH_IS_TRAP_BRKPT
|
|
instead of TRAP_BRKPT to abstract out these peculiarities. */
|
|
#if defined __i386__ || defined __x86_64__
|
|
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == SI_KERNEL)
|
|
#elif defined __powerpc__
|
|
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == SI_KERNEL || (X) == TRAP_BRKPT)
|
|
#else
|
|
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == 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_check_ptrace_features (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_traceexec (void);
|
|
extern int linux_supports_traceclone (void);
|
|
extern int linux_supports_tracevforkdone (void);
|
|
extern int linux_supports_tracesysgood (void);
|
|
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 */
|