[PATCH libinput] test: replace hand-rolled backtrace function with gstack

Peter Hutterer peter.hutterer at who-t.net
Thu Aug 9 00:03:17 UTC 2018


Let's use something that specializes in that task and does a better job of it
than whatever we'll come up with. Due to how it's implemented the stacktrace
will always show waitpid() as frame 0 now but we can live with that.

gstack prints to stdout but litest_log() uses stderr, so we cannot just call
system(), we have do do the pipe/fork/exec/waitpid/read dance.
We could use that to filter the #0 frame showing waidpid() from gstack but
meh.

This drops the libunwind and addr2line dependency and replaces it with gstack
instead.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 .gitlab-ci.yml |   6 +-
 meson.build    |  11 +--
 test/litest.c  | 188 +++++++++----------------------------------------
 3 files changed, 38 insertions(+), 167 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2e4f0f649..e683e2252 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -41,9 +41,9 @@ variables:
   # See the documentation here:                                                 #
   # https://wayland.freedesktop.org/libinput/doc/latest/building_libinput.html  #
   ###############################################################################
-  FEDORA_RPMS: 'git gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark                          valgrind binutils libwacom-devel cairo-devel   gtk3-devel   glib2-devel    mtdev-devel'
-  UBUNTU_DEBS: 'git gcc g++     pkg-config         meson check       libudev-dev   libevdev-dev   doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme valgrind binutils libwacom-dev   libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev'
-  ARCH_PKGS:   'git gcc         pkgconfig          meson check       libsystemd    libevdev       doxygen graphviz  python-sphinx  python-recommonmark                          valgrind binutils libwacom                     gtk3                        mtdev      '
+  FEDORA_RPMS: 'git gcc gcc-c++ pkgconf-pkg-config meson check-devel libudev-devel libevdev-devel doxygen graphviz python3-sphinx python3-recommonmark                          valgrind libwacom-devel cairo-devel   gtk3-devel   glib2-devel    mtdev-devel'
+  UBUNTU_DEBS: 'git gcc g++     pkg-config         meson check       libudev-dev   libevdev-dev   doxygen graphviz python3-sphinx python3-recommonmark python3-sphinx-rtd-theme valgrind libwacom-dev   libcairo2-dev libgtk-3-dev libglib2.0-dev libmtdev-dev'
+  ARCH_PKGS:   'git gcc         pkgconfig          meson check       libsystemd    libevdev       doxygen graphviz  python-sphinx  python-recommonmark                          valgrind libwacom                     gtk3                        mtdev      '
   FREEBSD_BUILD_PKGS: 'meson'
   FREEBSD_PKGS: 'libepoll-shim                                       libudev-devd  libevdev                                          libwacom                     gtk3                        libmtdev   '
   ############################ end of package lists #############################
diff --git a/meson.build b/meson.build
index ac631312e..964c50c46 100644
--- a/meson.build
+++ b/meson.build
@@ -643,18 +643,12 @@ executable('test-build-cxx',
 if get_option('tests')
 	dep_check = dependency('check', version : '>= 0.9.10')
 	valgrind = find_program('valgrind')
-	addr2line = find_program('addr2line')
-
-	if addr2line.found()
-		config_h.set('HAVE_ADDR2LINE', '1')
-		config_h.set_quoted('ADDR2LINE', addr2line.path())
-	endif
 
 	leftover_rules = find_program('test/check-leftover-udev-rules.sh')
 	test('leftover-rules', leftover_rules, is_parallel : false)
 
-	dep_libunwind = dependency('libunwind', required : false)
-	config_h.set10('HAVE_LIBUNWIND', dep_libunwind.found())
+	gstack = find_program('gstack', required : false)
+	config_h.set10('HAVE_GSTACK', gstack.found())
 
 	# for inhibit support during test run
 	dep_libsystemd = dependency('libsystemd', version : '>= 221', required : false)
@@ -748,7 +742,6 @@ if get_option('tests')
 	deps_litest = [
 		dep_libinput,
 		dep_check,
-		dep_libunwind,
 		dep_udev,
 		dep_libevdev,
 		dep_dl,
diff --git a/test/litest.c b/test/litest.c
index 5c87db953..06c3a4655 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -102,175 +102,53 @@ static inline char *litest_install_quirks(struct list *created_files_list);
 #define litest_vlog(...) { /* __VA_ARGS__ */ }
 #endif
 
-#if HAVE_LIBUNWIND
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-#include <dlfcn.h>
-
-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;
-	unsigned int i;
-
-	if (!cwd[0]) {
-		if (getcwd(cwd, sizeof(cwd)) == NULL)
-			cwd[0] = 0; /* contents otherwise undefined. */
-	}
-
-	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] = '?';
-	if (fgets(buffer, sizeof(buffer), f) == NULL) {
-		pclose(f);
-		return false;
-	}
-	pclose(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(i < strlen(cwd) && *s != '\0' && 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)
 {
-	unw_cursor_t cursor;
-	unw_context_t context;
-	unw_word_t off;
-	unw_proc_info_t pip;
-	int ret;
-	char procname[256];
-	Dl_info dlinfo;
+#if HAVE_GSTACK
+	pid_t parent, child;
+	int pipefd[2];
 
-	pip.unwind_info = NULL;
-	ret = unw_getcontext(&context);
-	if (ret) {
-		litest_log("unw_getcontext failed: %s [%d]\n",
-			   unw_strerror(ret),
-			   ret);
+	if (pipe(pipefd) == -1)
 		return;
-	}
 
-	ret = unw_init_local(&cursor, &context);
-	if (ret) {
-		litest_log("unw_init_local failed: %s [%d]\n",
-			   unw_strerror(ret),
-			   ret);
-		return;
-	}
+	parent = getpid();
+	child = fork();
 
-	litest_log("\nBacktrace:\n");
-	ret = unw_step(&cursor);
-	while (ret > 0) {
-		char file[PATH_MAX];
-		int line;
-		bool have_lineno = false;
-		const char *filename = "?";
-		int i = 0;
+	if (child == 0) {
+		char pid[8];
 
-		ret = unw_get_proc_info(&cursor, &pip);
-		if (ret) {
-			litest_log("unw_get_proc_info failed: %s [%d]\n",
-				   unw_strerror(ret),
-				   ret);
-			break;
-		}
+		close(pipefd[0]);
+		dup2(pipefd[1], STDOUT_FILENO);
 
-		ret = unw_get_proc_name(&cursor, procname, 256, &off);
-		if (ret && ret != -UNW_ENOMEM) {
-			if (ret != -UNW_EUNSPEC)
-				litest_log("unw_get_proc_name failed: %s [%d]\n",
-					   unw_strerror(ret),
-					   ret);
-			procname[0] = '?';
-			procname[1] = 0;
-		}
+		sprintf(pid, "%d", parent);
 
-		if (dladdr((void *)(pip.start_ip + off), &dlinfo) &&
-		    dlinfo.dli_fname &&
-		    *dlinfo.dli_fname) {
-			filename = dlinfo.dli_fname;
-			have_lineno = litest_backtrace_get_lineno(filename,
-								  (pip.start_ip + off),
-								  file,
-								  &line);
-		}
+		execlp("gstack", "gstack", pid, NULL);
+		exit(errno);
+	}
 
-		if (have_lineno) {
-			litest_log("%d: %s() (%s:%d)\n",
-				   i,
-				   procname,
-				   file,
-				   line);
-		} else  {
-			litest_log("%d: %s (%s%s+%#x) [%p]\n",
-				   i,
-				   filename,
-				   procname,
-				   ret == -UNW_ENOMEM ? "..." : "",
-				   (int)off,
-				   (void *)(pip.start_ip + off));
+	/* parent */
+	char buf[1024];
+	int status, nread;
+
+	close(pipefd[1]);
+	waitpid(child, &status, 0);
+
+	status = WEXITSTATUS(status);
+	if (status != 0) {
+		litest_log("ERROR: gstack failed, no backtrace available: %s\n",
+			   strerror(status));
+	} else {
+		litest_log("\nBacktrace:\n");
+		while ((nread = read(pipefd[0], buf, sizeof(buf) - 1)) > 0) {
+			buf[nread] = '\0';
+			litest_log("%s", buf);
 		}
-
-		i++;
-		ret = unw_step(&cursor);
-		if (ret < 0)
-			litest_log("unw_step failed: %s [%d]\n",
-				   unw_strerror(ret),
-				   ret);
+		litest_log("\n");
 	}
-	litest_log("\n");
-}
-#else /* HAVE_LIBUNWIND */
-static inline void
-litest_backtrace(void)
-{
-	/* thou shall install libunwind */
-}
+	close(pipefd[0]);
 #endif
+}
 
 LIBINPUT_ATTRIBUTE_PRINTF(5, 6)
 __attribute__((noreturn))
-- 
2.17.1



More information about the wayland-devel mailing list