Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Example on how to dump stack trace on SIGUSR2, useful if program gets stuck
/*
* unwindtest.c
* Copyright (C) 2017 Adrian Perez <aperez@igalia.com>
*
* Distributed under terms of the MIT license.
*/
#define _GNU_SOURCE
#include <ucontext.h>
#include <dlfcn.h>
#include <signal.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
static void
context_backtrace (ucontext_t *context)
{
unsigned frame_number = 0;
void *ip = NULL;
void **bp = NULL;
#if defined(REG_RIP)
ip = (void*) context->uc_mcontext.gregs[REG_RIP];
bp = (void**) context->uc_mcontext.gregs[REG_RBP];
#elif defined(REG_EIP)
ip = (void*) context->uc_mcontext.gregs[REG_EIP];
bp = (void**) context->uc_mcontext.gregs[REG_EBP];
#endif
while (bp && ip) {
Dl_info dlinfo;
if (!dladdr (ip, &dlinfo))
break;
const char *symbol = dlinfo.dli_sname;
fprintf (stderr, "% 2d: %p <%s+%lu> (%s)\n",
++frame_number,
ip,
symbol ? symbol : "(?)",
(uintptr_t) ip - (uintptr_t) dlinfo.dli_saddr,
dlinfo.dli_fname);
if (dlinfo.dli_sname && strcmp (dlinfo.dli_sname, "main") == 0)
break;
ip = bp[1];
bp = (void**) bp[0];
}
}
#define BACKTRACE( ) \
do { \
ucontext_t uc; \
getcontext (&uc); \
context_backtrace (&uc); \
} while (0)
static void
handle_signal (int signum, siginfo_t *info, void *context)
{
context_backtrace ((ucontext_t*) context);
}
void h (void) { BACKTRACE (); }
void g (void) { h (); }
void f (void) { g (); }
void lh (void) {
static volatile int x = 1;
while (x) /* noop */;
}
void lg (void) { lh (); }
void lf (void) { lg (); }
int main (int argc, char *argv[])
{
f ();
struct sigaction sa = { 0, };
sa.sa_sigaction = handle_signal;
sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sigaction (SIGUSR2, &sa, NULL);
printf ("PID: %lu\n", (unsigned long) getpid ());
lf ();
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment