diff --git a/CMakeLists.txt b/CMakeLists.txt index 2049351..33fd480 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,7 +66,40 @@ else() endif() # ========================================== Platform Support and Auto-config ========================================== -include(cmake/Autoconfig.cmake) +if(NOT EMSCRIPTEN) + include(cmake/Autoconfig.cmake) +else() + if( + CPPTRACE_UNWIND_WITH_UNWIND OR + CPPTRACE_UNWIND_WITH_LIBUNWIND OR + CPPTRACE_UNWIND_WITH_EXECINFO OR + CPPTRACE_UNWIND_WITH_WINAPI OR + CPPTRACE_UNWIND_WITH_DBGHELP OR + CPPTRACE_UNWIND_WITH_NOTHING + ) + message(FATAL_ERROR "Cpptrace config error: Unwinding back-end may not be specified under emscripten.") + endif() + if( + CPPTRACE_GET_SYMBOLS_WITH_LIBBACKTRACE OR + CPPTRACE_GET_SYMBOLS_WITH_LIBDL OR + CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE OR + CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF OR + CPPTRACE_GET_SYMBOLS_WITH_DBGHELP OR + CPPTRACE_GET_SYMBOLS_WITH_NOTHING + ) + message(FATAL_ERROR "Cpptrace config error: Symbol back-end may not be specified under emscripten.") + endif() + if( + CPPTRACE_DEMANGLE_WITH_CXXABI OR + CPPTRACE_DEMANGLE_WITH_WINAPI OR + CPPTRACE_DEMANGLE_WITH_NOTHING + ) + message(FATAL_ERROR "Cpptrace config error: Demangling back-end may not be specified under emscripten.") + endif() + set(CPPTRACE_UNWIND_WITH_NOTHING On) + set(CPPTRACE_GET_SYMBOLS_WITH_NOTHING On) + set(CPPTRACE_DEMANGLE_WITH_NOTHING On) +endif() # =================================================== Library Setup ==================================================== @@ -469,6 +502,13 @@ if(CPPTRACE_DEMANGLE_WITH_NOTHING) target_compile_definitions(${target_name} PUBLIC CPPTRACE_DEMANGLE_WITH_NOTHING) endif() +# Emscripten +if(EMSCRIPTEN) + target_compile_definitions(${target_name} PUBLIC CPPTRACE_EMSCRIPTEN) +endif() + +# Other options + if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "") target_compile_definitions(${target_name} PUBLIC CPPTRACE_BACKTRACE_PATH=${CPPTRACE_BACKTRACE_PATH}) endif() diff --git a/src/binary/module_base.cpp b/src/binary/module_base.cpp index 88deca2..56a4714 100644 --- a/src/binary/module_base.cpp +++ b/src/binary/module_base.cpp @@ -68,7 +68,7 @@ namespace detail { return it->second; } } - #else // Windows + #elif IS_WINDOWS Result get_module_image_base(const std::string& object_path) { static std::mutex mutex; std::lock_guard lock(mutex); diff --git a/src/binary/object.cpp b/src/binary/object.cpp index 7f4d524..3e83cf1 100644 --- a/src/binary/object.cpp +++ b/src/binary/object.cpp @@ -107,7 +107,7 @@ namespace detail { return frame; } #endif - #else + #elif IS_WINDOWS std::string get_module_name(HMODULE handle) { static std::mutex mutex; std::lock_guard lock(mutex); @@ -153,6 +153,10 @@ namespace detail { } return frame; } + #elif IS_EMSCRIPTEN + object_frame get_frame_object_info(frame_ptr) { + return {}; + } #endif std::vector get_frames_object_info(const std::vector& addresses) { diff --git a/src/binary/object.hpp b/src/binary/object.hpp index 933d6cd..ce50c69 100644 --- a/src/binary/object.hpp +++ b/src/binary/object.hpp @@ -7,7 +7,6 @@ #include namespace cpptrace { - namespace detail { object_frame get_frame_object_info(frame_ptr address); diff --git a/src/cpptrace.cpp b/src/cpptrace.cpp index 2315c62..815ebee 100644 --- a/src/cpptrace.cpp +++ b/src/cpptrace.cpp @@ -18,6 +18,7 @@ #include "binary/object.hpp" #include "binary/safe_dl.hpp" #include "snippets/snippet.hpp" +#include "platform/emscripten.hpp" namespace cpptrace { CPPTRACE_FORCE_NO_INLINE @@ -396,12 +397,16 @@ namespace cpptrace { CPPTRACE_FORCE_NO_INLINE stacktrace generate_trace(std::size_t skip, std::size_t max_depth) { try { + #if IS_EMSCRIPTEN + return detail::generate_emscripten_trace(skip + 1, max_depth); + #else std::vector frames = detail::capture_frames(skip + 1, max_depth); std::vector trace = detail::resolve_frames(frames); for(auto& frame : trace) { frame.symbol = detail::demangle(frame.symbol); } return {std::move(trace)}; + #endif } catch(...) { // NOSONAR if(!detail::should_absorb_trace_exceptions()) { throw; diff --git a/src/platform/emscripten.hpp b/src/platform/emscripten.hpp new file mode 100644 index 0000000..253df86 --- /dev/null +++ b/src/platform/emscripten.hpp @@ -0,0 +1,33 @@ +#ifndef EMSCRIPTEN_HPP +#define EMSCRIPTEN_HPP + +#include "platform/platform.hpp" + +#if IS_EMSCRIPTEN + +#include +#include +#include "utils/microfmt.hpp" + +namespace cpptrace { +namespace detail { + CPPTRACE_FORCE_NO_INLINE + stacktrace generate_emscripten_trace(std::size_t skip, std::size_t max_depth) { + int estimated_size = emscripten_get_callstack(0, nullptr, 0); + VERIFY(estimated_size >= 0); + // "Note that this might be fully accurate since subsequent calls will carry different line numbers, so it is + // best to allocate a few bytes extra to be safe." + // Thanks, emscripten + const auto max_size = estimated_size + 1000; + // actually do the trace now + std::unique_ptr buffer(new char[max_size]); + emscripten_get_callstack(0, buffer.get(), max_size); + microfmt::print("{}\n", buffer.get()); + return {}; + } +} +} + +#endif + +#endif diff --git a/src/platform/platform.hpp b/src/platform/platform.hpp index 89206e8..a9eeed2 100644 --- a/src/platform/platform.hpp +++ b/src/platform/platform.hpp @@ -14,6 +14,9 @@ #elif defined(__APPLE__) #undef IS_APPLE #define IS_APPLE 1 +#elif defined(__EMSCRIPTEN__) + #undef IS_EMSCRIPTEN + #define IS_EMSCRIPTEN 1 #else #error "Unexpected platform" #endif @@ -32,7 +35,7 @@ #undef IS_MSVC #define IS_MSVC 1 #else - #error "Unsupported compiler" +// #error "Unsupported compiler" #endif #define IS_LIBSTDCXX 0 diff --git a/src/symbols/symbols_core.cpp b/src/symbols/symbols_core.cpp index ab7574d..c707436 100644 --- a/src/symbols/symbols_core.cpp +++ b/src/symbols/symbols_core.cpp @@ -84,7 +84,9 @@ namespace detail { } std::vector resolve_frames(const std::vector& frames) { - #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) && defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) + #if IS_EMSCRIPTEN + return {}; // TODO + #elif defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) && defined(CPPTRACE_GET_SYMBOLS_WITH_DBGHELP) std::vector trace = libdwarf::resolve_frames(frames); fill_blanks(trace, dbghelp::resolve_frames); return trace; @@ -120,7 +122,9 @@ namespace detail { } std::vector resolve_frames(const std::vector& frames) { - #if defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) \ + #if IS_EMSCRIPTEN + return {}; // TODO + #elif defined(CPPTRACE_GET_SYMBOLS_WITH_LIBDWARF) \ || defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE) auto dlframes = get_frames_object_info(frames); #endif diff --git a/test/demo.cpp b/test/demo.cpp index 46ba38d..cb521ac 100644 --- a/test/demo.cpp +++ b/test/demo.cpp @@ -8,7 +8,7 @@ void trace() { cpptrace::generate_trace().print(); cpptrace::generate_trace().print_with_snippets(); - throw cpptrace::logic_error("foobar"); + // throw cpptrace::logic_error("foobar"); } void foo(int n) { diff --git a/test/unit/raw_trace.cpp b/test/unit/raw_trace.cpp index b5a2715..e6d7959 100644 --- a/test/unit/raw_trace.cpp +++ b/test/unit/raw_trace.cpp @@ -25,7 +25,7 @@ CPPTRACE_FORCE_NO_INLINE static void raw_trace_basic() { EXPECT_LE(raw_trace.frames[0], reinterpret_cast(raw_trace_basic) + 90); } -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) CPPTRACE_FORCE_NO_INLINE void raw_trace_basic_precise() { a: auto raw_trace = cpptrace::generate_raw_trace(); @@ -46,7 +46,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_basic_precise() { TEST(RawTrace, Basic) { raw_trace_basic(); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) raw_trace_basic_precise(); #endif [[maybe_unused]] volatile int x = 0; // prevent raw_trace_basic_precise() above being a jmp @@ -80,7 +80,7 @@ CPPTRACE_FORCE_NO_INLINE void record_parent(uintptr_t low_bound, uintptr_t high_ parents.insert(parents.begin(), {low_bound, high_bound}); } -#ifndef _MSC_VER +#if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_3() { a: auto raw_trace = cpptrace::generate_raw_trace(); @@ -161,7 +161,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_1() { TEST(RawTrace, MultipleCalls) { parents.clear(); raw_trace_multi_1(); - #ifndef _MSC_VER + #if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) raw_trace_multi_precise_1(); #endif }