From 5cb36973eae71c63585bd826cb9c1d01364096d6 Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Thu, 10 Apr 2025 18:07:19 +0400 Subject: [PATCH 1/7] Working on libunwind --- cmake/Configuration.cmake | 7 +++++++ dist/googletest | 2 +- src/Assembler/Main/Main.cpp | 29 +++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/cmake/Configuration.cmake b/cmake/Configuration.cmake index 4d0e4941..a866d3d4 100644 --- a/cmake/Configuration.cmake +++ b/cmake/Configuration.cmake @@ -37,6 +37,13 @@ function(set_compile_flags) add_link_options(-fsanitize=address,leak) message(STATUS "Enabling sanitizers") endif() + + find_library(LIBUNWIND unwind) + if (LIBUNWIND) + message(STATUS "Found libunwind") + add_compile_options(-DHCPU_ENABLE_LIBUNWIND) + add_link_options(-lunwind) + endif() endfunction() function(detect_compilers) diff --git a/dist/googletest b/dist/googletest index 2b6b042a..3fbe4db9 160000 --- a/dist/googletest +++ b/dist/googletest @@ -1 +1 @@ -Subproject commit 2b6b042a77446ff322cd7522ca068d9f2a21c1d1 +Subproject commit 3fbe4db9a39291ae8d7a9c5f1d75896bb4c5a18f diff --git a/src/Assembler/Main/Main.cpp b/src/Assembler/Main/Main.cpp index d2fcba4a..c01c69ee 100644 --- a/src/Assembler/Main/Main.cpp +++ b/src/Assembler/Main/Main.cpp @@ -13,6 +13,10 @@ #include +#ifdef HCPU_ENABLE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include +#endif constexpr const inline auto loglevel_assoc = mapbox::eternal::map({ {"debug", HyperCPU::LogLevel::DEBUG}, @@ -21,6 +25,31 @@ constexpr const inline auto loglevel_assoc = mapbox::eternal::map 0) { + unw_word_t offset, pc; + char sym[4096]; + + if (unw_get_reg(&cursor, UNW_REG_IP, &pc)) { + std::puts("Unwinding stack failed: couldn't get PC"); + } + } +} +#endif + int main(int argc, char** argv) { argparse::ArgumentParser program("hcasm"); program.add_argument("source") From 239a3c1ff4b8a22874c29d1b7d771a8ab39346c7 Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Thu, 10 Apr 2025 19:34:09 +0400 Subject: [PATCH 2/7] Add libbacktrace dependency, implement basic backtrace controller --- cmake/Configuration.cmake | 7 ++- dist/googletest | 2 +- src/Assembler/Main/BacktraceProvider.cpp | 80 ++++++++++++++++++++++++ src/Assembler/Main/BacktraceProvider.hpp | 31 +++++++++ src/Assembler/Main/Main.cpp | 31 ++------- test.cpp | 0 6 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 src/Assembler/Main/BacktraceProvider.cpp create mode 100644 src/Assembler/Main/BacktraceProvider.hpp create mode 100644 test.cpp diff --git a/cmake/Configuration.cmake b/cmake/Configuration.cmake index a866d3d4..a4e44b75 100644 --- a/cmake/Configuration.cmake +++ b/cmake/Configuration.cmake @@ -39,10 +39,11 @@ function(set_compile_flags) endif() find_library(LIBUNWIND unwind) - if (LIBUNWIND) - message(STATUS "Found libunwind") + find_library(LIBBACKTRACE backtrace) + if (LIBUNWIND AND LIBBACKTRACE) + message(STATUS "Found libunwind and libbacktrace") add_compile_options(-DHCPU_ENABLE_LIBUNWIND) - add_link_options(-lunwind) + add_link_options(-L/usr/local/lib -lunwind -lbacktrace) endif() endfunction() diff --git a/dist/googletest b/dist/googletest index 3fbe4db9..2b6b042a 160000 --- a/dist/googletest +++ b/dist/googletest @@ -1 +1 @@ -Subproject commit 3fbe4db9a39291ae8d7a9c5f1d75896bb4c5a18f +Subproject commit 2b6b042a77446ff322cd7522ca068d9f2a21c1d1 diff --git a/src/Assembler/Main/BacktraceProvider.cpp b/src/Assembler/Main/BacktraceProvider.cpp new file mode 100644 index 00000000..978ab92b --- /dev/null +++ b/src/Assembler/Main/BacktraceProvider.cpp @@ -0,0 +1,80 @@ +#ifdef HCPU_ENABLE_LIBUNWIND + +#include +#include +#include + +#define UNW_LOCAL_ONLY +#include +#include + +#include + +#include
+ +extern "C" { + void bt_create_error_callback(void*, const char* msg, int err) { + printf("Error %d occurred when initializing the stack trace: %s", err, msg); + } + + void bt_error_callback(void*, [[maybe_unused]] const char* msg, [[maybe_unused]] int err) { + std::puts("Error while getting the stacktrace!"); + } + + int bt_callback(void*, uintptr_t, const char* filename, int lineno, const char* function) { + const char* func_name = function; + int status; + char* demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status); + if (!status) { + func_name = demangled; + } + + fmt::println("{}:{} in function {}", filename, lineno, func_name); + + return 0; + } +} + +BacktraceController global_bt_controller; + +void BacktraceController::Run() { + backtrace_full((backtrace_state*)bt_state, 0, bt_callback, bt_error_callback, nullptr); + /* + if (unw_getcontext(&context) < 0) { + std::puts("Unwinding stack failed: couldn't initialize context"); + std::exit(1); + } + + if (unw_init_local(&cursor, &context) < 0) { + std::puts("Unwinding stack failed: couldn't initialize context"); + std::exit(1); + } + + unw_step(&cursor); // We should skip one more frame - RunBacktraceController + + while (unw_step(&cursor) > 0) { + unw_word_t offset, pc, sp; + char sym[512] = {""}; + char* name = sym; + + if (unw_get_reg(&cursor, UNW_REG_IP, &pc)) { + std::puts("Unwinding stack failed: couldn't get PC"); + std::exit(1); + } + + if (unw_get_reg(&cursor, UNW_REG_SP, &sp)) { + std::puts("Unwinding stack failed: couldn't get SP"); + std::exit(1); + } + + if (!unw_get_proc_name(&cursor, sym, sizeof(sym), &offset)) { + int status; + if ((name = abi::__cxa_demangle(sym, NULL, NULL, &status)) == 0) { + name = sym; + } + } + } + */ +} + +#endif \ No newline at end of file diff --git a/src/Assembler/Main/BacktraceProvider.hpp b/src/Assembler/Main/BacktraceProvider.hpp new file mode 100644 index 00000000..bbf06b18 --- /dev/null +++ b/src/Assembler/Main/BacktraceProvider.hpp @@ -0,0 +1,31 @@ +#ifdef HCPU_ENABLE_LIBUNWIND + +#include +#include + +extern "C" { + void bt_create_error_callback(void*, const char* msg, int err); +} + +class BacktraceController { +public: + BacktraceController() = default; + BacktraceController(char* name) { + bt_state = backtrace_create_state(name, 0, bt_create_error_callback, nullptr); + } + + void Run(); +private: + // libunwind + [[maybe_unused]] unw_cursor_t cursor; + [[maybe_unused]] unw_context_t context; + + // libbacktrace + void* bt_state; +}; + +extern BacktraceController global_bt_controller; + +void RunBacktraceController(); + +#endif \ No newline at end of file diff --git a/src/Assembler/Main/Main.cpp b/src/Assembler/Main/Main.cpp index c01c69ee..59c501ae 100644 --- a/src/Assembler/Main/Main.cpp +++ b/src/Assembler/Main/Main.cpp @@ -14,8 +14,7 @@ #include #ifdef HCPU_ENABLE_LIBUNWIND -#define UNW_LOCAL_ONLY -#include +#include
#endif constexpr const inline auto loglevel_assoc = mapbox::eternal::map({ @@ -25,32 +24,10 @@ constexpr const inline auto loglevel_assoc = mapbox::eternal::map 0) { - unw_word_t offset, pc; - char sym[4096]; - - if (unw_get_reg(&cursor, UNW_REG_IP, &pc)) { - std::puts("Unwinding stack failed: couldn't get PC"); - } - } -} -#endif - int main(int argc, char** argv) { + global_bt_controller = BacktraceController(argv[0]); + RunBacktraceController(); + std::exit(0); argparse::ArgumentParser program("hcasm"); program.add_argument("source") .help("source file to be assembled") diff --git a/test.cpp b/test.cpp new file mode 100644 index 00000000..e69de29b From 969d0f9533b86d5e297ed463dd4b91a823a12e52 Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Fri, 11 Apr 2025 20:39:02 +0400 Subject: [PATCH 3/7] Updated submodules --- .gitmodules | 6 ++++++ CMakeLists.txt | 1 - dist/libbacktrace | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) create mode 160000 dist/libbacktrace diff --git a/.gitmodules b/.gitmodules index f769b4dc..1ca87879 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,9 @@ [submodule "dist/benchmark"] path = dist/benchmark url = https://github.com/google/benchmark +[submodule "dist/libbacktrace"] + path = dist/libbacktrace + url = https://github.com/ianlancetaylor/libbacktrace +[submodule "dist/libunwind"] + path = dist/libunwind + url = https://github.com/libunwind/libunwind diff --git a/CMakeLists.txt b/CMakeLists.txt index 45a811a0..67707944 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,6 @@ message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "Generating source files list") include(cmake/SourceListGenerator.cmake) - add_subdirectory(dist/argparse) add_subdirectory(dist/pog) add_subdirectory(bench) diff --git a/dist/libbacktrace b/dist/libbacktrace new file mode 160000 index 00000000..79392187 --- /dev/null +++ b/dist/libbacktrace @@ -0,0 +1 @@ +Subproject commit 793921876c981ce49759114d7bb89bb89b2d3a2d From 8e53d5c899d50114c90a1162c6e764bae95c2633 Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Fri, 11 Apr 2025 21:46:34 +0400 Subject: [PATCH 4/7] Updated CMake, basic stacktrace printing --- src/Assembler/Main/BacktraceProvider.cpp | 40 ++++++++++++++++++++++-- src/Assembler/Main/BacktraceProvider.hpp | 11 +++++-- src/CMakeLists.txt | 24 ++++++++++++-- src/Logger/Colors.hpp | 1 + 4 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/Assembler/Main/BacktraceProvider.cpp b/src/Assembler/Main/BacktraceProvider.cpp index 978ab92b..e1c88ae9 100644 --- a/src/Assembler/Main/BacktraceProvider.cpp +++ b/src/Assembler/Main/BacktraceProvider.cpp @@ -11,6 +11,7 @@ #include #include
+#include extern "C" { void bt_create_error_callback(void*, const char* msg, int err) { @@ -22,6 +23,10 @@ extern "C" { } int bt_callback(void*, uintptr_t, const char* filename, int lineno, const char* function) { + if (global_bt_controller.HasFinished() || global_bt_controller.iteration++ != 2) { + return 0; + } + const char* func_name = function; int status; char* demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status); @@ -29,17 +34,32 @@ extern "C" { func_name = demangled; } + if (!func_name) { + func_name = ""; + } else if (!std::strcmp(func_name, "main")) { + global_bt_controller.SetFinished(); + } + + if (!filename) { + filename = ""; + } + fmt::println("{}:{} in function {}", filename, lineno, func_name); + std::free(demangled); + return 0; } + + void RunBacktraceController() { + global_bt_controller.Run(); + } } BacktraceController global_bt_controller; void BacktraceController::Run() { - backtrace_full((backtrace_state*)bt_state, 0, bt_callback, bt_error_callback, nullptr); - /* + fmt::println("\n{}[!] HyperCPU encountered a segmentation fault!{}", B_RED, RESET); if (unw_getcontext(&context) < 0) { std::puts("Unwinding stack failed: couldn't initialize context"); std::exit(1); @@ -49,7 +69,13 @@ void BacktraceController::Run() { std::puts("Unwinding stack failed: couldn't initialize context"); std::exit(1); } + fmt::println("{}[>] Libunwind context initialized successfully, generating stack trace...{}\n", B_GREEN, RESET); + + unw_step(&cursor); + backtrace_full((backtrace_state*)bt_state, 0, bt_callback, bt_error_callback, nullptr); + + /* unw_step(&cursor); // We should skip one more frame - RunBacktraceController while (unw_step(&cursor) > 0) { @@ -73,8 +99,18 @@ void BacktraceController::Run() { name = sym; } } + + fmt::println("{}", sym); } */ } +void BacktraceController::SetFinished() { + finished = true; +} + +bool BacktraceController::HasFinished() { + return finished; +} + #endif \ No newline at end of file diff --git a/src/Assembler/Main/BacktraceProvider.hpp b/src/Assembler/Main/BacktraceProvider.hpp index bbf06b18..f62edd94 100644 --- a/src/Assembler/Main/BacktraceProvider.hpp +++ b/src/Assembler/Main/BacktraceProvider.hpp @@ -10,11 +10,15 @@ extern "C" { class BacktraceController { public: BacktraceController() = default; - BacktraceController(char* name) { + BacktraceController(char* name) : iteration(0), finished(false) { bt_state = backtrace_create_state(name, 0, bt_create_error_callback, nullptr); } void Run(); + void SetFinished(); + bool HasFinished(); + + int iteration; // to slice entries that are not needed private: // libunwind [[maybe_unused]] unw_cursor_t cursor; @@ -22,10 +26,13 @@ class BacktraceController { // libbacktrace void* bt_state; + + // internals + bool finished; }; extern BacktraceController global_bt_controller; -void RunBacktraceController(); +extern "C" void RunBacktraceController(); #endif \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5bac8b39..8a524b9a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,5 @@ +include(ExternalProject) + set(GENERIC_INCLUDE_DIR ${HyperCPU_SOURCE_DIR}/src ${HyperCPU_SOURCE_DIR}/dist/argparse/include @@ -5,6 +7,22 @@ set(GENERIC_INCLUDE_DIR ${HyperCPU_SOURCE_DIR}/dist/eternal/include ${HyperCPU_SOURCE_DIR}/dist/HPool) +ExternalProject_Add( + libbacktrace + SOURCE_DIR + ${HyperCPU_SOURCE_DIR}/dist/libbacktrace + BUILD_IN_SOURCE + 0 + CONFIGURE_COMMAND + cd ${HyperCPU_SOURCE_DIR}/dist/libbacktrace && ./configure + BUILD_COMMAND + cd ${HyperCPU_SOURCE_DIR}/dist/libbacktrace && make -j$(nproc) + INSTALL_COMMAND + "" + BUILD_BYPRODUCTS + ${HyperCPU_SOURCE_DIR}/dist/libbacktrace/libbacktrace.la +) + add_library(emulator-core STATIC ${SOURCES_emulator-core}) target_include_directories(emulator-core PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Emulator) target_link_libraries(emulator-core ${LD_FLAGS} fmt) @@ -14,12 +32,14 @@ target_include_directories(assembler-core PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperC target_link_libraries(assembler-core pog) add_executable(hcasm ${SOURCES_assembler-main}) +add_dependencies(hcasm libbacktrace) target_include_directories(hcasm PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Assembler) -target_link_libraries(hcasm assembler-core pog) +target_link_libraries(hcasm assembler-core pog -L${HyperCPU_SOURCE_DIR}/dist/libbacktrace -lbacktrace) add_executable(hcemul ${SOURCES_emulator-main}) +add_dependencies(hcemul libbacktrace) target_include_directories(hcemul PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Emulator) -target_link_libraries(hcemul emulator-core assembler-core) +target_link_libraries(hcemul emulator-core assembler-core -L${HyperCPU_SOURCE_DIR}/dist/libbacktrace -lbacktrace) add_custom_target(default DEPENDS diff --git a/src/Logger/Colors.hpp b/src/Logger/Colors.hpp index bb43ca68..3d75e0a9 100644 --- a/src/Logger/Colors.hpp +++ b/src/Logger/Colors.hpp @@ -2,6 +2,7 @@ static constexpr char RESET[] = "\e[0m"; static constexpr char B_RED[] = "\e[1;31m"; +static constexpr char B_GREEN[] = "\e[1;32m"; static constexpr char B_YELLOW[] = "\e[1;33m"; static constexpr char RED[] = "\e[0;31m"; static constexpr char YELLOW[] = "\e[0;33m"; \ No newline at end of file From e9c381443f672292a874c91e57394b2aa0a32f08 Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Fri, 11 Apr 2025 23:18:34 +0400 Subject: [PATCH 5/7] Logic implemented, messages fixed --- src/Assembler/Main/BacktraceProvider.cpp | 60 ++++++++++-------------- src/Assembler/Main/BacktraceProvider.hpp | 8 ++-- 2 files changed, 28 insertions(+), 40 deletions(-) diff --git a/src/Assembler/Main/BacktraceProvider.cpp b/src/Assembler/Main/BacktraceProvider.cpp index e1c88ae9..36756c40 100644 --- a/src/Assembler/Main/BacktraceProvider.cpp +++ b/src/Assembler/Main/BacktraceProvider.cpp @@ -1,3 +1,4 @@ +#include #ifdef HCPU_ENABLE_LIBUNWIND #include @@ -19,35 +20,51 @@ extern "C" { } void bt_error_callback(void*, [[maybe_unused]] const char* msg, [[maybe_unused]] int err) { - std::puts("Error while getting the stacktrace!"); + fmt::println("{}[!] Error while getting the stacktrace!{}", B_RED, RESET); } int bt_callback(void*, uintptr_t, const char* filename, int lineno, const char* function) { - if (global_bt_controller.HasFinished() || global_bt_controller.iteration++ != 2) { + if (global_bt_controller.HasFinished() || global_bt_controller.iteration < 2) { + ++global_bt_controller.iteration; return 0; } + // Demangle function name const char* func_name = function; int status; + unw_word_t pc, sp; char* demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status); if (!status) { func_name = demangled; } + // Null pointer protection if (!func_name) { func_name = ""; } else if (!std::strcmp(func_name, "main")) { global_bt_controller.SetFinished(); } - if (!filename) { filename = ""; } - fmt::println("{}:{} in function {}", filename, lineno, func_name); + // Extract PC and SP + if (unw_get_reg(&global_bt_controller.cursor, UNW_REG_IP, &pc)) { + fmt::println("{}[!] Unwinding stack failed: couldn't get PC!{}", B_RED, RESET); + std::exit(1); + } - std::free(demangled); + if (unw_get_reg(&global_bt_controller.cursor, UNW_REG_SP, &sp)) { + fmt::println("{}[!] Unwinding stack failed: couldn't get SP!{}", B_RED, RESET); + std::exit(1); + } + fmt::println("{}frame #{} (PC: {:#x}, SP: {:#x}){}", B_YELLOW, global_bt_controller.iteration, pc, sp, RESET); + fmt::println("{}{}:{}, function: {}{}", B_YELLOW, filename, lineno, func_name, RESET); + + std::free(demangled); + + ++global_bt_controller.iteration; return 0; } @@ -61,12 +78,12 @@ BacktraceController global_bt_controller; void BacktraceController::Run() { fmt::println("\n{}[!] HyperCPU encountered a segmentation fault!{}", B_RED, RESET); if (unw_getcontext(&context) < 0) { - std::puts("Unwinding stack failed: couldn't initialize context"); + fmt::println("{}[!] Unwinding stack failed: couldn't initialize the context!{}", B_RED, RESET); std::exit(1); } if (unw_init_local(&cursor, &context) < 0) { - std::puts("Unwinding stack failed: couldn't initialize context"); + fmt::println("{}[!] Unwinding stack failed: couldn't initialize the context!{}", B_RED, RESET); std::exit(1); } fmt::println("{}[>] Libunwind context initialized successfully, generating stack trace...{}\n", B_GREEN, RESET); @@ -74,35 +91,6 @@ void BacktraceController::Run() { unw_step(&cursor); backtrace_full((backtrace_state*)bt_state, 0, bt_callback, bt_error_callback, nullptr); - - /* - unw_step(&cursor); // We should skip one more frame - RunBacktraceController - - while (unw_step(&cursor) > 0) { - unw_word_t offset, pc, sp; - char sym[512] = {""}; - char* name = sym; - - if (unw_get_reg(&cursor, UNW_REG_IP, &pc)) { - std::puts("Unwinding stack failed: couldn't get PC"); - std::exit(1); - } - - if (unw_get_reg(&cursor, UNW_REG_SP, &sp)) { - std::puts("Unwinding stack failed: couldn't get SP"); - std::exit(1); - } - - if (!unw_get_proc_name(&cursor, sym, sizeof(sym), &offset)) { - int status; - if ((name = abi::__cxa_demangle(sym, NULL, NULL, &status)) == 0) { - name = sym; - } - } - - fmt::println("{}", sym); - } - */ } void BacktraceController::SetFinished() { diff --git a/src/Assembler/Main/BacktraceProvider.hpp b/src/Assembler/Main/BacktraceProvider.hpp index f62edd94..d56285e9 100644 --- a/src/Assembler/Main/BacktraceProvider.hpp +++ b/src/Assembler/Main/BacktraceProvider.hpp @@ -19,11 +19,11 @@ class BacktraceController { bool HasFinished(); int iteration; // to slice entries that are not needed -private: - // libunwind - [[maybe_unused]] unw_cursor_t cursor; - [[maybe_unused]] unw_context_t context; + // libunwind + unw_cursor_t cursor; + unw_context_t context; +private: // libbacktrace void* bt_state; From f89d23f65f4688f71cc5b6a54898ed2ecb38a77c Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Mon, 14 Apr 2025 07:54:35 +0400 Subject: [PATCH 6/7] Enable signal handler, make CMake switch --- cmake/Configuration.cmake | 8 ++-- cmake/TargetAndFolderAssoc.cmake | 5 +++ cmake/Variables.cmake | 5 --- src/Assembler/Main/Main.cpp | 10 +++-- .../BacktraceProvider.cpp | 38 +++++++++++------ .../BacktraceProvider.hpp | 4 +- src/CMakeLists.txt | 41 +++++++++++-------- src/Emulator/Main/Main.cpp | 13 +++++- test/CMakeLists.txt | 10 ++--- 9 files changed, 86 insertions(+), 48 deletions(-) rename src/{Assembler/Main => BacktraceProvider}/BacktraceProvider.cpp (77%) rename src/{Assembler/Main => BacktraceProvider}/BacktraceProvider.hpp (87%) diff --git a/cmake/Configuration.cmake b/cmake/Configuration.cmake index a4e44b75..16e95fa8 100644 --- a/cmake/Configuration.cmake +++ b/cmake/Configuration.cmake @@ -39,11 +39,11 @@ function(set_compile_flags) endif() find_library(LIBUNWIND unwind) - find_library(LIBBACKTRACE backtrace) - if (LIBUNWIND AND LIBBACKTRACE) - message(STATUS "Found libunwind and libbacktrace") + set(LIBUNWIND ${LIBUNWIND} PARENT_SCOPE) + if (LIBUNWIND) + message(STATUS "Found libunwind") add_compile_options(-DHCPU_ENABLE_LIBUNWIND) - add_link_options(-L/usr/local/lib -lunwind -lbacktrace) + add_link_options(-L${ROOT_DIR}/dist/libbacktrace -lunwind -lbacktrace) endif() endfunction() diff --git a/cmake/TargetAndFolderAssoc.cmake b/cmake/TargetAndFolderAssoc.cmake index c2fc8e60..ee27762c 100644 --- a/cmake/TargetAndFolderAssoc.cmake +++ b/cmake/TargetAndFolderAssoc.cmake @@ -6,6 +6,8 @@ set(__TARGETS_LIST assembler-core assembler-main + backtrace-provider + # Testing modular_testing @@ -25,6 +27,9 @@ set(__DIRECTORIES_LIST # assembler-main target ${ROOT_DIR}/src/Assembler/Main +# backtrace-provider target + ${ROOT_DIR}/src/BacktraceProvider + # modulartesting_src target ${ROOT_DIR}/test/Modular diff --git a/cmake/Variables.cmake b/cmake/Variables.cmake index a6f3b6b3..1d185b4f 100644 --- a/cmake/Variables.cmake +++ b/cmake/Variables.cmake @@ -1,7 +1,2 @@ -if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(LTO_FLAG "-flto=thin") -elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(LTO_FLAG "-flto") -endif() set(DEBUG_COMPILE_FLAGS -Wall -Wextra -Werror -Wno-pointer-arith -O0 -ggdb3 -Wno-unused-const-variable -Wno-missing-field-initializers -Wno-stringop-overflow -Wno-unknown-warning-option -D__HCPU_DEBUG) set(FAST_COMPILE_FLAGS -Wall -Wextra -Werror -Wno-pointer-arith -O3 -Wno-unused-const-variable -Wno-missing-field-initializers -Wno-stringop-overflow -Wno-unknown-warning-option) diff --git a/src/Assembler/Main/Main.cpp b/src/Assembler/Main/Main.cpp index 59c501ae..5a8e6954 100644 --- a/src/Assembler/Main/Main.cpp +++ b/src/Assembler/Main/Main.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -14,7 +15,7 @@ #include #ifdef HCPU_ENABLE_LIBUNWIND -#include
+#include #endif constexpr const inline auto loglevel_assoc = mapbox::eternal::map({ @@ -25,9 +26,12 @@ constexpr const inline auto loglevel_assoc = mapbox::eternal::map #ifdef HCPU_ENABLE_LIBUNWIND +#include + +#include #include #include #include @@ -10,13 +12,26 @@ #include #include +#include -#include
+#include #include extern "C" { + void SignalHandler(int signal) { + switch(signal) { + case SIGSEGV: + catched_signal_type = "SIGSEGV"; + break; + case SIGFPE: + catched_signal_type = "SIGFPE"; + break; + } + global_bt_controller.Run(); + } + void bt_create_error_callback(void*, const char* msg, int err) { - printf("Error %d occurred when initializing the stack trace: %s", err, msg); + fmt::println("Error {} occurred when generating the stack trace: {}", err, msg); } void bt_error_callback(void*, [[maybe_unused]] const char* msg, [[maybe_unused]] int err) { @@ -24,7 +39,7 @@ extern "C" { } int bt_callback(void*, uintptr_t, const char* filename, int lineno, const char* function) { - if (global_bt_controller.HasFinished() || global_bt_controller.iteration < 2) { + if (global_bt_controller.HasFinished() || global_bt_controller.iteration < 3) { ++global_bt_controller.iteration; return 0; } @@ -33,9 +48,9 @@ extern "C" { const char* func_name = function; int status; unw_word_t pc, sp; - char* demangled = abi::__cxa_demangle(function, nullptr, nullptr, &status); + std::unique_ptr demangled{abi::__cxa_demangle(function, nullptr, nullptr, &status), &std::free}; if (!status) { - func_name = demangled; + func_name = demangled.get(); } // Null pointer protection @@ -62,21 +77,18 @@ extern "C" { fmt::println("{}frame #{} (PC: {:#x}, SP: {:#x}){}", B_YELLOW, global_bt_controller.iteration, pc, sp, RESET); fmt::println("{}{}:{}, function: {}{}", B_YELLOW, filename, lineno, func_name, RESET); - std::free(demangled); + unw_step(&global_bt_controller.cursor); ++global_bt_controller.iteration; return 0; } - - void RunBacktraceController() { - global_bt_controller.Run(); - } } BacktraceController global_bt_controller; +std::string_view catched_signal_type; void BacktraceController::Run() { - fmt::println("\n{}[!] HyperCPU encountered a segmentation fault!{}", B_RED, RESET); + fmt::println("\n{}[!] HyperCPU encountered a {}!{}", B_RED, catched_signal_type, RESET); if (unw_getcontext(&context) < 0) { fmt::println("{}[!] Unwinding stack failed: couldn't initialize the context!{}", B_RED, RESET); std::exit(1); @@ -91,6 +103,8 @@ void BacktraceController::Run() { unw_step(&cursor); backtrace_full((backtrace_state*)bt_state, 0, bt_callback, bt_error_callback, nullptr); + + std::abort(); } void BacktraceController::SetFinished() { diff --git a/src/Assembler/Main/BacktraceProvider.hpp b/src/BacktraceProvider/BacktraceProvider.hpp similarity index 87% rename from src/Assembler/Main/BacktraceProvider.hpp rename to src/BacktraceProvider/BacktraceProvider.hpp index d56285e9..4b0d8d55 100644 --- a/src/Assembler/Main/BacktraceProvider.hpp +++ b/src/BacktraceProvider/BacktraceProvider.hpp @@ -1,4 +1,5 @@ #ifdef HCPU_ENABLE_LIBUNWIND +#include #include #include @@ -32,7 +33,8 @@ class BacktraceController { }; extern BacktraceController global_bt_controller; +extern std::string_view catched_signal_type; -extern "C" void RunBacktraceController(); +extern "C" void SignalHandler(int); #endif \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8a524b9a..1a099227 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,45 +1,52 @@ include(ExternalProject) set(GENERIC_INCLUDE_DIR - ${HyperCPU_SOURCE_DIR}/src - ${HyperCPU_SOURCE_DIR}/dist/argparse/include - ${HyperCPU_SOURCE_DIR}/dist/pog/include - ${HyperCPU_SOURCE_DIR}/dist/eternal/include - ${HyperCPU_SOURCE_DIR}/dist/HPool) + ${ROOT_DIR}/src + ${ROOT_DIR}/dist/argparse/include + ${ROOT_DIR}/dist/pog/include + ${ROOT_DIR}/dist/eternal/include + ${ROOT_DIR}/dist/HPool) ExternalProject_Add( libbacktrace SOURCE_DIR - ${HyperCPU_SOURCE_DIR}/dist/libbacktrace + ${ROOT_DIR}/dist/libbacktrace BUILD_IN_SOURCE 0 CONFIGURE_COMMAND - cd ${HyperCPU_SOURCE_DIR}/dist/libbacktrace && ./configure + cd ${ROOT_DIR}/dist/libbacktrace && ./configure BUILD_COMMAND - cd ${HyperCPU_SOURCE_DIR}/dist/libbacktrace && make -j$(nproc) + cd ${ROOT_DIR}/dist/libbacktrace && make -j$(nproc) INSTALL_COMMAND "" BUILD_BYPRODUCTS - ${HyperCPU_SOURCE_DIR}/dist/libbacktrace/libbacktrace.la + ${ROOT_DIR}/dist/libbacktrace/libbacktrace.la ) add_library(emulator-core STATIC ${SOURCES_emulator-core}) -target_include_directories(emulator-core PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Emulator) +target_include_directories(emulator-core PUBLIC ${GENERIC_INCLUDE_DIR} ${ROOT_DIR}/src/Emulator) target_link_libraries(emulator-core ${LD_FLAGS} fmt) add_library(assembler-core STATIC ${SOURCES_assembler-core}) -target_include_directories(assembler-core PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Assembler) +target_include_directories(assembler-core PUBLIC ${GENERIC_INCLUDE_DIR} ${ROOT_DIR}/src/Assembler) target_link_libraries(assembler-core pog) +add_library(backtrace-provider STATIC ${SOURCES_backtrace-provider}) +target_include_directories(backtrace-provider PUBLIC ${GENERIC_INCLUDE_DIR}) +add_dependencies(backtrace-provider libbacktrace) + add_executable(hcasm ${SOURCES_assembler-main}) -add_dependencies(hcasm libbacktrace) -target_include_directories(hcasm PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Assembler) -target_link_libraries(hcasm assembler-core pog -L${HyperCPU_SOURCE_DIR}/dist/libbacktrace -lbacktrace) +target_include_directories(hcasm PUBLIC ${GENERIC_INCLUDE_DIR} ${ROOT_DIR}/src/Assembler) +target_link_libraries(hcasm assembler-core pog) add_executable(hcemul ${SOURCES_emulator-main}) -add_dependencies(hcemul libbacktrace) -target_include_directories(hcemul PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Emulator) -target_link_libraries(hcemul emulator-core assembler-core -L${HyperCPU_SOURCE_DIR}/dist/libbacktrace -lbacktrace) +target_include_directories(hcemul PUBLIC ${GENERIC_INCLUDE_DIR} ${ROOT_DIR}/src/Emulator) +target_link_libraries(hcemul emulator-core assembler-core) + +if (LIBUNWIND) + target_link_libraries(hcasm backtrace-provider -L${ROOT_DIR}/dist/libbacktrace backtrace) + target_link_libraries(hcemul backtrace-provider -L${ROOT_DIR}/dist/libbacktrace backtrace) +endif() add_custom_target(default DEPENDS diff --git a/src/Emulator/Main/Main.cpp b/src/Emulator/Main/Main.cpp index e5f2e8a4..1b824434 100644 --- a/src/Emulator/Main/Main.cpp +++ b/src/Emulator/Main/Main.cpp @@ -1,7 +1,8 @@ #include #include -#include +#include + #include #include #include @@ -12,9 +13,19 @@ #include +#ifdef HCPU_ENABLE_LIBUNWIND +#include +#endif + HyperCPU::GenericHeader ParseHeader(std::ifstream& binary); int main(int argc, char** argv) { +#ifdef HCPU_ENABLE_LIBUNWIND + global_bt_controller = BacktraceController(argv[0]); + + std::signal(SIGSEGV, SignalHandler); + std::signal(SIGFPE, SignalHandler); +#endif HyperCPU::Logger logger{HyperCPU::LogLevel::ERROR}; argparse::ArgumentParser program("hcemul", HCPU_VERSION); program.add_argument("binary") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5bb2c3b4..77e5ec8a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,15 +1,15 @@ include(../cmake/Variables.cmake) set(TESTS_INCLUDE_DIR - ${HyperCPU_SOURCE_DIR}/dist/eternal/include - ${HyperCPU_SOURCE_DIR}/src/Emulator - ${HyperCPU_SOURCE_DIR}/test) + ${ROOT_DIR}/dist/eternal/include + ${ROOT_DIR}/src/Emulator + ${ROOT_DIR}/test) -add_executable(modular_testing ${HyperCPU_SOURCE_DIR}/test/main.cpp ${SOURCES_modular_testing}) +add_executable(modular_testing ${ROOT_DIR}/test/main.cpp ${SOURCES_modular_testing}) target_link_libraries(modular_testing emulator-core assembler-core gtest pthread) target_include_directories(modular_testing PUBLIC ${TESTS_INCLUDE_DIR}) -add_executable(integration_testing ${HyperCPU_SOURCE_DIR}/test/main.cpp ${SOURCES_integration_testing}) +add_executable(integration_testing ${ROOT_DIR}/test/main.cpp ${SOURCES_integration_testing}) target_link_libraries(integration_testing emulator-core assembler-core gtest pthread) target_include_directories(integration_testing PUBLIC ${TESTS_INCLUDE_DIR}) From 9935deca01ba5f6ab746247b8a9ce6226a0327a1 Mon Sep 17 00:00:00 2001 From: HyperWinX Date: Mon, 14 Apr 2025 11:22:02 +0400 Subject: [PATCH 7/7] Fix workflow bug --- .github/workflows/distro-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/distro-ci.yml b/.github/workflows/distro-ci.yml index 75c6c769..56848d43 100644 --- a/.github/workflows/distro-ci.yml +++ b/.github/workflows/distro-ci.yml @@ -38,8 +38,9 @@ jobs: set -e DISTRO=$( cat /etc/*-release | tr [:upper:] [:lower:] | grep -Poi '(debian|ubuntu|fedora|gentoo|alpine)' | uniq ) if [ "$DISTRO" == "gentoo" ]; then source /etc/profile; fi - git clone https://github.com/HyperWinX/HyperCPU.git --recursive && cd HyperCPU + git clone https://github.com/HyperWinX/HyperCPU.git && cd HyperCPU git switch "${{ github.head_ref }}" + git submodule update --init --recursive cd dist/pog && git pull origin master && cd ../.. cmake -S. -Bbuild -DHCPU_COMPILER=clang -DHCPU_LTO=ON -DHCPU_SANITIZERS=OFF -DCMAKE_BUILD_TYPE=Release cmake --build build --target run-all-tests-github -j8