libbacktrace: support fetching executable name using sysctl

This supports FreeBSD and NetBSD when /proc is not mounted.
This commit is contained in:
Ian Lance Taylor
2020-02-15 15:33:11 -08:00
parent 559ab7cab4
commit 0f06cda953
4 changed files with 191 additions and 1 deletions

View File

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