Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package backward-cpp for openSUSE:Factory checked in at 2022-09-29 18:12:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/backward-cpp (Old) and /work/SRC/openSUSE:Factory/.backward-cpp.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "backward-cpp" Thu Sep 29 18:12:04 2022 rev:4 rq:1006501 version:1.6 Changes: -------- --- /work/SRC/openSUSE:Factory/backward-cpp/backward-cpp.changes 2021-02-16 09:19:26.563204598 +0100 +++ /work/SRC/openSUSE:Factory/.backward-cpp.new.2275/backward-cpp.changes 2022-09-29 18:12:16.599128593 +0200 @@ -1,0 +2,13 @@ +Tue Sep 27 17:19:31 UTC 2022 - Stefan Br??ns <stefan.bru...@rwth-aachen.de> + +- Update to version 1.6 + * RISC-V mcontext. + * Support for Apple Silicon. + * libunwind for Linux and macOS. + * C++17 compatibility. + * Various bug fixes +- Enable unit tests +- Change the devel package architecture to noarch, backward-cpp is + a header-only library. + +------------------------------------------------------------------- Old: ---- backward-cpp-1.5.tar.gz New: ---- backward-cpp-1.6.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ backward-cpp.spec ++++++ --- /var/tmp/diff_new_pack.M8vH66/_old 2022-09-29 18:12:17.143129656 +0200 +++ /var/tmp/diff_new_pack.M8vH66/_new 2022-09-29 18:12:17.147129665 +0200 @@ -1,7 +1,7 @@ # # spec file for package backward-cpp # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: backward-cpp -Version: 1.5 +Version: 1.6 Release: 0 Summary: Stack trace printer for C++ License: MIT @@ -34,6 +34,8 @@ %package devel Summary: Development files for backward-cpp Group: Development/Libraries/C and C++ +# backward-cpp is a header only library +BuildArch: noarch %description devel Development files for backward-cpp, a stack trace printer for C++. @@ -42,19 +44,22 @@ %autosetup -n backward-cpp-%{version} %build -%cmake -DCMAKE_INSTALL_LIBDIR=%{_libdir} +# LIBDIR is only used for the CMake Config files, and +# <prefix>/share/<name*> is a valid location +%cmake -DCMAKE_INSTALL_LIBDIR=%{_datadir} %cmake_build %install %cmake_install -%files -%license LICENSE.txt -%doc README.md +%check +%ctest %files devel +%license LICENSE.txt +%doc README.md %{_includedir}/backward.hpp -%{_libdir}/backward -%{_libdir}/backward/BackwardConfig.cmake +%{_datadir}/backward +%{_datadir}/backward/BackwardConfig.cmake %changelog ++++++ backward-cpp-1.5.tar.gz -> backward-cpp-1.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backward-cpp-1.5/BackwardConfig.cmake new/backward-cpp-1.6/BackwardConfig.cmake --- old/backward-cpp-1.5/BackwardConfig.cmake 2020-04-14 04:24:48.000000000 +0200 +++ new/backward-cpp-1.6/BackwardConfig.cmake 2021-08-13 00:49:08.000000000 +0200 @@ -28,6 +28,8 @@ "Use compiler's unwind API") set(STACK_WALKING_BACKTRACE FALSE CACHE BOOL "Use backtrace from (e)glibc for stack walking") +set(STACK_WALKING_LIBUNWIND FALSE CACHE BOOL + "Use libunwind for stack walking") set(STACK_DETAILS_AUTO_DETECT TRUE CACHE BOOL "Auto detect backward's stack details dependencies") @@ -50,16 +52,47 @@ ############################################################################### # CONFIGS ############################################################################### -if (${STACK_DETAILS_AUTO_DETECT}) - include(FindPackageHandleStandardArgs) +include(FindPackageHandleStandardArgs) + +if (STACK_WALKING_LIBUNWIND) + # libunwind works on the macOS without having to add special include + # paths or libraries + if (NOT APPLE) + find_path(LIBUNWIND_INCLUDE_DIR NAMES "libunwind.h") + find_library(LIBUNWIND_LIBRARY unwind) + + if (LIBUNWIND_LIBRARY) + include(CheckSymbolExists) + check_symbol_exists(UNW_INIT_SIGNAL_FRAME libunwind.h HAVE_UNW_INIT_SIGNAL_FRAME) + if (NOT HAVE_UNW_INIT_SIGNAL_FRAME) + message(STATUS "libunwind does not support unwinding from signal handler frames") + endif() + endif() + + set(LIBUNWIND_INCLUDE_DIRS ${LIBUNWIND_INCLUDE_DIR}) + set(LIBDWARF_LIBRARIES ${LIBUNWIND_LIBRARY}) + find_package_handle_standard_args(libunwind DEFAULT_MSG + LIBUNWIND_LIBRARY LIBUNWIND_INCLUDE_DIR) + mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARY) + list(APPEND _BACKWARD_LIBRARIES ${LIBUNWIND_LIBRARY}) + endif() + + # Disable other unwinders if libunwind is found + set(STACK_WALKING_UNWIND FALSE) + set(STACK_WALKING_BACKTRACE FALSE) +endif() +if (${STACK_DETAILS_AUTO_DETECT}) + if(NOT CMAKE_VERSION VERSION_LESS 3.17) + set(_name_mismatched_arg NAME_MISMATCHED) + endif() # find libdw find_path(LIBDW_INCLUDE_DIR NAMES "elfutils/libdw.h" "elfutils/libdwfl.h") find_library(LIBDW_LIBRARY dw) set(LIBDW_INCLUDE_DIRS ${LIBDW_INCLUDE_DIR} ) set(LIBDW_LIBRARIES ${LIBDW_LIBRARY} ) - find_package_handle_standard_args(libdw DEFAULT_MSG - LIBDW_LIBRARY LIBDW_INCLUDE_DIR) + find_package_handle_standard_args(libdw ${_name_mismatched_arg} + REQUIRED_VARS LIBDW_LIBRARY LIBDW_INCLUDE_DIR) mark_as_advanced(LIBDW_INCLUDE_DIR LIBDW_LIBRARY) # find libbfd @@ -69,8 +102,8 @@ find_library(LIBDL_LIBRARY dl) set(LIBBFD_INCLUDE_DIRS ${LIBBFD_INCLUDE_DIR} ${LIBDL_INCLUDE_DIR}) set(LIBBFD_LIBRARIES ${LIBBFD_LIBRARY} ${LIBDL_LIBRARY}) - find_package_handle_standard_args(libbfd DEFAULT_MSG - LIBBFD_LIBRARY LIBBFD_INCLUDE_DIR + find_package_handle_standard_args(libbfd ${_name_mismatched_arg} + REQUIRED_VARS LIBBFD_LIBRARY LIBBFD_INCLUDE_DIR LIBDL_LIBRARY LIBDL_INCLUDE_DIR) mark_as_advanced(LIBBFD_INCLUDE_DIR LIBBFD_LIBRARY LIBDL_INCLUDE_DIR LIBDL_LIBRARY) @@ -84,8 +117,8 @@ find_library(LIBDL_LIBRARY dl) set(LIBDWARF_INCLUDE_DIRS ${LIBDWARF_INCLUDE_DIR} ${LIBELF_INCLUDE_DIR} ${LIBDL_INCLUDE_DIR}) set(LIBDWARF_LIBRARIES ${LIBDWARF_LIBRARY} ${LIBELF_LIBRARY} ${LIBDL_LIBRARY}) - find_package_handle_standard_args(libdwarf DEFAULT_MSG - LIBDWARF_LIBRARY LIBDWARF_INCLUDE_DIR + find_package_handle_standard_args(libdwarf ${_name_mismatched_arg} + REQUIRED_VARS LIBDWARF_LIBRARY LIBDWARF_INCLUDE_DIR LIBELF_LIBRARY LIBELF_INCLUDE_DIR LIBDL_LIBRARY LIBDL_INCLUDE_DIR) mark_as_advanced(LIBDWARF_INCLUDE_DIR LIBDWARF_LIBRARY @@ -152,10 +185,18 @@ endmacro() if (NOT _BACKWARD_DEFINITIONS) - map_definitions("STACK_WALKING_" "BACKWARD_HAS_" UNWIND BACKTRACE) + map_definitions("STACK_WALKING_" "BACKWARD_HAS_" UNWIND LIBUNWIND BACKTRACE) map_definitions("STACK_DETAILS_" "BACKWARD_HAS_" BACKTRACE_SYMBOL DW BFD DWARF) endif() +if(WIN32) + list(APPEND _BACKWARD_LIBRARIES dbghelp psapi) + if(MINGW) + set(MINGW_MSVCR_LIBRARY "msvcr90$<$<CONFIG:DEBUG>:d>" CACHE STRING "Mingw MSVC runtime import library") + list(APPEND _BACKWARD_LIBRARIES ${MINGW_MSVCR_LIBRARY}) + endif() +endif() + set(BACKWARD_INCLUDE_DIR "${CMAKE_CURRENT_LIST_DIR}") set(BACKWARD_HAS_EXTERNAL_LIBRARIES FALSE) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backward-cpp-1.5/README.md new/backward-cpp-1.6/README.md --- old/backward-cpp-1.5/README.md 2020-04-14 04:24:48.000000000 +0200 +++ new/backward-cpp-1.6/README.md 2021-08-13 00:49:08.000000000 +0200 @@ -1,4 +1,4 @@ -Backward-cpp [](http://www.conan.io/source/backward/1.3.0/Manu343726/testing) [](https://travis-ci.org/bombela/backward-cpp) +Backward-cpp [](http://www.conan.io/source/backward/1.3.0/Manu343726/testing) ============ Backward is a beautiful stack trace pretty printer for C++. @@ -37,7 +37,9 @@ `backward.cpp` to your project, and don't forget to tell your build system. The code in `backward.cpp` is trivial anyway, you can simply copy what it's -doing at your convenience. +doing at your convenience. + +Note for [folly](https://github.com/facebook/folly) library users: must define `backward::SignalHandling sh;` after `folly::init(&argc, &argv);`. ## Configuration & Dependencies @@ -93,6 +95,35 @@ # through an IMPORTED target. target_link_libraries(mytarget PUBLIC Backward::Backward) ``` +### Libraries to unwind the stack + +On Linux and macOS, backtrace can back-trace or "walk" the stack using the +following libraries: + +#### unwind + +Unwind comes from libgcc, but there is an equivalent inside clang itself. With +unwind, the stacktrace is as accurate as it can possibly be, since this is +used by the C++ runtine in gcc/clang for stack unwinding on exception. + +Normally libgcc is already linked to your program by default. + +#### libunwind from the [libunwind project](https://github.com/libunwind/libunwind) + + apt-get install binutils-dev (or equivalent) + +Libunwind provides, in some cases, a more accurate stacktrace as it knows +to decode signal handler frames and lets us edit the context registers when +unwinding, allowing stack traces over bad function references. + +For best results make sure you are using libunwind 1.3 or later, which added +`unw_init_local2` and support for handling signal frames. + +CMake will warn you when configuring if your libunwind version doesn't support +signal frames. + +On macOS clang provides a libunwind API compatible library as part of its +environment, so no third party libraries are necessary. ### Compile with debug info @@ -110,17 +141,17 @@ ### Libraries to read the debug info -Backward support pretty printed stack traces on GNU/Linux only, it will compile -fine under other platforms but will not do anything. **Pull requests are -welcome :)** +Backward supports pretty printed stack traces on GNU/Linux, macOS and Windows, +it will compile fine under other platforms but will not do anything. **Pull +requests are welcome :)** Also, by default you will get a really basic stack trace, based on the `backtrace_symbols` API:  -You will need to install some dependencies to get the ultimate stack trace. Two -libraries are currently supported, the only difference is which one is the +You will need to install some dependencies to get the ultimate stack trace. +Three libraries are currently supported, the only difference is which one is the easiest for you to install, so pick your poison: #### libbfd from the [GNU/binutils](http://www.gnu.org/software/binutils/) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backward-cpp-1.5/backward.cpp new/backward-cpp-1.6/backward.cpp --- old/backward-cpp-1.5/backward.cpp 2020-04-14 04:24:48.000000000 +0200 +++ new/backward-cpp-1.6/backward.cpp 2021-08-13 00:49:08.000000000 +0200 @@ -11,7 +11,7 @@ // - line and column numbers // - source code snippet (assuming the file is accessible) -// Install one of the following library then uncomment one of the macro (or +// Install one of the following libraries then uncomment one of the macro (or // better, add the detection of the lib and the macro definition in your build // system) @@ -23,6 +23,16 @@ // - g++/clang++ -lbfd ... // #define BACKWARD_HAS_BFD 1 +// - apt-get install libdwarf-dev ... +// - g++/clang++ -ldwarf ... +// #define BACKWARD_HAS_DWARF 1 + +// Regardless of the library you choose to read the debug information, +// for potentially more detailed stack traces you can use libunwind +// - apt-get install libunwind-dev +// - g++/clang++ -lunwind +// #define BACKWARD_HAS_LIBUNWIND 1 + #include "backward.hpp" namespace backward { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backward-cpp-1.5/backward.hpp new/backward-cpp-1.6/backward.hpp --- old/backward-cpp-1.5/backward.hpp 2020-04-14 04:24:48.000000000 +0200 +++ new/backward-cpp-1.6/backward.hpp 2021-08-13 00:49:08.000000000 +0200 @@ -35,6 +35,9 @@ #define BACKWARD_CXX11 #define BACKWARD_ATLEAST_CXX11 #define BACKWARD_ATLEAST_CXX98 +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +#define BACKWARD_ATLEAST_CXX17 +#endif #else #define BACKWARD_CXX98 #define BACKWARD_ATLEAST_CXX98 @@ -49,6 +52,9 @@ // #define BACKWARD_SYSTEM_DARWIN // - specialization for Mac OS X 10.5 and later. // +// #define BACKWARD_SYSTEM_WINDOWS +// - specialization for Windows (Clang 9 and MSVC2017) +// // #define BACKWARD_SYSTEM_UNKNOWN // - placebo implementation, does nothing. // @@ -84,6 +90,8 @@ #include <streambuf> #include <string> #include <vector> +#include <exception> +#include <iterator> #if defined(BACKWARD_SYSTEM_LINUX) @@ -97,6 +105,11 @@ // exception. // - normally libgcc is already linked to your program by default. // +// #define BACKWARD_HAS_LIBUNWIND 1 +// - libunwind provides, in some cases, a more accurate stacktrace as it knows +// to decode signal handler frames and lets us edit the context registers when +// unwinding, allowing stack traces over bad function references. +// // #define BACKWARD_HAS_BACKTRACE == 1 // - backtrace seems to be a little bit more portable than libunwind, but on // linux, it uses unwind anyway, but abstract away a tiny information that is @@ -109,10 +122,13 @@ // Note that only one of the define should be set to 1 at a time. // #if BACKWARD_HAS_UNWIND == 1 +#elif BACKWARD_HAS_LIBUNWIND == 1 #elif BACKWARD_HAS_BACKTRACE == 1 #else #undef BACKWARD_HAS_UNWIND #define BACKWARD_HAS_UNWIND 1 +#undef BACKWARD_HAS_LIBUNWIND +#define BACKWARD_HAS_LIBUNWIND 0 #undef BACKWARD_HAS_BACKTRACE #define BACKWARD_HAS_BACKTRACE 0 #endif @@ -125,9 +141,10 @@ // - object filename // - function name // - source filename -// - line and column numbers -// - source code snippet (assuming the file is accessible) -// - variables name and values (if not optimized out) +// - line and column numbers +// - source code snippet (assuming the file is accessible) +// - variable names (if not optimized out) +// - variable values (not supported by backward-cpp) // - You need to link with the lib "dw": // - apt-get install libdw-dev // - g++/clang++ -ldw ... @@ -137,8 +154,8 @@ // - object filename // - function name // - source filename -// - line numbers -// - source code snippet (assuming the file is accessible) +// - line numbers +// - source code snippet (assuming the file is accessible) // - You need to link with the lib "bfd": // - apt-get install binutils-dev // - g++/clang++ -lbfd ... @@ -150,7 +167,8 @@ // - source filename // - line and column numbers // - source code snippet (assuming the file is accessible) -// - variables name and values (if not optimized out) +// - variable names (if not optimized out) +// - variable values (not supported by backward-cpp) // - You need to link with the lib "dwarf": // - apt-get install libdwarf-dev // - g++/clang++ -ldwarf ... @@ -257,6 +275,12 @@ // exception. // - normally libgcc is already linked to your program by default. // +// #define BACKWARD_HAS_LIBUNWIND 1 +// - libunwind comes from clang, which implements an API compatible version. +// - libunwind provides, in some cases, a more accurate stacktrace as it knows +// to decode signal handler frames and lets us edit the context registers when +// unwinding, allowing stack traces over bad function references. +// // #define BACKWARD_HAS_BACKTRACE == 1 // - backtrace is available by default, though it does not produce as much // information as another library might. @@ -268,11 +292,14 @@ // #if BACKWARD_HAS_UNWIND == 1 #elif BACKWARD_HAS_BACKTRACE == 1 +#elif BACKWARD_HAS_LIBUNWIND == 1 #else #undef BACKWARD_HAS_UNWIND #define BACKWARD_HAS_UNWIND 1 #undef BACKWARD_HAS_BACKTRACE #define BACKWARD_HAS_BACKTRACE 0 +#undef BACKWARD_HAS_LIBUNWIND +#define BACKWARD_HAS_LIBUNWIND 0 #endif // On Darwin, backward can extract detailed information about a stack trace @@ -310,14 +337,16 @@ #include <mutex> #include <thread> -#include <BaseTsd.h> +#include <basetsd.h> typedef SSIZE_T ssize_t; +#ifndef NOMINMAX #define NOMINMAX -#include <Windows.h> +#endif +#include <windows.h> #include <winnt.h> -#include <Psapi.h> +#include <psapi.h> #include <signal.h> #ifndef __clang__ @@ -325,8 +354,10 @@ #define NOINLINE __declspec(noinline) #endif +#ifdef _MSC_VER #pragma comment(lib, "psapi.lib") #pragma comment(lib, "dbghelp.lib") +#endif // Comment / packing is from stackoverflow: // https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app/28276227#28276227 @@ -371,6 +402,11 @@ #endif // BACKWARD_HAS_UNWIND == 1 +#if BACKWARD_HAS_LIBUNWIND == 1 +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#endif // BACKWARD_HAS_LIBUNWIND == 1 + #ifdef BACKWARD_ATLEAST_CXX11 #include <unordered_map> #include <utility> // for std::swap @@ -530,7 +566,7 @@ void update(T new_val) { _val = new_val; - _empty = static_cast<bool>(new_val); + _empty = !static_cast<bool>(new_val); } operator const dummy *() const { @@ -609,9 +645,9 @@ std::vector<std::string> out; size_t last = 0; size_t next = 0; - size_t delimiter_size = sizeof(kBackwardPathDelimiter)-1; + size_t delimiter_size = sizeof(kBackwardPathDelimiter) - 1; while ((next = s.find(kBackwardPathDelimiter, last)) != std::string::npos) { - out.push_back(s.substr(last, next-last)); + out.push_back(s.substr(last, next - last)); last = next + delimiter_size; } if (last <= s.length()) { @@ -682,14 +718,17 @@ size_t size() const { return 0; } Trace operator[](size_t) const { return Trace(); } size_t load_here(size_t = 0) { return 0; } - size_t load_from(void *, size_t = 0) { return 0; } + size_t load_from(void *, size_t = 0, void * = nullptr, void * = nullptr) { + return 0; + } size_t thread_id() const { return 0; } void skip_n_firsts(size_t) {} }; class StackTraceImplBase { public: - StackTraceImplBase() : _thread_id(0), _skip(0) {} + StackTraceImplBase() + : _thread_id(0), _skip(0), _context(nullptr), _error_addr(nullptr) {} size_t thread_id() const { return _thread_id; } @@ -717,17 +756,27 @@ #endif } + void set_context(void *context) { _context = context; } + void *context() const { return _context; } + + void set_error_addr(void *error_addr) { _error_addr = error_addr; } + void *error_addr() const { return _error_addr; } + size_t skip_n_firsts() const { return _skip; } private: size_t _thread_id; size_t _skip; + void *_context; + void *_error_addr; }; class StackTraceImplHolder : public StackTraceImplBase { public: size_t size() const { - return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0; + return (_stacktrace.size() >= skip_n_firsts()) + ? _stacktrace.size() - skip_n_firsts() + : 0; } Trace operator[](size_t idx) const { if (idx >= size()) { @@ -808,8 +857,11 @@ class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder { public: NOINLINE - size_t load_here(size_t depth = 32) { + size_t load_here(size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { load_thread_info(); + set_context(context); + set_error_addr(error_addr); if (depth == 0) { return 0; } @@ -819,8 +871,9 @@ skip_n_firsts(0); return size(); } - size_t load_from(void *addr, size_t depth = 32) { - load_here(depth + 8); + size_t load_from(void *addr, size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { + load_here(depth + 8, context, error_addr); for (size_t i = 0; i < _stacktrace.size(); ++i) { if (_stacktrace[i] == addr) { @@ -842,13 +895,193 @@ }; }; +#elif BACKWARD_HAS_LIBUNWIND == 1 + +template <> +class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder { +public: + __attribute__((noinline)) size_t load_here(size_t depth = 32, + void *_context = nullptr, + void *_error_addr = nullptr) { + set_context(_context); + set_error_addr(_error_addr); + load_thread_info(); + if (depth == 0) { + return 0; + } + _stacktrace.resize(depth + 1); + + int result = 0; + + unw_context_t ctx; + size_t index = 0; + + // Add the tail call. If the Instruction Pointer is the crash address it + // means we got a bad function pointer dereference, so we "unwind" the + // bad pointer manually by using the return address pointed to by the + // Stack Pointer as the Instruction Pointer and letting libunwind do + // the rest + + if (context()) { + ucontext_t *uctx = reinterpret_cast<ucontext_t *>(context()); +#ifdef REG_RIP // x86_64 + if (uctx->uc_mcontext.gregs[REG_RIP] == + reinterpret_cast<greg_t>(error_addr())) { + uctx->uc_mcontext.gregs[REG_RIP] = + *reinterpret_cast<size_t *>(uctx->uc_mcontext.gregs[REG_RSP]); + } + _stacktrace[index] = + reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_RIP]); + ++index; + ctx = *reinterpret_cast<unw_context_t *>(uctx); +#elif defined(REG_EIP) // x86_32 + if (uctx->uc_mcontext.gregs[REG_EIP] == + reinterpret_cast<greg_t>(error_addr())) { + uctx->uc_mcontext.gregs[REG_EIP] = + *reinterpret_cast<size_t *>(uctx->uc_mcontext.gregs[REG_ESP]); + } + _stacktrace[index] = + reinterpret_cast<void *>(uctx->uc_mcontext.gregs[REG_EIP]); + ++index; + ctx = *reinterpret_cast<unw_context_t *>(uctx); +#elif defined(__arm__) + // libunwind uses its own context type for ARM unwinding. + // Copy the registers from the signal handler's context so we can + // unwind + unw_getcontext(&ctx); + ctx.regs[UNW_ARM_R0] = uctx->uc_mcontext.arm_r0; + ctx.regs[UNW_ARM_R1] = uctx->uc_mcontext.arm_r1; + ctx.regs[UNW_ARM_R2] = uctx->uc_mcontext.arm_r2; + ctx.regs[UNW_ARM_R3] = uctx->uc_mcontext.arm_r3; + ctx.regs[UNW_ARM_R4] = uctx->uc_mcontext.arm_r4; + ctx.regs[UNW_ARM_R5] = uctx->uc_mcontext.arm_r5; + ctx.regs[UNW_ARM_R6] = uctx->uc_mcontext.arm_r6; + ctx.regs[UNW_ARM_R7] = uctx->uc_mcontext.arm_r7; + ctx.regs[UNW_ARM_R8] = uctx->uc_mcontext.arm_r8; + ctx.regs[UNW_ARM_R9] = uctx->uc_mcontext.arm_r9; + ctx.regs[UNW_ARM_R10] = uctx->uc_mcontext.arm_r10; + ctx.regs[UNW_ARM_R11] = uctx->uc_mcontext.arm_fp; + ctx.regs[UNW_ARM_R12] = uctx->uc_mcontext.arm_ip; + ctx.regs[UNW_ARM_R13] = uctx->uc_mcontext.arm_sp; + ctx.regs[UNW_ARM_R14] = uctx->uc_mcontext.arm_lr; + ctx.regs[UNW_ARM_R15] = uctx->uc_mcontext.arm_pc; + + // If we have crashed in the PC use the LR instead, as this was + // a bad function dereference + if (reinterpret_cast<unsigned long>(error_addr()) == + uctx->uc_mcontext.arm_pc) { + ctx.regs[UNW_ARM_R15] = + uctx->uc_mcontext.arm_lr - sizeof(unsigned long); + } + _stacktrace[index] = reinterpret_cast<void *>(ctx.regs[UNW_ARM_R15]); + ++index; +#elif defined(__APPLE__) && defined(__x86_64__) + unw_getcontext(&ctx); + // OS X's implementation of libunwind uses its own context object + // so we need to convert the passed context to libunwind's format + // (information about the data layout taken from unw_getcontext.s + // in Apple's libunwind source + ctx.data[0] = uctx->uc_mcontext->__ss.__rax; + ctx.data[1] = uctx->uc_mcontext->__ss.__rbx; + ctx.data[2] = uctx->uc_mcontext->__ss.__rcx; + ctx.data[3] = uctx->uc_mcontext->__ss.__rdx; + ctx.data[4] = uctx->uc_mcontext->__ss.__rdi; + ctx.data[5] = uctx->uc_mcontext->__ss.__rsi; + ctx.data[6] = uctx->uc_mcontext->__ss.__rbp; + ctx.data[7] = uctx->uc_mcontext->__ss.__rsp; + ctx.data[8] = uctx->uc_mcontext->__ss.__r8; + ctx.data[9] = uctx->uc_mcontext->__ss.__r9; + ctx.data[10] = uctx->uc_mcontext->__ss.__r10; + ctx.data[11] = uctx->uc_mcontext->__ss.__r11; + ctx.data[12] = uctx->uc_mcontext->__ss.__r12; + ctx.data[13] = uctx->uc_mcontext->__ss.__r13; + ctx.data[14] = uctx->uc_mcontext->__ss.__r14; + ctx.data[15] = uctx->uc_mcontext->__ss.__r15; + ctx.data[16] = uctx->uc_mcontext->__ss.__rip; + + // If the IP is the same as the crash address we have a bad function + // dereference The caller's address is pointed to by %rsp, so we + // dereference that value and set it to be the next frame's IP. + if (uctx->uc_mcontext->__ss.__rip == + reinterpret_cast<__uint64_t>(error_addr())) { + ctx.data[16] = + *reinterpret_cast<__uint64_t *>(uctx->uc_mcontext->__ss.__rsp); + } + _stacktrace[index] = reinterpret_cast<void *>(ctx.data[16]); + ++index; +#elif defined(__APPLE__) + unw_getcontext(&ctx) + // TODO: Convert the ucontext_t to libunwind's unw_context_t like + // we do in 64 bits + if (ctx.uc_mcontext->__ss.__eip == + reinterpret_cast<greg_t>(error_addr())) { + ctx.uc_mcontext->__ss.__eip = ctx.uc_mcontext->__ss.__esp; + } + _stacktrace[index] = + reinterpret_cast<void *>(ctx.uc_mcontext->__ss.__eip); + ++index; +#endif + } + + unw_cursor_t cursor; + if (context()) { +#if defined(UNW_INIT_SIGNAL_FRAME) + result = unw_init_local2(&cursor, &ctx, UNW_INIT_SIGNAL_FRAME); +#else + result = unw_init_local(&cursor, &ctx); +#endif + } else { + unw_getcontext(&ctx); + ; + result = unw_init_local(&cursor, &ctx); + } + + if (result != 0) + return 1; + + unw_word_t ip = 0; + + while (index <= depth && unw_step(&cursor) > 0) { + result = unw_get_reg(&cursor, UNW_REG_IP, &ip); + if (result == 0) { + _stacktrace[index] = reinterpret_cast<void *>(--ip); + ++index; + } + } + --index; + + _stacktrace.resize(index + 1); + skip_n_firsts(0); + return size(); + } + + size_t load_from(void *addr, size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { + load_here(depth + 8, context, error_addr); + + for (size_t i = 0; i < _stacktrace.size(); ++i) { + if (_stacktrace[i] == addr) { + skip_n_firsts(i); + _stacktrace[i] = (void *)((uintptr_t)_stacktrace[i]); + break; + } + } + + _stacktrace.resize(std::min(_stacktrace.size(), skip_n_firsts() + depth)); + return size(); + } +}; + #elif defined(BACKWARD_HAS_BACKTRACE) template <> class StackTraceImpl<system_tag::current_tag> : public StackTraceImplHolder { public: NOINLINE - size_t load_here(size_t depth = 32) { + size_t load_here(size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { + set_context(context); + set_error_addr(error_addr); load_thread_info(); if (depth == 0) { return 0; @@ -860,8 +1093,9 @@ return size(); } - size_t load_from(void *addr, size_t depth = 32) { - load_here(depth + 8); + size_t load_from(void *addr, size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { + load_here(depth + 8, context, error_addr); for (size_t i = 0; i < _stacktrace.size(); ++i) { if (_stacktrace[i] == addr) { @@ -888,8 +1122,10 @@ void set_thread_handle(HANDLE handle) { thd_ = handle; } NOINLINE - size_t load_here(size_t depth = 32) { - + size_t load_here(size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { + set_context(static_cast<CONTEXT*>(context)); + set_error_addr(error_addr); CONTEXT localCtx; // used when no context is provided if (depth == 0) { @@ -951,8 +1187,9 @@ return size(); } - size_t load_from(void *addr, size_t depth = 32) { - load_here(depth + 8); + size_t load_from(void *addr, size_t depth = 32, void *context = nullptr, + void *error_addr = nullptr) { + load_here(depth + 8, context, error_addr); for (size_t i = 0; i < _stacktrace.size(); ++i) { if (_stacktrace[i] == addr) { @@ -977,19 +1214,21 @@ /*************** TRACE RESOLVER ***************/ -template <typename TAG> class TraceResolverImpl; +class TraceResolverImplBase { +public: + virtual ~TraceResolverImplBase() {} -#ifdef BACKWARD_SYSTEM_UNKNOWN + virtual void load_addresses(void *const*addresses, int address_count) { + (void)addresses; + (void)address_count; + } -template <> class TraceResolverImpl<system_tag::unknown_tag> { -public: - template <class ST> void load_stacktrace(ST &) {} - ResolvedTrace resolve(ResolvedTrace t) { return t; } -}; + template <class ST> void load_stacktrace(ST &st) { + load_addresses(st.begin(), (int)st.size()); + } -#endif + virtual ResolvedTrace resolve(ResolvedTrace t) { return t; } -class TraceResolverImplBase { protected: std::string demangle(const char *funcname) { return _demangler.demangle(funcname); @@ -999,29 +1238,44 @@ details::demangler _demangler; }; +template <typename TAG> class TraceResolverImpl; + +#ifdef BACKWARD_SYSTEM_UNKNOWN + +template <> class TraceResolverImpl<system_tag::unknown_tag> + : public TraceResolverImplBase {}; + +#endif + #ifdef BACKWARD_SYSTEM_LINUX -class TraceResolverLinuxBase - : public TraceResolverImplBase { +class TraceResolverLinuxBase : public TraceResolverImplBase { public: TraceResolverLinuxBase() - : argv0_(get_argv0()), exec_path_(read_symlink("/proc/self/exe")) { - } + : argv0_(get_argv0()), exec_path_(read_symlink("/proc/self/exe")) {} std::string resolve_exec_path(Dl_info &symbol_info) const { - // mutates symbol_info.dli_fname to be filename to open and returns filename to display - if(symbol_info.dli_fname == argv0_) { + // mutates symbol_info.dli_fname to be filename to open and returns filename + // to display + if (symbol_info.dli_fname == argv0_) { // dladdr returns argv[0] in dli_fname for symbols contained in // the main executable, which is not a valid path if the // executable was found by a search of the PATH environment // variable; In that case, we actually open /proc/self/exe, which // is always the actual executable (even if it was deleted/replaced!) // but display the path that /proc/self/exe links to. + // However, this right away reduces probability of successful symbol + // resolution, because libbfd may try to find *.debug files in the + // same dir, in case symbols are stripped. As a result, it may try + // to find a file /proc/self/<exe_name>.debug, which obviously does + // not exist. /proc/self/exe is a last resort. First load attempt + // should go for the original executable file path. symbol_info.dli_fname = "/proc/self/exe"; return exec_path_; } else { return symbol_info.dli_fname; } } + private: std::string argv0_; std::string exec_path_; @@ -1063,15 +1317,14 @@ class TraceResolverLinuxImpl<trace_resolver_tag::backtrace_symbol> : public TraceResolverLinuxBase { public: - template <class ST> void load_stacktrace(ST &st) { - using namespace details; - if (st.size() == 0) { + void load_addresses(void *const*addresses, int address_count) override { + if (address_count == 0) { return; } - _symbols.reset(backtrace_symbols(st.begin(), (int)st.size())); + _symbols.reset(backtrace_symbols(addresses, address_count)); } - ResolvedTrace resolve(ResolvedTrace trace) { + ResolvedTrace resolve(ResolvedTrace trace) override { char *filename = _symbols[trace.idx]; char *funcname = filename; while (*funcname && *funcname != '(') { @@ -1108,9 +1361,7 @@ public: TraceResolverLinuxImpl() : _bfd_loaded(false) {} - template <class ST> void load_stacktrace(ST &) {} - - ResolvedTrace resolve(ResolvedTrace trace) { + ResolvedTrace resolve(ResolvedTrace trace) override { Dl_info symbol_info; // trace.addr is a virtual address in memory pointing to some code. @@ -1140,9 +1391,45 @@ } trace.object_filename = resolve_exec_path(symbol_info); - bfd_fileobject &fobj = load_object_with_bfd(symbol_info.dli_fname); - if (!fobj.handle) { - return trace; // sad, we couldn't load the object :( + bfd_fileobject *fobj; + // Before rushing to resolution need to ensure the executable + // file still can be used. For that compare inode numbers of + // what is stored by the executable's file path, and in the + // dli_fname, which not necessarily equals to the executable. + // It can be a shared library, or /proc/self/exe, and in the + // latter case has drawbacks. See the exec path resolution for + // details. In short - the dli object should be used only as + // the last resort. + // If inode numbers are equal, it is known dli_fname and the + // executable file are the same. This is guaranteed by Linux, + // because if the executable file is changed/deleted, it will + // be done in a new inode. The old file will be preserved in + // /proc/self/exe, and may even have inode 0. The latter can + // happen if the inode was actually reused, and the file was + // kept only in the main memory. + // + struct stat obj_stat; + struct stat dli_stat; + if (stat(trace.object_filename.c_str(), &obj_stat) == 0 && + stat(symbol_info.dli_fname, &dli_stat) == 0 && + obj_stat.st_ino == dli_stat.st_ino) { + // The executable file, and the shared object containing the + // address are the same file. Safe to use the original path. + // this is preferable. Libbfd will search for stripped debug + // symbols in the same directory. + fobj = load_object_with_bfd(trace.object_filename); + } else{ + // The original object file was *deleted*! The only hope is + // that the debug symbols are either inside the shared + // object file, or are in the same directory, and this is + // not /proc/self/exe. + fobj = nullptr; + } + if (fobj == nullptr || !fobj->handle) { + fobj = load_object_with_bfd(symbol_info.dli_fname); + if (!fobj->handle) { + return trace; + } } find_sym_result *details_selected; // to be filled. @@ -1277,7 +1564,7 @@ typedef details::hashtable<std::string, bfd_fileobject>::type fobj_bfd_map_t; fobj_bfd_map_t _fobj_bfd_map; - bfd_fileobject &load_object_with_bfd(const std::string &filename_object) { + bfd_fileobject *load_object_with_bfd(const std::string &filename_object) { using namespace details; if (!_bfd_loaded) { @@ -1288,11 +1575,11 @@ fobj_bfd_map_t::iterator it = _fobj_bfd_map.find(filename_object); if (it != _fobj_bfd_map.end()) { - return it->second; + return &it->second; } // this new object is empty for now. - bfd_fileobject &r = _fobj_bfd_map[filename_object]; + bfd_fileobject *r = &_fobj_bfd_map[filename_object]; // we do the work temporary in this one; bfd_handle_t bfd_handle; @@ -1341,9 +1628,9 @@ return r; // damned, that's a stripped file that you got there! } - r.handle = move(bfd_handle); - r.symtab = move(symtab); - r.dynamic_symtab = move(dynamic_symtab); + r->handle = move(bfd_handle); + r->symtab = move(symtab); + r->dynamic_symtab = move(dynamic_symtab); return r; } @@ -1362,15 +1649,15 @@ find_sym_result result; }; - find_sym_result find_symbol_details(bfd_fileobject &fobj, void *addr, + find_sym_result find_symbol_details(bfd_fileobject *fobj, void *addr, void *base_addr) { find_sym_context context; context.self = this; - context.fobj = &fobj; + context.fobj = fobj; context.addr = addr; context.base_addr = base_addr; context.result.found = false; - bfd_map_over_sections(fobj.handle.get(), &find_in_section_trampoline, + bfd_map_over_sections(fobj->handle.get(), &find_in_section_trampoline, static_cast<void *>(&context)); return context.result; } @@ -1379,24 +1666,24 @@ find_sym_context *context = static_cast<find_sym_context *>(data); context->self->find_in_section( reinterpret_cast<bfd_vma>(context->addr), - reinterpret_cast<bfd_vma>(context->base_addr), *context->fobj, section, + reinterpret_cast<bfd_vma>(context->base_addr), context->fobj, section, context->result); } - void find_in_section(bfd_vma addr, bfd_vma base_addr, bfd_fileobject &fobj, + void find_in_section(bfd_vma addr, bfd_vma base_addr, bfd_fileobject *fobj, asection *section, find_sym_result &result) { if (result.found) return; #ifdef bfd_get_section_flags - if ((bfd_get_section_flags(fobj.handle.get(), section) & SEC_ALLOC) == 0) + if ((bfd_get_section_flags(fobj->handle.get(), section) & SEC_ALLOC) == 0) #else if ((bfd_section_flags(section) & SEC_ALLOC) == 0) #endif return; // a debug section is never loaded automatically. #ifdef bfd_get_section_vma - bfd_vma sec_addr = bfd_get_section_vma(fobj.handle.get(), section); + bfd_vma sec_addr = bfd_get_section_vma(fobj->handle.get(), section); #else bfd_vma sec_addr = bfd_section_vma(section); #endif @@ -1418,15 +1705,15 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" #endif - if (!result.found && fobj.symtab) { + if (!result.found && fobj->symtab) { result.found = bfd_find_nearest_line( - fobj.handle.get(), section, fobj.symtab.get(), addr - sec_addr, + fobj->handle.get(), section, fobj->symtab.get(), addr - sec_addr, &result.filename, &result.funcname, &result.line); } - if (!result.found && fobj.dynamic_symtab) { + if (!result.found && fobj->dynamic_symtab) { result.found = bfd_find_nearest_line( - fobj.handle.get(), section, fobj.dynamic_symtab.get(), + fobj->handle.get(), section, fobj->dynamic_symtab.get(), addr - sec_addr, &result.filename, &result.funcname, &result.line); } #if defined(__clang__) @@ -1435,13 +1722,13 @@ } ResolvedTrace::source_locs_t - backtrace_inliners(bfd_fileobject &fobj, find_sym_result previous_result) { + backtrace_inliners(bfd_fileobject *fobj, find_sym_result previous_result) { // This function can be called ONLY after a SUCCESSFUL call to // find_symbol_details. The state is global to the bfd_handle. ResolvedTrace::source_locs_t results; while (previous_result.found) { find_sym_result result; - result.found = bfd_find_inliner_info(fobj.handle.get(), &result.filename, + result.found = bfd_find_inliner_info(fobj->handle.get(), &result.filename, &result.funcname, &result.line); if (result @@ -1484,9 +1771,7 @@ public: TraceResolverLinuxImpl() : _dwfl_handle_initialized(false) {} - template <class ST> void load_stacktrace(ST &) {} - - ResolvedTrace resolve(ResolvedTrace trace) { + ResolvedTrace resolve(ResolvedTrace trace) override { using namespace details; Dwarf_Addr trace_addr = (Dwarf_Addr)trace.addr; @@ -1779,9 +2064,9 @@ static const char *die_call_file(Dwarf_Die *die) { Dwarf_Attribute attr_mem; - Dwarf_Sword file_idx = 0; + Dwarf_Word file_idx = 0; - dwarf_formsdata(dwarf_attr(die, DW_AT_call_file, &attr_mem), &file_idx); + dwarf_formudata(dwarf_attr(die, DW_AT_call_file, &attr_mem), &file_idx); if (file_idx == 0) { return 0; @@ -1813,9 +2098,7 @@ public: TraceResolverLinuxImpl() : _dwarf_loaded(false) {} - template <class ST> void load_stacktrace(ST &) {} - - ResolvedTrace resolve(ResolvedTrace trace) { + ResolvedTrace resolve(ResolvedTrace trace) override { // trace.addr is a virtual address in memory pointing to some code. // Let's try to find from which loaded object it comes from. // The loaded object can be yourself btw. @@ -2831,7 +3114,7 @@ trace.object_function = demangler.demangle(linkage); dwarf_dealloc(dwarf, linkage, DW_DLA_STRING); } - dwarf_dealloc(dwarf, name, DW_DLA_ATTR); + dwarf_dealloc(dwarf, attr_mem, DW_DLA_ATTR); } break; @@ -3039,12 +3322,12 @@ Dwarf_Die cu_die) { Dwarf_Attribute attr_mem; Dwarf_Error error = DW_DLE_NE; - Dwarf_Signed file_index; + Dwarf_Unsigned file_index; std::string file; if (dwarf_attr(die, DW_AT_call_file, &attr_mem, &error) == DW_DLV_OK) { - if (dwarf_formsdata(attr_mem, &file_index, &error) != DW_DLV_OK) { + if (dwarf_formudata(attr_mem, &file_index, &error) != DW_DLV_OK) { file_index = 0; } dwarf_dealloc(dwarf, attr_mem, DW_DLA_ATTR); @@ -3056,8 +3339,9 @@ char **srcfiles = 0; Dwarf_Signed file_count = 0; if (dwarf_srcfiles(cu_die, &srcfiles, &file_count, &error) == DW_DLV_OK) { - if (file_index <= file_count) + if (file_count > 0 && file_index <= static_cast<Dwarf_Unsigned>(file_count)) { file = std::string(srcfiles[file_index - 1]); + } // Deallocate all strings! for (int i = 0; i < file_count; ++i) { @@ -3194,15 +3478,14 @@ class TraceResolverDarwinImpl<trace_resolver_tag::backtrace_symbol> : public TraceResolverImplBase { public: - template <class ST> void load_stacktrace(ST &st) { - using namespace details; - if (st.size() == 0) { + void load_addresses(void *const*addresses, int address_count) override { + if (address_count == 0) { return; } - _symbols.reset(backtrace_symbols(st.begin(), st.size())); + _symbols.reset(backtrace_symbols(addresses, address_count)); } - ResolvedTrace resolve(ResolvedTrace trace) { + ResolvedTrace resolve(ResolvedTrace trace) override { // parse: // <n> <file> <addr> <mangled-name> + <offset> char *filename = _symbols[trace.idx]; @@ -3300,9 +3583,9 @@ ret.base_address = mi.lpBaseOfDll; ret.load_size = mi.SizeOfImage; - GetModuleFileNameEx(process, module, temp, sizeof(temp)); + GetModuleFileNameExA(process, module, temp, sizeof(temp)); ret.image_name = temp; - GetModuleBaseName(process, module, temp, sizeof(temp)); + GetModuleBaseNameA(process, module, temp, sizeof(temp)); ret.module_name = temp; std::vector<char> img(ret.image_name.begin(), ret.image_name.end()); std::vector<char> mod(ret.module_name.begin(), ret.module_name.end()); @@ -3312,7 +3595,8 @@ } }; -template <> class TraceResolverImpl<system_tag::windows_tag> { +template <> class TraceResolverImpl<system_tag::windows_tag> + : public TraceResolverImplBase { public: TraceResolverImpl() { @@ -3337,8 +3621,6 @@ image_type = h->FileHeader.Machine; } - template <class ST> void load_stacktrace(ST &) {} - static const int max_sym_len = 255; struct symbol_t { SYMBOL_INFO sym; @@ -3347,27 +3629,28 @@ DWORD64 displacement; - ResolvedTrace resolve(ResolvedTrace t) { + ResolvedTrace resolve(ResolvedTrace t) override { HANDLE process = GetCurrentProcess(); char name[256]; - memset(&sym, sizeof(sym), 0); + memset(&sym, 0, sizeof(sym)); sym.sym.SizeOfStruct = sizeof(SYMBOL_INFO); sym.sym.MaxNameLen = max_sym_len; if (!SymFromAddr(process, (ULONG64)t.addr, &displacement, &sym.sym)) { // TODO: error handling everywhere - LPTSTR lpMsgBuf; + char* lpMsgBuf; DWORD dw = GetLastError(); - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, 0, NULL); - - printf(lpMsgBuf); + if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (char*)&lpMsgBuf, 0, NULL)) { + std::fprintf(stderr, "%s\n", lpMsgBuf); + LocalFree(lpMsgBuf); + } // abort(); } @@ -3410,12 +3693,13 @@ // 1. If BACKWARD_CXX_SOURCE_PREFIXES is set then assume it contains // a colon-separated list of path prefixes. Try prepending each // to the given path until a valid file is found. - const std::vector<std::string>& prefixes = get_paths_from_env_variable(); + const std::vector<std::string> &prefixes = get_paths_from_env_variable(); for (size_t i = 0; i < prefixes.size(); ++i) { // Double slashes (//) should not be a problem. std::string new_path = prefixes[i] + '/' + path; _file.reset(new std::ifstream(new_path.c_str())); - if (is_open()) break; + if (is_open()) + break; } // 2. If no valid file found then fallback to opening the path as-is. if (!_file || !is_open()) { @@ -3519,14 +3803,14 @@ std::vector<std::string> get_paths_from_env_variable_impl() { std::vector<std::string> paths; - const char* prefixes_str = std::getenv("BACKWARD_CXX_SOURCE_PREFIXES"); + const char *prefixes_str = std::getenv("BACKWARD_CXX_SOURCE_PREFIXES"); if (prefixes_str && prefixes_str[0]) { paths = details::split_source_prefixes(prefixes_str); } return paths; } - const std::vector<std::string>& get_paths_from_env_variable() { + const std::vector<std::string> &get_paths_from_env_variable() { static std::vector<std::string> paths = get_paths_from_env_variable_impl(); return paths; } @@ -3605,7 +3889,7 @@ cfile_streambuf(FILE *_sink) : sink(_sink) {} int_type underflow() override { return traits_type::eof(); } int_type overflow(int_type ch) override { - if (traits_type::not_eof(ch) && fwrite(&ch, sizeof ch, 1, sink) == 1) { + if (traits_type::not_eof(ch) && fputc(ch, sink) != EOF) { return ch; } return traits_type::eof(); @@ -3928,12 +4212,19 @@ #elif defined(__arm__) error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.arm_pc); #elif defined(__aarch64__) - error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.pc); + #if defined(__APPLE__) + error_addr = reinterpret_cast<void *>(uctx->uc_mcontext->__ss.__pc); + #else + error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.pc); + #endif #elif defined(__mips__) - error_addr = reinterpret_cast<void *>(reinterpret_cast<struct sigcontext*>(&uctx->uc_mcontext)->sc_pc); + error_addr = reinterpret_cast<void *>( + reinterpret_cast<struct sigcontext *>(&uctx->uc_mcontext)->sc_pc); #elif defined(__ppc__) || defined(__powerpc) || defined(__powerpc__) || \ defined(__POWERPC__) error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.regs->nip); +#elif defined(__riscv) + error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.__gregs[REG_PC]); #elif defined(__s390x__) error_addr = reinterpret_cast<void *>(uctx->uc_mcontext.psw.addr); #elif defined(__APPLE__) && defined(__x86_64__) @@ -3944,9 +4235,10 @@ #warning ":/ sorry, ain't know no nothing none not of your architecture!" #endif if (error_addr) { - st.load_from(error_addr, 32); + st.load_from(error_addr, 32, reinterpret_cast<void *>(uctx), + info->si_addr); } else { - st.load_here(32); + st.load_here(32, reinterpret_cast<void *>(uctx), info->si_addr); } Printer printer; @@ -4014,8 +4306,10 @@ signal(SIGABRT, signal_handler); _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); - set_terminate(&terminator); - set_unexpected(&terminator); + std::set_terminate(&terminator); +#ifndef BACKWARD_ATLEAST_CXX17 + std::set_unexpected(&terminator); +#endif _set_purecall_handler(&terminator); _set_invalid_parameter_handler(&invalid_parameter_handler); } @@ -4143,9 +4437,8 @@ StackTrace st; st.set_machine_type(printer.resolver().machine_type()); - st.set_context(ctx()); st.set_thread_handle(thread_handle()); - st.load_here(32 + skip_frames); + st.load_here(32 + skip_frames, ctx()); st.skip_n_firsts(skip_frames); printer.address = true; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/backward-cpp-1.5/test/_test_main.cpp new/backward-cpp-1.6/test/_test_main.cpp --- old/backward-cpp-1.5/test/_test_main.cpp 2020-04-14 04:24:48.000000000 +0200 +++ new/backward-cpp-1.6/test/_test_main.cpp 2021-08-13 00:49:08.000000000 +0200 @@ -26,7 +26,7 @@ #include <cstdlib> #ifdef _WIN32 -#include <Windows.h> +#include <windows.h> #define strcasecmp _stricmp #else #include <sys/wait.h>