From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13003 invoked by alias); 21 Aug 2013 03:09:20 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 12979 invoked by uid 89); 21 Aug 2013 03:09:19 -0000 X-Spam-SWARE-Status: No, score=-4.6 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL autolearn=ham version=3.3.2 Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Wed, 21 Aug 2013 03:09:13 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1VBynF-0004jz-G3 from Luis_Gustavo@mentor.com ; Tue, 20 Aug 2013 20:09:09 -0700 Received: from NA1-MAIL.mgc.mentorg.com ([147.34.98.181]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Tue, 20 Aug 2013 20:09:09 -0700 Received: from [172.30.2.208] ([172.30.2.208]) by NA1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 20 Aug 2013 20:09:07 -0700 Message-ID: <52142F4B.7030702@codesourcery.com> Date: Wed, 21 Aug 2013 03:09:00 -0000 From: Luis Machado Reply-To: lgustavo@codesourcery.com User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130803 Thunderbird/17.0.8 MIME-Version: 1.0 To: Pedro Alves CC: "'gdb-patches@sourceware.org'" , Tom Tromey Subject: Re: [PATCH, v2] Share ptrace options discovery/linux native code between GDB and gdbserver References: <5212A9E1.6030707@codesourcery.com> <52139BBA.60300@redhat.com> In-Reply-To: <52139BBA.60300@redhat.com> Content-Type: multipart/mixed; boundary="------------010000070709070302010203" X-Virus-Found: No X-SW-Source: 2013-08/txt/msg00561.txt.bz2 This is a multi-part message in MIME format. --------------010000070709070302010203 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 11475 Hi, On 08/20/2013 01:39 PM, Pedro Alves wrote: > On 08/20/2013 12:27 AM, Luis Machado wrote: > >> diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c >> index d5ac061..4198d1d 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. */ >> @@ -222,6 +228,284 @@ 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 ARG as parameter. */ >> + >> +static int >> +linux_fork_to_function (void *arg, void (*function) (void *)) > > The describing comment and the function prototype imply some > sort of generity. But ... > >> +{ >> + int child_pid; >> + >> + gdb_byte *stack = (gdb_byte *) arg; > > The arg has a definite particular use. > >> + >> + /* Sanity check the function pointer. */ >> + gdb_assert (function != NULL); >> + >> +#if defined(__UCLIBC__) && defined(HAS_NOMMU) >> +#define STACK_SIZE 4096 >> + >> + if (arg == NULL) >> + stack = xmalloc (STACK_SIZE * 4); > > Etc. Something's odd with the abstration. > I've improved this now. We have a special case for MMU-less targets (gdbserver's side), though it is not quite clear due to the lack of comments in that code. >> + >> + /* Use CLONE_VM instead of fork, to support uClinux (no MMU). */ >> + #ifdef __ia64__ >> + child_pid = __clone2 (function, stack, STACK_SIZE, >> + CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2); >> + #else /* !__ia64__ */ >> + child_pid = clone (function, stack + STACK_SIZE, >> + CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2); >> + #endif /* !__ia64__ */ >> +#else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */ >> + child_pid = fork (); >> + >> + if (child_pid == 0) >> + function (stack); >> +#endif /* defined(__UCLIBC) && defined(HAS_NOMMU) */ >> + >> + if (child_pid == -1) >> + perror_with_name (("fork")); >> + >> + return child_pid; >> +} >> + > > >> + >> +/* 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); >> + >> +#ifdef GDBSERVER >> + /* gdbserver does not support PTRACE_O_TRACEFORK yet. */ > > > This here doesn't look right ... > >> +#else >> + /* 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_O_TRACEFORK); >> +#endif >> + >> + if (ret != 0) > > ... as this looks like will always be reached for gdbserver. > The PTRACE_O_TRACEFORK testing is being used in gdbserver as > proxy for close tracing support. > I've removed the guards now. gdbserver should be able to run this chunk of code and lie about not supporting PTRACE_O_TRACEFORK later on. >> +#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_O_TRACESYSGOOD); >> + current_ptrace_options |= (ret == 0)? PTRACE_O_TRACESYSGOOD : 0; > > Space before '?'. > > Arguably, > > if (ret == 0) > current_ptrace_options |= PTRACE_O_TRACESYSGOOD; > > would be more straightforward to read. > I've used your suggestion now. >> +/* Enable reporting of all currently supported ptrace events. */ >> + >> +void >> +linux_enable_event_reporting (ptid_t ptid) > > Could you preserve gdbserver's prototype here, please? That > is, take a single integer pid rather than a ptid. > Done. >> + /* 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 (); >> + >> + /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to >> + support read-only process state. */ > > This comment really belongs close to where current_ptrace_options > is set. That in, in the original code, read it as attached to > the "current_ptrace_options |= " bits above, not the ptrace call > below. > Moved closer to where it belongs. >> +/* Returns non-zero if PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK, >> + PTRACE_O_TRACECLONE and PTRACE_O_TRACEEXEC are supported by >> + ptrace, 0 otherwise */ > > Missing period. Given the name of the function, I'd suggest instead: > > /* 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. > Done. Thanks. >> + >> +int >> +linux_supports_tracefork (void) >> +{ >> + return ptrace_supports_feature (PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK >> + | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC); > > Well, this is now wrong given gdbserver will only set PTRACE_O_TRACECLONE > in the current_ptrace_options. Given the revised comment above, > this can all be replaced with: > > return ptrace_supports_feature (PTRACE_O_TRACECLONE); > > and so it'll work for both gdb and gdbserver. When gdbserver supports > tracing forks, we can go back here and check PTRACE_O_TRACEFORK instead, > just for clarity of the code. WDYT? I don't think it looks great, but it should do the job for the moment while we teach gdbserver to support the other features. Good enough maybe? > > BTW, these function are extern, and the same describing comment is > duplicated in the declarations in the header file. Best leave only one > copy, near the declarations. > Done. >> diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h >> index 8f02c82..005da3d 100644 >> --- a/gdb/common/linux-ptrace.h >> +++ b/gdb/common/linux-ptrace.h >> @@ -22,6 +22,24 @@ struct buffer; >> > >> +#ifdef GDBSERVER >> +#if !defined (PTRACE_TYPE_ARG3) > > Why the #if !defines if the PTRACE_TYPE_... definitions > have been removed from linux-low.h ? > I've replaced these with a configure-time check in configure.ac as Tromey hinted at, similar to GDB's. Looks cleaner this way. Thanks Tom. >> +#define PTRACE_TYPE_ARG3 void * >> +#endif >> + >> +#if !defined (PTRACE_TYPE_ARG4) >> +#define PTRACE_TYPE_ARG4 void * >> +#endif >> +#endif /* GDBSERVER */ > > These are gone now. >> diff --git a/gdb/config.in b/gdb/config.in >> index 76abd04..5a80001 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 3 for ptrace. */ >> +#undef PTRACE_TYPE_ARG4 > > Off by one in comment... > >> + >> /* Define to the type of arg 5 for ptrace. */ >> #undef PTRACE_TYPE_ARG5 >> > >> diff --git a/gdb/configure.ac b/gdb/configure.ac >> index 667821f..0982cac 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.]) > > ... but here the comment looks right, so I think you just > forgot to regenerate config.in. > Fixed by regenerating the required files. >> INCLUDE_CFLAGS = -I. -I${srcdir} -I$(srcdir)/../common \ >> -I$(srcdir)/../regformats -I$(srcdir)/../ -I$(INCLUDE_DIR) \ >> $(INCGNU) >> @@ -157,8 +162,10 @@ SFILES= $(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \ >> $(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \ >> $(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \ >> $(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \ >> - $(srcdir)/common/filestuff.c $(srcdir)/target/waitstatus.c \ >> - $(srcdir)/common/mips-linux-watch.c >> + $(srcdir)/common/filestuff.c $(srcdir)/common/linux-ptrace.c \ >> + $(srcdir)/common/mips-linux-watch.c \ >> + $(srcdir)/target/waitstatus.c \ >> + $(srcdir)/nat/linux-waitpid.c \ > > Hmm, so linux-ptrace.c was missing? (It's a bit harder than expected to > see what's doing on in this hunk, given the order's been changed.) > It seems linux-procfs.c is missing too, and probably others. Please do that > as separate patch... This is penance for forgetting that backslash in the > last line, and forcing me to look closer. ;-) > The identation problem with the mips-linux-watch.c entry bothered me, but turns out the inclusion of linux-ptrace.c and linux-waitpid.c isn't needed at all. I have a successful build without any change to SFILES. >> >> DEPFILES = @GDBSERVER_DEPFILES@ >> >> @@ -447,7 +454,8 @@ server_h = $(srcdir)/server.h $(regcache_h) $(srcdir)/target.h \ >> $(generated_files) >> >> gdbthread_h = $(srcdir)/gdbthread.h $(target_h) $(srcdir)/server.h >> -linux_low_h = $(srcdir)/linux-low.h $(gdbthread_h) >> +linux_low_h = $(srcdir)/linux-low.h $(srcdir)/../nat/linux-nat.h \ >> + $(srcdir)/../nat/linux-waitpid.h $(gdbthread_h) > > Is this really necessary, given we now have automatic dependencies > in gdbserver? $linux_low_h even used anywhere at all. Looks > like these variables are just waiting to be garbage collected... > Probably not. I removed this change now. I've also included linux-ptrace.o by default in the linux object files list (in configure.srv). All the other small nits are hopefully fixed now as well. Regression-tested again. Results look good. Thanks! Luis --------------010000070709070302010203 Content-Type: text/x-patch; name="ptrace_share.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="ptrace_share.diff" Content-length: 71430 2013-08-20 Luis Machado 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_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_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_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_tracefork. (initialize_low): Remove call to linux_test_for_tracefork. * linux-low.h (PTRACE_TYPE_ARG3): Remove. (PTRACE_TYPE_ARG4): Likewise. Include linux-ptrace.h. * configure.ac: Check ptrace return and argument types. * configure: Regenerate. * config.in: Regenerate. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 45cddaf..c75ec38 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 d5ac061..bcd3c94 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. */ @@ -222,6 +228,283 @@ 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 ARG as parameter. + + For MMU-less targets, if ARG is NULL, stack space is allocated + via malloc and passed to FUNCTION. */ + +static int +linux_fork_to_function (void *arg, void (*function) (void *)) +{ + int child_pid; +#if defined(__UCLIBC__) && defined(HAS_NOMMU) + gdb_byte *stack; +#endif + + /* Sanity check the function pointer. */ + gdb_assert (function != NULL); + +#if defined(__UCLIBC__) && defined(HAS_NOMMU) +#define STACK_SIZE 4096 + + if (arg == NULL) + stack = xmalloc (STACK_SIZE * 4); + else + stack = (gdb_byte *) arg; + + /* Use CLONE_VM instead of fork, to support uClinux (no MMU). */ + #ifdef __ia64__ + child_pid = __clone2 (function, stack, STACK_SIZE, + CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2); + #else /* !__ia64__ */ + child_pid = clone (function, stack + STACK_SIZE, + CLONE_VM | SIGCHLD, stack + STACK_SIZE * 2); + #endif /* !__ia64__ */ +#else /* !defined(__UCLIBC) && defined(HAS_NOMMU) */ + child_pid = fork (); + + if (child_pid == 0) + function (arg); +#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 (void *arg) +{ + /* Free any allocated stack. */ + xfree (arg); + + /* 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 (void *arg) +{ + ptrace (PTRACE_TRACEME, 0, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) 0); + kill (getpid (), SIGSTOP); + + /* Fork a grandchild. */ + linux_fork_to_function (arg, 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_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_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_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, + 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_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 8f02c82..4f7456f 100644 --- a/gdb/common/linux-ptrace.h +++ b/gdb/common/linux-ptrace.h @@ -22,6 +22,14 @@ 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 + #ifndef PTRACE_GETSIGINFO # define PTRACE_GETSIGINFO 0x4202 # define PTRACE_SETSIGINFO 0x4203 @@ -69,5 +77,9 @@ 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_tracevforkdone (void); +extern int linux_supports_tracesysgood (void); #endif /* COMMON_LINUX_PTRACE_H */ diff --git a/gdb/config.in b/gdb/config.in index 76abd04..03b0972 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 2b2202e..55425f6 100644 --- a/gdb/config/aarch64/linux.mh +++ b/gdb/config/aarch64/linux.mh @@ -19,7 +19,7 @@ # along with this program. If not, see . NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o aarch64-linux-nat.o \ +NATDEPFILES= linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/alpha/alpha-linux.mh b/gdb/config/alpha/alpha-linux.mh index 9eb9e4b..ba46ec8 100644 --- a/gdb/config/alpha/alpha-linux.mh +++ b/gdb/config/alpha/alpha-linux.mh @@ -1,6 +1,6 @@ # Host: Little-endian Alpha running Linux NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o alpha-linux-nat.o \ +NATDEPFILES= linux-waitpid.o linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/arm/linux.mh b/gdb/config/arm/linux.mh index c0a1c66..af42783 100644 --- a/gdb/config/arm/linux.mh +++ b/gdb/config/arm/linux.mh @@ -1,7 +1,7 @@ # Host: ARM based machine running GNU/Linux NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o arm-linux-nat.o \ +NATDEPFILES= linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/i386/linux.mh b/gdb/config/i386/linux.mh index 7c64e83..d5f64e5 100644 --- a/gdb/config/i386/linux.mh +++ b/gdb/config/i386/linux.mh @@ -1,7 +1,7 @@ # Host: Intel 386 running GNU/Linux. NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 \ diff --git a/gdb/config/i386/linux64.mh b/gdb/config/i386/linux64.mh index 8d782c1..8d35a31 100644 --- a/gdb/config/i386/linux64.mh +++ b/gdb/config/i386/linux64.mh @@ -1,5 +1,5 @@ # Host: GNU/Linux x86-64 -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 \ diff --git a/gdb/config/ia64/linux.mh b/gdb/config/ia64/linux.mh index 1a4c68e..0917fc3 100644 --- a/gdb/config/ia64/linux.mh +++ b/gdb/config/ia64/linux.mh @@ -1,7 +1,7 @@ # Host: Intel IA-64 running GNU/Linux NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 \ diff --git a/gdb/config/m32r/linux.mh b/gdb/config/m32r/linux.mh index b461806..e8c7caa 100644 --- a/gdb/config/m32r/linux.mh +++ b/gdb/config/m32r/linux.mh @@ -1,7 +1,7 @@ # Host: M32R based machine running GNU/Linux NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/m68k/linux.mh b/gdb/config/m68k/linux.mh index e3aaf38..40405ca 100644 --- a/gdb/config/m68k/linux.mh +++ b/gdb/config/m68k/linux.mh @@ -1,7 +1,7 @@ # Host: Motorola m68k running GNU/Linux. NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh index a4f23e3..3dca2db 100644 --- a/gdb/config/mips/linux.mh +++ b/gdb/config/mips/linux.mh @@ -1,6 +1,6 @@ # Host: Linux/MIPS NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \ +NATDEPFILES= linux-waitpid.o 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 diff --git a/gdb/config/pa/linux.mh b/gdb/config/pa/linux.mh index fa46db6..53331e1 100644 --- a/gdb/config/pa/linux.mh +++ b/gdb/config/pa/linux.mh @@ -1,6 +1,6 @@ # Host: Hewlett-Packard PA-RISC machine, running Linux NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 diff --git a/gdb/config/powerpc/linux.mh b/gdb/config/powerpc/linux.mh index b0d4ce7..9d4f496 100644 --- a/gdb/config/powerpc/linux.mh +++ b/gdb/config/powerpc/linux.mh @@ -3,7 +3,7 @@ XM_CLIBS= NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/powerpc/ppc64-linux.mh b/gdb/config/powerpc/ppc64-linux.mh index 367a818..24f3287 100644 --- a/gdb/config/powerpc/ppc64-linux.mh +++ b/gdb/config/powerpc/ppc64-linux.mh @@ -3,7 +3,7 @@ XM_CLIBS= NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/config/powerpc/spu-linux.mh b/gdb/config/powerpc/spu-linux.mh index 1bc279a..200fe6b 100644 --- a/gdb/config/powerpc/spu-linux.mh +++ b/gdb/config/powerpc/spu-linux.mh @@ -3,6 +3,6 @@ # This implements a 'pseudo-native' GDB running on the # PPU side of the Cell BE and debugging the SPU side. -NATDEPFILES = spu-linux-nat.o fork-child.o inf-ptrace.o \ +NATDEPFILES = spu-linux-nat.o fork-child.o linux-waitpid.o linux-waitpid.o inf-ptrace.o \ linux-procfs.o linux-ptrace.o diff --git a/gdb/config/sparc/linux.mh b/gdb/config/sparc/linux.mh index 6a2cefd..537ecf7 100644 --- a/gdb/config/sparc/linux.mh +++ b/gdb/config/sparc/linux.mh @@ -1,7 +1,7 @@ # Host: GNU/Linux SPARC NAT_FILE= config/nm-linux.h NATDEPFILES= sparc-nat.o sparc-linux-nat.o \ - core-regset.o fork-child.o inf-ptrace.o \ + core-regset.o fork-child.o linux-waitpid.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 diff --git a/gdb/config/sparc/linux64.mh b/gdb/config/sparc/linux64.mh index d1e1a97..f021864 100644 --- a/gdb/config/sparc/linux64.mh +++ b/gdb/config/sparc/linux64.mh @@ -2,7 +2,7 @@ NAT_FILE= config/nm-linux.h NATDEPFILES= sparc-nat.o sparc64-nat.o sparc64-linux-nat.o \ core-regset.o \ - fork-child.o inf-ptrace.o \ + fork-child.o linux-waitpid.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 diff --git a/gdb/config/tilegx/linux.mh b/gdb/config/tilegx/linux.mh index 56ef694..c70b452 100644 --- a/gdb/config/tilegx/linux.mh +++ b/gdb/config/tilegx/linux.mh @@ -1,7 +1,7 @@ # Host: Tilera TILE-Gx running GNU/Linux. NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o \ +NATDEPFILES= linux-waitpid.o 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 \ diff --git a/gdb/config/xtensa/linux.mh b/gdb/config/xtensa/linux.mh index deffe25..afa0043 100644 --- a/gdb/config/xtensa/linux.mh +++ b/gdb/config/xtensa/linux.mh @@ -2,7 +2,7 @@ NAT_FILE= config/nm-linux.h -NATDEPFILES= inf-ptrace.o fork-child.o xtensa-linux-nat.o \ +NATDEPFILES= linux-waitpid.o 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 NAT_CDEPS = $(srcdir)/proc-service.list diff --git a/gdb/configure b/gdb/configure index 8067825..a722b93 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 667821f..0982cac 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/Makefile.in b/gdb/gdbserver/Makefile.in index 2cdbf47..45e03a2 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/config.in b/gdb/gdbserver/config.in index dada2fb..c00d0e4 100644 --- a/gdb/gdbserver/config.in +++ b/gdb/gdbserver/config.in @@ -26,6 +26,10 @@ */ #undef HAVE_DECL_PERROR +/* Define to 1 if you have the declaration of `ptrace', and to 0 if you don't. + */ +#undef HAVE_DECL_PTRACE + /* Define to 1 if you have the declaration of `strerror', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR @@ -76,6 +80,9 @@ /* Define to 1 if you have the `dl' library (-ldl). */ #undef HAVE_LIBDL +/* Define to 1 if you have the `mcheck' library (-lmcheck). */ +#undef HAVE_LIBMCHECK + /* Define if the target supports branch tracing. */ #undef HAVE_LINUX_BTRACE @@ -256,6 +263,18 @@ /* Additional package description */ #undef PKGVERSION +/* 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 + +/* Define as the return type of ptrace. */ +#undef PTRACE_TYPE_RET + /* Bug reporting address */ #undef REPORT_BUGS_TO diff --git a/gdb/gdbserver/configure b/gdb/gdbserver/configure index 193aedc..7e61fa9 100755 --- a/gdb/gdbserver/configure +++ b/gdb/gdbserver/configure @@ -5222,6 +5222,194 @@ _ACEOF fi +# +# Check the return and argument types of ptrace. No canned test for +# this, so roll our own. +# +gdb_ptrace_headers=' +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_PTRACE_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif +' +# There is no point in checking if we don't have a prototype. +ac_fn_c_check_decl "$LINENO" "ptrace" "ac_cv_have_decl_ptrace" "$gdb_ptrace_headers +" +if test "x$ac_cv_have_decl_ptrace" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_PTRACE $ac_have_decl +_ACEOF +if test $ac_have_decl = 1; then : + +else + + : ${gdb_cv_func_ptrace_ret='int'} + : ${gdb_cv_func_ptrace_args='int,int,long,long'} + +fi + +# Check return type. Varargs (used on GNU/Linux) conflict with the +# empty argument list, so check for that explicitly. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking return type of ptrace" >&5 +$as_echo_n "checking return type of ptrace... " >&6; } +if test "${gdb_cv_func_ptrace_ret+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ +extern long ptrace (enum __ptrace_request, ...); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_ret='long' +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ +extern int ptrace (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_ret='int' +else + gdb_cv_func_ptrace_ret='long' +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_ptrace_ret" >&5 +$as_echo "$gdb_cv_func_ptrace_ret" >&6; } + +cat >>confdefs.h <<_ACEOF +#define PTRACE_TYPE_RET $gdb_cv_func_ptrace_ret +_ACEOF + +# Check argument types. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking types of arguments for ptrace" >&5 +$as_echo_n "checking types of arguments for ptrace... " >&6; } +if test "${gdb_cv_func_ptrace_args+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ +extern long ptrace (enum __ptrace_request, ...); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_args='int,int,long,long' +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' 'void *'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ + +extern $gdb_cv_func_ptrace_ret + ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4"; + break 4; +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + for gdb_arg5 in 'int *' 'int' 'long'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$gdb_ptrace_headers +int +main () +{ + +extern $gdb_cv_func_ptrace_ret + ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4, $gdb_arg5); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4,$gdb_arg5"; + break 5; +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done + done + done + done +done +# Provide a safe default value. +: ${gdb_cv_func_ptrace_args='int,int,long,long'} + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_func_ptrace_args" >&5 +$as_echo "$gdb_cv_func_ptrace_args" >&6; } +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$gdb_cv_func_ptrace_args" | sed 's/\*/\*/g'` +IFS=$ac_save_IFS +shift + +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 +#define PTRACE_TYPE_ARG5 $5 +_ACEOF + +fi +# +# End of ptrace type checks +# + # Check whether --with-pkgversion was given. diff --git a/gdb/gdbserver/configure.ac b/gdb/gdbserver/configure.ac index 456a1f7..84ff9ea 100644 --- a/gdb/gdbserver/configure.ac +++ b/gdb/gdbserver/configure.ac @@ -214,6 +214,83 @@ AC_CHECK_TYPES([Elf32_auxv_t, Elf64_auxv_t], [], [], #include ) +# +# Check the return and argument types of ptrace. No canned test for +# this, so roll our own. +# +gdb_ptrace_headers=' +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_PTRACE_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif +' +# There is no point in checking if we don't have a prototype. +AC_CHECK_DECLS(ptrace, [], [ + : ${gdb_cv_func_ptrace_ret='int'} + : ${gdb_cv_func_ptrace_args='int,int,long,long'} +], $gdb_ptrace_headers) +# Check return type. Varargs (used on GNU/Linux) conflict with the +# empty argument list, so check for that explicitly. +AC_CACHE_CHECK([return type of ptrace], gdb_cv_func_ptrace_ret, + AC_TRY_COMPILE($gdb_ptrace_headers, + [extern long ptrace (enum __ptrace_request, ...);], + gdb_cv_func_ptrace_ret='long', + AC_TRY_COMPILE($gdb_ptrace_headers, + [extern int ptrace ();], + gdb_cv_func_ptrace_ret='int', + gdb_cv_func_ptrace_ret='long'))) +AC_DEFINE_UNQUOTED(PTRACE_TYPE_RET, $gdb_cv_func_ptrace_ret, + [Define as the return type of ptrace.]) +# Check argument types. +AC_CACHE_CHECK([types of arguments for ptrace], gdb_cv_func_ptrace_args, [ + AC_TRY_COMPILE($gdb_ptrace_headers, + [extern long ptrace (enum __ptrace_request, ...);], + [gdb_cv_func_ptrace_args='int,int,long,long'],[ +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' 'void *'; do + AC_TRY_COMPILE($gdb_ptrace_headers, [ +extern $gdb_cv_func_ptrace_ret + ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4); +], [gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4"; + break 4;]) + for gdb_arg5 in 'int *' 'int' 'long'; do + AC_TRY_COMPILE($gdb_ptrace_headers, [ +extern $gdb_cv_func_ptrace_ret + ptrace ($gdb_arg1, $gdb_arg2, $gdb_arg3, $gdb_arg4, $gdb_arg5); +], [ +gdb_cv_func_ptrace_args="$gdb_arg1,$gdb_arg2,$gdb_arg3,$gdb_arg4,$gdb_arg5"; + break 5;]) + done + done + done + done +done +# Provide a safe default value. +: ${gdb_cv_func_ptrace_args='int,int,long,long'} +])]) +ac_save_IFS=$IFS; IFS=',' +set dummy `echo "$gdb_cv_func_ptrace_args" | sed 's/\*/\*/g'` +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.]) +fi +# +# End of ptrace type checks +# + ACX_PKGVERSION([GDB]) ACX_BUGURL([http://www.gnu.org/software/gdb/bugs/]) AC_DEFINE_UNQUOTED([PKGVERSION], ["$PKGVERSION"], [Additional package description]) diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv index b9dfd6c..29f89c4 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_native_linux_obj="linux-waitpid.o linux-low.o linux-osdata.o linux-procfs.o linux-ptrace.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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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_native_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 217cd2e..ffc145e 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). */ @@ -1998,7 +1916,7 @@ linux_wait_for_event (ptid_t ptid, int *wstat, int options) if (event_child->must_set_ptrace_flags) { - linux_enable_event_reporting (lwpid_of (event_child)); + linux_enable_event_reporting (pid_of (event_child)); event_child->must_set_ptrace_flags = 0; } @@ -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) { @@ -4833,7 +4589,7 @@ linux_look_up_symbols (void) /* 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); + thread_db_init (!linux_supports_tracefork ()); #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 e051ab6..4bf0dc3 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 db23433..0aac73a 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 PTID. */ 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 cb8f1da..855c802 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -128,8 +128,6 @@ 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 0000000..4d84aa5 --- /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 0000000..2debea4 --- /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 0000000..0df29d8 --- /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 */ --------------010000070709070302010203--