diff options
author | Luis Machado <luisgpm@br.ibm.com> | 2013-08-22 23:46:30 +0000 |
---|---|---|
committer | Luis Machado <luisgpm@br.ibm.com> | 2013-08-22 23:46:30 +0000 |
commit | 96d7229d2aa856ef96a420827f3e785081af66ea (patch) | |
tree | 8611905663226a3fe25cd6e68e040d795dbbb47c /gdb/linux-nat.c | |
parent | a5829458a109d5c8a80bd17ec8c5e5550e94c70c (diff) | |
download | gdb-96d7229d2aa856ef96a420827f3e785081af66ea.zip gdb-96d7229d2aa856ef96a420827f3e785081af66ea.tar.gz gdb-96d7229d2aa856ef96a420827f3e785081af66ea.tar.bz2 |
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.
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, |