Support libbacktrace on Linux
We've supported libbacktrace as an optional dependency on Windows for a while now. At the same time, our backtrace implementation on Linux is very inefficient. Optionally use libbacktrace on Linux too, when requested at configure time. This is much less code and much faster at runtime, but we retain the old implementation as well for the time being so that we are not adding an additional mandatory dependency. Currently the LIBBACKTRACE option is off by default because installing libbacktrace is surprisingly difficult to do; most distros do not package it. It would be nice to enable it at least for the release builds so that end users on Linux get faster backtraces. That should be possible but I'm not attempting it yet. Using libbacktrace without debug info is useless, so enabling LIBBACKTRACE forces -g1 even on release builds in the Makefile.
This commit is contained in:
parent
b3c3acda8d
commit
25f6c3a67d
|
@ -25,6 +25,7 @@ concurrency:
|
|||
# - CMAKE=1
|
||||
# - LOCALIZE=0
|
||||
# - LTO=1
|
||||
# - LIBBACKTRACE=1 (on Linux and Windows)
|
||||
# - Tests with important mods enabled (Magiclysm)
|
||||
# - A clang-tidy run
|
||||
# - SANITIZE=address,undefined
|
||||
|
@ -85,7 +86,7 @@ jobs:
|
|||
cmake: 0
|
||||
localize: 1
|
||||
test-stage: 1
|
||||
native: linux64
|
||||
native: linux64
|
||||
archive-success: basic-build
|
||||
dont_skip_data_only_changes: 1
|
||||
title: Basic Build and Test (Clang 6, Ubuntu, Curses)
|
||||
|
@ -103,6 +104,7 @@ jobs:
|
|||
localize: 1
|
||||
gold: 1
|
||||
lto: 1
|
||||
libbacktrace: 1
|
||||
native: linux64
|
||||
title: GCC 9, Curses, LTO
|
||||
# ~850MB in a clean build
|
||||
|
@ -165,6 +167,7 @@ jobs:
|
|||
tiles: 1
|
||||
sound: 1
|
||||
localize: 1
|
||||
libbacktrace: 1
|
||||
title: GCC 11, Ubuntu cross-compile to MinGW-Win64, Tiles, Sound
|
||||
ldflags: -static-libgcc -static-libstdc++
|
||||
mxe_target: x86_64-w64-mingw32.static.gcc11
|
||||
|
@ -209,6 +212,7 @@ jobs:
|
|||
NATIVE: ${{ matrix.native }}
|
||||
GOLD: ${{ matrix.gold }}
|
||||
LTO: ${{ matrix.lto }}
|
||||
LIBBACKTRACE: ${{ matrix.libbacktrace }}
|
||||
RELEASE: ${{ matrix.release }}
|
||||
ARCHIVE_SUCCESS: ${{ matrix.archive-success }}
|
||||
CCACHE_LIMIT: ${{ matrix.ccache_limit }}
|
||||
|
|
12
Makefile
12
Makefile
|
@ -40,7 +40,7 @@
|
|||
# make LOCALIZE=0
|
||||
# Disable backtrace support, not available on all platforms
|
||||
# make BACKTRACE=0
|
||||
# Use libbacktrace. Only has effect if BACKTRACE=1. (currently only for MinGW builds)
|
||||
# Use libbacktrace. Only has effect if BACKTRACE=1. (currently only for MinGW and Linux builds)
|
||||
# make LIBBACKTRACE=1
|
||||
# Compile localization files for specified languages
|
||||
# make localization LANGUAGES="<lang_id_1>[ lang_id_2][ ...]"
|
||||
|
@ -398,7 +398,11 @@ ifeq ($(RELEASE), 1)
|
|||
OTHERS += $(RELEASE_FLAGS)
|
||||
DEBUG =
|
||||
ifndef DEBUG_SYMBOLS
|
||||
DEBUGSYMS =
|
||||
ifeq ($(LIBBACKTRACE), 1)
|
||||
DEBUGSYMS = -g1
|
||||
else
|
||||
DEBUGSYMS =
|
||||
endif
|
||||
endif
|
||||
DEFINES += -DRELEASE
|
||||
# Check for astyle or JSON regressions on release builds.
|
||||
|
@ -780,9 +784,6 @@ ifeq ($(TARGETSYSTEM),WINDOWS)
|
|||
LDFLAGS += -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lversion
|
||||
ifeq ($(BACKTRACE),1)
|
||||
LDFLAGS += -ldbghelp
|
||||
ifeq ($(LIBBACKTRACE),1)
|
||||
LDFLAGS += -lbacktrace
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -790,6 +791,7 @@ ifeq ($(BACKTRACE),1)
|
|||
DEFINES += -DBACKTRACE
|
||||
ifeq ($(LIBBACKTRACE),1)
|
||||
DEFINES += -DLIBBACKTRACE
|
||||
LDFLAGS += -lbacktrace
|
||||
endif
|
||||
endif
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ then
|
|||
-DCMAKE_BUILD_TYPE="$build_type" \
|
||||
-DTILES=${TILES:-0} \
|
||||
-DSOUND=${SOUND:-0} \
|
||||
-DLIBBACKTRACE=${LIBBACKTRACE:-0} \
|
||||
"${cmake_extra_opts[@]}" \
|
||||
..
|
||||
if [ -n "$CATA_CLANG_TIDY" ]
|
||||
|
@ -213,7 +214,7 @@ then
|
|||
# fills the log with nonsense.
|
||||
TERM=dumb ./gradlew assembleExperimentalRelease -Pj=$num_jobs -Plocalize=false -Pabi_arm_32=false -Pabi_arm_64=true -Pdeps=/home/travis/build/CleverRaven/Cataclysm-DDA/android/app/deps.zip
|
||||
else
|
||||
make -j "$num_jobs" RELEASE=1 CCACHE=1 CROSS="$CROSS_COMPILATION" LINTJSON=0
|
||||
make -j "$num_jobs" RELEASE=1 CCACHE=1 CROSS="$CROSS_COMPILATION" LINTJSON=0 LIBBACKTRACE="$LIBBACKTRACE"
|
||||
|
||||
export ASAN_OPTIONS=detect_odr_violation=1
|
||||
export UBSAN_OPTIONS=print_stacktrace=1
|
||||
|
|
|
@ -36,8 +36,15 @@ if [[ "$TRAVIS_EVENT_TYPE" == "pull_request" ]]; then
|
|||
fi
|
||||
|
||||
set -x
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
|
||||
$travis_retry sudo apt-get --yes install parallel
|
||||
if [[ "$LIBBACKTRACE" == "1" ]]; then
|
||||
git clone https://github.com/ianlancetaylor/libbacktrace.git
|
||||
(
|
||||
cd libbacktrace
|
||||
git checkout 4d2dd0b172f2c9192f83ba93425f868f2a13c553
|
||||
./configure
|
||||
make -j$(nproc)
|
||||
sudo make install
|
||||
)
|
||||
fi
|
||||
|
||||
if [ -n "${CODE_COVERAGE}" ]; then
|
||||
|
|
|
@ -129,12 +129,13 @@ if (TILES)
|
|||
target_link_libraries(cataclysm-tiles-common setupapi.lib)
|
||||
if (BACKTRACE)
|
||||
target_link_libraries(cataclysm-tiles-common dbghelp.lib)
|
||||
if (LIBBACKTRACE)
|
||||
target_link_libraries(cataclysm-tiles-common backtrace)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (LIBBACKTRACE)
|
||||
target_link_libraries(cataclysm-tiles-common backtrace)
|
||||
endif ()
|
||||
|
||||
if (RELEASE)
|
||||
install(TARGETS cataclysm-tiles DESTINATION ${BIN_PREFIX})
|
||||
endif ()
|
||||
|
@ -193,12 +194,13 @@ if (CURSES)
|
|||
target_link_libraries(cataclysm-common version.lib)
|
||||
if (BACKTRACE)
|
||||
target_link_libraries(cataclysm-common dbghelp.lib)
|
||||
if (LIBBACKTRACE)
|
||||
target_link_libraries(cataclysm-common backtrace)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (LIBBACKTRACE)
|
||||
target_link_libraries(cataclysm-tiles-common backtrace)
|
||||
endif ()
|
||||
|
||||
if (RELEASE)
|
||||
install(TARGETS cataclysm DESTINATION ${BIN_PREFIX})
|
||||
endif ()
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
# if defined(_WIN32)
|
||||
# include <dbghelp.h>
|
||||
# if defined(LIBBACKTRACE)
|
||||
# include <backtrace.h>
|
||||
# include <winnt.h>
|
||||
# endif
|
||||
# elif defined(__ANDROID__)
|
||||
|
@ -70,6 +69,10 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(LIBBACKTRACE)
|
||||
# include <backtrace.h>
|
||||
#endif
|
||||
|
||||
#if defined(TILES)
|
||||
#include "sdl_wrappers.h"
|
||||
#endif // TILES
|
||||
|
@ -806,7 +809,7 @@ static std::ostream &operator<<( std::ostream &out, DebugClass cl )
|
|||
}
|
||||
|
||||
#if defined(BACKTRACE)
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__ANDROID__)
|
||||
#if !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__ANDROID__) && !defined(LIBBACKTRACE)
|
||||
// Verify that a string is safe for passing as an argument to addr2line.
|
||||
// In particular, we want to avoid any characters of significance to the shell.
|
||||
static bool debug_is_safe_string( const char *start, const char *finish )
|
||||
|
@ -913,7 +916,7 @@ static cata::optional<uintptr_t> debug_compute_load_offset(
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(LIBBACKTRACE)
|
||||
#if defined(LIBBACKTRACE)
|
||||
// wrap libbacktrace to use std::function instead of function pointers
|
||||
using bt_error_callback = std::function<void( const char *, int )>;
|
||||
using bt_full_callback = std::function<int( uintptr_t, const char *, int, const char * )>;
|
||||
|
@ -930,6 +933,27 @@ static backtrace_state *bt_create_state( const char *const filename, const int t
|
|||
const_cast<bt_error_callback *>( &cb ) );
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
static int bt_full( backtrace_state *const state, int skip, const bt_full_callback &cb_full,
|
||||
const bt_error_callback &cb_error )
|
||||
{
|
||||
using cb_pair = std::pair<const bt_full_callback &, const bt_error_callback &>;
|
||||
cb_pair cb { cb_full, cb_error };
|
||||
return backtrace_full( state, skip,
|
||||
// backtrace callback
|
||||
[]( void *const data, const uintptr_t pc, const char *const filename,
|
||||
const int lineno, const char *const function ) -> int {
|
||||
cb_pair &cb = *reinterpret_cast<cb_pair *>( data );
|
||||
return cb.first( pc, filename, lineno, function );
|
||||
},
|
||||
// error callback
|
||||
[]( void *const data, const char *const msg, const int errnum ) {
|
||||
cb_pair &cb = *reinterpret_cast<cb_pair *>( data );
|
||||
cb.second( msg, errnum );
|
||||
},
|
||||
&cb );
|
||||
}
|
||||
#else
|
||||
static int bt_pcinfo( backtrace_state *const state, const uintptr_t pc,
|
||||
const bt_full_callback &cb_full, const bt_error_callback &cb_error )
|
||||
{
|
||||
|
@ -970,6 +994,7 @@ static int bt_syminfo( backtrace_state *const state, const uintptr_t addr,
|
|||
&cb );
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
class sym_init
|
||||
|
@ -1004,12 +1029,12 @@ struct backtrace_module_info_t {
|
|||
};
|
||||
static std::map<DWORD64, backtrace_module_info_t> bt_module_info_map;
|
||||
#endif
|
||||
#elif !defined(__ANDROID__)
|
||||
#elif !defined(__ANDROID__) && !defined(LIBBACKTRACE)
|
||||
static constexpr int bt_cnt = 20;
|
||||
static void *bt[bt_cnt];
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(__ANDROID__)
|
||||
#if !defined(_WIN32) && !defined(__ANDROID__) && !defined(LIBBACKTRACE)
|
||||
static void write_demangled_frame( std::ostream &out, const char *frame )
|
||||
{
|
||||
#if defined(__linux__)
|
||||
|
@ -1062,6 +1087,23 @@ static void write_demangled_frame( std::ostream &out, const char *frame )
|
|||
#if !defined(__ANDROID__)
|
||||
void debug_write_backtrace( std::ostream &out )
|
||||
{
|
||||
#if defined(LIBBACKTRACE)
|
||||
auto bt_full_print = [&out]( const uintptr_t pc, const char *const filename,
|
||||
const int lineno, const char *const function ) -> int {
|
||||
std::string file = filename ? filename : "[unknown src]";
|
||||
size_t src = file.find( "/src/" );
|
||||
if( src != std::string::npos )
|
||||
{
|
||||
file.erase( 0, src );
|
||||
file = "…" + file;
|
||||
}
|
||||
out << "\n 0x" << std::hex << pc << std::dec
|
||||
<< " " << file << ":" << lineno
|
||||
<< " " << ( function ? demangle( function ) : "[unknown func]" );
|
||||
return 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
if( !sym_init_ ) {
|
||||
sym_init_ = std::make_unique<sym_init>();
|
||||
|
@ -1143,18 +1185,8 @@ void debug_write_backtrace( std::ostream &out )
|
|||
<< ", msg = " << ( msg ? msg : "[no msg]" )
|
||||
<< "),";
|
||||
} );
|
||||
bt_pcinfo( bt_module_info.state, de_aslr_pc,
|
||||
// backtrace callback
|
||||
[&out]( const uintptr_t pc, const char *const filename,
|
||||
const int lineno, const char *const function ) -> int {
|
||||
out << "\n (libbacktrace: 0x" << std::hex << pc << std::dec
|
||||
<< " " << ( filename ? filename : "[unknown src]" )
|
||||
<< ":" << lineno
|
||||
<< " " << ( function ? function : "[unknown func]" )
|
||||
<< "),";
|
||||
return 0;
|
||||
},
|
||||
// error callback
|
||||
bt_pcinfo( bt_module_info.state, de_aslr_pc, bt_full_print,
|
||||
// error callback
|
||||
[&out]( const char *const msg, const int errnum ) {
|
||||
out << "\n (backtrace_pcinfo failed: errno = " << errnum
|
||||
<< ", msg = " << ( msg ? msg : "[no msg]" )
|
||||
|
@ -1165,7 +1197,18 @@ void debug_write_backtrace( std::ostream &out )
|
|||
}
|
||||
out << "\n";
|
||||
#else
|
||||
# if defined(__CYGWIN__)
|
||||
# if defined(LIBBACKTRACE)
|
||||
auto bt_error = [&out]( const char *err_msg, int errnum ) {
|
||||
out << "\n libbacktrace error " << errnum << ": " << err_msg;
|
||||
};
|
||||
static backtrace_state *bt_state = bt_create_state( nullptr, 0, bt_error );
|
||||
if( bt_state ) {
|
||||
bt_full( bt_state, 0, bt_full_print, bt_error );
|
||||
out << std::endl;
|
||||
} else {
|
||||
out << "\n\n Failed to initialize libbacktrace\n";
|
||||
}
|
||||
# elif defined(__CYGWIN__)
|
||||
// BACKTRACE is not supported under CYGWIN!
|
||||
( void ) out;
|
||||
# else
|
||||
|
|
Loading…
Reference in New Issue