* Makefile.in (symfile.o): Update.
authorDaniel Jacobowitz <drow@false.org>
Tue, 29 Jan 2008 22:47:20 +0000 (22:47 +0000)
committerDaniel Jacobowitz <drow@false.org>
Tue, 29 Jan 2008 22:47:20 +0000 (22:47 +0000)
* NEWS: Mention exec tracing support.
* inf-ttrace.c (inf_ttrace_wait): Return TARGET_WAITKIND_EXECD for
exec events.
* infcmd.c (kill_if_already_running, detach_command)
(disconnect_command): Replace SOLIB_RESTART with no_shared_libraries.
* infrun.c (MAY_FOLLOW_EXEC, may_follow_exec): Delete.
(follow_exec): Do not check may_follow_exec.  Do not mourn and push
targets.  Apply the sysroot path to the loaded executable.  Use
no_shared_libraries.
* linux-nat.c (linux_child_follow_fork): Print fork following
messages if verbose.
(kill_wait_callback): Kill again before waiting a second time.
* symfile.c (symbol_file_clear): Replace SOLIB_RESTART with
no_shared_libraries.

* gdb.base/foll-exec.exp: Update header.  Skip on remote targets.
Run on GNU/Linux.
(do_exec_tests): Check for systems which do not support catchpoints.
Do not match START.
* gdb.base/foll-fork.exp: Update header.  Skip on remote targets.
Run on GNU/Linux.  Enable verbose output.
(check_fork_catchpoints): New.
(explicit_fork_child_follow, catch_fork_child_follow)
(tcatch_fork_parent_follow): Update expected messages.
(do_fork_tests): Use check_fork_catchpoints.
* gdb.base/foll-vfork.exp: Update header.  Skip on remote targets.
Run on GNU/Linux.  Enable verbose output.
(check_vfork_catchpoints): New.
(vfork_parent_follow_to_bp, tcatch_vfork_then_child_follow): Update
expected messages.
(do_vfork_and_exec_tests): Use check_fork_catchpoints.

gdb/ChangeLog
gdb/Makefile.in
gdb/NEWS
gdb/infcmd.c
gdb/infrun.c
gdb/linux-nat.c
gdb/symfile.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/foll-exec.exp
gdb/testsuite/gdb.base/foll-fork.exp
gdb/testsuite/gdb.base/foll-vfork.exp

index 83cfc220da99c4f23093d3f01146c4f058af8c38..15d2cd080954304f79bfa768b6827a144c84b197 100644 (file)
@@ -1,3 +1,21 @@
+2008-01-29  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * Makefile.in (symfile.o): Update.
+       * NEWS: Mention exec tracing support.
+       * inf-ttrace.c (inf_ttrace_wait): Return TARGET_WAITKIND_EXECD for
+       exec events.
+       * infcmd.c (kill_if_already_running, detach_command)
+       (disconnect_command): Replace SOLIB_RESTART with no_shared_libraries.
+       * infrun.c (MAY_FOLLOW_EXEC, may_follow_exec): Delete.
+       (follow_exec): Do not check may_follow_exec.  Do not mourn and push
+       targets.  Apply the sysroot path to the loaded executable.  Use
+       no_shared_libraries.
+       * linux-nat.c (linux_child_follow_fork): Print fork following
+       messages if verbose.
+       (kill_wait_callback): Kill again before waiting a second time.
+       * symfile.c (symbol_file_clear): Replace SOLIB_RESTART with
+       no_shared_libraries.
+
 2008-01-29  Joel Brobecker  <brobecker@adacore.com>
 
        * amd64-tdep.c (amd64_classify): Add handling of TYPE_CODE_CHAR.
index 113efb14d69b2f0a593438c9044970ae62ee4f70..ce5573d8c31c39d1b82675ee4a2de60f6128b762 100644 (file)
@@ -2850,7 +2850,7 @@ symfile.o: symfile.c $(defs_h) $(bfdlink_h) $(symtab_h) $(gdbtypes_h) \
        $(gdb_stabs_h) $(gdb_obstack_h) $(completer_h) $(bcache_h) \
        $(hashtab_h) $(readline_h) $(gdb_assert_h) $(block_h) \
        $(gdb_string_h) $(gdb_stat_h) $(observer_h) $(exec_h) \
-       $(parser_defs_h) $(varobj_h) $(elf_bfd_h)
+       $(parser_defs_h) $(varobj_h) $(elf_bfd_h) $(solib_h)
 symfile-mem.o: symfile-mem.c $(defs_h) $(symtab_h) $(gdbcore_h) \
        $(objfiles_h) $(exceptions_h) $(gdbcmd_h) $(target_h) $(value_h) \
        $(symfile_h) $(observer_h) $(auxv_h) $(elf_common_h)
index 4b9d764b67a649417e2f0f1951498cc541ddbf39..44d08c666c256a0ff17bd09527e334fb55f7435e 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -82,6 +82,9 @@ vFile:pwrite:
 vFile:unlink:
   Open, close, read, write, and delete files on the remote system.
 
+* GDB on GNU/Linux and HP/UX can now debug through "exec" of a new
+process.
+
 *** Changes in GDB 6.7
 
 * Resolved 101 resource leaks, null pointer dereferences, etc. in gdb, 
index a5334591cf2e2957ff616c8a93fbaee0d91083b6..704e189fe8db9760fcffd2aa02b49e1aabd158b1 100644 (file)
@@ -454,9 +454,7 @@ kill_if_already_running (int from_tty)
 Start it from the beginning? "))
        error (_("Program not restarted."));
       target_kill ();
-#if defined(SOLIB_RESTART)
-      SOLIB_RESTART ();
-#endif
+      no_shared_libraries (NULL, from_tty);
       init_wait_for_inferior ();
     }
 }
@@ -1974,9 +1972,7 @@ detach_command (char *args, int from_tty)
 {
   dont_repeat ();              /* Not for the faint of heart.  */
   target_detach (args, from_tty);
-#if defined(SOLIB_RESTART)
-  SOLIB_RESTART ();
-#endif
+  no_shared_libraries (NULL, from_tty);
   if (deprecated_detach_hook)
     deprecated_detach_hook ();
 }
@@ -1994,9 +1990,7 @@ disconnect_command (char *args, int from_tty)
 {
   dont_repeat ();              /* Not for the faint of heart */
   target_disconnect (args, from_tty);
-#if defined(SOLIB_RESTART)
-  SOLIB_RESTART ();
-#endif
+  no_shared_libraries (NULL, from_tty);
   if (deprecated_detach_hook)
     deprecated_detach_hook ();
 }
index c3d262eb79b182970760fd717021573a54ce2581..c8637361d4c6d56662672ca20f031e8614c4af88 100644 (file)
@@ -105,15 +105,6 @@ int sync_execution = 0;
 
 static ptid_t previous_inferior_ptid;
 
-/* This is true for configurations that may follow through execl() and
-   similar functions.  At present this is only true for HP-UX native.  */
-
-#ifndef MAY_FOLLOW_EXEC
-#define MAY_FOLLOW_EXEC (0)
-#endif
-
-static int may_follow_exec = MAY_FOLLOW_EXEC;
-
 static int debug_infrun = 0;
 static void
 show_debug_infrun (struct ui_file *file, int from_tty,
@@ -369,9 +360,6 @@ follow_exec (int pid, char *execd_pathname)
   int saved_pid = pid;
   struct target_ops *tgt;
 
-  if (!may_follow_exec)
-    return;
-
   /* This is an exec event that we actually wish to pay attention to.
      Refresh our symbol table to the newly exec'd program, remove any
      momentary bp's, etc.
@@ -406,17 +394,20 @@ follow_exec (int pid, char *execd_pathname)
   /* We've followed the inferior through an exec.  Therefore, the
      inferior has essentially been killed & reborn. */
 
-  /* First collect the run target in effect.  */
-  tgt = find_run_target ();
-  /* If we can't find one, things are in a very strange state...  */
-  if (tgt == NULL)
-    error (_("Could find run target to save before following exec"));
-
   gdb_flush (gdb_stdout);
-  target_mourn_inferior ();
-  inferior_ptid = pid_to_ptid (saved_pid);
+  generic_mourn_inferior ();
   /* Because mourn_inferior resets inferior_ptid. */
-  push_target (tgt);
+  inferior_ptid = pid_to_ptid (saved_pid);
+
+  if (gdb_sysroot && *gdb_sysroot)
+    {
+      char *name = alloca (strlen (gdb_sysroot)
+                           + strlen (execd_pathname)
+                           + 1);
+      strcpy (name, gdb_sysroot);
+      strcat (name, execd_pathname);
+      execd_pathname = name;
+    }
 
   /* That a.out is now the one to use. */
   exec_file_attach (execd_pathname, 0);
@@ -427,9 +418,7 @@ follow_exec (int pid, char *execd_pathname)
   /* Reset the shared library package.  This ensures that we get
      a shlib event when the child reaches "_start", at which point
      the dld will have had a chance to initialize the child. */
-#if defined(SOLIB_RESTART)
-  SOLIB_RESTART ();
-#endif
+  no_shared_libraries (NULL, 0);
 #ifdef SOLIB_CREATE_INFERIOR_HOOK
   SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
 #else
index 4f75ad933c84a15685af75fd5fb1d24c103bdcfa..b021db42098554d22739251b6821523285ce2975 100644 (file)
@@ -383,7 +383,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       /* Detach new forked process?  */
       if (detach_fork)
        {
-         if (debug_linux_nat)
+         if (info_verbose || debug_linux_nat)
            {
              target_terminal_ours ();
              fprintf_filtered (gdb_stdlog,
@@ -468,7 +468,7 @@ linux_child_follow_fork (struct target_ops *ops, int follow_child)
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
-      if (debug_linux_nat)
+      if (info_verbose || debug_linux_nat)
        {
          target_terminal_ours ();
          fprintf_filtered (gdb_stdlog,
@@ -2348,11 +2348,18 @@ kill_wait_callback (struct lwp_info *lp, void *data)
       do
        {
          pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
-         if (pid != (pid_t) -1 && debug_linux_nat)
+         if (pid != (pid_t) -1)
            {
-             fprintf_unfiltered (gdb_stdlog,
-                                 "KWC: wait %s received unknown.\n",
-                                 target_pid_to_str (lp->ptid));
+             if (debug_linux_nat)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "KWC: wait %s received unknown.\n",
+                                   target_pid_to_str (lp->ptid));
+             /* The Linux kernel sometimes fails to kill a thread
+                completely after PTRACE_KILL; that goes from the stop
+                point in do_fork out to the one in
+                get_signal_to_deliever and waits again.  So kill it
+                again.  */
+             kill_callback (lp, NULL);
            }
        }
       while (pid == GET_LWP (lp->ptid));
@@ -2363,11 +2370,14 @@ kill_wait_callback (struct lwp_info *lp, void *data)
   do
     {
       pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
-      if (pid != (pid_t) -1 && debug_linux_nat)
+      if (pid != (pid_t) -1)
        {
-         fprintf_unfiltered (gdb_stdlog,
-                             "KWC: wait %s received unk.\n",
-                             target_pid_to_str (lp->ptid));
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "KWC: wait %s received unk.\n",
+                               target_pid_to_str (lp->ptid));
+         /* See the call to kill_callback above.  */
+         kill_callback (lp, NULL);
        }
     }
   while (pid == GET_LWP (lp->ptid));
index f7c1efc2815a5c3012e42b59f2d39b50aafff315..5e554fed56e55f6cd49314b4c0fe44a720763ef6 100644 (file)
@@ -52,6 +52,7 @@
 #include "parser-defs.h"
 #include "varobj.h"
 #include "elf-bfd.h"
+#include "solib.h"
 
 #include <sys/types.h>
 #include <fcntl.h>
@@ -1217,9 +1218,7 @@ symbol_file_clear (int from_tty)
        storage has just been released, we'd better wipe the solib
        descriptors as well.
      */
-#if defined(SOLIB_RESTART)
-    SOLIB_RESTART ();
-#endif
+    no_shared_libraries (NULL, from_tty);
 
     symfile_objfile = NULL;
     if (from_tty)
index b0ddbca0a433c7b8cca2c9504a04fd60f140dca3..3de37e7728ec0ee9d680ffeb31ef261936aecc3f 100644 (file)
@@ -1,3 +1,22 @@
+2008-01-29  Daniel Jacobowitz  <dan@codesourcery.com>
+
+       * gdb.base/foll-exec.exp: Update header.  Skip on remote targets.
+       Run on GNU/Linux.
+       (do_exec_tests): Check for systems which do not support catchpoints.
+       Do not match START.
+       * gdb.base/foll-fork.exp: Update header.  Skip on remote targets.
+       Run on GNU/Linux.  Enable verbose output.
+       (check_fork_catchpoints): New.
+       (explicit_fork_child_follow, catch_fork_child_follow)
+       (tcatch_fork_parent_follow): Update expected messages.
+       (do_fork_tests): Use check_fork_catchpoints.
+       * gdb.base/foll-vfork.exp: Update header.  Skip on remote targets.
+       Run on GNU/Linux.  Enable verbose output.
+       (check_vfork_catchpoints): New.
+       (vfork_parent_follow_to_bp, tcatch_vfork_then_child_follow): Update
+       expected messages.
+       (do_vfork_and_exec_tests): Use check_fork_catchpoints.
+
 2008-01-29  Jim Blandy  <jimb@red-bean.com>
 
        * lib/gdbserver-support.exp (gdb_target_cmd): Recognize 'unknown
index 21c69afb6ddd74cb2ca47a471174676dedd66e33..1a4d2a7064fc4d4517bcc9a8d9cf52ce98168a52 100644 (file)
 # 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 <http://www.gnu.org/licenses/>.  */
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Please email any bugs, comments, and/or additions to this file to:
-# bug-gdb@prep.ai.mit.edu
-
-if $tracelevel then {
-       strace $tracelevel
-       }
-
-if { ![isnative] } then {
+if { [is_remote target] || ![isnative] } then {
     continue
 }
 
@@ -48,7 +41,7 @@ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb
 
 # Until "catch exec" is implemented on other targets...
 #
-if ![istarget "hppa*-hp-hpux*"] then {
+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
     continue
 }
 
@@ -93,6 +86,33 @@ proc do_exec_tests {} {
      return
    }
 
+   # Verify that the system supports "catch exec".
+   gdb_test "catch exec" "Catchpoint \[0-9\]* \\(exec\\)" "insert first exec catchpoint"
+   set has_exec_catchpoints 0
+   gdb_test_multiple "continue" "continue to first exec catchpoint" {
+     -re ".*Your system does not support exec catchpoints.*$gdb_prompt $" {
+       unsupported "continue to first exec catchpoint"
+     }
+     -re ".*Catchpoint.*$gdb_prompt $" {
+       set has_exec_catchpoints 1
+       pass "continue to first exec catchpoint"
+     }
+   }
+
+   if {$has_exec_catchpoints == 0} {
+     unsupported "exec catchpoints"
+     return
+   }
+
+   zap_session
+
+   # Start the program running, and stop at main.
+   #
+   if ![runto_main] then {
+     perror "Couldn't run ${testfile}"
+     return
+   }
+
    # Verify that we can see various global and local variables
    # in this program, and that they have expected values.  Some
    # of these variables are also declared in the program we'll
@@ -213,7 +233,7 @@ proc do_exec_tests {} {
    setup_xfail hppa2.0w-hp-hpux* CLLbs16760
    send_gdb "continue\n"
    gdb_expect {
-     -re ".*Executing new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .START..*$gdb_prompt $"\
+     -re ".*Executing new program:.*${testfile2}.*Catchpoint .*(exec\'d .*${testfile2}).*in .*$gdb_prompt $"\
                      {pass "hit catch exec"}
      -re "$gdb_prompt $" {fail "hit catch exec"}
      timeout         {fail "(timeout) hit catch exec"}
index 7ce72e16c10ad337be5e0cede52ad2ab72e373e8..b3aae8c4191615ad727105e7c184e79414788fb2 100644 (file)
 # 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 <http://www.gnu.org/licenses/>.  */
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Please email any bugs, comments, and/or additions to this file to:
-# bug-gdb@prep.ai.mit.edu
-
-if $tracelevel then {
-       strace $tracelevel
-       }
-
-if { ![isnative] } then {
+if { [is_remote target] || ![isnative] } then {
     continue
 }
 
 set prms_id 0
 set bug_id 0
 
+global srcfile
 set testfile "foll-fork"
 set srcfile ${testfile}.c
 set binfile ${objdir}/${subdir}/${testfile}
@@ -41,10 +35,32 @@ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb
 # Until "set follow-fork-mode" and "catch fork" are implemented on
 # other targets...
 #
-if ![istarget "hppa*-hp-hpux*"] then {
+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
     continue
 }
 
+proc check_fork_catchpoints {} {
+  global gdb_prompt
+
+  # Verify that the system supports "catch fork".
+  gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" "insert first fork catchpoint"
+  set has_fork_catchpoints 0
+  gdb_test_multiple "continue" "continue to first fork catchpoint" {
+    -re ".*Your system does not support fork catchpoints.*$gdb_prompt $" {
+      unsupported "continue to first fork catchpoint"
+    }
+    -re ".*Catchpoint.*$gdb_prompt $" {
+      set has_fork_catchpoints 1
+      pass "continue to first fork catchpoint"
+    }
+  }
+
+  if {$has_fork_catchpoints == 0} {
+    unsupported "fork catchpoints"
+    return -code return
+  }
+}
+
 proc default_fork_parent_follow {} {
    global gdb_prompt
 
@@ -115,7 +131,7 @@ proc explicit_fork_child_follow {} {
    }
    send_gdb "next 2\n"
    gdb_expect {
-      -re "Detaching from program:.*Attaching after fork to.*$gdb_prompt $"\
+      -re "Attaching after fork to.*$gdb_prompt $"\
                       {pass "explicit child follow, no catchpoints"}
       -re "$gdb_prompt $" {fail "explicit child follow, no catchpoints"}
       timeout         {fail "(timeout) explicit child follow, no catchpoints"}
@@ -129,6 +145,7 @@ proc explicit_fork_child_follow {} {
 
 proc catch_fork_child_follow {} {
    global gdb_prompt
+   global srcfile
 
    send_gdb "catch fork\n"
    gdb_expect {
@@ -153,7 +170,7 @@ proc catch_fork_child_follow {} {
 
    send_gdb "continue\n"
    gdb_expect {
-      -re "Catchpoint.*(forked process.*),.*in _fork_sys.*$gdb_prompt $"\
+      -re "Catchpoint.*(forked process.*),.*in .*fork.*$gdb_prompt $"\
                       {pass "explicit child follow, catch fork"}
       -re "$gdb_prompt $" {fail "explicit child follow, catch fork"}
       timeout         {fail "(timeout) explicit child follow, catch fork"}
@@ -175,7 +192,7 @@ proc catch_fork_child_follow {} {
       -re "$gdb_prompt $" {pass "set follow child"}
       timeout         {fail "(timeout) set follow child"}
    }
-   send_gdb "tbreak 24\n"
+   send_gdb "tbreak ${srcfile}:24\n"
    gdb_expect {
       -re "Breakpoint.*, line 24.*$gdb_prompt $"\
                       {pass "set follow child, tbreak"}
@@ -184,7 +201,7 @@ proc catch_fork_child_follow {} {
    }
    send_gdb "continue\n"
    gdb_expect {
-      -re ".*Detaching from program:.*Attaching after fork to.* at .*24.*$gdb_prompt $"\
+      -re "Attaching after fork to.* at .*24.*$gdb_prompt $"\
                       {pass "set follow child, hit tbreak"}
       -re "$gdb_prompt $" {fail "set follow child, hit tbreak"}
       timeout         {fail "(timeout) set follow child, hit tbreak"}
@@ -211,6 +228,7 @@ proc catch_fork_child_follow {} {
 
 proc tcatch_fork_parent_follow {} {
    global gdb_prompt
+   global srcfile
 
    send_gdb "catch fork\n"
    gdb_expect {
@@ -225,7 +243,7 @@ proc tcatch_fork_parent_follow {} {
 
    send_gdb "continue\n"
    gdb_expect {
-      -re ".*in _fork_sys.*$gdb_prompt $"\
+      -re ".*in .*fork.*$gdb_prompt $"\
                       {pass "explicit parent follow, tcatch fork"}
       -re "$gdb_prompt $" {fail "explicit parent follow, tcatch fork"}
       timeout         {fail "(timeout) explicit parent follow, tcatch fork"}
@@ -235,7 +253,7 @@ proc tcatch_fork_parent_follow {} {
       -re "$gdb_prompt $" {pass "set follow parent"}
       timeout         {fail "(timeout) set follow parent"}
    }
-   send_gdb "tbreak 24\n"
+   send_gdb "tbreak ${srcfile}:24\n"
    gdb_expect {
       -re "Breakpoint.*, line 24.*$gdb_prompt $"\
                       {pass "set follow parent, tbreak"}
@@ -313,6 +331,10 @@ By default, the debugger will follow the parent process..*$gdb_prompt $"\
      timeout         {fail "set follow to nonsense is prohibited (reset parent)"}
    }
 
+   # Check that fork catchpoints are supported, as an indicator for whether
+   # fork-following is supported.
+   if [runto_main] then { check_fork_catchpoints }
+
    # Test the default behaviour, which is to follow the parent of a
    # fork, and detach from the child.  Do this without catchpoints.
    #
@@ -357,6 +379,9 @@ gdb_start
 gdb_reinitialize_dir $srcdir/$subdir
 gdb_load ${binfile}
 
+# The "Detaching..." and "Attaching..." messages may be hidden by
+# default.
+gdb_test "set verbose" ""
 
 # This is a test of gdb's ability to follow the parent, child or both
 # parent and child of a Unix fork() system call.
index 9f94c868e0ae75119605147815f1c82afe81a743..4500999d40e2a25c34d9c73dab968adf17acc342 100644 (file)
 # 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 <http://www.gnu.org/licenses/>.  */
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Please email any bugs, comments, and/or additions to this file to:
-# bug-gdb@prep.ai.mit.edu
-
-if $tracelevel then {
-       strace $tracelevel
-       }
-
-if { ![isnative] } then {
+if { [is_remote target] || ![isnative] } then {
     continue
 }
 
@@ -35,6 +28,7 @@ set bug_id 0
 ##  return 0
 ##}
 
+global srcfile
 set testfile "foll-vfork"
 set testfile2 "vforked-prog"
 set srcfile ${testfile}.c
@@ -56,7 +50,7 @@ if  { [gdb_compile "${srcdir}/${subdir}/${srcfile2}" "${binfile2}" executable {d
 # Until "set follow-fork-mode" and "catch vfork" are implemented on
 # other targets...
 #
-if ![istarget "hppa*-hp-hpux*"] then {
+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
     continue
 }
 
@@ -73,6 +67,29 @@ if [istarget "hppa*-hp-hpux10.20"] then {
 set oldtimeout $timeout
 set timeout [expr "$timeout + 10"]
 
+proc check_vfork_catchpoints {} {
+  global gdb_prompt
+  global has_vfork_catchpoints
+
+  # Verify that the system supports "catch vfork".
+  gdb_test "catch vfork" "Catchpoint \[0-9\]* \\(vfork\\)" "insert first vfork catchpoint"
+  set has_vfork_catchpoints 0
+  gdb_test_multiple "continue" "continue to first vfork catchpoint" {
+    -re ".*Your system does not support vfork catchpoints.*$gdb_prompt $" {
+      unsupported "continue to first vfork catchpoint"
+    }
+    -re ".*Catchpoint.*$gdb_prompt $" {
+      set has_vfork_catchpoints 1
+      pass "continue to first vfork catchpoint"
+    }
+  }
+
+  if {$has_vfork_catchpoints == 0} {
+    unsupported "vfork catchpoints"
+    return -code return
+  }
+}
+
 proc vfork_parent_follow_through_step {} {
    global gdb_prompt
 
@@ -97,20 +114,21 @@ proc vfork_parent_follow_through_step {} {
 
 proc vfork_parent_follow_to_bp {} {
    global gdb_prompt
+   global srcfile
 
    send_gdb "set follow parent\n"
    gdb_expect {
       -re "$gdb_prompt $" {pass "set follow parent, vfork to bp"}
       timeout         {fail "set follow parent, vfork to bp"}
    }
-   send_gdb "break 18\n"
+   send_gdb "break ${srcfile}:18\n"
    gdb_expect {
       -re "$gdb_prompt $" {pass "break, vfork to bp"}
       timeout         {fail "break, vfork to bp"}
    }
    send_gdb "continue\n"
    gdb_expect {
-      -re ".*Detaching after fork from process.*Breakpoint.*18.*$gdb_prompt "\
+      -re ".*Detaching after fork from child process.*Breakpoint.*18.*$gdb_prompt "\
                       {pass "vfork parent follow, to bp"}
       -re "$gdb_prompt $" {fail "vfork parent follow, to bp"}
       timeout         {fail "(timeout) vfork parent follow, to bp" }
@@ -133,7 +151,7 @@ proc vfork_and_exec_child_follow_to_main_bp {} {
    }
    send_gdb "continue\n"
    gdb_expect {
-      -re "Detaching from program.*Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
+      -re "Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
                       {pass "vfork and exec child follow, to main bp"}
       -re "$gdb_prompt $" {fail "vfork and exec child follow, to main bp"}
       timeout         {fail "(timeout) vfork and exec child follow, to main bp" }
@@ -191,7 +209,7 @@ proc vfork_and_exec_child_follow_through_step {} {
    }
    send_gdb "next\n"
    gdb_expect {
-      -re "Detaching from program.*Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
+      -re "Attaching after fork to.*Executing new program.*Breakpoint.*vforked-prog.c:9.*$gdb_prompt "\
                       {pass "vfork and exec child follow, through step"}
       -re "$gdb_prompt $" {fail "vfork and exec child follow, through step"}
       timeout         {fail "(timeout) vfork and exec child follow, through step" }
@@ -248,7 +266,7 @@ proc tcatch_vfork_then_parent_follow {} {
    gdb_expect {
       -re "0x\[0-9a-fA-F\]*.*vfork.*$gdb_prompt "\
                       {pass "vfork parent follow, tcatch vfork"}
-      -re "0x\[0-9a-fA-F\]*.*_vfork.*$gdb_prompt "\
+      -re "vfork \\(\\) at.*$gdb_prompt "\
                       {pass "vfork parent follow, tcatch vfork"}
       -re "$gdb_prompt $" {fail "vfork parent follow, tcatch vfork"}
       timeout         {fail "(timeout) vfork parent follow, tcatch vfork"}
@@ -269,6 +287,7 @@ proc tcatch_vfork_then_parent_follow {} {
 
 proc tcatch_vfork_then_child_follow {} {
    global gdb_prompt
+   global srcfile
    global srcfile2
 
    send_gdb "set follow child\n"
@@ -287,6 +306,8 @@ proc tcatch_vfork_then_child_follow {} {
 # HP-UX 10.20 seems to stop you in "vfork", while more recent HP-UXs
 # stop you in "_vfork".
    gdb_expect {
+      -re "vfork \\(\\) at .*$gdb_prompt $"\
+                      {pass "vfork child follow, tcatch vfork"}
       -re "0x\[0-9a-fA-F\]*.*vfork.*$gdb_prompt "\
                       {pass "vfork child follow, tcatch vfork"}
       -re "0x\[0-9a-fA-F\]*.*_vfork.*$gdb_prompt "\
@@ -296,8 +317,10 @@ proc tcatch_vfork_then_child_follow {} {
    }
    send_gdb "finish\n"
    gdb_expect {
-      -re "Run till exit from.*vfork.*${srcfile2}:9.*$gdb_prompt "\
+      -re "Run till exit from.*vfork.*${srcfile}:12.*$gdb_prompt "\
                       {pass "vfork child follow, finish after tcatch vfork"}
+      -re "Run till exit from.*vfork.*${srcfile2}:9.*$gdb_prompt "\
+                      {pass "vfork child follow, finish after tcatch vfork (followed exec)"}
       -re "$gdb_prompt $" {fail "vfork child follow, finish after tcatch vfork"}
       timeout         {fail "(timeout) vfork child follow, finish after tcatch vfork" }
    }
@@ -311,6 +334,10 @@ proc tcatch_vfork_then_child_follow {} {
 proc do_vfork_and_exec_tests {} {
    global gdb_prompt
 
+   # Check that vfork catchpoints are supported, as an indicator for whether
+   # vfork-following is supported.
+   if [runto_main] then { check_vfork_catchpoints }
+
    # Try following the parent process by stepping through a call to
    # vfork.  Do this without catchpoints.
    if [runto_main] then { vfork_parent_follow_through_step }
@@ -362,6 +389,9 @@ gdb_start
 gdb_reinitialize_dir $srcdir/$subdir
 gdb_load ${binfile}
 
+# The "Detaching..." and "Attaching..." messages may be hidden by
+# default.
+gdb_test "set verbose" ""
 
 # This is a test of gdb's ability to follow the parent or child
 # of a Unix vfork() system call.  (The child will subsequently