From 261356844a6cb3404f2627a58302f296fb6bebb2 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <iant@golang.org>
Date: Sat, 15 Feb 2020 15:29:02 -0800
Subject: libbacktrace: support fetching executable name using sysctl

This supports FreeBSD and NetBSD when /proc is not mounted.

libbacktrace/
	* fileline.c (sysctl_exec_name): New static function.
	(sysctl_exec_name1): New macro or static function.
	(sysctl_exec_name2): Likewise.
	(fileline_initialize): Try sysctl_exec_name[12].
	* configure.ac: Check for sysctl args to fetch executable name.
	* configure: Regenerate.
	* config.h.in: Regenerate.
---
 libbacktrace/ChangeLog    | 10 ++++++
 libbacktrace/config.h.in  |  8 +++++
 libbacktrace/configure    | 70 +++++++++++++++++++++++++++++++++++++++
 libbacktrace/configure.ac | 30 +++++++++++++++++
 libbacktrace/fileline.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 201 insertions(+), 1 deletion(-)

(limited to 'libbacktrace')

diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index c031dff..1739be9 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
@@ -1,3 +1,13 @@
+2020-05-08  Ian Lance Taylor  <iant@golang.org>
+
+	* fileline.c (sysctl_exec_name): New static function.
+	(sysctl_exec_name1): New macro or static function.
+	(sysctl_exec_name2): Likewise.
+	(fileline_initialize): Try sysctl_exec_name[12].
+	* configure.ac: Check for sysctl args to fetch executable name.
+	* configure: Regenerate.
+	* config.h.in: Regenerate.
+
 2020-02-15  Ian Lance Taylor  <iant@golang.org>
 
 	* ztest.c (test_large): Update file to current libgo test file.
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index d2c0bdb..034ef81 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -34,6 +34,14 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
+/* Define to 1 if you have KERN_PROC and KERN_PROC_PATHNAME in <sys/sysctl.h>.
+   */
+#undef HAVE_KERN_PROC
+
+/* Define to 1 if you have KERN_PROCARGS and KERN_PROC_PATHNAME in
+   <sys/sysctl.h>. */
+#undef HAVE_KERN_PROC_ARGS
+
 /* Define to 1 if you have the <link.h> header file. */
 #undef HAVE_LINK_H
 
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 676adb8..33ce5891 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -13182,6 +13182,76 @@ $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h
 
 fi
 
+# Check for sysctl definitions.
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for KERN_PROC" >&5
+$as_echo_n "checking for KERN_PROC... " >&6; }
+if ${libbacktrace_cv_proc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+int
+main ()
+{
+int mib0 = CTL_KERN; int mib1 = KERN_PROC; int mib2 = KERN_PROC_PATHNAME;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libbacktrace_cv_proc=yes
+else
+  libbacktrace_cv_proc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_proc" >&5
+$as_echo "$libbacktrace_cv_proc" >&6; }
+if test "$libbacktrace_cv_proc" = "yes"; then
+
+$as_echo "#define HAVE_KERN_PROC 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for KERN_PROG_ARGS" >&5
+$as_echo_n "checking for KERN_PROG_ARGS... " >&6; }
+if ${libbacktrace_cv_procargs+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+int
+main ()
+{
+int mib0 = CTL_KERN; int mib1 = KERN_PROC_ARGS; int mib2 = KERN_PROC_PATHNAME;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  libbacktrace_cv_procargs=yes
+else
+  libbacktrace_cv_procargs=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_procargs" >&5
+$as_echo "$libbacktrace_cv_procargs" >&6; }
+if test "$libbacktrace_cv_procargs" = "yes"; then
+
+$as_echo "#define HAVE_KERN_PROC_ARGS 1" >>confdefs.h
+
+fi
+
 # Check for the clock_gettime function.
 for ac_func in clock_gettime
 do :
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 3730d7c..5beed68 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -388,6 +388,36 @@ if test "$have_getexecname" = "yes"; then
   AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
 fi
 
+# Check for sysctl definitions.
+
+AC_CACHE_CHECK([for KERN_PROC],
+[libbacktrace_cv_proc],
+[AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([
+#include <sys/types.h>
+#include <sys/sysctl.h>
+], [int mib0 = CTL_KERN; int mib1 = KERN_PROC; int mib2 = KERN_PROC_PATHNAME;])],
+  [libbacktrace_cv_proc=yes],
+  [libbacktrace_cv_proc=no])])
+if test "$libbacktrace_cv_proc" = "yes"; then
+  AC_DEFINE([HAVE_KERN_PROC], 1,
+            [Define to 1 if you have KERN_PROC and KERN_PROC_PATHNAME in <sys/sysctl.h>.])
+fi
+
+AC_CACHE_CHECK([for KERN_PROG_ARGS],
+[libbacktrace_cv_procargs],
+[AC_COMPILE_IFELSE(
+  [AC_LANG_PROGRAM([
+#include <sys/types.h>
+#include <sys/sysctl.h>
+], [int mib0 = CTL_KERN; int mib1 = KERN_PROC_ARGS; int mib2 = KERN_PROC_PATHNAME;])],
+  [libbacktrace_cv_procargs=yes],
+  [libbacktrace_cv_procargs=no])])
+if test "$libbacktrace_cv_procargs" = "yes"; then
+  AC_DEFINE([HAVE_KERN_PROC_ARGS], 1,
+            [Define to 1 if you have KERN_PROCARGS and KERN_PROC_PATHNAME in <sys/sysctl.h>.])
+fi
+
 # Check for the clock_gettime function.
 AC_CHECK_FUNCS(clock_gettime)
 clock_gettime_link=
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index fd5edbe..cc1011e 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -39,6 +39,10 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #include <stdlib.h>
 #include <unistd.h>
 
+#if defined (HAVE_KERN_PROC_ARGS) || defined (HAVE_KERN_PROC)
+#include <sys/sysctl.h>
+#endif
+
 #include "backtrace.h"
 #include "internal.h"
 
@@ -46,6 +50,78 @@ POSSIBILITY OF SUCH DAMAGE.  */
 #define getexecname() NULL
 #endif
 
+#if !defined (HAVE_KERN_PROC_ARGS) && !defined (HAVE_KERN_PROC)
+
+#define sysctl_exec_name1(state, error_callback, data) NULL
+#define sysctl_exec_name2(state, error_callback, data) NULL
+
+#else /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
+
+static char *
+sysctl_exec_name (struct backtrace_state *state,
+		  int mib0, int mib1, int mib2, int mib3,
+		  backtrace_error_callback error_callback, void *data)
+{
+  int mib[4];
+  size_t len;
+  char *name;
+  size_t rlen;
+
+  mib[0] = mib0;
+  mib[1] = mib1;
+  mib[2] = mib2;
+  mib[3] = mib3;
+
+  if (sysctl (mib, 4, NULL, &len, NULL, 0) < 0)
+    return NULL;
+  name = (char *) backtrace_alloc (state, len, error_callback, data);
+  if (name == NULL)
+    return NULL;
+  rlen = len;
+  if (sysctl (mib, 4, name, &rlen, NULL, 0) < 0)
+    {
+      backtrace_free (state, name, len, error_callback, data);
+      return NULL;
+    }
+  return name;
+}
+
+#ifdef HAVE_KERN_PROC_ARGS
+
+static char *
+sysctl_exec_name1 (struct backtrace_state *state,
+		   backtrace_error_callback error_callback, void *data)
+{
+  /* This variant is used on NetBSD.  */
+  return sysctl_exec_name (state, CTL_KERN, KERN_PROC_ARGS, -1,
+			   KERN_PROC_PATHNAME, error_callback, data);
+}
+
+#else
+
+#define sysctl_exec_name1(state, error_callback, data) NULL
+
+#endif
+
+#ifdef HAVE_KERN_PROC
+
+static char *
+sysctl_exec_name2 (struct backtrace_state *state,
+		   backtrace_error_callback error_callback, void *data)
+{
+  /* This variant is used on FreeBSD.  */
+  return sysctl_exec_name (state, CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1,
+			   error_callback, data);
+}
+
+#else
+
+#define sysctl_exec_name2(state, error_callback, data) NULL
+
+#endif
+
+#endif /* defined (HAVE_KERN_PROC_ARGS) || |defined (HAVE_KERN_PROC) */
+
 /* Initialize the fileline information from the executable.  Returns 1
    on success, 0 on failure.  */
 
@@ -83,7 +159,7 @@ fileline_initialize (struct backtrace_state *state,
 
   descriptor = -1;
   called_error_callback = 0;
-  for (pass = 0; pass < 5; ++pass)
+  for (pass = 0; pass < 7; ++pass)
     {
       int does_not_exist;
 
@@ -106,6 +182,12 @@ fileline_initialize (struct backtrace_state *state,
 		    (long) getpid ());
 	  filename = buf;
 	  break;
+	case 5:
+	  filename = sysctl_exec_name1 (state, error_callback, data);
+	  break;
+	case 6:
+	  filename = sysctl_exec_name2 (state, error_callback, data);
+	  break;
 	default:
 	  abort ();
 	}
-- 
cgit v1.1