bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#include "lib.h"
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#include "str.h"
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#include "backtrace-string.h"
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#define MAX_STACK_SIZE 30
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#define STACK_SKIP_COUNT 2
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#if defined(HAVE_BACKTRACE_SYMBOLS) && defined(HAVE_EXECINFO_H)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen/* Linux */
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#include <execinfo.h>
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainenint backtrace_append(string_t *str)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen{
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen void *stack[MAX_STACK_SIZE];
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen char **strings;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen int ret, i;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
fd1f0e9ef52b3e157cfd1a01c464c2ac7458ab17Timo Sirainen ret = backtrace(stack, N_ELEMENTS(stack));
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen if (ret <= STACK_SKIP_COUNT)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return -1;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen strings = backtrace_symbols(stack, ret);
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen for (i = STACK_SKIP_COUNT; i < ret; i++) {
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen if (i > STACK_SKIP_COUNT)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen str_append(str, " -> ");
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen if (strings != NULL)
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen str_append(str, strings[i]);
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen else {
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen /* out of memory case */
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen str_printfa(str, "0x%p", stack[i]);
e7e0016aeb7b64254707061257400fcde26a7b9eTimo Sirainen }
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen }
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen free(strings);
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return 0;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen}
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#elif defined(HAVE_WALKCONTEXT) && defined(HAVE_UCONTEXT_H)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen/* Solaris */
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#include <ucontext.h>
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainenstruct walk_context {
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen string_t *str;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen unsigned int pos;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen};
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenstatic int walk_callback(uintptr_t ptr, int signo ATTR_UNUSED,
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen void *context)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen{
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen struct walk_context *ctx = context;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen if (ctx->pos >= STACK_SKIP_COUNT) {
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen if (ctx->pos > STACK_SKIP_COUNT)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen str_append(ctx->str, " -> ");
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen str_printfa(ctx->str, "0x%p", (void *)ptr);
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen }
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen ctx->pos++;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return 0;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen}
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainenint backtrace_append(string_t *str)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen{
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen ucontext_t uc;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen struct walk_context ctx;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen if (getcontext(&uc) < 0)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return -1;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen ctx.str = str;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen ctx.pos = 0;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen walkcontext(&uc, walk_callback, &ctx);
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return 0;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen}
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#else
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenint backtrace_append(string_t *str ATTR_UNUSED)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen{
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return -1;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen}
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen#endif
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainenint backtrace_get(const char **backtrace_r)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen{
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen string_t *str;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen str = t_str_new(512);
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen if (backtrace_append(str) < 0)
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return -1;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen *backtrace_r = str_c(str);
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen return 0;
7ba4c0608e32d0cc8a8600cb8b9987b2b56e2bf8Timo Sirainen}