mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-24 17:00: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])
|
AC_DEFINE(HAVE_LIBUNWIND, 1, [Have libunwind support])
|
||||||
fi
|
fi
|
||||||
AM_CONDITIONAL(HAVE_LIBUNWIND, [test "x$HAVE_LIBUNWIND" = xyes])
|
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([m], [atan2])
|
||||||
AC_CHECK_LIB([rt], [clock_gettime])
|
AC_CHECK_LIB([rt], [clock_gettime])
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,68 @@ static int verbose = 0;
|
||||||
#define litest_vlog(...) /* __VA_ARGS__ */
|
#define litest_vlog(...) /* __VA_ARGS__ */
|
||||||
#endif
|
#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
|
static void
|
||||||
litest_backtrace(void)
|
litest_backtrace(void)
|
||||||
{
|
{
|
||||||
|
|
@ -100,6 +162,10 @@ litest_backtrace(void)
|
||||||
litest_log("\nBacktrace:\n");
|
litest_log("\nBacktrace:\n");
|
||||||
ret = unw_step(&cursor);
|
ret = unw_step(&cursor);
|
||||||
while (ret > 0) {
|
while (ret > 0) {
|
||||||
|
char file[PATH_MAX];
|
||||||
|
int line;
|
||||||
|
bool have_lineno = false;
|
||||||
|
|
||||||
ret = unw_get_proc_info(&cursor, &pip);
|
ret = unw_get_proc_info(&cursor, &pip);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
litest_log("unw_get_proc_info failed: %s [%d]\n",
|
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) &&
|
if (dladdr((void *)(pip.start_ip + off), &dlinfo) &&
|
||||||
dlinfo.dli_fname &&
|
dlinfo.dli_fname &&
|
||||||
*dlinfo.dli_fname)
|
*dlinfo.dli_fname) {
|
||||||
filename = dlinfo.dli_fname;
|
filename = dlinfo.dli_fname;
|
||||||
else
|
have_lineno = litest_backtrace_get_lineno(filename,
|
||||||
|
(pip.start_ip + off),
|
||||||
|
file,
|
||||||
|
&line);
|
||||||
|
} else {
|
||||||
filename = "?";
|
filename = "?";
|
||||||
|
}
|
||||||
|
|
||||||
litest_log("%u: %s (%s%s+%#x) [%p]\n",
|
if (have_lineno) {
|
||||||
i++,
|
litest_log("%u: %s() (%s:%d)\n",
|
||||||
filename,
|
i,
|
||||||
procname,
|
procname,
|
||||||
ret == -UNW_ENOMEM ? "..." : "",
|
file,
|
||||||
(int)off,
|
line);
|
||||||
(void *)(pip.start_ip + off));
|
} 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);
|
ret = unw_step(&cursor);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
litest_log("unw_step failed: %s [%d]\n",
|
litest_log("unw_step failed: %s [%d]\n",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue