forked from Imagelibrary/binutils-gdb
Unify ptrace options discovery code and make both GDB and
gdbserver use it. gdb/ * Makefile.in (HFILES_NO_SRCDIR): Add nat/linux-nat.h and nat/linux-waitpid.h. (linux-waitpid.o): New object file rule. * common/linux-ptrace.c: Include nat/linux-waitpid.h. (current_ptrace_options): Moved from linux-nat.c. (linux_ptrace_test_ret_to_nx): Use type casts for ptrace parameters. (linux_fork_to_function): New function. (linux_grandchild_function): Likewise. (linux_child_function): Likewise. (linux_check_ptrace_features): New function, heavily based on linux-nat.c:linux_test_for_tracefork. (linux_enable_event_reporting): New function. (ptrace_supports_feature): Likewise. (linux_supports_tracefork): Likewise. (linux_supports_traceclone): Likewise. (linux_supports_tracevforkdone): Likewise. (linux_supports_tracesysgood): Likewise. * common/linux-ptrace.h (HAS_NOMMU): Moved from gdbserver/linux-low.c. (linux_enable_event_reporting): New declaration. (linux_supports_tracefork): Likewise. (linux_supports_traceclone): Likewise. (linux_supports_tracevforkdone): Likewise. (linux_supports_tracesysgood): Likewise. * config.in (PTRACE_TYPE_ARG4): Regenerate. * config/aarch64/linux.mh (NATDEPFILES): Add linux-waitpid.o. * config/alpha/alpha-linux.mh (NATDEPFILES): Likewise. * config/arm/linux.mh (NATDEPFILES): Likewise. * config/i386/linux.mh (NATDEPFILES): Likewise. * config/i386/linux64.mh (NATDEPFILES): Likewise. * config/ia64/linux.mh (NATDEPFILES): Likewise. * config/m32r/linux.mh (NATDEPFILES): Likewise. * config/m68k/linux.mh (NATDEPFILES): Likewise. * config/mips/linux.mh (NATDEPFILES): Likewise. * config/pa/linux.mh (NATDEPFILES): Likewise.. * config/powerpc/linux.mh (NATDEPFILES): Likewise.. * config/powerpc/ppc64-linux.mh (NATDEPFILES): Likewise. * config/powerpc/spu-linux.mh (NATDEPFILES): Likewise. * config/sparc/linux.mh (NATDEPFILES): Likewise. * config/sparc/linux64.mh (NATDEPFILES): Likewise. * config/tilegx/linux.mh (NATDEPFILES): Likewise. * config/xtensa/linux.mh (NATDEPFILES): Likewise. * configure.ac (AC_CACHE_CHECK): Add void * to the list of ptrace's 4th argument's types. Check the type of PTRACE_TYPE_ARG4. * configure: Regenerate. * linux-nat.c: Include nat/linux-nat.h and nat/linux-waitpid.h. (SYSCALL_SIGTRAP): Moved to nat/linux-nat.h. (linux_supports_tracefork_flag): Remove. (linux_supports_tracesysgood_flag): Likewise. (linux_supports_tracevforkdone_flag): Likewise. (current_ptrace_options): Moved to common/linux-ptrace.c. (linux_tracefork_child): Remove. (my_waitpid): Remove. (linux_test_for_tracefork): Renamed to linux_check_ptrace_features and moved to common/linux-ptrace.c. (linux_test_for_tracesysgood): Remove. (linux_supports_tracesysgood): Remove. (linux_supports_tracefork): Remove. (linux_supports_tracevforkdone): Remove. (linux_enable_tracesysgood): Remove. (linux_enable_event_reporting): Remove. (linux_init_ptrace): New function. (linux_child_post_attach): Call linux_init_ptrace. (linux_child_post_startup_inferior): Call linux_init_ptrace. (linux_child_follow_fork): Call linux_supports_tracefork and linux_supports_tracevforkdone. (linux_child_insert_fork_catchpoint): Call linux_supports_tracefork. (linux_child_insert_vfork_catchpoint): Likewise. (linux_child_set_syscall_catchpoint): Call linux_supports_tracesysgood. (lin_lwp_attach_lwp): Call linux_supports_tracefork. * nat/linux-nat.h: New file. * nat/linux-waitpid.c: New file. * nat/linux-waitpid.h: New file. gdb/gdbserver/ * Makefile.in: Explain why ../target and ../nat are not listed as include file search paths. (linux-waitpid.o): New object file rule. * configure.srv (srv_native_linux_obj): New variable. Replace all occurrences of linux native object files with $srv_native_linux_obj. * linux-low.c: Include nat/linux-nat.h and nat/linux-waitpid.h. (HAS_NOMMU): Move defining logic to common/linux-ptrace.c. (linux_enable_event_reporting): Remove declaration. (my_waitpid): Moved to common/linux-waitpid.c. (linux_wait_for_event): Pass ptid when calling linux_enable_event_reporting. (linux_supports_tracefork_flag): Remove. (linux_enable_event_reporting): Likewise. (linux_tracefork_grandchild): Remove. (STACK_SIZE): Moved to common/linux-ptrace.c. (linux_tracefork_child): Remove. (linux_test_for_tracefork): Remove. (linux_look_up_symbols): Call linux_supports_traceclone. (initialize_low): Remove call to linux_test_for_tracefork. * linux-low.h (PTRACE_TYPE_ARG3): Move to common/linux-ptrace.h. (PTRACE_TYPE_ARG4): Likewise. Include linux-ptrace.h.
This commit is contained in:
271
gdb/linux-nat.c
271
gdb/linux-nat.c
@@ -20,6 +20,8 @@
|
||||
#include "defs.h"
|
||||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
#include "nat/linux-nat.h"
|
||||
#include "nat/linux-waitpid.h"
|
||||
#include "gdb_string.h"
|
||||
#include "gdb_wait.h"
|
||||
#include "gdb_assert.h"
|
||||
@@ -171,11 +173,6 @@ blocked. */
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
/* Unlike other extended result codes, WSTOPSIG (status) on
|
||||
PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but
|
||||
instead SIGTRAP with bit 7 set. */
|
||||
#define SYSCALL_SIGTRAP (SIGTRAP | 0x80)
|
||||
|
||||
/* The single-threaded native GNU/Linux target_ops. We save a pointer for
|
||||
the use of the multi-threaded target. */
|
||||
static struct target_ops *linux_ops;
|
||||
@@ -226,24 +223,6 @@ struct simple_pid_list
|
||||
};
|
||||
struct simple_pid_list *stopped_pids;
|
||||
|
||||
/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACEFORK
|
||||
can not be used, 1 if it can. */
|
||||
|
||||
static int linux_supports_tracefork_flag = -1;
|
||||
|
||||
/* This variable is a tri-state flag: -1 for unknown, 0 if
|
||||
PTRACE_O_TRACESYSGOOD can not be used, 1 if it can. */
|
||||
|
||||
static int linux_supports_tracesysgood_flag = -1;
|
||||
|
||||
/* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have
|
||||
PTRACE_O_TRACEVFORKDONE. */
|
||||
|
||||
static int linux_supports_tracevforkdone_flag = -1;
|
||||
|
||||
/* Stores the current used ptrace() options. */
|
||||
static int current_ptrace_options = 0;
|
||||
|
||||
/* Async mode support. */
|
||||
|
||||
/* The read/write ends of the pipe registered as waitable file in the
|
||||
@@ -349,244 +328,26 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid, int *statusp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* A helper function for linux_test_for_tracefork, called after fork (). */
|
||||
/* Initialize ptrace warnings and check for supported ptrace
|
||||
features given PID. */
|
||||
|
||||
static void
|
||||
linux_tracefork_child (void)
|
||||
linux_init_ptrace (pid_t pid)
|
||||
{
|
||||
ptrace (PTRACE_TRACEME, 0, 0, 0);
|
||||
kill (getpid (), SIGSTOP);
|
||||
fork ();
|
||||
_exit (0);
|
||||
}
|
||||
|
||||
/* Wrapper function for waitpid which handles EINTR. */
|
||||
|
||||
static int
|
||||
my_waitpid (int pid, int *statusp, int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
ret = waitpid (pid, statusp, flags);
|
||||
}
|
||||
while (ret == -1 && errno == EINTR);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.
|
||||
|
||||
First, we try to enable fork tracing on ORIGINAL_PID. If this fails,
|
||||
we know that the feature is not available. This may change the tracing
|
||||
options for ORIGINAL_PID, but we'll be setting them shortly anyway.
|
||||
|
||||
However, if it succeeds, we don't know for sure that the feature is
|
||||
available; old versions of PTRACE_SETOPTIONS ignored unknown options. We
|
||||
create a child process, attach to it, use PTRACE_SETOPTIONS to enable
|
||||
fork tracing, and let it fork. If the process exits, we assume that we
|
||||
can't use TRACEFORK; if we get the fork notification, and we can extract
|
||||
the new child's PID, then we assume that we can. */
|
||||
|
||||
static void
|
||||
linux_test_for_tracefork (int original_pid)
|
||||
{
|
||||
int child_pid, ret, status;
|
||||
long second_pid;
|
||||
|
||||
linux_supports_tracefork_flag = 0;
|
||||
linux_supports_tracevforkdone_flag = 0;
|
||||
|
||||
ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACEFORK);
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
child_pid = fork ();
|
||||
if (child_pid == -1)
|
||||
perror_with_name (("fork"));
|
||||
|
||||
if (child_pid == 0)
|
||||
linux_tracefork_child ();
|
||||
|
||||
ret = my_waitpid (child_pid, &status, 0);
|
||||
if (ret == -1)
|
||||
perror_with_name (("waitpid"));
|
||||
else if (ret != child_pid)
|
||||
error (_("linux_test_for_tracefork: waitpid: unexpected result %d."), ret);
|
||||
if (! WIFSTOPPED (status))
|
||||
error (_("linux_test_for_tracefork: waitpid: unexpected status %d."),
|
||||
status);
|
||||
|
||||
ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
warning (_("linux_test_for_tracefork: failed to kill child"));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = my_waitpid (child_pid, &status, 0);
|
||||
if (ret != child_pid)
|
||||
warning (_("linux_test_for_tracefork: failed "
|
||||
"to wait for killed child"));
|
||||
else if (!WIFSIGNALED (status))
|
||||
warning (_("linux_test_for_tracefork: unexpected "
|
||||
"wait status 0x%x from killed child"), status);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check whether PTRACE_O_TRACEVFORKDONE is available. */
|
||||
ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0,
|
||||
PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
|
||||
linux_supports_tracevforkdone_flag = (ret == 0);
|
||||
|
||||
ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
|
||||
if (ret != 0)
|
||||
warning (_("linux_test_for_tracefork: failed to resume child"));
|
||||
|
||||
ret = my_waitpid (child_pid, &status, 0);
|
||||
|
||||
if (ret == child_pid && WIFSTOPPED (status)
|
||||
&& status >> 16 == PTRACE_EVENT_FORK)
|
||||
{
|
||||
second_pid = 0;
|
||||
ret = ptrace (PTRACE_GETEVENTMSG, child_pid, 0, &second_pid);
|
||||
if (ret == 0 && second_pid != 0)
|
||||
{
|
||||
int second_status;
|
||||
|
||||
linux_supports_tracefork_flag = 1;
|
||||
my_waitpid (second_pid, &second_status, 0);
|
||||
ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
|
||||
if (ret != 0)
|
||||
warning (_("linux_test_for_tracefork: "
|
||||
"failed to kill second child"));
|
||||
my_waitpid (second_pid, &status, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
warning (_("linux_test_for_tracefork: unexpected result from waitpid "
|
||||
"(%d, status 0x%x)"), ret, status);
|
||||
|
||||
do
|
||||
{
|
||||
ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
|
||||
if (ret != 0)
|
||||
warning ("linux_test_for_tracefork: failed to kill child");
|
||||
my_waitpid (child_pid, &status, 0);
|
||||
}
|
||||
while (WIFSTOPPED (status));
|
||||
}
|
||||
|
||||
/* Determine if PTRACE_O_TRACESYSGOOD can be used to follow syscalls.
|
||||
|
||||
We try to enable syscall tracing on ORIGINAL_PID. If this fails,
|
||||
we know that the feature is not available. This may change the tracing
|
||||
options for ORIGINAL_PID, but we'll be setting them shortly anyway. */
|
||||
|
||||
static void
|
||||
linux_test_for_tracesysgood (int original_pid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
linux_supports_tracesysgood_flag = 0;
|
||||
|
||||
ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD);
|
||||
if (ret != 0)
|
||||
return;
|
||||
|
||||
linux_supports_tracesysgood_flag = 1;
|
||||
}
|
||||
|
||||
/* Determine wether we support PTRACE_O_TRACESYSGOOD option available.
|
||||
This function also sets linux_supports_tracesysgood_flag. */
|
||||
|
||||
static int
|
||||
linux_supports_tracesysgood (int pid)
|
||||
{
|
||||
if (linux_supports_tracesysgood_flag == -1)
|
||||
linux_test_for_tracesysgood (pid);
|
||||
return linux_supports_tracesysgood_flag;
|
||||
}
|
||||
|
||||
/* Return non-zero iff we have tracefork functionality available.
|
||||
This function also sets linux_supports_tracefork_flag. */
|
||||
|
||||
static int
|
||||
linux_supports_tracefork (int pid)
|
||||
{
|
||||
if (linux_supports_tracefork_flag == -1)
|
||||
linux_test_for_tracefork (pid);
|
||||
return linux_supports_tracefork_flag;
|
||||
}
|
||||
|
||||
static int
|
||||
linux_supports_tracevforkdone (int pid)
|
||||
{
|
||||
if (linux_supports_tracefork_flag == -1)
|
||||
linux_test_for_tracefork (pid);
|
||||
return linux_supports_tracevforkdone_flag;
|
||||
}
|
||||
|
||||
static void
|
||||
linux_enable_tracesysgood (ptid_t ptid)
|
||||
{
|
||||
int pid = ptid_get_lwp (ptid);
|
||||
|
||||
if (pid == 0)
|
||||
pid = ptid_get_pid (ptid);
|
||||
|
||||
if (linux_supports_tracesysgood (pid) == 0)
|
||||
return;
|
||||
|
||||
current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
|
||||
|
||||
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
linux_enable_event_reporting (ptid_t ptid)
|
||||
{
|
||||
int pid = ptid_get_lwp (ptid);
|
||||
|
||||
if (pid == 0)
|
||||
pid = ptid_get_pid (ptid);
|
||||
|
||||
if (! linux_supports_tracefork (pid))
|
||||
return;
|
||||
|
||||
current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
|
||||
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE;
|
||||
|
||||
if (linux_supports_tracevforkdone (pid))
|
||||
current_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
|
||||
|
||||
/* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
|
||||
read-only process state. */
|
||||
|
||||
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
|
||||
linux_enable_event_reporting (pid);
|
||||
linux_ptrace_init_warnings ();
|
||||
}
|
||||
|
||||
static void
|
||||
linux_child_post_attach (int pid)
|
||||
{
|
||||
linux_enable_event_reporting (pid_to_ptid (pid));
|
||||
linux_enable_tracesysgood (pid_to_ptid (pid));
|
||||
linux_ptrace_init_warnings ();
|
||||
linux_init_ptrace (pid);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_child_post_startup_inferior (ptid_t ptid)
|
||||
{
|
||||
linux_enable_event_reporting (ptid);
|
||||
linux_enable_tracesysgood (ptid);
|
||||
linux_ptrace_init_warnings ();
|
||||
linux_init_ptrace (ptid_get_pid (ptid));
|
||||
}
|
||||
|
||||
/* Return the number of known LWPs in the tgid given by PID. */
|
||||
@@ -772,9 +533,9 @@ holding the child stopped. Try \"set detach-on-fork\" or \
|
||||
parent_inf->pspace->breakpoints_not_allowed = detach_fork;
|
||||
|
||||
parent_lp = find_lwp_pid (pid_to_ptid (parent_pid));
|
||||
gdb_assert (linux_supports_tracefork_flag >= 0);
|
||||
gdb_assert (linux_supports_tracefork () >= 0);
|
||||
|
||||
if (linux_supports_tracevforkdone (0))
|
||||
if (linux_supports_tracevforkdone ())
|
||||
{
|
||||
if (debug_linux_nat)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
@@ -945,7 +706,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \
|
||||
static int
|
||||
linux_child_insert_fork_catchpoint (int pid)
|
||||
{
|
||||
return !linux_supports_tracefork (pid);
|
||||
return !linux_supports_tracefork ();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -957,7 +718,7 @@ linux_child_remove_fork_catchpoint (int pid)
|
||||
static int
|
||||
linux_child_insert_vfork_catchpoint (int pid)
|
||||
{
|
||||
return !linux_supports_tracefork (pid);
|
||||
return !linux_supports_tracefork ();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -969,7 +730,7 @@ linux_child_remove_vfork_catchpoint (int pid)
|
||||
static int
|
||||
linux_child_insert_exec_catchpoint (int pid)
|
||||
{
|
||||
return !linux_supports_tracefork (pid);
|
||||
return !linux_supports_tracefork ();
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -982,7 +743,7 @@ static int
|
||||
linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
|
||||
int table_size, int *table)
|
||||
{
|
||||
if (!linux_supports_tracesysgood (pid))
|
||||
if (!linux_supports_tracesysgood ())
|
||||
return 1;
|
||||
|
||||
/* On GNU/Linux, we ignore the arguments. It means that we only
|
||||
@@ -1429,7 +1190,7 @@ lin_lwp_attach_lwp (ptid_t ptid)
|
||||
|
||||
if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) < 0)
|
||||
{
|
||||
if (linux_supports_tracefork_flag)
|
||||
if (linux_supports_tracefork ())
|
||||
{
|
||||
/* If we haven't stopped all threads when we get here,
|
||||
we may have seen a thread listed in thread_db's list,
|
||||
|
||||
Reference in New Issue
Block a user