This libbacktrace patch adds the ability to fetch the executable name
on FreeBSD and NetBSD using sysctl when /proc is not mounted.
Bootstrapped and ran libbacktrace tests on x86_64-pc-linux-gnu.
Committed to mainline.

Ian

2020-05-08  Ian Lance Taylor  <i...@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.
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index 3730d7c4b06..5beed68ccf6 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 fd5edbe5ddb..cc1011e8b5d 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 ();
        }

Reply via email to