diff --git a/CMakeLists.txt b/CMakeLists.txt index 7918af9a..957663ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,6 +71,36 @@ else() set(BBASM_MODE "string") endif() +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + include(CheckCXXSourceCompiles) + + check_cxx_source_compiles(" + #include + int main() { return 0; } + " HAVE_GLIBC) + + if (HAVE_GLIBC) + set(USE_LIBUNWIND OFF) + else() + set(USE_LIBUNWIND ON) + find_library(LIBUNWIND_LIBRARY NAMES unwind) + find_path(LIBUNWIND_INCLUDE_DIR NAMES libunwind.h) + + if(LIBUNWIND_LIBRARY) + find_library(LIBUNWIND_LIBRARY_ARCH NAMES "unwind-${CMAKE_SYSTEM_PROCESSOR}") + if(LIBUNWIND_LIBRARY_ARCH) + set(LIBUNWIND_LIBRARY "${LIBUNWIND_LIBRARY};${LIBUNWIND_LIBRARY_ARCH}") + endif() + endif() + + if(NOT LIBUNWIND_LIBRARY OR NOT LIBUNWIND_INCLUDE_DIR) + message(FATAL_ERROR "libunwind not found. Install libunwind-dev") + endif() + endif() +else() + set(USE_LIBUNWIND OFF) +endif() + find_package(Threads) if (NOT Threads_FOUND) add_definitions(-DNPNR_DISABLE_THREADS) @@ -364,6 +394,10 @@ function(add_nextpnr_architecture target) target_link_libraries(nextpnr-${target} PRIVATE nextpnr-${target}-core) if (BUILD_GUI) target_link_libraries(nextpnr-${target} PRIVATE nextpnr-${target}-gui) + if (USE_LIBUNWIND) + target_include_directories(nextpnr-${target} PRIVATE ${LIBUNWIND_INCLUDE_DIR}) + target_link_libraries(nextpnr-${target} PRIVATE ${LIBUNWIND_LIBRARY}) + endif() endif() install(TARGETS nextpnr-${target} RUNTIME DESTINATION bin) @@ -382,6 +416,10 @@ function(add_nextpnr_architecture target) if (BUILD_GUI) target_link_libraries(nextpnr-${target}-test PRIVATE nextpnr-${target}-gui) target_link_libraries(nextpnr-${target}-test PRIVATE nextpnr_test_gui) + if (USE_LIBUNWIND) + target_include_directories(nextpnr-${target}-test PRIVATE ${LIBUNWIND_INCLUDE_DIR}) + target_link_libraries(nextpnr-${target}-test PRIVATE ${LIBUNWIND_LIBRARY}) + endif() endif() endif() diff --git a/gui/application.cc b/gui/application.cc index a5581356..eec6cc8b 100644 --- a/gui/application.cc +++ b/gui/application.cc @@ -28,7 +28,11 @@ #include "log.h" #ifdef __linux__ +#if defined(__GLIBC__) #include +#else +#include +#endif #endif NEXTPNR_NAMESPACE_BEGIN @@ -48,17 +52,41 @@ namespace { #ifdef __linux__ std::string get_backtrace_str() { + std::ostringstream ss; + ss << "Backtrace: " << std::endl; + #if defined(__GLIBC__) static const size_t MAX_BT_SIZE = 1024; std::array bt_data; int bt_len = backtrace(bt_data.data(), MAX_BT_SIZE); char **bt_symbols = backtrace_symbols(bt_data.data(), bt_len); if (bt_symbols == nullptr) return ""; - std::ostringstream ss; - ss << "Backtrace: " << std::endl; for (int i = 0; i < bt_len; i++) ss << " " << bt_symbols[i] << std::endl; free(bt_symbols); + #else + unw_cursor_t cursor; + unw_context_t context; + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + int frame_num = 0; + while (unw_step(&cursor) > 0) { + unw_word_t ip; + char func_name[256]; + unw_word_t offset; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + if (unw_get_proc_name(&cursor, func_name, sizeof(func_name), &offset) == 0) { + ss << " #" << frame_num << ": " << func_name << " + 0x" + << std::hex << offset << " [0x" << ip << "]\n"; + } else { + ss << " #" << frame_num << ": -- unknown -- [0x" + << std::hex << ip << "]\n"; + } + frame_num++; + } + #endif return ss.str(); } #else