Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/distro-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions cmake/Configuration.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ function(set_compile_flags)
add_link_options(-fsanitize=address,leak)
message(STATUS "Enabling sanitizers")
endif()

find_library(LIBUNWIND unwind)
set(LIBUNWIND ${LIBUNWIND} PARENT_SCOPE)
if (LIBUNWIND)
message(STATUS "Found libunwind")
add_compile_options(-DHCPU_ENABLE_LIBUNWIND)
add_link_options(-L${ROOT_DIR}/dist/libbacktrace -lunwind -lbacktrace)
endif()
endfunction()

function(detect_compilers)
Expand Down
5 changes: 5 additions & 0 deletions cmake/TargetAndFolderAssoc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ set(__TARGETS_LIST
assembler-core
assembler-main

backtrace-provider


# Testing
modular_testing
Expand All @@ -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

Expand Down
5 changes: 0 additions & 5 deletions cmake/Variables.cmake
Original file line number Diff line number Diff line change
@@ -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)
1 change: 1 addition & 0 deletions dist/libbacktrace
Submodule libbacktrace added at 793921
10 changes: 10 additions & 0 deletions src/Assembler/Main/Main.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <csignal>
#include <filesystem>
#include <fstream>

Expand All @@ -13,6 +14,9 @@

#include <mapbox/eternal.hpp>

#ifdef HCPU_ENABLE_LIBUNWIND
#include <BacktraceProvider/BacktraceProvider.hpp>
#endif

constexpr const inline auto loglevel_assoc = mapbox::eternal::map<mapbox::eternal::string, HyperCPU::LogLevel>({
{"debug", HyperCPU::LogLevel::DEBUG},
Expand All @@ -22,6 +26,12 @@ constexpr const inline auto loglevel_assoc = mapbox::eternal::map<mapbox::eterna
});

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
argparse::ArgumentParser program("hcasm");
program.add_argument("source")
.help("source file to be assembled")
Expand Down
118 changes: 118 additions & 0 deletions src/BacktraceProvider/BacktraceProvider.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#ifdef HCPU_ENABLE_LIBUNWIND

#include <memory>

#include <csignal>
#include <cstdlib>
#include <cstdio>
#include <cxxabi.h>

#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <backtrace.h>

#include <fmt/printf.h>
#include <fmt/base.h>

#include <BacktraceProvider/BacktraceProvider.hpp>
#include <Logger/Colors.hpp>

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) {
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) {
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 < 3) {
++global_bt_controller.iteration;
return 0;
}

// Demangle function name
const char* func_name = function;
int status;
unw_word_t pc, sp;
std::unique_ptr<char, decltype(&std::free)> demangled{abi::__cxa_demangle(function, nullptr, nullptr, &status), &std::free};
if (!status) {
func_name = demangled.get();
}

// Null pointer protection
if (!func_name) {
func_name = "<unknown>";
} else if (!std::strcmp(func_name, "main")) {
global_bt_controller.SetFinished();
}
if (!filename) {
filename = "<unknown>";
}

// 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);
}

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);

unw_step(&global_bt_controller.cursor);

++global_bt_controller.iteration;
return 0;
}
}

BacktraceController global_bt_controller;
std::string_view catched_signal_type;

void BacktraceController::Run() {
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);
}

if (unw_init_local(&cursor, &context) < 0) {
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);

unw_step(&cursor);

backtrace_full((backtrace_state*)bt_state, 0, bt_callback, bt_error_callback, nullptr);

std::abort();
}

void BacktraceController::SetFinished() {
finished = true;
}

bool BacktraceController::HasFinished() {
return finished;
}

#endif
40 changes: 40 additions & 0 deletions src/BacktraceProvider/BacktraceProvider.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifdef HCPU_ENABLE_LIBUNWIND
#include <string_view>

#include <backtrace.h>
#include <libunwind.h>

extern "C" {
void bt_create_error_callback(void*, const char* msg, int err);
}

class BacktraceController {
public:
BacktraceController() = default;
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

// libunwind
unw_cursor_t cursor;
unw_context_t context;
private:
// libbacktrace
void* bt_state;

// internals
bool finished;
};

extern BacktraceController global_bt_controller;
extern std::string_view catched_signal_type;

extern "C" void SignalHandler(int);

#endif
45 changes: 36 additions & 9 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,26 +1,53 @@
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
${ROOT_DIR}/dist/libbacktrace
BUILD_IN_SOURCE
0
CONFIGURE_COMMAND
cd ${ROOT_DIR}/dist/libbacktrace && ./configure
BUILD_COMMAND
cd ${ROOT_DIR}/dist/libbacktrace && make -j$(nproc)
INSTALL_COMMAND
""
BUILD_BYPRODUCTS
${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})
target_include_directories(hcasm PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Assembler)
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})
target_include_directories(hcemul PUBLIC ${GENERIC_INCLUDE_DIR} ${HyperCPU_SOURCE_DIR}/src/Emulator)
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
hcasm
Expand Down
13 changes: 12 additions & 1 deletion src/Emulator/Main/Main.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include <filesystem>
#include <limits>

#include <Assembler/Utils/Extension.hpp>
#include <csignal>

#include <Assembler/Core/Compiler.hpp>
#include <Emulator/Core/CPU/CPU.hpp>
#include <Emulator/Main/Main.hpp>
Expand All @@ -12,9 +13,19 @@

#include <argparse/argparse.hpp>

#ifdef HCPU_ENABLE_LIBUNWIND
#include <BacktraceProvider/BacktraceProvider.hpp>
#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")
Expand Down
1 change: 1 addition & 0 deletions src/Logger/Colors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Empty file added test.cpp
Empty file.
10 changes: 5 additions & 5 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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})

Expand Down