#include <kern/backtrace.h>
#include <kern/kalloc.h>
#include <sys/errno.h>
#include <sys/sysctl.h>
#include <sys/systm.h>
#if DEVELOPMENT || DEBUG
#define MAX_BACKTRACE (128)
#define BACKTRACE_USER (0)
static int backtrace_sysctl SYSCTL_HANDLER_ARGS;
SYSCTL_NODE(_kern, OID_AUTO, backtrace, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
"backtrace");
SYSCTL_PROC(_kern_backtrace, OID_AUTO, user,
CTLFLAG_RW | CTLFLAG_LOCKED, (void *)BACKTRACE_USER,
sizeof(uint64_t), backtrace_sysctl, "O",
"take user backtrace of current thread");
static int
backtrace_sysctl SYSCTL_HANDLER_ARGS
{
#pragma unused(oidp, arg2)
uintptr_t type = (uintptr_t)arg1;
uintptr_t *bt = NULL;
unsigned int bt_len = 0, bt_filled = 0;
size_t bt_size = 0;
int error = 0;
if (type != BACKTRACE_USER) {
return EINVAL;
}
if (req->oldptr == USER_ADDR_NULL || req->oldlen == 0) {
return EFAULT;
}
bt_len = req->oldlen > MAX_BACKTRACE ? MAX_BACKTRACE : (unsigned int)req->oldlen;
bt_size = sizeof(bt[0]) * bt_len;
bt = kheap_alloc(KHEAP_TEMP, bt_size, Z_WAITOK | Z_ZERO);
if (!bt) {
return ENOBUFS;
}
bt_filled = backtrace_user(bt, bt_len, &error, NULL, NULL);
if (error != 0) {
goto out;
}
bt_filled = min(bt_filled, bt_len);
error = copyout(bt, req->oldptr, sizeof(bt[0]) * bt_filled);
if (error) {
goto out;
}
req->oldidx = bt_filled;
out:
kheap_free(KHEAP_TEMP, bt, bt_size);
return error;
}
#endif