mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
AK: Always use our assertion failure method, and add backtrace to it
On platforms that support it, enable using ``<execinfo.h>`` to get backtrace(3) to dump a backtrace on assertion failure. This should make debugging things like WebContent crashes in Lagom much easier.
This commit is contained in:
parent
3056ff6b11
commit
4641af7873
Notes:
sideshowbarker
2024-07-16 22:14:49 +09:00
Author: https://github.com/ADKaster Commit: https://github.com/SerenityOS/serenity/commit/4641af7873 Pull-request: https://github.com/SerenityOS/serenity/pull/20852
3 changed files with 65 additions and 10 deletions
|
@ -6,13 +6,68 @@
|
||||||
|
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
#include <AK/Format.h>
|
#include <AK/Format.h>
|
||||||
|
#include <AK/Platform.h>
|
||||||
|
#include <AK/StringView.h>
|
||||||
|
|
||||||
|
#if defined(AK_OS_LINUX) || defined(AK_OS_BSD_GENERIC) || defined(AK_OS_SOLARIS)
|
||||||
|
# define EXECINFO_BACKTRACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(EXECINFO_BACKTRACE)
|
||||||
|
# include <cxxabi.h>
|
||||||
|
# include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(KERNEL)
|
#if !defined(KERNEL)
|
||||||
|
|
||||||
|
# if defined(EXECINFO_BACKTRACE)
|
||||||
|
namespace {
|
||||||
|
ALWAYS_INLINE void dump_backtrace()
|
||||||
|
{
|
||||||
|
// Grab symbols and dso name for up to 256 frames
|
||||||
|
void* trace[256] = {};
|
||||||
|
int const num_frames = backtrace(trace, sizeof(trace));
|
||||||
|
char** syms = backtrace_symbols(trace, num_frames);
|
||||||
|
|
||||||
|
for (auto i = 0; i < num_frames; ++i) {
|
||||||
|
// If there is a C++ symbol name in the line of the backtrace, demangle it
|
||||||
|
StringView sym(syms[i], strlen(syms[i]));
|
||||||
|
if (auto idx = sym.find("_Z"sv); idx.has_value()) {
|
||||||
|
// Play C games with the original string so we can print before and after the mangled symbol with a C API
|
||||||
|
// We don't want to call dbgln() here on substring StringView because we might VERIFY() within AK::Format
|
||||||
|
syms[i][idx.value() - 1] = '\0';
|
||||||
|
(void)fprintf(stderr, "%s ", syms[i]);
|
||||||
|
|
||||||
|
auto end_of_sym = sym.find(' ', idx.value()).value_or(sym.length() - 1);
|
||||||
|
syms[i][end_of_sym] = '\0';
|
||||||
|
|
||||||
|
size_t buf_size = 128u;
|
||||||
|
char* buf = static_cast<char*>(malloc(buf_size));
|
||||||
|
auto* raw_str = &syms[i][idx.value()];
|
||||||
|
buf = abi::__cxa_demangle(raw_str, buf, &buf_size, nullptr);
|
||||||
|
|
||||||
|
(void)fputs(buf ? buf : raw_str, stderr);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
(void)fprintf(stderr, " %s", &syms[i][end_of_sym + 1]);
|
||||||
|
} else {
|
||||||
|
(void)fputs(sym.characters_without_null_termination(), stderr);
|
||||||
|
}
|
||||||
|
(void)fputs("\n", stderr);
|
||||||
|
}
|
||||||
|
free(syms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void ak_verification_failed(char const* message)
|
void ak_verification_failed(char const* message)
|
||||||
{
|
{
|
||||||
dbgln("VERIFICATION FAILED: {}", message);
|
dbgln("VERIFICATION FAILED: {}", message);
|
||||||
|
# if defined(EXECINFO_BACKTRACE)
|
||||||
|
dump_backtrace();
|
||||||
|
# endif
|
||||||
__builtin_trap();
|
__builtin_trap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,12 @@
|
||||||
#else
|
#else
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
extern "C" __attribute__((noreturn)) void ak_verification_failed(char const*);
|
extern "C" __attribute__((noreturn)) void ak_verification_failed(char const*);
|
||||||
# if !defined(NDEBUG) && !defined(WIN32)
|
# define __stringify_helper(x) #x
|
||||||
# define VERIFY assert
|
# define __stringify(x) __stringify_helper(x)
|
||||||
# else
|
# define VERIFY(expr) \
|
||||||
# define __stringify_helper(x) #x
|
(__builtin_expect(!(expr), 0) \
|
||||||
# define __stringify(x) __stringify_helper(x)
|
? ak_verification_failed(#expr " at " __FILE__ ":" __stringify(__LINE__)) \
|
||||||
# define VERIFY(expr) \
|
: (void)0)
|
||||||
(__builtin_expect(!(expr), 0) \
|
|
||||||
? ak_verification_failed(#expr "\n" __FILE__ ":" __stringify(__LINE__)) \
|
|
||||||
: (void)0)
|
|
||||||
# endif
|
|
||||||
# define VERIFY_NOT_REACHED() VERIFY(false) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
|
# define VERIFY_NOT_REACHED() VERIFY(false) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
|
||||||
static constexpr bool TODO = false;
|
static constexpr bool TODO = false;
|
||||||
# define TODO() VERIFY(TODO) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
|
# define TODO() VERIFY(TODO) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */
|
||||||
|
|
|
@ -331,6 +331,10 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||||
# Solaris has socket and networking related functions in two extra libraries
|
# Solaris has socket and networking related functions in two extra libraries
|
||||||
target_link_libraries(LibCore PRIVATE nsl socket)
|
target_link_libraries(LibCore PRIVATE nsl socket)
|
||||||
endif()
|
endif()
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "BSD$")
|
||||||
|
# BSD Platforms have backtrace(3) in a separate library
|
||||||
|
target_link_libraries(LibCore PRIVATE execinfo)
|
||||||
|
endif()
|
||||||
target_sources(LibCore PRIVATE ${AK_SOURCES})
|
target_sources(LibCore PRIVATE ${AK_SOURCES})
|
||||||
|
|
||||||
# LibMain
|
# LibMain
|
||||||
|
|
Loading…
Reference in a new issue