Emscripten experimentation

This commit is contained in:
Jeremy Rifkin 2024-11-10 10:11:12 -06:00
parent 04b85a0dfa
commit da533c0ef0
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
10 changed files with 100 additions and 12 deletions

View File

@ -66,7 +66,40 @@ else()
endif() endif()
# ========================================== Platform Support and Auto-config ========================================== # ========================================== 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 ==================================================== # =================================================== Library Setup ====================================================
@ -469,6 +502,13 @@ if(CPPTRACE_DEMANGLE_WITH_NOTHING)
target_compile_definitions(${target_name} PUBLIC CPPTRACE_DEMANGLE_WITH_NOTHING) target_compile_definitions(${target_name} PUBLIC CPPTRACE_DEMANGLE_WITH_NOTHING)
endif() endif()
# Emscripten
if(EMSCRIPTEN)
target_compile_definitions(${target_name} PUBLIC CPPTRACE_EMSCRIPTEN)
endif()
# Other options
if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "") if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")
target_compile_definitions(${target_name} PUBLIC CPPTRACE_BACKTRACE_PATH=${CPPTRACE_BACKTRACE_PATH}) target_compile_definitions(${target_name} PUBLIC CPPTRACE_BACKTRACE_PATH=${CPPTRACE_BACKTRACE_PATH})
endif() endif()

View File

@ -68,7 +68,7 @@ namespace detail {
return it->second; return it->second;
} }
} }
#else // Windows #elif IS_WINDOWS
Result<std::uintptr_t, internal_error> get_module_image_base(const std::string& object_path) { Result<std::uintptr_t, internal_error> get_module_image_base(const std::string& object_path) {
static std::mutex mutex; static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);

View File

@ -107,7 +107,7 @@ namespace detail {
return frame; return frame;
} }
#endif #endif
#else #elif IS_WINDOWS
std::string get_module_name(HMODULE handle) { std::string get_module_name(HMODULE handle) {
static std::mutex mutex; static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
@ -153,6 +153,10 @@ namespace detail {
} }
return frame; return frame;
} }
#elif IS_EMSCRIPTEN
object_frame get_frame_object_info(frame_ptr) {
return {};
}
#endif #endif
std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addresses) { std::vector<object_frame> get_frames_object_info(const std::vector<frame_ptr>& addresses) {

View File

@ -7,7 +7,6 @@
#include <cstdint> #include <cstdint>
namespace cpptrace { namespace cpptrace {
namespace detail { namespace detail {
object_frame get_frame_object_info(frame_ptr address); object_frame get_frame_object_info(frame_ptr address);

View File

@ -18,6 +18,7 @@
#include "binary/object.hpp" #include "binary/object.hpp"
#include "binary/safe_dl.hpp" #include "binary/safe_dl.hpp"
#include "snippets/snippet.hpp" #include "snippets/snippet.hpp"
#include "platform/emscripten.hpp"
namespace cpptrace { namespace cpptrace {
CPPTRACE_FORCE_NO_INLINE CPPTRACE_FORCE_NO_INLINE
@ -396,12 +397,16 @@ namespace cpptrace {
CPPTRACE_FORCE_NO_INLINE CPPTRACE_FORCE_NO_INLINE
stacktrace generate_trace(std::size_t skip, std::size_t max_depth) { stacktrace generate_trace(std::size_t skip, std::size_t max_depth) {
try { try {
#if IS_EMSCRIPTEN
return detail::generate_emscripten_trace(skip + 1, max_depth);
#else
std::vector<frame_ptr> frames = detail::capture_frames(skip + 1, max_depth); std::vector<frame_ptr> frames = detail::capture_frames(skip + 1, max_depth);
std::vector<stacktrace_frame> trace = detail::resolve_frames(frames); std::vector<stacktrace_frame> trace = detail::resolve_frames(frames);
for(auto& frame : trace) { for(auto& frame : trace) {
frame.symbol = detail::demangle(frame.symbol); frame.symbol = detail::demangle(frame.symbol);
} }
return {std::move(trace)}; return {std::move(trace)};
#endif
} catch(...) { // NOSONAR } catch(...) { // NOSONAR
if(!detail::should_absorb_trace_exceptions()) { if(!detail::should_absorb_trace_exceptions()) {
throw; throw;

View File

@ -0,0 +1,33 @@
#ifndef EMSCRIPTEN_HPP
#define EMSCRIPTEN_HPP
#include "platform/platform.hpp"
#if IS_EMSCRIPTEN
#include <emscripten.h>
#include <memory>
#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<char[]> buffer(new char[max_size]);
emscripten_get_callstack(0, buffer.get(), max_size);
microfmt::print("{}\n", buffer.get());
return {};
}
}
}
#endif
#endif

View File

@ -14,6 +14,9 @@
#elif defined(__APPLE__) #elif defined(__APPLE__)
#undef IS_APPLE #undef IS_APPLE
#define IS_APPLE 1 #define IS_APPLE 1
#elif defined(__EMSCRIPTEN__)
#undef IS_EMSCRIPTEN
#define IS_EMSCRIPTEN 1
#else #else
#error "Unexpected platform" #error "Unexpected platform"
#endif #endif
@ -32,7 +35,7 @@
#undef IS_MSVC #undef IS_MSVC
#define IS_MSVC 1 #define IS_MSVC 1
#else #else
#error "Unsupported compiler" // #error "Unsupported compiler"
#endif #endif
#define IS_LIBSTDCXX 0 #define IS_LIBSTDCXX 0

View File

@ -84,7 +84,9 @@ namespace detail {
} }
std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& frames) { std::vector<stacktrace_frame> resolve_frames(const std::vector<object_frame>& 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<stacktrace_frame> trace = libdwarf::resolve_frames(frames); std::vector<stacktrace_frame> trace = libdwarf::resolve_frames(frames);
fill_blanks(trace, dbghelp::resolve_frames); fill_blanks(trace, dbghelp::resolve_frames);
return trace; return trace;
@ -120,7 +122,9 @@ namespace detail {
} }
std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& frames) { std::vector<stacktrace_frame> resolve_frames(const std::vector<frame_ptr>& 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) || defined(CPPTRACE_GET_SYMBOLS_WITH_ADDR2LINE)
auto dlframes = get_frames_object_info(frames); auto dlframes = get_frames_object_info(frames);
#endif #endif

View File

@ -8,7 +8,7 @@
void trace() { void trace() {
cpptrace::generate_trace().print(); cpptrace::generate_trace().print();
cpptrace::generate_trace().print_with_snippets(); cpptrace::generate_trace().print_with_snippets();
throw cpptrace::logic_error("foobar"); // throw cpptrace::logic_error("foobar");
} }
void foo(int n) { void foo(int n) {

View File

@ -25,7 +25,7 @@ CPPTRACE_FORCE_NO_INLINE static void raw_trace_basic() {
EXPECT_LE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(raw_trace_basic) + 90); EXPECT_LE(raw_trace.frames[0], reinterpret_cast<uintptr_t>(raw_trace_basic) + 90);
} }
#ifndef _MSC_VER #if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__)
CPPTRACE_FORCE_NO_INLINE void raw_trace_basic_precise() { CPPTRACE_FORCE_NO_INLINE void raw_trace_basic_precise() {
a: a:
auto raw_trace = cpptrace::generate_raw_trace(); auto raw_trace = cpptrace::generate_raw_trace();
@ -46,7 +46,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_basic_precise() {
TEST(RawTrace, Basic) { TEST(RawTrace, Basic) {
raw_trace_basic(); raw_trace_basic();
#ifndef _MSC_VER #if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__)
raw_trace_basic_precise(); raw_trace_basic_precise();
#endif #endif
[[maybe_unused]] volatile int x = 0; // prevent raw_trace_basic_precise() above being a jmp [[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}); 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() { CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_3() {
a: a:
auto raw_trace = cpptrace::generate_raw_trace(); auto raw_trace = cpptrace::generate_raw_trace();
@ -161,7 +161,7 @@ CPPTRACE_FORCE_NO_INLINE void raw_trace_multi_precise_1() {
TEST(RawTrace, MultipleCalls) { TEST(RawTrace, MultipleCalls) {
parents.clear(); parents.clear();
raw_trace_multi_1(); raw_trace_multi_1();
#ifndef _MSC_VER #if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__)
raw_trace_multi_precise_1(); raw_trace_multi_precise_1();
#endif #endif
} }