diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f84236b..5e9d53ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") option(TOMATO_MAIN_SO "Build tomato as a shared object (for eg android apps)" ANDROID) option(TOMATO_ASAN "Build tomato with asan (gcc/clang/msvc)" OFF) +option(TOMATO_BREAKPAD "Build tomato with breakpad crash dumping" OFF) option(TOMATO_TOX_AV "Build tomato with ToxAV" OFF) -message("II TOMATO_TOX_AV: ${TOMATO_TOX_AV}") if (TOMATO_ASAN) if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") @@ -43,6 +43,17 @@ if (TOMATO_ASAN) endif() endif() +message("II TOMATO_BREAKPAD: ${TOMATO_BREAKPAD}") +if (TOMATO_BREAKPAD) + if (LINUX) # TODO: test if android + # HACK: workaround an ugly cmake bug, + # where subdirs can now propergate enable_language upwards + enable_language(ASM) + endif() +endif() + +message("II TOMATO_TOX_AV: ${TOMATO_TOX_AV}") + # uggly, but it needs to be defined for all of tomato. # but this also means that we can not compile tomato in the same cmake as plugins add_compile_definitions(ENTT_API_EXPORT) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index be952376..6b8ecd6d 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -24,3 +24,7 @@ add_subdirectory(./libwebp) add_subdirectory(./qoi) add_subdirectory(./sdl_image) +if (TOMATO_BREAKPAD) + add_subdirectory(./breakpad) +endif() + diff --git a/external/breakpad/CMakeLists.txt b/external/breakpad/CMakeLists.txt new file mode 100644 index 00000000..58e82416 --- /dev/null +++ b/external/breakpad/CMakeLists.txt @@ -0,0 +1,130 @@ +cmake_minimum_required(VERSION 3.16...3.24 FATAL_ERROR) + +include(FetchContent) + +if (NOT TARGET breakpad_client) + + if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR ${CMAKE_SYSTEM_NAME} STREQUAL "Android") + if (NOT TARGET lss) + FetchContent_Declare(lss + GIT_REPOSITORY https://chromium.googlesource.com/linux-syscall-support/ + GIT_TAG 9719c1e1e676814c456b55f5f070eabad6709d31 + + FIND_PACKAGE_ARGS # for the future + ) + FetchContent_GetProperties(lss) + if(NOT lss_POPULATED) + FetchContent_Populate(lss) + + # HACK: breakpad expects this at a specific path + configure_file( + ${lss_SOURCE_DIR}/linux_syscall_support.h + ${CMAKE_CURRENT_BINARY_DIR}/third_party/lss/linux_syscall_support.h + @ONLY + ) + + add_library(lss INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/third_party/lss/linux_syscall_support.h) + target_include_directories(lss INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) + endif() + endif() + endif() + + FetchContent_Declare(breakpad + GIT_REPOSITORY https://chromium.googlesource.com/breakpad/breakpad + GIT_TAG v2023.06.01 + + FIND_PACKAGE_ARGS # for the future + ) + FetchContent_GetProperties(breakpad) + if(NOT breakpad_POPULATED) + FetchContent_Populate(breakpad) + + enable_language(ASM) + add_library(breakpad_common STATIC + ${breakpad_SOURCE_DIR}/src/common/convert_UTF.h + ${breakpad_SOURCE_DIR}/src/common/convert_UTF.cc + ${breakpad_SOURCE_DIR}/src/common/md5.h + ${breakpad_SOURCE_DIR}/src/common/md5.cc + ${breakpad_SOURCE_DIR}/src/common/string_conversion.h + ${breakpad_SOURCE_DIR}/src/common/string_conversion.cc + ) + target_include_directories(breakpad_common PUBLIC "${breakpad_SOURCE_DIR}/src") + + if (WIN32) + # TODO: common + + add_library(breakpad_client STATIC) + target_sources(breakpad_client + PUBLIC + ${breakpad_SOURCE_DIR}/src/client/windows/handler/exception_handler.h + ${breakpad_SOURCE_DIR}/src/client/windows/common/ipc_protocol.h + ${breakpad_SOURCE_DIR}/src/client/windows/crash_generation/crash_generation_client.h + PRIVATE + ${breakpad_SOURCE_DIR}/src/client/windows/handler/exception_handler.cc + ) + #elseif() # TODO: mac, ios and any other platform + else() # assume linux + target_sources(breakpad_common PUBLIC + ${breakpad_SOURCE_DIR}/src/common/linux/elf_core_dump.cc + ${breakpad_SOURCE_DIR}/src/common/linux/elfutils.h + ${breakpad_SOURCE_DIR}/src/common/linux/elfutils.cc + ${breakpad_SOURCE_DIR}/src/common/linux/file_id.h + ${breakpad_SOURCE_DIR}/src/common/linux/file_id.cc + ${breakpad_SOURCE_DIR}/src/common/linux/guid_creator.h + ${breakpad_SOURCE_DIR}/src/common/linux/guid_creator.cc + ${breakpad_SOURCE_DIR}/src/common/linux/linux_libc_support.cc + ${breakpad_SOURCE_DIR}/src/common/linux/memory_mapped_file.cc + ${breakpad_SOURCE_DIR}/src/common/linux/safe_readlink.cc + ${breakpad_SOURCE_DIR}/src/common/linux/breakpad_getcontext.h + ${breakpad_SOURCE_DIR}/src/common/linux/breakpad_getcontext.S + ) + #set_property(SOURCE ${breakpad_SOURCE_DIR}/src/common/linux/breakpad_getcontext.S APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp") + + add_library(breakpad_client STATIC) + target_sources(breakpad_client + PUBLIC + ${breakpad_SOURCE_DIR}/src/client/linux/handler/exception_handler.h + ${breakpad_SOURCE_DIR}/src/client/linux/handler/minidump_descriptor.h + ${breakpad_SOURCE_DIR}/src/client/linux/crash_generation/crash_generation_client.h + ${breakpad_SOURCE_DIR}/src/client/linux/log/log.h + ${breakpad_SOURCE_DIR}/src/client/linux/microdump_writer/microdump_writer.h + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/minidump_writer.h + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/pe_file.h + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/pe_structs.h + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/proc_cpuinfo_reader.h + PRIVATE + ${breakpad_SOURCE_DIR}/src/client/linux/handler/exception_handler.cc + ${breakpad_SOURCE_DIR}/src/client/linux/handler/minidump_descriptor.cc + ${breakpad_SOURCE_DIR}/src/client/linux/crash_generation/crash_generation_client.cc + ${breakpad_SOURCE_DIR}/src/client/linux/crash_generation/crash_generation_server.cc + ${breakpad_SOURCE_DIR}/src/client/linux/log/log.cc + ${breakpad_SOURCE_DIR}/src/client/linux/microdump_writer/microdump_writer.cc + ${breakpad_SOURCE_DIR}/src/client/linux/dump_writer_common/thread_info.cc + ${breakpad_SOURCE_DIR}/src/client/linux/dump_writer_common/ucontext_reader.cc + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/minidump_writer.cc + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/linux_core_dumper.cc + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/linux_dumper.cc + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/linux_ptrace_dumper.cc + ${breakpad_SOURCE_DIR}/src/client/linux/minidump_writer/pe_file.cc + ) + endif() + + if (TARGET lss) + target_link_libraries(breakpad_common PUBLIC lss) + target_link_libraries(breakpad_client PUBLIC lss) + endif() + + if (TARGET breakpad_client) + target_sources(breakpad_client PUBLIC + ${breakpad_SOURCE_DIR}/src/client/minidump_file_writer-inl.h + ${breakpad_SOURCE_DIR}/src/client/minidump_file_writer.h + ${breakpad_SOURCE_DIR}/src/client/minidump_file_writer.cc + ) + target_link_libraries(breakpad_client PUBLIC breakpad_common) + target_include_directories(breakpad_client PUBLIC "${breakpad_SOURCE_DIR}/src") + target_compile_features(breakpad_client PUBLIC cxx_std_11) + endif() + endif() + #FetchContent_MakeAvailable(breakpad) +endif() + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6636b62b..42baa544 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,6 +126,16 @@ target_sources(tomato PUBLIC ./debug_video_tap.cpp ) +if (TOMATO_BREAKPAD) + target_sources(tomato PUBLIC + ./breakpad_client.hpp + ./breakpad_client.cpp + ) + + target_link_libraries(tomato PUBLIC breakpad_client) + target_compile_definitions(tomato PUBLIC TOMATO_BREAKPAD) +endif() + if (TOMATO_TOX_AV) target_sources(tomato PUBLIC ./tox_av.hpp @@ -167,9 +177,6 @@ target_link_libraries(tomato PUBLIC SDL3_image::SDL3_image ) -# probably not enough -#target_compile_definitions(tomato PUBLIC ENTT_API_EXPORT) - set_target_properties(tomato PROPERTIES POSITION_INDEPENDENT_CODE ON) ######################################## diff --git a/src/breakpad_client.cpp b/src/breakpad_client.cpp new file mode 100644 index 00000000..7a8027d9 --- /dev/null +++ b/src/breakpad_client.cpp @@ -0,0 +1,10 @@ +#include "./breakpad_client.hpp" + +// if linux + +bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void*, bool succeeded) { + fprintf(stderr, "Crash detected, MiniDump written to: %s\n", descriptor.path()); + return succeeded; +} + +// endif linux diff --git a/src/breakpad_client.hpp b/src/breakpad_client.hpp new file mode 100644 index 00000000..728574b0 --- /dev/null +++ b/src/breakpad_client.hpp @@ -0,0 +1,22 @@ +#pragma once + +// TODO: if linux/android + +#include + +bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void*, bool succeeded); + +#define BREAKPAD_MAIN_INIT \ + google_breakpad::MinidumpDescriptor bp_descriptor{"/tmp"}; \ + bp_descriptor.set_sanitize_stacks(true); /* *should* remove most PII from stack mem dump */ \ + bp_descriptor.set_size_limit(50*1024*1024); /* limit to 50mb */ \ + google_breakpad::ExceptionHandler bp_eh{ \ + bp_descriptor, \ + nullptr, \ + dumpCallback, \ + nullptr, \ + true, /* install handler */ \ + -1, /* dump in-process (OOP would be better) */ \ + } + +// endif linux diff --git a/src/main.cpp b/src/main.cpp index 1e66ce6e..4ce7ffdb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,14 +19,24 @@ #include #include +#ifdef TOMATO_BREAKPAD +# include "./breakpad_client.hpp" +#endif + int main(int argc, char** argv) { + runSysCheck(); + +#ifdef TOMATO_BREAKPAD + // TODO: maybe run before sys check? + BREAKPAD_MAIN_INIT; +#endif + // better args std::vector args; for (int i = 0; i < argc; i++) { args.push_back(argv[i]); } - runSysCheck(); SDL_SetAppMetadata("tomato", "0.0.0-wip", nullptr);