From 96d7229d2aa856ef96a420827f3e785081af66ea Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Thu, 22 Aug 2013 23:46:30 +0000 Subject: [PATCH] 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. --- gdb/ChangeLog | 81 ++++++++ gdb/Makefile.in | 11 +- gdb/common/linux-ptrace.c | 304 +++++++++++++++++++++++++++++- gdb/common/linux-ptrace.h | 21 +++ gdb/config.in | 3 + gdb/config/aarch64/linux.mh | 2 +- gdb/config/alpha/alpha-linux.mh | 3 +- gdb/config/arm/linux.mh | 3 +- gdb/config/i386/linux.mh | 2 +- gdb/config/i386/linux64.mh | 3 +- gdb/config/ia64/linux.mh | 2 +- gdb/config/m32r/linux.mh | 3 +- gdb/config/m68k/linux.mh | 3 +- gdb/config/mips/linux.mh | 3 +- gdb/config/pa/linux.mh | 2 +- gdb/config/powerpc/linux.mh | 3 +- gdb/config/powerpc/ppc64-linux.mh | 3 +- gdb/config/powerpc/spu-linux.mh | 2 +- gdb/config/sparc/linux.mh | 2 +- gdb/config/sparc/linux64.mh | 2 +- gdb/config/tilegx/linux.mh | 2 +- gdb/config/xtensa/linux.mh | 3 +- gdb/configure | 7 +- gdb/configure.ac | 4 +- gdb/gdbserver/ChangeLog | 27 +++ gdb/gdbserver/Makefile.in | 11 ++ gdb/gdbserver/configure.srv | 69 +++---- gdb/gdbserver/linux-low.c | 257 +------------------------ gdb/gdbserver/linux-low.h | 5 +- gdb/linux-nat.c | 271 ++------------------------ gdb/linux-nat.h | 3 - gdb/nat/linux-nat.h | 28 +++ gdb/nat/linux-waitpid.c | 120 ++++++++++++ gdb/nat/linux-waitpid.h | 27 +++ 34 files changed, 715 insertions(+), 577 deletions(-) create mode 100644 gdb/nat/linux-nat.h create mode 100644 gdb/nat/linux-waitpid.c create mode 100644 gdb/nat/linux-waitpid.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8d939d96e55..de6a83500e5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,84 @@ +2013-08-22 Luis Machado + + * 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. + 2013-08-22 Samuel Bronson ARM Linux support for `catch syscall'. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 45cddafa3c4..c75ec38bd41 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -855,7 +855,7 @@ common/format.h common/host-defs.h utils.h common/queue.h common/gdb_string.h \ common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \ gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h \ ctf.h common/i386-cpuid.h common/i386-gcc-cpuid.h target/resume.h \ -target/wait.h target/waitstatus.h +target/wait.h target/waitstatus.h nat/linux-nat.h nat/linux-waitpid.h # Header files that already have srcdir in them, or which are in objdir. @@ -2037,6 +2037,15 @@ waitstatus.o: ${srcdir}/target/waitstatus.c $(COMPILE) $(srcdir)/target/waitstatus.c $(POSTCOMPILE) +# gdb/nat/ dependencies +# +# Need to explicitly specify the compile rule as make will do nothing +# or try to compile the object file into the sub-directory. + +linux-waitpid.o: ${srcdir}/nat/linux-waitpid.c + $(COMPILE) $(srcdir)/nat/linux-waitpid.c + $(POSTCOMPILE) + # # gdb/tui/ dependencies # diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c index d5ac061ccb7..c4808ab0776 100644 --- a/gdb/common/linux-ptrace.c +++ b/gdb/common/linux-ptrace.c @@ -25,10 +25,16 @@ #include "linux-ptrace.h" #include "linux-procfs.h" +#include "nat/linux-waitpid.h" #include "buffer.h" #include "gdb_assert.h" #include "gdb_wait.h" +/* Stores the currently supported ptrace options. A value of + -1 means we did not check for features yet. A value of 0 means + there are no supported features. */ +static int current_ptrace_options = -1; + /* Find all possible reasons we could fail to attach PID and append these newline terminated reason strings to initialized BUFFER. '\0' termination of BUFFER must be done by the caller. */ @@ -97,7 +103,8 @@ linux_ptrace_test_ret_to_nx (void) return; case 0: - l = ptrace (PTRACE_TRACEME, 0, NULL, NULL); + l = ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) NULL, + (PTRACE_TYPE_ARG4) NULL); if (l != 0) warning (_("linux_ptrace_test_ret_to_nx: Cannot PTRACE_TRACEME: %s"), strerror (errno)); @@ -163,9 +170,11 @@ linux_ptrace_test_ret_to_nx (void) errno = 0; #if defined __i386__ - l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (EIP * 4), NULL); + l = ptrace (PTRACE_PEEKUSER, child, (PTRACE_TYPE_ARG3) (uintptr_t) (EIP * 4), + (PTRACE_TYPE_ARG4) NULL); #elif defined __x86_64__ - l = ptrace (PTRACE_PEEKUSER, child, (void *) (uintptr_t) (RIP * 8), NULL); + l = ptrace (PTRACE_PEEKUSER, child, (PTRACE_TYPE_ARG3) (uintptr_t) (RIP * 8), + (PTRACE_TYPE_ARG4) NULL); #else # error "!__i386__ && !__x86_64__" #endif @@ -178,7 +187,8 @@ linux_ptrace_test_ret_to_nx (void) pc = (void *) (uintptr_t) l; kill (child, SIGKILL); - ptrace (PTRACE_KILL, child, NULL, NULL); + ptrace (PTRACE_KILL, child, (PTRACE_TYPE_ARG3) NULL, + (PTRACE_TYPE_ARG4) NULL); errno = 0; got_pid = waitpid (child, &kill_status, 0); @@ -222,6 +232,292 @@ linux_ptrace_test_ret_to_nx (void) #endif /* defined __i386__ || defined __x86_64__ */ } +/* Helper function to fork a process and make the child process call + the function FUNCTION, passing CHILD_STACK as parameter. + + For MMU-less targets, clone is used instead of fork, and + CHILD_STACK is used as stack space for the cloned child. If NULL, + stack space is allocated via malloc (and subsequently passed to + FUNCTION). For MMU targets, CHILD_STACK is ignored. */ + +static int +linux_fork_to_function (gdb_byte *child_stack, void (*function) (gdb_byte *)) +{ + int child_pid; + + /* Sanity check the function pointer. */ + gdb_assert (function != NULL); + +#if defined(__UCLIBC__) && defined(HAS_NOMMU) +#define STACK_SIZE 4096 + + if (child_stack == NULL) + child_stack = xmalloc (STACK_SIZE * 4); + + /* Use CLONE_VM instead of fork, to support uClinux (no MMU). */ + #ifdef __ia64__ + child_pid = __clone2 (function, child_stack, STACK_SIZE, + CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2); + #else /* !__ia64__ */ + child_pid = clone (function, child_stack + STACK_SIZE, + CLONE_VM | SIGCHLD, child_stack + STACK_SIZE * 2); + #endif /* !__ia64__ */ +#else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */ + child_pid = fork (); + + if (child_pid == 0) + function (NULL); +#endif /* defined(__UCLIBC) && defined(HAS_NOMMU) */ + + if (child_pid == -1) + perror_with_name (("fork")); + + return child_pid; +} + +/* A helper function for linux_check_ptrace_features, called after + the child forks a grandchild. */ + +static void +linux_grandchild_function (gdb_byte *child_stack) +{ + /* Free any allocated stack. */ + xfree (child_stack); + + /* This code is only reacheable by the grandchild (child's child) + process. */ + _exit (0); +} + +/* A helper function for linux_check_ptrace_features, called after + the parent process forks a child. The child allows itself to + be traced by its parent. */ + +static void +linux_child_function (gdb_byte *child_stack) +{ + ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); + kill (getpid (), SIGSTOP); + + /* Fork a grandchild. */ + linux_fork_to_function (child_stack, linux_grandchild_function); + + /* This code is only reacheable by the child (grandchild's parent) + process. */ + _exit (0); +} + +/* Determine ptrace features available on this target. */ + +static void +linux_check_ptrace_features (void) +{ + int child_pid, ret, status; + long second_pid; + + /* Initialize the options. */ + current_ptrace_options = 0; + + /* Fork a child so we can do some testing. The child will call + linux_child_function and will get traced. The child will + eventually fork a grandchild so we can test fork event + reporting. */ + child_pid = linux_fork_to_function (NULL, linux_child_function); + + ret = my_waitpid (child_pid, &status, 0); + if (ret == -1) + perror_with_name (("waitpid")); + else if (ret != child_pid) + error (_("linux_check_ptrace_features: waitpid: unexpected result %d."), + ret); + if (! WIFSTOPPED (status)) + error (_("linux_check_ptrace_features: waitpid: unexpected status %d."), + status); + + /* First, set the PTRACE_O_TRACEFORK option. If this fails, we + know for sure that it is not supported. */ + ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) PTRACE_O_TRACEFORK); + + if (ret != 0) + { + ret = ptrace (PTRACE_KILL, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) 0); + if (ret != 0) + { + warning (_("linux_check_ptrace_features: failed to kill child")); + return; + } + + ret = my_waitpid (child_pid, &status, 0); + if (ret != child_pid) + warning (_("linux_check_ptrace_features: failed " + "to wait for killed child")); + else if (!WIFSIGNALED (status)) + warning (_("linux_check_ptrace_features: unexpected " + "wait status 0x%x from killed child"), status); + + return; + } + +#ifdef GDBSERVER + /* gdbserver does not support PTRACE_O_TRACESYSGOOD or + PTRACE_O_TRACEVFORKDONE yet. */ +#else + /* Check if the target supports PTRACE_O_TRACESYSGOOD. */ + ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) PTRACE_O_TRACESYSGOOD); + if (ret == 0) + current_ptrace_options |= PTRACE_O_TRACESYSGOOD; + + /* Check if the target supports PTRACE_O_TRACEVFORKDONE. */ + ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) (PTRACE_O_TRACEFORK + | PTRACE_O_TRACEVFORKDONE)); + if (ret == 0) + current_ptrace_options |= PTRACE_O_TRACEVFORKDONE; +#endif + + /* Setting PTRACE_O_TRACEFORK did not cause an error, however we + don't know for sure that the feature is available; old + versions of PTRACE_SETOPTIONS ignored unknown options. + Therefore, we attach to the child process, use PTRACE_SETOPTIONS + to enable fork tracing, and let it fork. If the process exits, + we assume that we can't use PTRACE_O_TRACEFORK; if we get the + fork notification, and we can extract the new child's PID, then + we assume that we can. + + We do not explicitly check for vfork tracing here. It is + assumed that vfork tracing is available whenever fork tracing + is available. */ + ret = ptrace (PTRACE_CONT, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) 0); + if (ret != 0) + warning (_("linux_check_ptrace_features: failed to resume child")); + + ret = my_waitpid (child_pid, &status, 0); + + /* Check if we received a fork event notification. */ + if (ret == child_pid && WIFSTOPPED (status) + && status >> 16 == PTRACE_EVENT_FORK) + { + /* We did receive a fork event notification. Make sure its PID + is reported. */ + second_pid = 0; + ret = ptrace (PTRACE_GETEVENTMSG, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) &second_pid); + if (ret == 0 && second_pid != 0) + { + int second_status; + + /* We got the PID from the grandchild, which means fork + tracing is supported. */ +#ifdef GDBSERVER + /* Do not enable all the options for now since gdbserver does not + properly support them. This restriction will be lifted when + gdbserver is augmented to support them. */ + current_ptrace_options |= PTRACE_O_TRACECLONE; +#else + current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK + | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC; + + /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to + support read-only process state. */ +#endif + + /* Do some cleanup and kill the grandchild. */ + my_waitpid (second_pid, &second_status, 0); + ret = ptrace (PTRACE_KILL, second_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) 0); + if (ret != 0) + warning (_("linux_check_ptrace_features: " + "failed to kill second child")); + my_waitpid (second_pid, &status, 0); + } + } + else + warning (_("linux_check_ptrace_features: unexpected result from waitpid " + "(%d, status 0x%x)"), ret, status); + + /* Clean things up and kill any pending children. */ + do + { + ret = ptrace (PTRACE_KILL, child_pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) 0); + if (ret != 0) + warning ("linux_check_ptrace_features: failed to kill child"); + my_waitpid (child_pid, &status, 0); + } + while (WIFSTOPPED (status)); +} + +/* Enable reporting of all currently supported ptrace events. */ + +void +linux_enable_event_reporting (pid_t pid) +{ + /* Check if we have initialized the ptrace features for this + target. If not, do it now. */ + if (current_ptrace_options == -1) + linux_check_ptrace_features (); + + /* Set the options. */ + ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0, + (PTRACE_TYPE_ARG4) (uintptr_t) current_ptrace_options); +} + +/* Returns non-zero if PTRACE_OPTIONS is contained within + CURRENT_PTRACE_OPTIONS, therefore supported. Returns 0 + otherwise. */ + +static int +ptrace_supports_feature (int ptrace_options) +{ + gdb_assert (current_ptrace_options >= 0); + + return ((current_ptrace_options & ptrace_options) == ptrace_options); +} + +/* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace, + 0 otherwise. Note that if PTRACE_EVENT_FORK is supported so is + PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, + since they were all added to the kernel at the same time. */ + +int +linux_supports_tracefork (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEFORK); +} + +/* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace, + 0 otherwise. Note that if PTRACE_EVENT_CLONE is supported so is + PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK, + since they were all added to the kernel at the same time. */ + +int +linux_supports_traceclone (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACECLONE); +} + +/* Returns non-zero if PTRACE_O_TRACEVFORKDONE is supported by + ptrace, 0 otherwise. */ + +int +linux_supports_tracevforkdone (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACEVFORKDONE); +} + +/* Returns non-zero if PTRACE_O_TRACESYSGOOD is supported by ptrace, + 0 otherwise. */ + +int +linux_supports_tracesysgood (void) +{ + return ptrace_supports_feature (PTRACE_O_TRACESYSGOOD); +} + /* Display possible problems on this system. Display them only once per GDB execution. */ diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h index 8f02c82ea06..39c943e456f 100644 --- a/gdb/common/linux-ptrace.h +++ b/gdb/common/linux-ptrace.h @@ -22,6 +22,22 @@ struct buffer; #include +#ifdef __UCLIBC__ +#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__)) +/* PTRACE_TEXT_ADDR and friends. */ +#include +#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 @@ -69,5 +85,10 @@ struct buffer; extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer); extern void linux_ptrace_init_warnings (void); +extern void linux_enable_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); #endif /* COMMON_LINUX_PTRACE_H */ diff --git a/gdb/config.in b/gdb/config.in index 76abd04a09d..03b097266f5 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -659,6 +659,9 @@ /* Define to the type of arg 3 for ptrace. */ #undef PTRACE_TYPE_ARG3 +/* Define to the type of arg 4 for ptrace. */ +#undef PTRACE_TYPE_ARG4 + /* Define to the type of arg 5 for ptrace. */ #undef PTRACE_TYPE_ARG5 diff --git a/gdb/config/aarch64/linux.mh b/gdb/config/aarch64/linux.mh index 2b2202e8cf4..18a12abd1b1 100644 --- a/gdb/config/aarch64/linux.mh +++ b/gdb/config/aarch64/linux.mh @@ -21,7 +21,7 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o \ proc-service.o linux-thread-db.o linux-nat.o linux-fork.o \ - linux-procfs.o linux-ptrace.o linux-osdata.o + linux-procfs.o linux-ptrace.o linux-osdata.o linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES= -ldl $(RDYNAMIC) diff --git a/gdb/config/alpha/alpha-linux.mh b/gdb/config/alpha/alpha-linux.mh index 9eb9e4b7291..81819a16bb0 100644 --- a/gdb/config/alpha/alpha-linux.mh +++ b/gdb/config/alpha/alpha-linux.mh @@ -2,7 +2,8 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o alpha-linux-nat.o \ fork-child.o proc-service.o linux-thread-db.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list # The dynamically loaded libthread_db needs access to symbols in the diff --git a/gdb/config/arm/linux.mh b/gdb/config/arm/linux.mh index c0a1c66804a..63c3eae45cd 100644 --- a/gdb/config/arm/linux.mh +++ b/gdb/config/arm/linux.mh @@ -3,7 +3,8 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o arm-linux-nat.o \ proc-service.o linux-thread-db.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES= -ldl $(RDYNAMIC) diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh index 7c64e836325..10a25849117 100644 --- a/gdb/config/i386/linux.mh +++ b/gdb/config/i386/linux.mh @@ -5,7 +5,7 @@ NATDEPFILES= inf-ptrace.o fork-child.o \ i386-nat.o i386-linux-nat.o \ proc-service.o linux-thread-db.o \ linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ - linux-btrace.o + linux-btrace.o linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list # The dynamically loaded libthread_db needs access to symbols in the diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh index 8d782c1a335..686c363510d 100644 --- a/gdb/config/i386/linux64.mh +++ b/gdb/config/i386/linux64.mh @@ -3,7 +3,8 @@ NATDEPFILES= inf-ptrace.o fork-child.o \ i386-nat.o amd64-nat.o amd64-linux-nat.o \ linux-nat.o linux-osdata.o \ proc-service.o linux-thread-db.o linux-fork.o \ - linux-procfs.o linux-ptrace.o linux-btrace.o + linux-procfs.o linux-ptrace.o linux-btrace.o \ + linux-waitpid.o NAT_FILE= config/nm-linux.h NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/ia64/linux.mh b/gdb/config/ia64/linux.mh index 1a4c68e0937..a2aff442f69 100644 --- a/gdb/config/ia64/linux.mh +++ b/gdb/config/ia64/linux.mh @@ -5,7 +5,7 @@ NATDEPFILES= inf-ptrace.o fork-child.o \ core-regset.o ia64-linux-nat.o \ proc-service.o linux-thread-db.o \ linux-nat.o linux-osdata.o linux-fork.o \ - linux-procfs.o linux-ptrace.o + linux-procfs.o linux-ptrace.o linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES = -ldl $(RDYNAMIC) diff --git a/gdb/config/m32r/linux.mh b/gdb/config/m32r/linux.mh index b4618064bff..e9bb82cbc5a 100644 --- a/gdb/config/m32r/linux.mh +++ b/gdb/config/m32r/linux.mh @@ -3,7 +3,8 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ m32r-linux-nat.o proc-service.o linux-thread-db.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES= -ldl $(RDYNAMIC) diff --git a/gdb/config/m68k/linux.mh b/gdb/config/m68k/linux.mh index e3aaf382c8c..bcec2958a14 100644 --- a/gdb/config/m68k/linux.mh +++ b/gdb/config/m68k/linux.mh @@ -4,7 +4,8 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ m68klinux-nat.o \ proc-service.o linux-thread-db.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list # The dynamically loaded libthread_db needs access to symbols in the diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh index a4f23e3c9d7..021838e0af7 100644 --- a/gdb/config/mips/linux.mh +++ b/gdb/config/mips/linux.mh @@ -3,7 +3,8 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \ linux-thread-db.o proc-service.o \ linux-nat.o linux-osdata.o linux-fork.o \ - linux-procfs.o linux-ptrace.o mips-linux-watch.o + linux-procfs.o linux-ptrace.o linux-waitpid.o \ + mips-linux-watch.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES = -ldl $(RDYNAMIC) diff --git a/gdb/config/pa/linux.mh b/gdb/config/pa/linux.mh index fa46db6ebe5..f1c0c32783b 100644 --- a/gdb/config/pa/linux.mh +++ b/gdb/config/pa/linux.mh @@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ hppa-linux-nat.o proc-service.o linux-thread-db.o \ linux-nat.o linux-osdata.o linux-fork.o \ - linux-procfs.o linux-ptrace.o + linux-procfs.o linux-ptrace.o linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES = -ldl $(RDYNAMIC) diff --git a/gdb/config/powerpc/linux.mh b/gdb/config/powerpc/linux.mh index b0d4ce7c55c..a807d3fac06 100644 --- a/gdb/config/powerpc/linux.mh +++ b/gdb/config/powerpc/linux.mh @@ -5,7 +5,8 @@ XM_CLIBS= NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ ppc-linux-nat.o proc-service.o linux-thread-db.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES = -ldl $(RDYNAMIC) diff --git a/gdb/config/powerpc/ppc64-linux.mh b/gdb/config/powerpc/ppc64-linux.mh index 367a81853b5..4b91408fbe6 100644 --- a/gdb/config/powerpc/ppc64-linux.mh +++ b/gdb/config/powerpc/ppc64-linux.mh @@ -5,7 +5,8 @@ XM_CLIBS= NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o \ ppc-linux-nat.o proc-service.o linux-thread-db.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list # The PowerPC has severe limitations on TOC size, and uses them even diff --git a/gdb/config/powerpc/spu-linux.mh b/gdb/config/powerpc/spu-linux.mh index 1bc279a8138..7ce7a5ff141 100644 --- a/gdb/config/powerpc/spu-linux.mh +++ b/gdb/config/powerpc/spu-linux.mh @@ -4,5 +4,5 @@ # PPU side of the Cell BE and debugging the SPU side. NATDEPFILES = spu-linux-nat.o fork-child.o inf-ptrace.o \ - linux-procfs.o linux-ptrace.o + linux-procfs.o linux-ptrace.o linux-waitpid.o diff --git a/gdb/config/sparc/linux.mh b/gdb/config/sparc/linux.mh index 6a2cefd7b5c..d80259176d7 100644 --- a/gdb/config/sparc/linux.mh +++ b/gdb/config/sparc/linux.mh @@ -4,7 +4,7 @@ NATDEPFILES= sparc-nat.o sparc-linux-nat.o \ core-regset.o fork-child.o inf-ptrace.o \ proc-service.o linux-thread-db.o \ linux-nat.o linux-osdata.o linux-fork.o \ - linux-procfs.o linux-ptrace.o + linux-procfs.o linux-ptrace.o linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list # The dynamically loaded libthread_db needs access to symbols in the diff --git a/gdb/config/sparc/linux64.mh b/gdb/config/sparc/linux64.mh index d1e1a97162f..c83097ec54d 100644 --- a/gdb/config/sparc/linux64.mh +++ b/gdb/config/sparc/linux64.mh @@ -5,7 +5,7 @@ NATDEPFILES= sparc-nat.o sparc64-nat.o sparc64-linux-nat.o \ fork-child.o inf-ptrace.o \ proc-service.o linux-thread-db.o \ linux-nat.o linux-osdata.o linux-fork.o \ - linux-procfs.o linux-ptrace.o + linux-procfs.o linux-ptrace.o linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list # The dynamically loaded libthread_db needs access to symbols in the diff --git a/gdb/config/tilegx/linux.mh b/gdb/config/tilegx/linux.mh index 56ef694b1f3..1ed9c33c120 100644 --- a/gdb/config/tilegx/linux.mh +++ b/gdb/config/tilegx/linux.mh @@ -5,7 +5,7 @@ NATDEPFILES= inf-ptrace.o fork-child.o \ tilegx-linux-nat.o \ proc-service.o linux-thread-db.o \ linux-nat.o linux-osdata.o linux-fork.o \ - linux-procfs.o linux-ptrace.o + linux-procfs.o linux-ptrace.o linux-waitpid.o # The dynamically loaded libthread_db needs access to symbols in the # gdb executable. diff --git a/gdb/config/xtensa/linux.mh b/gdb/config/xtensa/linux.mh index deffe25ed42..8ef84b46cdf 100644 --- a/gdb/config/xtensa/linux.mh +++ b/gdb/config/xtensa/linux.mh @@ -4,7 +4,8 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= inf-ptrace.o fork-child.o xtensa-linux-nat.o \ linux-thread-db.o proc-service.o \ - linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o + linux-nat.o linux-osdata.o linux-fork.o linux-procfs.o linux-ptrace.o \ + linux-waitpid.o NAT_CDEPS = $(srcdir)/proc-service.list LOADLIBES = -ldl $(RDYNAMIC) diff --git a/gdb/configure b/gdb/configure index 80678256bfa..a722b930831 100755 --- a/gdb/configure +++ b/gdb/configure @@ -10336,7 +10336,7 @@ else for gdb_arg1 in 'int' 'long'; do for gdb_arg2 in 'pid_t' 'int' 'long'; do for gdb_arg3 in 'int *' 'caddr_t' 'int' 'long' 'void *'; do - for gdb_arg4 in 'int' 'long'; do + for gdb_arg4 in 'int' 'long' 'void *'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $gdb_ptrace_headers @@ -10399,6 +10399,11 @@ cat >>confdefs.h <<_ACEOF #define PTRACE_TYPE_ARG3 $3 _ACEOF + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_ARG4 $4 +_ACEOF + if test -n "$5"; then cat >>confdefs.h <<_ACEOF diff --git a/gdb/configure.ac b/gdb/configure.ac index 667821f1ecc..0982cac82a4 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -1207,7 +1207,7 @@ AC_CACHE_CHECK([types of arguments for ptrace], gdb_cv_func_ptrace_args, [ for gdb_arg1 in 'int' 'long'; do for gdb_arg2 in 'pid_t' 'int' 'long'; do for gdb_arg3 in 'int *' 'caddr_t' 'int' 'long' 'void *'; do - for gdb_arg4 in 'int' 'long'; do + for gdb_arg4 in 'int' 'long' 'void *'; do AC_TRY_COMPILE($gdb_ptrace_headers, [ extern $gdb_cv_func_ptrace_ret ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4); @@ -1234,6 +1234,8 @@ IFS=$ac_save_IFS shift AC_DEFINE_UNQUOTED(PTRACE_TYPE_ARG3, $[3], [Define to the type of arg 3 for ptrace.]) +AC_DEFINE_UNQUOTED(PTRACE_TYPE_ARG4, $[4], + [Define to the type of arg 4 for ptrace.]) if test -n "$[5]"; then AC_DEFINE_UNQUOTED(PTRACE_TYPE_ARG5, $[5], [Define to the type of arg 5 for ptrace.]) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 19687863034..fe3660c020d 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,30 @@ +2013-08-22 Luis Machado + + * 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. + 2013-08-21 Pedro Alves * config.in: Renegerate. diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in index 2cdbf47bffb..45e03a2353a 100644 --- a/gdb/gdbserver/Makefile.in +++ b/gdb/gdbserver/Makefile.in @@ -100,6 +100,11 @@ GNULIB_H = $(GNULIB_BUILDDIR)/import/string.h @GNULIB_STDINT_H@ # -I. for config files. # -I${srcdir} for our headers. # -I$(srcdir)/../regformats for regdef.h. +# +# We do not include ../target or ../nat in here because headers +# in those directories should be included with the subdirectory. +# e.g.: "target/wait.h". +# INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../common \ -I$(srcdir)/../regformats -I$(srcdir)/../ -I$(INCLUDE_DIR) \ $(INCGNU) @@ -562,6 +567,12 @@ linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h) mips-linux-watch.o: ../common/mips-linux-watch.c $(mips_linux_watch_h) $(server_h) $(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< +# Native object files rules from ../nat + +linux-waitpid.o: ../nat/linux-waitpid.c + $(COMPILE) $< + $(POSTCOMPILE) + # We build vasprintf with -DHAVE_CONFIG_H because we want that unit to # include our config.h file. Otherwise, some system headers do not get # included, and the compiler emits a warning about implicitly defined diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index b9dfd6c6cb6..b3c04210fe7 100644 --- a/gdb/gdbserver/configure.srv +++ b/gdb/gdbserver/configure.srv @@ -39,16 +39,18 @@ srv_amd64_xmlfiles="i386/amd64.xml i386/amd64-avx.xml i386/x32.xml i386/x32-avx. srv_i386_linux_xmlfiles="i386/i386-linux.xml i386/i386-avx-linux.xml i386/i386-mmx-linux.xml i386/32bit-linux.xml $srv_i386_32bit_xmlfiles" srv_amd64_linux_xmlfiles="i386/amd64-linux.xml i386/amd64-avx-linux.xml i386/64bit-linux.xml i386/x32-linux.xml i386/x32-avx-linux.xml $srv_i386_64bit_xmlfiles" + +# Linux object files. This is so we don't have to repeat +# these files over and over again. +srv_linux_obj="linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.o linux-waitpid.o" + # Input is taken from the "${target}" variable. case "${target}" in aarch64*-*-linux*) srv_regobj="aarch64.o" srv_tgtobj="linux-aarch64-low.o" - srv_tgtobj="${srv_tgtobj} linux-low.o" - srv_tgtobj="${srv_tgtobj} linux-osdata.o" - srv_tgtobj="${srv_tgtobj} linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="${srv_tgtobj} $srv_linux_obj" srv_xmlfiles="aarch64.xml" srv_xmlfiles="${srv_xmlfiles} aarch64-core.xml" srv_xmlfiles="${srv_xmlfiles} aarch64-fpu.xml" @@ -60,8 +62,7 @@ case "${target}" in srv_regobj="${srv_regobj} arm-with-vfpv2.o" srv_regobj="${srv_regobj} arm-with-vfpv3.o" srv_regobj="${srv_regobj} arm-with-neon.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-arm-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-arm-low.o" srv_xmlfiles="arm-with-iwmmxt.xml" srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml" srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml" @@ -83,20 +84,17 @@ case "${target}" in srv_mingwce=yes ;; bfin-*-*linux*) srv_regobj=reg-bfin.o - srv_tgtobj="linux-low.o linux-osdata.o linux-bfin-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-bfin-low.o" srv_linux_usrregs=yes srv_linux_thread_db=yes ;; crisv32-*-linux*) srv_regobj=reg-crisv32.o - srv_tgtobj="linux-low.o linux-osdata.o linux-crisv32-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-crisv32-low.o" srv_linux_regsets=yes srv_linux_thread_db=yes ;; cris-*-linux*) srv_regobj=reg-cris.o - srv_tgtobj="linux-low.o linux-osdata.o linux-cris-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-cris-low.o" srv_linux_usrregs=yes srv_linux_thread_db=yes ;; @@ -110,8 +108,8 @@ case "${target}" in srv_regobj="$srv_regobj $srv_amd64_linux_regobj" srv_xmlfiles="${srv_xmlfiles} $srv_amd64_linux_xmlfiles" fi - srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o" + srv_tgtobj="$srv_linux_obj linux-x86-low.o i386-low.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} linux-btrace.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes @@ -146,13 +144,11 @@ case "${target}" in srv_qnx="yes" ;; ia64-*-linux*) srv_regobj=reg-ia64.o - srv_tgtobj="linux-low.o linux-osdata.o linux-ia64-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-ia64-low.o" srv_linux_usrregs=yes ;; m32r*-*-linux*) srv_regobj=reg-m32r.o - srv_tgtobj="linux-low.o linux-osdata.o linux-m32r-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-m32r-low.o" srv_linux_usrregs=yes srv_linux_thread_db=yes ;; @@ -161,8 +157,7 @@ case "${target}" in else srv_regobj=reg-m68k.o fi - srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-m68k-low.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes @@ -172,8 +167,7 @@ case "${target}" in else srv_regobj=reg-m68k.o fi - srv_tgtobj="linux-low.o linux-osdata.o linux-m68k-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-m68k-low.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes @@ -182,8 +176,7 @@ case "${target}" in srv_regobj="${srv_regobj} mips-dsp-linux.o" srv_regobj="${srv_regobj} mips64-linux.o" srv_regobj="${srv_regobj} mips64-dsp-linux.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-mips-low.o" srv_tgtobj="${srv_tgtobj} mips-linux-watch.o" srv_xmlfiles="mips-linux.xml" srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml" @@ -202,8 +195,7 @@ case "${target}" in srv_linux_thread_db=yes ;; nios2*-*-linux*) srv_regobj="nios2-linux.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-nios2-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-nios2-low.o" srv_xmlfiles="nios2-linux.xml" srv_xmlfiles="${srv_xmlfiles} nios2-cpu.xml" srv_linux_regsets=yes @@ -225,8 +217,7 @@ case "${target}" in srv_regobj="${srv_regobj} powerpc-isa205-64l.o" srv_regobj="${srv_regobj} powerpc-isa205-altivec64l.o" srv_regobj="${srv_regobj} powerpc-isa205-vsx64l.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-ppc-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-ppc-low.o" srv_xmlfiles="rs6000/powerpc-32l.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-altivec32l.xml" srv_xmlfiles="${srv_xmlfiles} rs6000/powerpc-cell32l.xml" @@ -271,8 +262,7 @@ case "${target}" in srv_regobj="${srv_regobj} s390x-linux64.o" srv_regobj="${srv_regobj} s390x-linux64v1.o" srv_regobj="${srv_regobj} s390x-linux64v2.o" - srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-s390-low.o" srv_xmlfiles="s390-linux32.xml" srv_xmlfiles="${srv_xmlfiles} s390-linux32v1.xml" srv_xmlfiles="${srv_xmlfiles} s390-linux32v2.xml" @@ -292,15 +282,13 @@ case "${target}" in srv_linux_thread_db=yes ;; sh*-*-linux*) srv_regobj=reg-sh.o - srv_tgtobj="linux-low.o linux-osdata.o linux-sh-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-sh-low.o" srv_linux_usrregs=yes srv_linux_regsets=yes srv_linux_thread_db=yes ;; sparc*-*-linux*) srv_regobj=reg-sparc64.o - srv_tgtobj="linux-low.o linux-osdata.o linux-sparc-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-sparc-low.o" srv_linux_regsets=yes srv_linux_thread_db=yes ;; @@ -316,15 +304,14 @@ case "${target}" in srv_xmlfiles="${srv_xmlfiles} tic6x-core.xml" srv_xmlfiles="${srv_xmlfiles} tic6x-gp.xml" srv_xmlfiles="${srv_xmlfiles} tic6x-c6xp.xml" - srv_tgtobj="linux-low.o linux-osdata.o linux-tic6x-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-tic6x-low.o" srv_linux_regsets=yes srv_linux_usrregs=yes srv_linux_thread_db=yes ;; x86_64-*-linux*) srv_regobj="$srv_amd64_linux_regobj $srv_i386_linux_regobj" - srv_tgtobj="linux-low.o linux-osdata.o linux-x86-low.o i386-low.o i387-fp.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o linux-btrace.o" + srv_tgtobj="$srv_linux_obj linux-x86-low.o i386-low.o i387-fp.o" + srv_tgtobj="${srv_tgtobj} linux-btrace.o" srv_xmlfiles="$srv_i386_linux_xmlfiles $srv_amd64_linux_xmlfiles" srv_linux_usrregs=yes # This is for i386 progs. srv_linux_regsets=yes @@ -343,14 +330,12 @@ case "${target}" in ;; xtensa*-*-linux*) srv_regobj=reg-xtensa.o - srv_tgtobj="linux-low.o linux-osdata.o linux-xtensa-low.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-xtensa-low.o" srv_linux_regsets=yes ;; tilegx-*-linux*) srv_regobj=reg-tilegx.o srv_regobj="${srv_regobj} reg-tilegx32.o" - srv_tgtobj="linux-low.o linux-tile-low.o linux-osdata.o linux-procfs.o" - srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_tgtobj="$srv_linux_obj linux-osdata.o" srv_linux_regsets=yes srv_linux_thread_db=yes ;; diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 217cd2efee8..12208dcc1e1 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -21,6 +21,8 @@ #include "linux-osdata.h" #include "agent.h" +#include "nat/linux-nat.h" +#include "nat/linux-waitpid.h" #include "gdb_wait.h" #include #include @@ -75,14 +77,6 @@ #define __SIGRTMIN 32 #endif -#ifdef __UCLIBC__ -#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__)) -/* PTRACE_TEXT_ADDR and friends. */ -#include -#define HAS_NOMMU -#endif -#endif - /* Some targets did not define these ptrace constants from the start, so gdbserver defines them locally here. In the future, these may be removed after they are added to asm/ptrace.h. */ @@ -236,7 +230,6 @@ static void proceed_all_lwps (void); static int finish_step_over (struct lwp_info *lwp); static CORE_ADDR get_stop_pc (struct lwp_info *lwp); static int kill_lwp (unsigned long lwpid, int signo); -static void linux_enable_event_reporting (int pid); /* True if the low target can hardware single-step. Such targets don't need a BREAKPOINT_REINSERT_ADDR callback. */ @@ -376,81 +369,6 @@ linux_add_process (int pid, int attached) return proc; } -/* Wrapper function for waitpid which handles EINTR, and emulates - __WALL for systems where that is not available. */ - -static int -my_waitpid (int pid, int *status, int flags) -{ - int ret, out_errno; - - if (debug_threads) - fprintf (stderr, "my_waitpid (%d, 0x%x)\n", pid, flags); - - if (flags & __WALL) - { - sigset_t block_mask, org_mask, wake_mask; - int wnohang; - - wnohang = (flags & WNOHANG) != 0; - flags &= ~(__WALL | __WCLONE); - flags |= WNOHANG; - - /* Block all signals while here. This avoids knowing about - LinuxThread's signals. */ - sigfillset (&block_mask); - sigprocmask (SIG_BLOCK, &block_mask, &org_mask); - - /* ... except during the sigsuspend below. */ - sigemptyset (&wake_mask); - - while (1) - { - /* Since all signals are blocked, there's no need to check - for EINTR here. */ - ret = waitpid (pid, status, flags); - out_errno = errno; - - if (ret == -1 && out_errno != ECHILD) - break; - else if (ret > 0) - break; - - if (flags & __WCLONE) - { - /* We've tried both flavors now. If WNOHANG is set, - there's nothing else to do, just bail out. */ - if (wnohang) - break; - - if (debug_threads) - fprintf (stderr, "blocking\n"); - - /* Block waiting for signals. */ - sigsuspend (&wake_mask); - } - - flags ^= __WCLONE; - } - - sigprocmask (SIG_SETMASK, &org_mask, NULL); - } - else - { - do - ret = waitpid (pid, status, flags); - while (ret == -1 && errno == EINTR); - out_errno = errno; - } - - if (debug_threads) - fprintf (stderr, "my_waitpid (%d, 0x%x): status(%x), %d\n", - pid, flags, status ? *status : -1, ret); - - errno = out_errno; - return ret; -} - /* Handle a GNU/Linux extended wait response. If we see a clone event, we need to add the new LWP to our list (and not report the trap to higher layers). */ @@ -4659,168 +4577,6 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) return 0; } -/* Non-zero if the kernel supports PTRACE_O_TRACEFORK. */ -static int linux_supports_tracefork_flag; - -static void -linux_enable_event_reporting (int pid) -{ - if (!linux_supports_tracefork_flag) - return; - - ptrace (PTRACE_SETOPTIONS, pid, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) PTRACE_O_TRACECLONE); -} - -/* Helper functions for linux_test_for_tracefork, called via clone (). */ - -static int -linux_tracefork_grandchild (void *arg) -{ - _exit (0); -} - -#define STACK_SIZE 4096 - -static int -linux_tracefork_child (void *arg) -{ - ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); - kill (getpid (), SIGSTOP); - -#if !(defined(__UCLIBC__) && defined(HAS_NOMMU)) - - if (fork () == 0) - linux_tracefork_grandchild (NULL); - -#else /* defined(__UCLIBC__) && defined(HAS_NOMMU) */ - -#ifdef __ia64__ - __clone2 (linux_tracefork_grandchild, arg, STACK_SIZE, - CLONE_VM | SIGCHLD, NULL); -#else - clone (linux_tracefork_grandchild, (char *) arg + STACK_SIZE, - CLONE_VM | SIGCHLD, NULL); -#endif - -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */ - - _exit (0); -} - -/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events. Make - sure that we can enable the option, and that it had the desired - effect. */ - -static void -linux_test_for_tracefork (void) -{ - int child_pid, ret, status; - long second_pid; -#if defined(__UCLIBC__) && defined(HAS_NOMMU) - char *stack = xmalloc (STACK_SIZE * 4); -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */ - - linux_supports_tracefork_flag = 0; - -#if !(defined(__UCLIBC__) && defined(HAS_NOMMU)) - - child_pid = fork (); - if (child_pid == 0) - linux_tracefork_child (NULL); - -#else /* defined(__UCLIBC__) && defined(HAS_NOMMU) */ - - /* Use CLONE_VM instead of fork, to support uClinux (no MMU). */ -#ifdef __ia64__ - child_pid = __clone2 (linux_tracefork_child, stack, STACK_SIZE, - CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2); -#else /* !__ia64__ */ - child_pid = clone (linux_tracefork_child, stack + STACK_SIZE, - CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2); -#endif /* !__ia64__ */ - -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */ - - if (child_pid == -1) - perror_with_name ("clone"); - - 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, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) PTRACE_O_TRACEFORK); - if (ret != 0) - { - ret = ptrace (PTRACE_KILL, child_pid, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) 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; - } - - ret = ptrace (PTRACE_CONT, child_pid, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) 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, (PTRACE_TYPE_ARG3) 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, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) 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, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) 0); - if (ret != 0) - warning ("linux_test_for_tracefork: failed to kill child"); - my_waitpid (child_pid, &status, 0); - } - while (WIFSTOPPED (status)); - -#if defined(__UCLIBC__) && defined(HAS_NOMMU) - free (stack); -#endif /* defined(__UCLIBC__) && defined(HAS_NOMMU) */ -} - - static void linux_look_up_symbols (void) { @@ -4830,10 +4586,10 @@ linux_look_up_symbols (void) if (proc->private->thread_db != NULL) return; - /* If the kernel supports tracing forks then it also supports tracing - clones, and then we don't need to use the magic thread event breakpoint - to learn about threads. */ - thread_db_init (!linux_supports_tracefork_flag); + /* If the kernel supports tracing clones, then we don't need to + use the magic thread event breakpoint to learn about + threads. */ + thread_db_init (!linux_supports_traceclone ()); #endif } @@ -6097,7 +5853,6 @@ initialize_low (void) set_breakpoint_data (the_low_target.breakpoint, the_low_target.breakpoint_len); linux_init_signals (); - linux_test_for_tracefork (); linux_ptrace_init_warnings (); sigchld_action.sa_handler = sigchld_handler; diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index e051ab6c82f..4bf0dc37d66 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -22,8 +22,9 @@ #include "gdbthread.h" #include "gdb_proc_service.h" -#define PTRACE_TYPE_ARG3 void * -#define PTRACE_TYPE_ARG4 void * +/* Included for ptrace type definitions. */ +#include "linux-ptrace.h" + #define PTRACE_XFER_TYPE long #ifdef HAVE_LINUX_REGSETS diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index db23433d5fa..46e3dbfec4c 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, diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index cb8f1dacce8..044f646b389 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -127,9 +127,6 @@ extern void lin_thread_get_thread_signals (sigset_t *mask); void linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored); -/* linux-nat functions for handling fork events. */ -extern void linux_enable_event_reporting (ptid_t ptid); - extern int lin_lwp_attach_lwp (ptid_t ptid); extern void linux_stop_lwp (struct lwp_info *lwp); diff --git a/gdb/nat/linux-nat.h b/gdb/nat/linux-nat.h new file mode 100644 index 00000000000..4d84aa555a5 --- /dev/null +++ b/gdb/nat/linux-nat.h @@ -0,0 +1,28 @@ +/* Code for native debugging support for GNU/Linux (LWP layer). + + Copyright (C) 2000-2013 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 . */ + +#ifndef LINUX_NAT_H +#define LINUX_NAT_H + +/* 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) + +#endif /* LINUX_NAT_H */ diff --git a/gdb/nat/linux-waitpid.c b/gdb/nat/linux-waitpid.c new file mode 100644 index 00000000000..2debea48875 --- /dev/null +++ b/gdb/nat/linux-waitpid.c @@ -0,0 +1,120 @@ +/* Wrapper implementation for waitpid for GNU/Linux (LWP layer). + + Copyright (C) 2001-2013 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 . */ + +#ifdef GDBSERVER +#include "server.h" +#else +#include "defs.h" +#include "signal.h" +#endif + +#include "nat/linux-nat.h" +#include "nat/linux-waitpid.h" +#include "gdb_wait.h" + +/* Print debugging output based on the format string FORMAT and + its parameters. */ + +static inline void +linux_debug (const char *format, ...) +{ +#ifdef GDBSERVER + if (debug_threads) + { + va_list args; + va_start (args, format); + vfprintf (stderr, format, args); + fprintf (stderr, "\n"); + va_end (args); + } +#else + /* GDB-specific debugging output. */ +#endif +} + +/* Wrapper function for waitpid which handles EINTR, and emulates + __WALL for systems where that is not available. */ + +int +my_waitpid (int pid, int *status, int flags) +{ + int ret, out_errno; + + linux_debug ("my_waitpid (%d, 0x%x)\n", pid, flags); + + if (flags & __WALL) + { + sigset_t block_mask, org_mask, wake_mask; + int wnohang; + + wnohang = (flags & WNOHANG) != 0; + flags &= ~(__WALL | __WCLONE); + flags |= WNOHANG; + + /* Block all signals while here. This avoids knowing about + LinuxThread's signals. */ + sigfillset (&block_mask); + sigprocmask (SIG_BLOCK, &block_mask, &org_mask); + + /* ... except during the sigsuspend below. */ + sigemptyset (&wake_mask); + + while (1) + { + /* Since all signals are blocked, there's no need to check + for EINTR here. */ + ret = waitpid (pid, status, flags); + out_errno = errno; + + if (ret == -1 && out_errno != ECHILD) + break; + else if (ret > 0) + break; + + if (flags & __WCLONE) + { + /* We've tried both flavors now. If WNOHANG is set, + there's nothing else to do, just bail out. */ + if (wnohang) + break; + + linux_debug ("blocking\n"); + + /* Block waiting for signals. */ + sigsuspend (&wake_mask); + } + flags ^= __WCLONE; + } + + sigprocmask (SIG_SETMASK, &org_mask, NULL); + } + else + { + do + ret = waitpid (pid, status, flags); + while (ret == -1 && errno == EINTR); + out_errno = errno; + } + + linux_debug ("my_waitpid (%d, 0x%x): status(%x), %d\n", + pid, flags, status ? *status : -1, ret); + + errno = out_errno; + return ret; +} diff --git a/gdb/nat/linux-waitpid.h b/gdb/nat/linux-waitpid.h new file mode 100644 index 00000000000..0df29d8ef5c --- /dev/null +++ b/gdb/nat/linux-waitpid.h @@ -0,0 +1,27 @@ +/* Wrapper for waitpid for GNU/Linux (LWP layer). + + Copyright (C) 2000-2013 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 . */ + +#ifndef LINUX_WAITPID_H +#define LINUX_WAITPID_H + +/* Wrapper function for waitpid which handles EINTR, and emulates + __WALL for systems where that is not available. */ +extern int my_waitpid (int pid, int *status, int flags); + +#endif /* LINUX_WAITPID_H */ -- 2.30.2