diff options
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r-- | gdb/linux-nat.c | 271 |
1 files changed, 16 insertions, 255 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index db23433..46e3dbf 100644 --- a/gdb/linux-nat.c +++ b/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 (). */ - -static void -linux_tracefork_child (void) -{ - 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. */ +/* Initialize ptrace warnings and check for supported ptrace + features given PID. */ static void -linux_test_for_tracefork (int original_pid) +linux_init_ptrace (pid_t 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, |