From fe26c3145d4d41b8a09a1cb042fc030420bd5183 Mon Sep 17 00:00:00 2001 From: R-Goc Date: Sat, 8 Feb 2025 23:05:42 +0100 Subject: [PATCH] AK: Add stacktrace support using the standard lib This commit adds support for using the standard library implementation of if libbacktrace is not found. This can also be explicitly enabled through ENABLE_STD_STACKTRACE for platforms that have libbacktrace available. Co-Authored-By: Andrew Kaster --- AK/Assertions.cpp | 25 ++++++++--- AK/CMakeLists.txt | 14 +----- Meta/CMake/common_options.cmake | 6 +++ Meta/CMake/stacktrace.cmake | 76 +++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 18 deletions(-) create mode 100644 Meta/CMake/stacktrace.cmake diff --git a/AK/Assertions.cpp b/AK/Assertions.cpp index bc096d6a72a..f5adf981f35 100644 --- a/AK/Assertions.cpp +++ b/AK/Assertions.cpp @@ -8,18 +8,22 @@ #include #include #include -#include -#include #if defined(AK_OS_ANDROID) && (__ANDROID_API__ >= 33) # include # define EXECINFO_BACKTRACE # define PRINT_ERROR(s) __android_log_write(ANDROID_LOG_WARN, "AK", (s)) #else -# define PRINT_ERROR(s) (void)fputs((s), stderr) +# include +# define PRINT_ERROR(s) (void)::fputs((s), stderr) #endif -#if defined(AK_HAS_BACKTRACE_HEADER) +#if defined(AK_HAS_STD_STACKTRACE) +# include +# include +#elif defined(AK_HAS_BACKTRACE_HEADER) +# include +# include # include #endif @@ -29,7 +33,16 @@ # define ERRORLN warnln #endif -#if defined(AK_HAS_BACKTRACE_HEADER) +#if defined(AK_HAS_STD_STACKTRACE) +namespace { +ALWAYS_INLINE void dump_backtrace() +{ + // We assume the stacktrace implementation demangles symbols, as does microsoft/STL + PRINT_ERROR(std::to_string(std::stacktrace::current(2)).c_str()); + PRINT_ERROR("\n"); +} +} +#elif defined(AK_HAS_BACKTRACE_HEADER) namespace { ALWAYS_INLINE void dump_backtrace() { @@ -94,7 +107,7 @@ bool ak_colorize_output(void) void ak_trap(void) { -#if defined(AK_HAS_BACKTRACE_HEADER) +#if defined(AK_HAS_BACKTRACE_HEADER) || defined(AK_HAS_STD_STACKTRACE) dump_backtrace(); #endif __builtin_trap(); diff --git a/AK/CMakeLists.txt b/AK/CMakeLists.txt index 6705f945379..11bfad3f689 100644 --- a/AK/CMakeLists.txt +++ b/AK/CMakeLists.txt @@ -49,19 +49,9 @@ serenity_lib(AK ak) serenity_install_headers(AK) serenity_install_sources(AK) -find_package(Backtrace) +include(stacktrace) configure_file(Backtrace.h.in Backtrace.h @ONLY) - -if (Backtrace_FOUND) - if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.30) - target_link_libraries(AK PRIVATE Backtrace::Backtrace) - else() - target_include_directories(AK PRIVATE ${Backtrace_INCLUDE_DIRS}) - target_link_libraries(AK PRIVATE ${Backtrace_LIBRARIES}) - endif() -else() - message(WARNING "Backtrace not found, stack traces will be unavailable") -endif() +link_stacktrace_library(AK STD_DEFINITION AK_HAS_STD_STACKTRACE) find_package(simdutf REQUIRED) swizzle_target_properties_for_swift(simdutf::simdutf) diff --git a/Meta/CMake/common_options.cmake b/Meta/CMake/common_options.cmake index 72f71003ba6..23bd279c767 100644 --- a/Meta/CMake/common_options.cmake +++ b/Meta/CMake/common_options.cmake @@ -13,6 +13,11 @@ if (POLICY CMP0157) set(CMAKE_Swift_COMPILATION_MODE "$,wholemodule,incremental>") endif() +# Check arguments to return() +if (POLICY CMP0140) + cmake_policy(SET CMP0140 NEW) +endif() + serenity_option(ENABLE_COMPILETIME_FORMAT_CHECK ON CACHE BOOL "Enable compiletime format string checks") serenity_option(ENABLE_UNDEFINED_SANITIZER OFF CACHE BOOL "Enable undefined behavior sanitizer testing in gcc/clang") serenity_option(UNDEFINED_BEHAVIOR_IS_FATAL OFF CACHE BOOL "Make undefined behavior sanitizer errors non-recoverable") @@ -35,6 +40,7 @@ serenity_option(ENABLE_CLANG_PLUGINS_INVALID_FUNCTION_MEMBERS OFF CACHE BOOL "En serenity_option(ENABLE_GUI_TARGETS ON CACHE BOOL "Enable building GUI targets") serenity_option(ENABLE_INSTALL_HEADERS ON CACHE BOOL "Enable installing headers") serenity_option(ENABLE_SWIFT OFF CACHE BOOL "Enable building Swift files") +serenity_option(ENABLE_STD_STACKTRACE OFF CACHE BOOL "Force use of std::stacktrace instead of libbacktrace. If it is not supported the build will fail") if (ENABLE_SWIFT) include(${CMAKE_CURRENT_LIST_DIR}/Swift/swift-settings.cmake) diff --git a/Meta/CMake/stacktrace.cmake b/Meta/CMake/stacktrace.cmake new file mode 100644 index 00000000000..f23f4b53ea1 --- /dev/null +++ b/Meta/CMake/stacktrace.cmake @@ -0,0 +1,76 @@ +# +# Provides definitions for stack trace support via libbacktrace or std::stacktrace +# + +include_guard() + +find_package(Backtrace) +include(CheckCXXSourceCompiles) + +function(check_std_stacktrace link_lib library_target out_var) + set(CMAKE_REQUIRED_LIBRARIES ${link_lib}) + set(check_var HAVE_STD_STACKTRACE_CHECK) + if (link_lib) + set(check_var "HAVE_STD_STACKTRACE_WITH_${link_lib}") + endif() + check_cxx_source_compiles(" + #include + #include + #include + #if !defined(__cpp_lib_stacktrace) || (__cpp_lib_stacktrace < 202011L) + # error \"No std::stacktrace available\" + #endif + int main() { + std::cout << std::stacktrace::current() << std::endl; + return 0; + }" + ${check_var} + ) + set(${out_var} ${${check_var}}) + if (${out_var}) + target_link_libraries(${library_target} PRIVATE "${link_lib}") + endif() + return(PROPAGATE ${out_var}) +endfunction() + +function(link_stacktrace_library target) + cmake_parse_arguments(PARSE_ARGV 1 ARG "" "STD_DEFINITION" "") + + if (Backtrace_FOUND AND NOT ENABLE_STD_STACKTRACE) + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.30) + target_link_libraries(${target} PRIVATE Backtrace::Backtrace) + else() + target_include_directories(${target} PRIVATE ${Backtrace_INCLUDE_DIRS}) + target_link_libraries(${target} PRIVATE ${Backtrace_LIBRARIES}) + endif() + else() + check_std_stacktrace("" ${target} HAVE_STD_STACKTRACE) + + if(NOT HAVE_STD_STACKTRACE AND CMAKE_CXX_COMPILER_ID STREQUAL GNU) + if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14.1) + check_std_stacktrace("stdc++exp" ${target} HAVE_STD_STACKTRACE) + else() + check_std_stacktrace("stdc++_libbacktrace" ${target} HAVE_STD_STACKTRACE) + endif() + endif() + + if (NOT HAVE_STD_STACKTRACE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang$") + foreach(lib IN ITEMS "stdc++exp" "stdc++_libbacktrace" "c++experimental" ) + check_std_stacktrace("${lib}" ${target} HAVE_STD_STACKTRACE) + if(HAVE_STD_STACKTRACE) + break() + endif() + endforeach() + endif() + + if(HAVE_STD_STACKTRACE) + target_compile_definitions(${target} PRIVATE ${ARG_STD_DEFINITION}) + else() + set(msg_level WARNING) + if (ENABLE_STD_STACKTRACE) + set(msg_level FATAL_ERROR) + endif() + message(${msg_level} "Backtrace and not found, stack traces will be unavailable") + endif() + endif() +endfunction()