Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

linux: avoid using signal-unsafe functions in signal handler #254

Merged
merged 2 commits into from
Jan 18, 2025
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
14 changes: 10 additions & 4 deletions src/core/error/callstack.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@

#pragma once

#include "core/strings/string_stream.h"
#include "core/strings/types.h"
#include "core/types.h"
#include "device/log.h"

namespace crown
{
namespace error
{
/// Fills @a ss with the current call stack.
void callstack(StringStream &ss);
/// Initializes the callstack subsystem.
s32 callstack_init();

/// Shutdowns the callstack subsystem.
void callstack_shutdown();

/// Logs the current call stack.
void callstack(log_internal::System system, LogSeverity::Enum severity = LogSeverity::LOG_INFO);

} // namespace error

Expand Down
19 changes: 14 additions & 5 deletions src/core/error/callstack_emscripten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,32 @@
#include "core/platform.h"

#if CROWN_PLATFORM_EMSCRIPTEN
#include "core/error/callstack.h"
#include "core/memory/allocator.h"
#include "core/memory/globals.h"
#include "core/strings/string_stream.inl"
#include <emscripten/emscripten.h>

namespace crown
{
namespace error
{
void callstack(StringStream &ss)
s32 callstack_init()
{
return 0;
}

void callstack_shutdown()
{
CE_NOOP();
}

void callstack(log_internal::System system, LogSeverity::Enum severity)
{
int size = emscripten_get_callstack(EM_LOG_C_STACK | EM_LOG_JS_STACK, NULL, 0);

char *data = (char *)default_allocator().allocate(size);
emscripten_get_callstack(EM_LOG_C_STACK | EM_LOG_JS_STACK, data, size);

ss << data;

log_internal::logx(severity, system, data);
default_allocator().deallocate(data);
}

Expand Down
201 changes: 151 additions & 50 deletions src/core/error/callstack_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,27 @@
#include "core/platform.h"

#if CROWN_PLATFORM_LINUX && (CROWN_COMPILER_GCC || CROWN_COMPILER_CLANG)
#include "core/error/callstack.h"
#include "core/process.h"
#include "core/strings/string.inl"
#include "core/strings/string_stream.inl"
#include <cxxabi.h>
#include <execinfo.h>
#include <stdlib.h> // free
#include <string.h> // strchr
#include <unistd.h> // getpid
#include <cxxabi.h> // __cxa_demangle
#include <execinfo.h> // backtrace, backtrace_symbols_fd
#include <stdio.h> // fdopen, fgets
#include <stdlib.h> // free
#include <string.h> // strchr
#include <sys/wait.h> // waitpid
#include <unistd.h> // getpid
#include <stb_sprintf.h>

namespace crown
{
namespace error
{
static int symbol_fds[2];
static int demangled_fds[2];
static int exit_fds[2];
static pid_t demangler;

static const char *addr2line(char *line, int len, const char *addr)
{
char process_exe[256];
Expand All @@ -46,54 +53,148 @@ namespace error
return "<addr2line missing>";
}

void callstack(StringStream &ss)
static void demangler_main()
{
void *array[64];
int size = backtrace(array, countof(array));
char **messages = backtrace_symbols(array, size);

// skip first stack frame (points here)
for (int i = 1; i < size && messages != NULL; ++i) {
char *msg = messages[i];
char *mangled_name = strchr(msg, '(');
char *offset_begin = strchr(msg, '+');
char *offset_end = strchr(msg, ')');
char *addr_begin = strchr(msg, '[');
char *addr_end = strchr(msg, ']');

char buf[512];

// Attempt to demangle the symbol
if (mangled_name && offset_begin && offset_end && mangled_name < offset_begin) {
*mangled_name++ = '\0';
*offset_begin++ = '\0';
*offset_end++ = '\0';
*addr_begin++ = '\0';
*addr_end++ = '\0';

int demangle_ok;
char *real_name = abi::__cxa_demangle(mangled_name, 0, 0, &demangle_ok);
char line[256];
memset(line, 0, sizeof(line));

stbsp_snprintf(buf
, sizeof(buf)
, " [%2d] %s: (%s)+%s in %s\n"
, i
, msg
, (demangle_ok == 0 ? real_name : mangled_name)
, offset_begin
, addr2line(line, sizeof(line), addr_begin)
);

free(real_name);
} else {
stbsp_snprintf(buf, sizeof(buf), " [%2d] %s\n", i, msg);
FILE *fp = fdopen(symbol_fds[0], "r");
if (fp == NULL)
return;

while (true) {
fd_set fdset;

FD_ZERO(&fdset);
FD_SET(symbol_fds[0], &fdset);
FD_SET(exit_fds[0], &fdset);
int maxfd = max(symbol_fds[0], exit_fds[0]);

if (select(maxfd + 1, &fdset, NULL, NULL, NULL) <= 0)
continue;

if (FD_ISSET(exit_fds[0], &fdset)) {
break;
} else if (FD_ISSET(symbol_fds[0], &fdset)) {
char msg[512];
char buf[512];

while (fgets(msg, sizeof(msg), fp) != NULL) {
u32 len = strlen32(msg);
if (len <= 1)
break;
msg[len - 1] = '\0';

char *mangled_name = strchr(msg, '(');
char *offset_begin = strchr(msg, '+');
char *offset_end = strchr(msg, ')');
char *addr_begin = strchr(msg, '[');
char *addr_end = strchr(msg, ']');

// Attempt to demangle the symbol.
if (mangled_name && offset_begin && offset_end && mangled_name < offset_begin) {
*mangled_name++ = '\0';
*offset_begin++ = '\0';
*offset_end++ = '\0';
*addr_begin++ = '\0';
*addr_end++ = '\0';

int demangle_ok;
char *real_name = abi::__cxa_demangle(mangled_name, 0, 0, &demangle_ok);
char line[256];
memset(line, 0, sizeof(line));

stbsp_snprintf(buf
, sizeof(buf)
, "%s(%s+%s) in %s"
, msg
, (demangle_ok == 0 ? real_name : mangled_name)
, offset_begin
, addr2line(line, sizeof(line), addr_begin)
);

free(real_name);
} else {
stbsp_snprintf(buf, sizeof(buf), "%s", msg);
}

write(demangled_fds[1], buf, sizeof(buf));
}
}
}

fclose(fp);
}

void callstack_shutdown()
{
int wstatus;

if (demangler <= 0)
return;

write(exit_fds[1], "q", 1);
waitpid(demangler, &wstatus, 0);
demangler = 0;
}

ss << buf;
s32 callstack_init()
{
s32 ret = -1;

if (pipe(symbol_fds) < 0)
goto close_0;
if (pipe(demangled_fds) < 0)
goto close_1;
if (pipe(exit_fds) < 0)
goto close_2;

demangler = fork();
if (demangler == -1) {
close(symbol_fds[0]);
close(symbol_fds[1]);
close(demangled_fds[0]);
close(demangled_fds[1]);
close(exit_fds[0]);
close(exit_fds[1]);
return -1;
} else if (demangler == 0) {
close(symbol_fds[1]);
close(demangled_fds[0]);
close(exit_fds[1]);
demangler_main();
} else {
ret = 0;
}

close(exit_fds[0]);
close_2:
close(demangled_fds[1]);
close_1:
close(symbol_fds[0]);
close_0:
return ret;
}

void callstack(log_internal::System system, LogSeverity::Enum severity)
{
char msg[512] = {};
void *array[64];

if (demangler <= 0) {
log_internal::logx(severity, system, "Callstack unavailable.");
return;
}

// Get symbols and write them to demangler process.
int size = backtrace(array, countof(array));
backtrace_symbols_fd(array, size, symbol_fds[1]);
write(symbol_fds[1], "\n", 1);

// Log demangled symbols.
for (int i = 0; i < size; ++i) {
if (read(demangled_fds[0], msg, sizeof(msg)) <= 0)
break;
if (i >= 1) // Skip this very function.
log_internal::logx(severity, system, "[%2d] %s", i, msg);
}
free(messages);
}

} // namespace error
Expand Down
18 changes: 14 additions & 4 deletions src/core/error/callstack_noop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
#include "core/platform.h"

#if CROWN_PLATFORM_ANDROID
#include "core/strings/string_stream.inl"
#include "core/error/callstack.h"

namespace crown
{
namespace error
{
void callstack(StringStream &ss)
s32 callstack_init()
{
ss << "Not supported";
return 0;
}

void callstack_shutdown()
{
CE_NOOP();
}

void callstack(log_internal::System system, LogSeverity::Enum severity)
{
log_internal::logx(severity, system, "Callstack not supported on this platform.");
}

} // namespace error

} // namespace crown

#endif
#endif // if CROWN_PLATFORM_ANDROID
31 changes: 18 additions & 13 deletions src/core/error/callstack_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#include "core/platform.h"

#if CROWN_PLATFORM_WINDOWS
#include "core/strings/string_stream.inl"
#include "core/error/callstack.h"
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
Expand All @@ -16,13 +16,22 @@
#include <dbghelp.h>
#pragma warning(pop)
#include <new>
#include <stb_sprintf.h>

namespace crown
{
namespace error
{
void callstack(StringStream &ss)
s32 callstack_init()
{
return 0;
}

void callstack_shutdown()
{
CE_NOOP();
}

void callstack(log_internal::System system, LogSeverity::Enum severity)
{
SymInitialize(GetCurrentProcess(), NULL, TRUE);
SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
Expand Down Expand Up @@ -85,27 +94,23 @@ namespace error
);
res = res && SymFromAddr(GetCurrentProcess(), stack.AddrPC.Offset, 0, sym);

char str[512];

if (res == TRUE) {
stbsp_snprintf(str
, sizeof(str)
, " [%2i] %s in %s:%d\n"
log_internal::logx(severity
, system
, "[%2i] %s in %s:%d"
, num
, sym->Name
, line.FileName
, line.LineNumber
);
} else {
stbsp_snprintf(str
, sizeof(str)
, " [%2i] 0x%p\n"
log_internal::logx(severity
, system
, "[%2i] 0x%p"
, num
, stack.AddrPC.Offset
);
}

ss << str;
}

SymCleanup(GetCurrentProcess());
Expand Down
Loading