diff options
| author | David Lamparter <equinox@diac24.net> | 2021-03-02 19:33:45 +0100 |
|---|---|---|
| committer | David Lamparter <equinox@opensourcerouting.org> | 2021-11-10 12:36:50 +0100 |
| commit | ef990bd94bc5e5b37214d1188915f585de1dc12a (patch) | |
| tree | 2aaca9e41990c55695102405b349220d00ad9217 /lib/zlog.c | |
| parent | 4894e9c12a8ee0165930900bc3c3391060108516 (diff) | |
lib: add `debug uid XXXXX-XXXXX backtrace`
Looks much prettier if `libunwind` is available, but works with glibc or
libexecinfo's `backtrace()` too.
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'lib/zlog.c')
| -rw-r--r-- | lib/zlog.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/lib/zlog.c b/lib/zlog.c index 6fd52cae62..1b0751559d 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -47,12 +47,19 @@ #include <mach/mach_traps.h> #endif +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <dlfcn.h> +#endif + #include "memory.h" #include "atomlist.h" #include "printfrr.h" #include "frrcu.h" #include "zlog.h" #include "libfrr_trace.h" +#include "thread.h" DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message"); DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer"); @@ -508,6 +515,87 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref, XFREE(MTYPE_LOG_MESSAGE, msg->text); } +static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio) +{ + struct thread *tc = pthread_getspecific(thread_current); + const char *uid = xref->xref.xrefdata->uid; + bool found_thread = false; + + zlog(prio, "| (%s) message in thread %jd, at %s(), %s:%d", uid, + zlog_gettid(), xref->xref.func, xref->xref.file, xref->xref.line); + +#ifdef HAVE_LIBUNWIND + const char *threadfunc = tc ? tc->xref->funcname : NULL; + bool found_caller = false; + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, off, sp; + Dl_info dlinfo; + + unw_getcontext(&uc); + + unw_init_local(&cursor, &uc); + while (unw_step(&cursor) > 0) { + char buf[96], name[128] = "?"; + bool is_thread = false; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + if (unw_is_signal_frame(&cursor)) + zlog(prio, "| (%s) ---- signal ----", uid); + + if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) { + if (!strcmp(buf, xref->xref.func)) + found_caller = true; + if (threadfunc && !strcmp(buf, threadfunc)) + found_thread = is_thread = true; + + snprintf(name, sizeof(name), "%s+%#lx", buf, (long)off); + } + + if (!found_caller) + continue; + + if (dladdr((void *)ip, &dlinfo)) + zlog(prio, "| (%s) %-36s %16lx+%08lx %16lx %s", uid, + name, (long)dlinfo.dli_fbase, + (long)ip - (long)dlinfo.dli_fbase, (long)sp, + dlinfo.dli_fname); + else + zlog(prio, "| (%s) %-36s %16lx %16lx", uid, name, + (long)ip, (long)sp); + + if (is_thread) + zlog(prio, "| (%s) ^- scheduled from %s(), %s:%u", uid, + tc->xref->xref.func, tc->xref->xref.file, + tc->xref->xref.line); + } +#elif defined(HAVE_GLIBC_BACKTRACE) + void *frames[64]; + char **names = NULL; + int n_frames, i; + + n_frames = backtrace(frames, array_size(frames)); + if (n_frames < 0) + n_frames = 0; + if (n_frames) + names = backtrace_symbols(frames, n_frames); + + for (i = 0; i < n_frames; i++) { + void *retaddr = frames[i]; + char *loc = names[i]; + + zlog(prio, "| (%s) %16lx %-36s", uid, (long)retaddr, loc); + } + free(names); +#endif + if (!found_thread && tc) + zlog(prio, "| (%s) scheduled from %s(), %s:%u", uid, + tc->xref->xref.func, tc->xref->xref.file, + tc->xref->xref.line); +} + void vzlogx(const struct xref_logmsg *xref, int prio, const char *fmt, va_list ap) { @@ -545,6 +633,15 @@ void vzlogx(const struct xref_logmsg *xref, int prio, vzlog_tls(zlog_tls, xref, prio, fmt, ap); else vzlog_notls(xref, prio, fmt, ap); + + if (xref) { + struct xrefdata_logmsg *xrdl; + + xrdl = container_of(xref->xref.xrefdata, struct xrefdata_logmsg, + xrefdata); + if (xrdl->fl_print_bt) + zlog_backtrace_msg(xref, prio); + } } void zlog_sigsafe(const char *text, size_t len) |
