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 <[email protected]>
* 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 ();
}