From f7b97d7482e5db7ed444b9aa10e0aadd13e3067c Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Tue, 3 Dec 2019 15:58:59 +0000 Subject: [PATCH] support stack unwinding on assert via Unwind Signed-off-by: Ivailo Monev --- .travis.yml | 2 +- CMakeLists.txt | 19 ++++++++++++++ cmake/modules/FindUnwind.cmake | 44 +++++++++++++++++++++++++++++++++ package/archlinux/PKGBUILD | 2 +- package/debian/control | 5 ++-- src/core/CMakeLists.txt | 9 +++++++ src/core/global/qconfig.h.cmake | 1 + src/core/global/qglobal.cpp | 38 ++++++++++++++++++++++++++++ src/tools/moc/CMakeLists.txt | 1 + 9 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 cmake/modules/FindUnwind.cmake diff --git a/.travis.yml b/.travis.yml index 1355e0d7c..7c7726f7c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ services: - xvfb before_install: - sudo apt-get update -qq - - sudo apt-get install -qq ninja-build libpcre3-dev libssl-dev zlib1g-dev libc6-dev libpng-dev libjpeg-dev libtiff-dev libmng-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev libicu-dev unixodbc-dev libpq-dev libpqtypes-dev libmysqld-dev libaio-dev libwrap0-dev liblz4-dev libsqlite3-dev xorg-dev + - sudo apt-get install -qq ninja-build libpcre3-dev libssl-dev zlib1g-dev libc6-dev libpng-dev libjpeg-dev libtiff-dev libmng-dev libcups2-dev libfreetype6-dev libfontconfig1-dev libdbus-1-dev libicu-dev unixodbc-dev libpq-dev libpqtypes-dev libmysqld-dev libaio-dev libwrap0-dev liblz4-dev libsqlite3-dev libunwind-dev xorg-dev - wget 'http://mirrors.kernel.org/ubuntu/pool/universe/libz/libzstd/libzstd1_1.3.1+dfsg-1~ubuntu0.16.04.1_amd64.deb' - wget 'http://mirrors.kernel.org/ubuntu/pool/universe/libz/libzstd/libzstd1-dev_1.3.1+dfsg-1~ubuntu0.16.04.1_amd64.deb' - sudo dpkg -i *.deb diff --git a/CMakeLists.txt b/CMakeLists.txt index b6419ff32..7ac3afdf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ if(NOT CMAKE_VERSION VERSION_LESS "3.3.0") endif() include(CheckIncludeFile) +include(CheckIncludeFileCXX) include(CheckTypeSize) include(FeatureSummary) include(KatieMacros) @@ -156,6 +157,9 @@ add_feature_info(resolv WITH_RESOLV "build resolv support") option(WITH_NSL "Build NSL support" ON) add_feature_info(nsl WITH_NSL "build NSL support") +option(WITH_UNWIND "Build Unwind support" ON) +add_feature_info(unwind WITH_UNWIND "build Unwind support") + # optional features option(KATIE_TESTS "Build automatic tests" OFF) add_feature_info(tests KATIE_TESTS "build automatic tests") @@ -203,6 +207,9 @@ if(KATIE_ALLINONE) add_definitions(-DQT_ALLINONE) endif() +# for symbols mangling while unwinding in core component +check_include_file_cxx(cxxabi.h HAVE_CXXABI) + # for 3rd party source used in test component check_include_file(sys/time.h HAVE_SYS_TIME_H) @@ -426,6 +433,14 @@ set_package_properties(MySQL PROPERTIES TYPE OPTIONAL ) +find_package(Unwind) +set_package_properties(Unwind PROPERTIES + PURPOSE "Required for stack traces on assert" + DESCRIPTION "A (mostly) platform-independent unwind API" + URL "https://www.nongnu.org/libunwind/index.html" + TYPE OPTIONAL +) + if(KATIE_TESTS OR KATIE_BENCHMARKS) message(WARNING "\nUnless it is intentionall you should not enable testing, deploying tests builds" @@ -494,6 +509,10 @@ if(NOT WITH_TIFF OR NOT TIFF_FOUND) katie_definition(-DQT_NO_IMAGEFORMAT_TIFF) endif() +if(NOT WITH_UNWIND OR NOT UNWIND_FOUND OR NOT HAVE_CXXABI) + katie_definition(-DQT_NO_UNWIND) +endif() + # conditional features if(NOT WITH_ACCESSIBILITY) katie_definition(-DQT_NO_ACCESSIBILITY) diff --git a/cmake/modules/FindUnwind.cmake b/cmake/modules/FindUnwind.cmake new file mode 100644 index 000000000..dd97306db --- /dev/null +++ b/cmake/modules/FindUnwind.cmake @@ -0,0 +1,44 @@ +# - Try to find Unwind +# Once done this will define +# +# UNWIND_FOUND - system has Unwind +# UNWIND_INCLUDES - the Unwind include directory +# UNWIND_LIBRARIES - the libraries needed to use Unwind +# +# Copyright (c) 2015-2019, Ivailo Monev, +# +# Redistribution and use is allowed according to the terms of the BSD license. + +if(UNWIND_INCLUDES AND UNWIND_LIBRARIES) + set(UNWIND_FIND_QUIETLY TRUE) +endif() + +if(NOT WIN32) + include(FindPkgConfig) + pkg_check_modules(PC_UNWIND QUIET libunwind) +endif() + +find_path(UNWIND_INCLUDES + NAMES + libunwind.h + HINTS + $ENV{UNWINDDIR}/include + ${PC_UNWIND_INCLUDEDIR} + ${INCLUDE_INSTALL_DIR} +) + +find_library(UNWIND_LIBRARIES + unwind + HINTS + $ENV{UNWINDDIR}/lib + ${PC_UNWIND_LIBDIR} + ${LIB_INSTALL_DIR} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Unwind + VERSION_VAR PC_UNWIND_VERSION + REQUIRED_VARS UNWIND_LIBRARIES UNWIND_INCLUDES +) + +mark_as_advanced(UNWIND_INCLUDES UNWIND_LIBRARIES) diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD index c65ae3d3e..975e0ef72 100644 --- a/package/archlinux/PKGBUILD +++ b/package/archlinux/PKGBUILD @@ -10,7 +10,7 @@ url='https://github.com/fluxer/katie' license=('LGPL' 'FDL' 'custom') depends=('openssl' 'zlib' 'cups' 'libice' 'libsm' 'pcre' 'libxcursor' 'icu' 'libxext' 'libxfixes' 'libxi' 'libxinerama' 'libxrandr' 'libxrender' - 'libx11' 'fontconfig' 'freetype2' 'libmng' 'zstd') + 'libx11' 'fontconfig' 'freetype2' 'libmng' 'zstd' 'libunwind') makedepends=('cmake' 'git' 'postgresql' 'libmariadbclient' 'unixodbc' 'unifdef') optdepends=('postgresql-libs: PostgreSQL driver' 'libmariadbclient: MariaDB driver' diff --git a/package/debian/control b/package/debian/control index 48ddcbd01..805f32736 100644 --- a/package/debian/control +++ b/package/debian/control @@ -10,12 +10,13 @@ Build-Depends: debhelper (>= 9~), g++, libssl-dev, zlib1g-dev, libzstd-dev, libc6-dev, libpng-dev, libjpeg-dev, libtiff5-dev, libmng-dev, libcups2-dev, libfreetype6-dev, libfontconfig1-dev, libpcre3-dev, libdbus-1-dev, unixodbc-dev, libpq-dev, libpqtypes-dev, libmariadbclient-dev, libicu-dev, - libmariadbd-dev, libaio-dev, libsqlite3-dev, xorg-dev, cmake, git + libmariadbd-dev, libaio-dev, libsqlite3-dev, xorg-dev, cmake, git, + libunwind-dev Package: katie-git Architecture: i386 amd64 Depends: ${shlibs:Depends}, ${misc:Depends}, openssl, zlib1g, libzstd1, libc6, libpng16-16, libjpeg62-turbo, libtiffxx5, libmng1, libcups2, libfreetype6, - libfontconfig1, libpcre3, libdbus-1-3, libsqlite3-0, libicu63 + libfontconfig1, libpcre3, libdbus-1-3, libsqlite3-0, libicu63, libunwind8 Recommends: unixodbc, libpq5, libmariadbclient, xorg Description: C++ toolkit derived from the Qt 4.8 framework diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1057e2e60..5a8c522c2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -259,6 +259,15 @@ if(WITH_THREADS AND THREADS_FOUND) ) endif() +if(WITH_UNWIND AND UNWIND_FOUND AND HAVE_CXXABI) + set(EXTRA_CORE_LIBS + ${EXTRA_CORE_LIBS} + ${UNWIND_LIBRARIES} + ) + include_directories(${UNWIND_INCLUDES}) +endif() + + set(CORE_HEADERS ${CORE_HEADERS} ${CMAKE_CURRENT_SOURCE_DIR}/qcorecommon_p.h diff --git a/src/core/global/qconfig.h.cmake b/src/core/global/qconfig.h.cmake index 85be51167..bfe8b8490 100644 --- a/src/core/global/qconfig.h.cmake +++ b/src/core/global/qconfig.h.cmake @@ -321,6 +321,7 @@ #cmakedefine QT_NO_UNDOSTACK #cmakedefine QT_NO_UNDOVIEW #cmakedefine QT_NO_UNSETENV +#cmakedefine QT_NO_UNWIND #cmakedefine QT_NO_URLINFO #cmakedefine QT_NO_URL_CAST_FROM_STRING #cmakedefine QT_NO_VALIDATOR diff --git a/src/core/global/qglobal.cpp b/src/core/global/qglobal.cpp index d15e75d7a..8e6440323 100644 --- a/src/core/global/qglobal.cpp +++ b/src/core/global/qglobal.cpp @@ -56,6 +56,12 @@ # include #endif +#ifndef QT_NO_UNWIND +# define UNW_LOCAL_ONLY +# include +# include +#endif + QT_BEGIN_NAMESPACE @@ -1352,11 +1358,42 @@ void qBadAlloc() QT_THROW(std::bad_alloc()); } +static inline void qt_print_backtrace() +{ +#ifndef QT_NO_UNWIND + unw_cursor_t cursor; + unw_context_t context; + + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + while (unw_step(&cursor) > 0) { + unw_word_t offset; + char sym[256]; + if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { + int status; + char* demangled = abi::__cxa_demangle(sym, nullptr, nullptr, &status); + if (status == 0) { + printf(" %s\n", demangled); + free(demangled); + } else { + printf(" %s\n", sym); + } + + + } else { + printf("qt_print_backtrace: unable to obtain symbol name for this frame\n"); + } + } +#endif +} + /* The Q_ASSERT macro calls this function when the test fails. */ void qt_assert(const char *assertion, const char *file, int line) { + qt_print_backtrace(); qFatal("ASSERT: \"%s\" in file %s, line %d", assertion, file, line); } @@ -1365,6 +1402,7 @@ void qt_assert(const char *assertion, const char *file, int line) */ void qt_assert_x(const char *where, const char *what, const char *file, int line) { + qt_print_backtrace(); qFatal("ASSERT failure in %s: \"%s\", file %s, line %d", where, what, file, line); } diff --git a/src/tools/moc/CMakeLists.txt b/src/tools/moc/CMakeLists.txt index ffc325619..9f67fb142 100644 --- a/src/tools/moc/CMakeLists.txt +++ b/src/tools/moc/CMakeLists.txt @@ -39,6 +39,7 @@ set(BOOTSTRAP_DEFINITIONS -DQT_NO_COMPRESS -DQT_NO_EXCEPTIONS -DQT_NO_REGEXP + -DQT_NO_UNWIND ) set(BOOTSTRAP_SOURCES