mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 04:30:06 +01:00
test: extract file:line from backtrace with addr2line
libunwind gives us a file and an address and usually a function name. Beyond that, it's mostly guessing. Fork off addr2line to resolve the addresses that libunwind gives us, if we succeed we get a backtrace like this: Backtrace: 0: litest_fail_comparison_int() (./test/litest.c:268) 1: disable_button_scrolling() (./test/pointer.c:115) 2: middlebutton_doubleclick() (./test/pointer.c:991) 3: /lib64/libcheck.so.0 (srunner_run+0x7f5) [0x7f6c12d8c025] 4: litest_run() (./test/litest.c:689) 5: main() (./test/pointer.c:1280) 6: /lib64/libc.so.6 (__libc_start_main+0xf0) [0x7f6c11a73790] 7: ./test/test-pointer (_start+0x29) [0x403d99] 8: ? (?+0x29) [0x29] Note: I intentionally swapped function/file name in the output to make it easier to spot which one is fully resolved and which one is the basic libunwind output. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
dc3dbc4dfc
commit
b8af89f173
2 changed files with 94 additions and 9 deletions
|
|
@ -68,6 +68,11 @@ if test "x$HAVE_LIBUNWIND" = "xyes"; then
|
|||
AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$HAVE_LIBUNWIND" = xyes])
|
||||
AC_PATH_PROG(ADDR2LINE, [addr2line])
|
||||
if test "x$ADDR2LINE" != "x"; then
|
||||
AC_DEFINE_UNQUOTED(HAVE_ADDR2LINE, 1, [addr2line found])
|
||||
AC_DEFINE_UNQUOTED(ADDR2LINE, ["$ADDR2LINE"], [Path to addr2line])
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB([m], [atan2])
|
||||
AC_CHECK_LIB([rt], [clock_gettime])
|
||||
|
|
|
|||
|
|
@ -66,6 +66,68 @@ static int verbose = 0;
|
|||
#define litest_vlog(...) /* __VA_ARGS__ */
|
||||
#endif
|
||||
|
||||
static char cwd[PATH_MAX];
|
||||
|
||||
static bool
|
||||
litest_backtrace_get_lineno(const char *executable,
|
||||
unw_word_t addr,
|
||||
char *file_return,
|
||||
int *line_return)
|
||||
{
|
||||
#if HAVE_ADDR2LINE
|
||||
FILE* f;
|
||||
char buffer[PATH_MAX];
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
if (!cwd[0])
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
|
||||
sprintf (buffer,
|
||||
ADDR2LINE " -C -e %s -i %lx",
|
||||
executable,
|
||||
(unsigned long) addr);
|
||||
|
||||
f = popen(buffer, "r");
|
||||
if (f == NULL) {
|
||||
litest_log("Failed to execute: %s\n", buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer[0] = '?';
|
||||
fgets(buffer, sizeof(buffer), f);
|
||||
fclose(f);
|
||||
|
||||
if (buffer[0] == '?')
|
||||
return false;
|
||||
|
||||
s = strrchr(buffer, ':');
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
*s = '\0';
|
||||
s++;
|
||||
sscanf(s, "%d", line_return);
|
||||
|
||||
/* now strip cwd from buffer */
|
||||
s = buffer;
|
||||
i = 0;
|
||||
while(cwd[i] == *s) {
|
||||
*s = '\0';
|
||||
s++;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
*(--s) = '.';
|
||||
strcpy(file_return, s);
|
||||
|
||||
return true;
|
||||
#else /* HAVE_ADDR2LINE */
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
litest_backtrace(void)
|
||||
{
|
||||
|
|
@ -100,6 +162,10 @@ litest_backtrace(void)
|
|||
litest_log("\nBacktrace:\n");
|
||||
ret = unw_step(&cursor);
|
||||
while (ret > 0) {
|
||||
char file[PATH_MAX];
|
||||
int line;
|
||||
bool have_lineno = false;
|
||||
|
||||
ret = unw_get_proc_info(&cursor, &pip);
|
||||
if (ret) {
|
||||
litest_log("unw_get_proc_info failed: %s [%d]\n",
|
||||
|
|
@ -120,19 +186,33 @@ litest_backtrace(void)
|
|||
|
||||
if (dladdr((void *)(pip.start_ip + off), &dlinfo) &&
|
||||
dlinfo.dli_fname &&
|
||||
*dlinfo.dli_fname)
|
||||
*dlinfo.dli_fname) {
|
||||
filename = dlinfo.dli_fname;
|
||||
else
|
||||
have_lineno = litest_backtrace_get_lineno(filename,
|
||||
(pip.start_ip + off),
|
||||
file,
|
||||
&line);
|
||||
} else {
|
||||
filename = "?";
|
||||
}
|
||||
|
||||
litest_log("%u: %s (%s%s+%#x) [%p]\n",
|
||||
i++,
|
||||
filename,
|
||||
procname,
|
||||
ret == -UNW_ENOMEM ? "..." : "",
|
||||
(int)off,
|
||||
(void *)(pip.start_ip + off));
|
||||
if (have_lineno) {
|
||||
litest_log("%u: %s() (%s:%d)\n",
|
||||
i,
|
||||
procname,
|
||||
file,
|
||||
line);
|
||||
} else {
|
||||
litest_log("%u: %s (%s%s+%#x) [%p]\n",
|
||||
i,
|
||||
filename,
|
||||
procname,
|
||||
ret == -UNW_ENOMEM ? "..." : "",
|
||||
(int)off,
|
||||
(void *)(pip.start_ip + off));
|
||||
}
|
||||
|
||||
i++;
|
||||
ret = unw_step(&cursor);
|
||||
if (ret < 0)
|
||||
litest_log("unw_step failed: %s [%d]\n",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue