aboutsummaryrefslogtreecommitdiffstats
path: root/libtest/libtest_print_backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libtest/libtest_print_backtrace.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/libtest/libtest_print_backtrace.c b/libtest/libtest_print_backtrace.c
new file mode 100644
index 0000000..8fa0fd5
--- /dev/null
+++ b/libtest/libtest_print_backtrace.c
@@ -0,0 +1,122 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+
+#if defined(__linux__)
+# define HAVE_LINE_INFO
+#endif
+
+
+void
+libtest_print_backtrace(FILE *fp, const char *indent, size_t first, const struct backtrace *backtrace)
+{
+ static _Thread_local int recursion_guard = 0;
+ int saved_errno;
+ unw_word_t rip;
+ unw_cursor_t cursor;
+ unw_context_t context;
+ Dwarf_Addr ip;
+ size_t i;
+#if defined(HAVE_LINE_INFO)
+ Dwfl_Callbacks callbacks;
+ char *debuginfo_path = NULL;
+ Dwfl *dwfl = NULL;
+ Dwfl_Line *line = NULL;
+ Dwfl_Module *module = NULL;
+ int lineno = 0; /* initialised for compiler happiness */
+ const char *filename = NULL;
+ const char *funcname = NULL;
+#endif
+
+ if (recursion_guard)
+ return;
+ saved_errno = errno;
+ recursion_guard = 1;
+ libtest_malloc_internal_usage++;
+
+ if (!backtrace) {
+ if (unw_getcontext(&context))
+ goto out;
+ if (unw_init_local(&cursor, &context))
+ goto out;
+ }
+
+#if defined(__linux__)
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.find_elf = &dwfl_linux_proc_find_elf;
+ callbacks.find_debuginfo = &dwfl_standard_find_debuginfo;
+ callbacks.section_address = NULL;
+ callbacks.debuginfo_path = &debuginfo_path;
+
+ dwfl = dwfl_begin(&callbacks);
+ if (dwfl) {
+ if (dwfl_linux_proc_report(dwfl, getpid()) ||
+ dwfl_report_end(dwfl, NULL, NULL)) {
+ dwfl_end(dwfl);
+ dwfl = NULL;
+ }
+ }
+#endif
+
+ for (i = 0u; backtrace ? i < backtrace->n : unw_step(&cursor) > 0; i++) {
+ if (backtrace) {
+ ip = backtrace->trace[i];
+ } else {
+ if (unw_get_reg(&cursor, UNW_REG_IP, &rip))
+ break;
+ ip = (Dwarf_Addr)rip;
+ }
+ if (i < first)
+ continue;
+
+#if defined(HAVE_LINE_INFO)
+ if (dwfl) {
+ module = dwfl_addrmodule(dwfl, ip);
+ funcname = module ? dwfl_module_addrname(module, ip) : NULL;
+ line = dwfl_getsrc(dwfl, ip);
+ if (line) {
+ filename = dwfl_lineinfo(line, &(Dwarf_Addr){0}, &lineno, NULL, NULL, NULL);
+# ifdef USE_BASENAMES_IN_BACKTRACES
+ if (strrchr(filename, '/'))
+ filename = &strrchr(filename, '/')[1];
+# endif
+ }
+ }
+#endif
+
+#if defined(HAVE_LINE_INFO)
+ fprintf(fp, "%s0x%016"PRIxPTR": %s", indent, (uintptr_t)ip, funcname ? funcname : "???");
+ if (line)
+ fprintf(fp, " (%s:%i)\n", filename, lineno);
+ else
+ fprintf(fp, "\n");
+#else
+ fprintf(fp, "%s0x%016"PRIxPTR"\n", indent, (uintptr_t)ip);
+#endif
+ }
+
+#if defined(HAVE_LINE_INFO)
+ if (dwfl)
+ dwfl_end(dwfl);
+#endif
+
+out:
+ libtest_malloc_internal_usage--;
+ recursion_guard = 0;
+ errno = saved_errno;
+}
+
+
+#else
+
+
+CONST int
+main(void)
+{
+ /* How would one even test this, and what would be the point? */
+ return 0;
+}
+
+
+#endif