Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Apr 2012 13:15:37 -0700
From:      Dmitry Mikulin <dmitrym@juniper.net>
To:        <toolchain@freebsd.org>
Subject:   gdb support for follow-fork
Message-ID:  <4F8737E9.6010300@juniper.net>

next in thread | raw e-mail | index | archive | help
--------------090403050708010606090605
Content-Type: text/plain; charset="ISO-8859-1"; format=flowed
Content-Transfer-Encoding: 7bit

Hi,

I implemented support for follow-fork mode in gdb and would like to submit it for a review. The feature allows users to specify which process to follow when the inferior does a fork(). The default mode is to stay with the parent. A gdb command is used to switch between following the child/parent:

set follow-fork-mode child
set follow-fork-mode parent

When gdb is set to follow the child, it detaches from the parent at the fork() point and continues to trace the newly created child.

Gdb uses support that has recently been implemented in the FreeBSD kernel. A new ptrace() request, PT_FOLLOW_FORK was added to generate a SIGTRAP at the point where a child process is created. This allows gdb switch from parent to child. PT_FOLLOW_EXEC was added to SIGTRAP on return from exit() to allow gdb to load a new binary for debugging.

I attached the patch here.
Please let me know if can provide additional info.
Thanks.
Dmitry.



--------------090403050708010606090605
Content-Type: text/x-patch; name="gdb-6.1.1-follow-fork.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="gdb-6.1.1-follow-fork.patch"

Index: gnu/usr.bin/gdb/libgdb/fbsd-nat.c
===================================================================
--- gnu/usr.bin/gdb/libgdb/fbsd-nat.c	(revision 0)
+++ gnu/usr.bin/gdb/libgdb/fbsd-nat.c	(revision 0)
@@ -0,0 +1,343 @@
+/* Native-dependent code for FreeBSD.
+
+   Copyright (C) 2002, 2003, 2004 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 2 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, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "symfile.h"
+#include "gdbcore.h"
+#include "gdbthread.h"
+#include "gdb_assert.h"
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/wait.h>
+
+extern struct target_ops child_ops;
+void clear_step_resume_breakpoint (void);
+void clear_step_resume_breakpoint_thread (void);
+void (*reactivate_threads) (char*) = NULL;
+void (*disable_threads) (void) = NULL;
+
+static void (*mourn_inferior_beneath) (void);
+static void (*detach_beneath) (char *args, int from_tty);
+static ptid_t (*wait_beneath) (ptid_t ptid, 
+			       struct target_waitstatus *ourstatus);
+int follow_event_pid = 0;
+
+/* Return a the name of file that can be opened to get the symbols for
+   the child process identified by PID.  */
+
+char *
+fbsd_pid_to_exec_file (int pid)
+{
+  size_t len = MAXPATHLEN;
+  char *buf = xcalloc (len, sizeof (char));
+  char *path;
+
+#ifdef KERN_PROC_PATHNAME
+  int mib[4];
+
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_PROC;
+  mib[2] = KERN_PROC_PATHNAME;
+  mib[3] = pid;
+  if (sysctl (mib, 4, buf, &len, NULL, 0) == 0)
+    return buf;
+#endif
+
+  path = xstrprintf ("/proc/%d/file", pid);
+  if (readlink (path, buf, MAXPATHLEN) == -1)
+    {
+      xfree (buf);
+      buf = NULL;
+    }
+
+  xfree (path);
+  return buf;
+}
+
+/* Wait for the child specified by PTID to do something.  Return the
+   process ID of the child, or MINUS_ONE_PTID in case of error; store
+   the status in *OURSTATUS.  */
+
+static ptid_t
+inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  pid_t pid;
+  int status, save_errno;
+
+  do
+    {
+      set_sigint_trap ();
+      set_sigio_trap ();
+      do
+	{
+	  pid = waitpid (PIDGET (ptid), &status, 0);
+	  save_errno = errno;
+	}
+      while (pid == -1 && errno == EINTR);
+
+      clear_sigio_trap ();
+      clear_sigint_trap ();
+
+      if (pid == -1)
+	{
+	  fprintf_unfiltered (gdb_stderr,
+			      _("Child process unexpectedly missing: %s.\n"),
+			      safe_strerror (save_errno));
+
+	  /* Claim it exited with unknown signal.  */
+	  ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
+	  ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
+	  return minus_one_ptid;
+	}
+
+      /* Ignore terminated detached child processes.  */
+      if (!WIFSTOPPED (status) && pid != PIDGET (inferior_ptid))
+	pid = -1;
+    }
+  while (pid == -1);
+
+  store_waitstatus (ourstatus, status);
+  return pid_to_ptid (pid);
+}
+
+static ptid_t
+fbsd_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+{
+  struct ptrace_lwpinfo lwpinfo;
+  struct target_waitstatus stat;
+  ptid_t ret;
+  static ptid_t forking_child = {0,0,0};
+
+  ret = wait_beneath (ptid, ourstatus);
+
+#ifdef PL_FLAG_FORKED
+  if (PIDGET (ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED &&
+      (ourstatus->value.sig == TARGET_SIGNAL_TRAP ||
+       ourstatus->value.sig == TARGET_SIGNAL_STOP) &&
+      (ptrace(PT_LWPINFO, PIDGET (ret), (caddr_t)&lwpinfo, 
+	      sizeof lwpinfo) == 0))
+    {
+      if (lwpinfo.pl_flags & PL_FLAG_CHILD)
+	{
+	  /* Leave the child in a stopped state until we get a fork event in 
+	     the parent. That's when we decide which process to follow. */
+	  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+	  forking_child = ret;
+	}
+      else if (lwpinfo.pl_flags & PL_FLAG_FORKED)
+	{
+	  /* We'd better be in the middle of processing a fork() event. */
+	  gdb_assert (!ptid_equal (forking_child, null_ptid));
+	  ourstatus->kind = TARGET_WAITKIND_FORKED;
+	  ourstatus->value.related_pid = lwpinfo.pl_child_pid;
+	  forking_child = null_ptid;
+	}
+      else if (lwpinfo.pl_flags & PL_FLAG_EXEC &&
+	  PIDGET (ret) == follow_event_pid)
+	{
+	  ourstatus->kind = TARGET_WAITKIND_EXECD;
+	  ourstatus->value.execd_pathname =
+	    xstrdup (fbsd_pid_to_exec_file (PIDGET (ret)));
+	}
+    }
+#endif
+
+  return ret;
+}
+
+static void
+fbsd_enable_event_reporting (int pid)
+{
+#ifdef PT_FOLLOW_FORK
+  follow_event_pid = pid;
+  if (ptrace(PT_FOLLOW_FORK, pid, 0, 1) < 0)
+    error (_("Cannot follow fork on this target."));
+#endif 
+}
+
+static void
+fbsd_post_attach (int pid)
+{
+  fbsd_enable_event_reporting (pid);
+}
+
+static void
+fbsd_post_startup_inferior (ptid_t ptid)
+{
+  fbsd_enable_event_reporting (PIDGET (ptid));
+}
+
+int
+fbsd_follow_fork (struct target_ops *ops, int follow_child)
+{
+  ptid_t last_ptid, ret, child_ptid;
+  struct target_waitstatus last_status;
+  int parent_pid, child_pid;
+  struct target_waitstatus ourstatus;
+
+  get_last_target_status (&last_ptid, &last_status);
+  parent_pid = PIDGET (last_ptid);
+  child_pid = last_status.value.related_pid;
+
+  if (follow_child)
+    {
+      detach_breakpoints (child_pid);
+      remove_breakpoints ();
+      child_ptid = pid_to_ptid (child_pid);
+
+      target_detach (NULL, 0);
+      inferior_ptid = child_ptid;
+
+      /* Reinstall ourselves, since we might have been removed in
+	 target_detach (which does other necessary cleanup).  */
+      push_target (ops);
+
+      /* Need to restore some of the actions done by the threaded detach */
+      if (reactivate_threads) 
+	{
+	  reactivate_threads (fbsd_pid_to_exec_file (child_pid));
+	  reactivate_threads = NULL;
+	}
+
+      /* Reset breakpoints in the child as appropriate.  */
+      clear_step_resume_breakpoint_thread ();
+      follow_inferior_reset_breakpoints ();
+
+      /* Enable fork/exec event reporting for the child. */
+      fbsd_enable_event_reporting (child_pid);
+    }
+  else /* Follow parent */
+    {
+      /* Before detaching from the child, remove all breakpoints from
+         it.  (This won't actually modify the breakpoint list, but will
+         physically remove the breakpoints from the child.) */
+      detach_breakpoints (child_pid);
+      ptrace (PT_DETACH, child_pid, (caddr_t) 1, 0);
+    }
+
+  return 0;
+}
+
+/* EXECD_PATHNAME is assumed to be non-NULL. */
+
+static void
+fbsd_follow_exec (int pid, char *execd_pathname)
+{
+  struct target_waitstatus status;
+  ptid_t ret = inferior_ptid;
+
+  /* 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.
+
+     If there are breakpoints, they aren't really inserted now,
+     since the exec() transformed our inferior into a fresh set
+     of instructions.
+
+     We want to preserve symbolic breakpoints on the list, since
+     we have hopes that they can be reset after the new a.out's
+     symbol table is read.
+
+     However, any "raw" breakpoints must be removed from the list
+     (e.g., the solib bp's), since their address is probably invalid
+     now.
+
+     And, we DON'T want to call delete_breakpoints() here, since
+     that may write the bp's "shadow contents" (the instruction
+     value that was overwritten witha TRAP instruction).  Since
+     we now have a new a.out, those shadow contents aren't valid. */
+  update_breakpoints_after_exec ();
+
+  /* If there was one, it's gone now.  We cannot truly step-to-next
+     statement through an exec(). */
+  clear_step_resume_breakpoint ();
+  step_range_start = 0;
+  step_range_end = 0;
+
+  /* What is this a.out's name? */
+  printf_unfiltered (_("Executing new program: %s\n"), execd_pathname);
+
+  /* We've followed the inferior through an exec.  Therefore, the
+     inferior has essentially been killed & reborn. */
+
+  gdb_flush (gdb_stdout);
+
+  /* Disable thread library */
+  if (disable_threads)
+    {
+      disable_threads ();
+      disable_threads = NULL;
+    }
+
+  generic_mourn_inferior ();
+  inferior_ptid = ret;
+
+  /* That a.out is now the one to use. */
+  exec_file_attach (execd_pathname, 0);
+
+  /* And also is where symbols can be found. */
+  symbol_file_add_main (execd_pathname, 0);
+
+  /* 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
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+  SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
+#else
+  solib_create_inferior_hook ();
+#endif
+
+  /* Reinsert all breakpoints.  (Those which were symbolic have
+     been reset to the proper address in the new a.out, thanks
+     to symbol_file_command...) */
+  insert_breakpoints ();
+}
+
+static void fbsd_mourn_inferior (void)
+{
+  follow_event_pid = 0;
+  mourn_inferior_beneath ();
+}
+
+static void fbsd_detach (char *args, int from_tty)
+{
+  follow_event_pid = 0;
+  detach_beneath (args, from_tty);
+}
+
+void
+_initialize_fbsdnat (void)
+{
+  wait_beneath = inf_ptrace_wait;
+  detach_beneath = child_ops.to_detach;
+  mourn_inferior_beneath = child_ops.to_mourn_inferior;
+  child_ops.to_wait = fbsd_wait;
+  child_ops.to_detach = fbsd_detach;
+  child_ops.to_mourn_inferior = fbsd_mourn_inferior;
+  child_ops.to_post_attach = fbsd_post_attach;
+  child_ops.to_post_startup_inferior = fbsd_post_startup_inferior;
+  child_ops.to_follow_fork = fbsd_follow_fork;
+  child_ops.to_follow_exec = fbsd_follow_exec;
+}
Index: gnu/usr.bin/gdb/libgdb/fbsd-threads.c
===================================================================
--- gnu/usr.bin/gdb/libgdb/fbsd-threads.c	(revision 232978)
+++ gnu/usr.bin/gdb/libgdb/fbsd-threads.c	(working copy)
@@ -68,6 +68,9 @@ extern struct target_ops core_ops;
 
 /* Pointer to the next function on the objfile event chain.  */
 static void (*target_new_objfile_chain) (struct objfile *objfile);
+ 
+/* Non-zero while processing thread library re-activation after fork() */
+static int fbsd_forking;
 
 /* Non-zero if there is a thread module */
 static int fbsd_thread_present;
@@ -154,6 +157,10 @@ static int fbsd_thread_alive (ptid_t ptid);
 static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
                const td_thrinfo_t *ti_p, int verbose);
 static void fbsd_thread_detach (char *args, int from_tty);
+extern void (*reactivate_threads) (char*);
+extern void (*disable_threads) (void);
+static void fbsd_thread_activate (void);
+static void fbsd_thread_deactivate (void);
 
 /* Building process ids.  */
 
@@ -405,15 +412,50 @@ disable_thread_event_reporting (void)
   td_death_bp_addr = 0;
 }
 
+static void 
+fbsd_thread_reactivate_after_fork (char *pathname)
+{
+  fbsd_forking = 1;
+
+  /* That a.out is now the one to use. */
+  exec_file_attach (pathname, 0);
+
+  /* And also is where symbols can be found. */
+  symbol_file_add_main (pathname, 0);
+  push_target (&fbsd_thread_ops);
+
+#ifdef SOLIB_CREATE_INFERIOR_HOOK
+  SOLIB_CREATE_INFERIOR_HOOK (PIDGET (inferior_ptid));
+#else
+  solib_create_inferior_hook ();
+#endif
+  fbsd_forking = 0;
+}
+
+static void 
+fbsd_thread_disable_after_exec (void)
+{
+  if (fbsd_thread_active)
+    fbsd_thread_deactivate ();
+
+  unpush_target (&fbsd_thread_ops);
+}
+
 static void
 fbsd_thread_activate (void)
 {
   fbsd_thread_active = 1;
+  reactivate_threads = fbsd_thread_reactivate_after_fork;
+  disable_threads = fbsd_thread_disable_after_exec;
   init_thread_list();
   if (fbsd_thread_core == 0)
     enable_thread_event_reporting ();
-  fbsd_thread_find_new_threads ();
-  get_current_thread ();
+
+  if (!fbsd_forking) 
+    {
+      fbsd_thread_find_new_threads ();
+      get_current_thread ();
+    }
 }
 
 static void
@@ -626,7 +668,7 @@ fbsd_thread_resume (ptid_t ptid, int step, enum ta
     }
 
   lwp = GET_LWP (work_ptid);
-  if (lwp == 0)
+  if (lwp == 0 && GET_THREAD (work_ptid) != 0)
     {
       /* check user thread */
       ret = td_ta_map_id2thr_p (thread_agent, GET_THREAD(work_ptid), &th);
@@ -790,6 +832,9 @@ fbsd_thread_wait (ptid_t ptid, struct target_waits
   ret = child_ops.to_wait (ptid, ourstatus);
   if (GET_PID(ret) >= 0 && ourstatus->kind == TARGET_WAITKIND_STOPPED)
     {
+      if (thread_list_empty ())
+	fbsd_thread_find_new_threads ();
+
       lwp = get_current_lwp (GET_PID(ret));
       ret = thread_from_lwp (BUILD_LWP(lwp, GET_PID(ret)),
          &th, &ti);
@@ -1065,6 +1110,9 @@ fbsd_thread_create_inferior (char *exec_file, char
 static void
 fbsd_thread_post_startup_inferior (ptid_t ptid)
 {
+  if (child_ops.to_post_startup_inferior)
+    child_ops.to_post_startup_inferior (ptid);
+
   if (fbsd_thread_present && !fbsd_thread_active)
     {
       /* The child process is now the actual multi-threaded
Index: gnu/usr.bin/gdb/arch/arm/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/arm/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/arm/init.c	(working copy)
@@ -113,6 +113,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -225,4 +226,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/arm/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/arm/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/arm/Makefile	(working copy)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 GENSRCS+= xm.h
-LIBSRCS+= armfbsd-nat.c
+LIBSRCS+= armfbsd-nat.c fbsd-nat.c
 LIBSRCS+= arm-tdep.c armfbsd-tdep.c solib.c solib-svr4.c
 .if !defined(GDB_CROSS_DEBUGGER)
 LIBSRCS+= fbsd-threads.c
Index: gnu/usr.bin/gdb/arch/powerpc/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/powerpc/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/powerpc/init.c	(working copy)
@@ -113,6 +113,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -227,4 +228,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/powerpc/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/powerpc/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/powerpc/Makefile	(working copy)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 .if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= fbsd-proc.c fbsd-threads.c gcore.c
+LIBSRCS+= fbsd-nat.c fbsd-proc.c fbsd-threads.c gcore.c
 LIBSRCS+= ppcfbsd-nat.c
 .endif
 LIBSRCS+= solib.c solib-svr4.c
Index: gnu/usr.bin/gdb/arch/sparc64/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/sparc64/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/sparc64/init.c	(working copy)
@@ -114,6 +114,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -229,4 +230,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/ia64/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/ia64/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/ia64/init.c	(working copy)
@@ -113,6 +113,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -227,4 +228,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/ia64/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/ia64/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/ia64/Makefile	(working copy)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 .if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= fbsd-proc.c fbsd-threads.c gcore.c
+LIBSRCS+= fbsd-nat.c fbsd-proc.c fbsd-threads.c gcore.c
 LIBSRCS+= ia64-fbsd-nat.c
 .endif
 LIBSRCS+= solib.c solib-svr4.c
Index: gnu/usr.bin/gdb/arch/mips/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/mips/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/mips/init.c	(working copy)
@@ -112,6 +112,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -230,4 +231,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/mips/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/mips/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/mips/Makefile	(working copy)
@@ -4,7 +4,7 @@
 # XXX Should set DEFAULT_BFD_VEC based on target.
 #
 .if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= mipsfbsd-nat.c fbsd-threads.c
+LIBSRCS+= fbsd-nat.c mipsfbsd-nat.c fbsd-threads.c
 .endif
 LIBSRCS+= solib.c solib-svr4.c
 LIBSRCS+= mips-tdep.c mipsfbsd-tdep.c fbsd-proc.c
Index: gnu/usr.bin/gdb/arch/i386/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/i386/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/i386/init.c	(working copy)
@@ -116,6 +116,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -233,4 +234,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/i386/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/i386/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/i386/Makefile	(working copy)
@@ -2,7 +2,7 @@
 
 GENSRCS+= xm.h
 .if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= fbsd-proc.c fbsd-threads.c gcore.c
+LIBSRCS+= fbsd-nat.c fbsd-proc.c fbsd-threads.c gcore.c
 LIBSRCS+= i386-nat.c i386bsd-nat.c i386fbsd-nat.c
 .endif
 LIBSRCS+= solib.c solib-svr4.c
Index: gnu/usr.bin/gdb/arch/powerpc64/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/powerpc64/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/powerpc64/init.c	(working copy)
@@ -113,6 +113,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -227,4 +228,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/powerpc64/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/powerpc64/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/powerpc64/Makefile	(working copy)
@@ -1,7 +1,7 @@
 # $FreeBSD$
 
 .if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= fbsd-proc.c fbsd-threads.c gcore.c
+LIBSRCS+= fbsd-nat.c fbsd-proc.c fbsd-threads.c gcore.c
 LIBSRCS+= ppcfbsd-nat.c
 .endif
 LIBSRCS+= solib.c solib-svr4.c
Index: gnu/usr.bin/gdb/arch/amd64/init.c
===================================================================
--- gnu/usr.bin/gdb/arch/amd64/init.c	(revision 232978)
+++ gnu/usr.bin/gdb/arch/amd64/init.c	(working copy)
@@ -115,6 +115,7 @@ extern initialize_file_ftype _initialize_tui_out;
 extern initialize_file_ftype _initialize_tui_regs;
 extern initialize_file_ftype _initialize_tui_stack;
 extern initialize_file_ftype _initialize_tui_win;
+extern initialize_file_ftype _initialize_fbsdnat;
 void
 initialize_all_files (void)
 {
@@ -231,4 +232,5 @@ initialize_all_files (void)
   _initialize_tui_regs ();
   _initialize_tui_stack ();
   _initialize_tui_win ();
+  _initialize_fbsdnat ();
 }
Index: gnu/usr.bin/gdb/arch/amd64/Makefile
===================================================================
--- gnu/usr.bin/gdb/arch/amd64/Makefile	(revision 232978)
+++ gnu/usr.bin/gdb/arch/amd64/Makefile	(working copy)
@@ -2,7 +2,7 @@
 
 GENSRCS+= xm.h
 .if !defined(GDB_CROSS_DEBUGGER)
-LIBSRCS+= fbsd-proc.c fbsd-threads.c gcore.c
+LIBSRCS+= fbsd-nat.c fbsd-proc.c fbsd-threads.c gcore.c
 LIBSRCS+= amd64-nat.c amd64bsd-nat.c amd64fbsd-nat.c
 .endif
 LIBSRCS+= solib.c solib-svr4.c
Index: contrib/gdb/gdb/target.c
===================================================================
--- contrib/gdb/gdb/target.c	(revision 232978)
+++ contrib/gdb/gdb/target.c	(working copy)
@@ -1307,6 +1307,52 @@ target_async_mask (int mask)
 }
 
 /* Look through the list of possible targets for a target that can
+   follow forks.  */
+
+int
+target_follow_fork (int follow_child)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    {
+      if (t->to_follow_fork != NULL)
+	{
+	  int retval = t->to_follow_fork (t, follow_child);
+	  if (targetdebug)
+	    fprintf_unfiltered (gdb_stdlog, "target_follow_fork (%d) = %d\n",
+				follow_child, retval);
+	  return retval;
+	}
+    }
+
+  /* Some target returned a fork event, but did not know how to follow it.  */
+  internal_error (__FILE__, __LINE__,
+		  "could not find a target to follow fork");
+}
+
+int
+target_follow_exec (int pid, char *execd_pathname)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    {
+      if (t->to_follow_exec != NULL)
+	{
+	  t->to_follow_exec (pid, execd_pathname);
+	  if (targetdebug)
+	    fprintf_unfiltered (gdb_stdlog, "target_follow_exec (%d, %s)\n",
+				pid, execd_pathname);
+	  return;
+	}
+    }
+
+  /* If target does not specify a follow_exec handler, call the default. */
+  follow_exec (pid, execd_pathname);
+}
+
+/* Look through the list of possible targets for a target that can
    execute a run or attach command without any other data.  This is
    used to locate the default process stratum.
 
@@ -2159,9 +2205,9 @@ debug_to_remove_vfork_catchpoint (int pid)
 }
 
 static int
-debug_to_follow_fork (int follow_child)
+debug_to_follow_fork (struct target_ops* ops, int follow_child)
 {
-  int retval =  debug_target.to_follow_fork (follow_child);
+  int retval =  debug_target.to_follow_fork (ops, follow_child);
 
   fprintf_unfiltered (gdb_stdlog, "target_follow_fork (%d) = %d\n",
 		      follow_child, retval);
Index: contrib/gdb/gdb/target.h
===================================================================
--- contrib/gdb/gdb/target.h	(revision 232978)
+++ contrib/gdb/gdb/target.h	(working copy)
@@ -362,7 +362,8 @@ struct target_ops
     int (*to_remove_fork_catchpoint) (int);
     int (*to_insert_vfork_catchpoint) (int);
     int (*to_remove_vfork_catchpoint) (int);
-    int (*to_follow_fork) (int);
+    int (*to_follow_fork) (struct target_ops*, int);
+    void (*to_follow_exec) (int, char*);
     int (*to_insert_exec_catchpoint) (int);
     int (*to_remove_exec_catchpoint) (int);
     int (*to_reported_exec_events_per_exec_call) (void);
@@ -761,8 +762,7 @@ extern void target_load (char *arg, int from_tty);
    This function returns 1 if the inferior should not be resumed
    (i.e. there is another event pending).  */
 
-#define target_follow_fork(follow_child) \
-     (*current_target.to_follow_fork) (follow_child)
+int target_follow_fork (int follow_child);
 
 /* On some targets, we can catch an inferior exec event when it
    occurs.  These functions insert/remove an already-created
@@ -1248,4 +1248,6 @@ extern void push_remote_target (char *name, int fr
 /* Blank target vector entries are initialized to target_ignore. */
 void target_ignore (void);
 
+int target_follow_exec (int pid, char *execd_pathname);
+
 #endif /* !defined (TARGET_H) */
Index: contrib/gdb/gdb/infrun.c
===================================================================
--- contrib/gdb/gdb/infrun.c	(revision 232978)
+++ contrib/gdb/gdb/infrun.c	(working copy)
@@ -384,9 +384,22 @@ follow_inferior_reset_breakpoints (void)
   insert_breakpoints ();
 }
 
+void 
+clear_step_resume_breakpoint_thread (void)
+{
+  if (step_resume_breakpoint)
+    step_resume_breakpoint->thread = -1;
+}
+
+void 
+clear_step_resume_breakpoint (void)
+{
+  step_resume_breakpoint = NULL;
+}
+
 /* EXECD_PATHNAME is assumed to be non-NULL. */
 
-static void
+void
 follow_exec (int pid, char *execd_pathname)
 {
   int saved_pid = pid;
@@ -1648,7 +1661,8 @@ handle_inferior_event (struct execution_control_st
 
       /* This causes the eventpoints and symbol table to be reset.  Must
          do this now, before trying to determine whether to stop. */
-      follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname);
+      target_follow_exec (PIDGET (inferior_ptid), 
+			  pending_follow.execd_pathname);
       xfree (pending_follow.execd_pathname);
 
       stop_pc = read_pc_pid (ecs->ptid);
Index: contrib/gdb/gdb/thread.c
===================================================================
--- contrib/gdb/gdb/thread.c	(revision 232978)
+++ contrib/gdb/gdb/thread.c	(working copy)
@@ -65,6 +65,12 @@ static void restore_current_thread (ptid_t);
 static void switch_to_thread (ptid_t ptid);
 static void prune_threads (void);
 
+int
+thread_list_empty ()
+{
+  return thread_list == NULL;
+}
+
 void
 delete_step_resume_breakpoint (void *arg)
 {
Index: contrib/gdb/gdb/gdbthread.h
===================================================================
--- contrib/gdb/gdb/gdbthread.h	(revision 232978)
+++ contrib/gdb/gdb/gdbthread.h	(working copy)
@@ -75,6 +75,8 @@ struct thread_info
   struct private_thread_info *private;
 };
 
+extern int thread_list_empty (void);
+
 /* Create an empty thread list, or empty the existing one.  */
 extern void init_thread_list (void);
 
Index: contrib/gdb/gdb/objfiles.c
===================================================================
--- contrib/gdb/gdb/objfiles.c	(revision 232978)
+++ contrib/gdb/gdb/objfiles.c	(working copy)
@@ -482,11 +482,11 @@ free_all_objfiles (void)
 {
   struct objfile *objfile, *temp;
 
+  clear_symtab_users ();
   ALL_OBJFILES_SAFE (objfile, temp)
   {
     free_objfile (objfile);
   }
-  clear_symtab_users ();
 }
 
 /* Relocate OBJFILE to NEW_OFFSETS.  There should be OBJFILE->NUM_SECTIONS

--------------090403050708010606090605--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4F8737E9.6010300>