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 (); }