aboutsummaryrefslogtreecommitdiffstats
path: root/libtest/libtest_print_backtrace.c
blob: 8fa0fd557afd6dc93e99d49315ebb895a27f9d2c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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