Skip to content

Commit 6cca486

Browse files
committed
crash handler on linux
1 parent 76fec88 commit 6cca486

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#ifdef CAGE_SYSTEM_LINUX
2+
3+
#include <csignal>
4+
#include <cstddef>
5+
#include <cstdio>
6+
#include <cstdlib>
7+
#include <cstring>
8+
#include <cerrno>
9+
#include <execinfo.h>
10+
#include <sys/mman.h>
11+
#include <ucontext.h>
12+
#include <unistd.h>
13+
14+
#include <cage-core/core.h>
15+
16+
namespace cage
17+
{
18+
int crashHandlerLogFileFd = STDERR_FILENO;
19+
20+
namespace
21+
{
22+
void *altStackMem = nullptr;
23+
constexpr int OldHandlersCount = 16;
24+
struct sigaction prevHandlers[OldHandlersCount] = {};
25+
26+
struct sigaction *prevHandler(int sig)
27+
{
28+
if (sig >= 0 && sig < OldHandlersCount)
29+
return &prevHandlers[sig];
30+
return nullptr;
31+
}
32+
33+
const char *sigToStr(int sig)
34+
{
35+
switch (sig)
36+
{
37+
case SIGSEGV:
38+
return "SIGSEGV";
39+
case SIGABRT:
40+
return "SIGABRT";
41+
case SIGFPE:
42+
return "SIGFPE";
43+
case SIGILL:
44+
return "SIGILL";
45+
case SIGBUS:
46+
return "SIGBUS";
47+
case SIGTRAP:
48+
return "SIGTRAP";
49+
case SIGTERM:
50+
return "SIGTERM";
51+
default:
52+
return "UNKNOWN";
53+
}
54+
}
55+
56+
void safeWrite(const String &s)
57+
{
58+
write(crashHandlerLogFileFd, s.c_str(), s.length());
59+
}
60+
61+
void printStackTrace()
62+
{
63+
// backtrace (best-effort; not strictly async-signal-safe)
64+
static constexpr int kMaxFrames = 256;
65+
void *frames[kMaxFrames];
66+
int n = backtrace(frames, kMaxFrames);
67+
safeWrite(Stringizer() + "stack trace:\n");
68+
backtrace_symbols_fd(frames, n, crashHandlerLogFileFd); // writes directly to fd
69+
}
70+
71+
void crashHandler(int sig, siginfo_t *si, void *uctx)
72+
{
73+
safeWrite(Stringizer() + "signal caught: " + sigToStr(sig) + " (" + sig + ")\n");
74+
75+
if (si)
76+
safeWrite(Stringizer() + "fault addr: " + (uintptr_t)si->si_addr + ", code: " + si->si_code + "\n");
77+
78+
printStackTrace();
79+
80+
if (struct sigaction *prev = prevHandler(sig))
81+
{
82+
if (prev->sa_flags & SA_SIGINFO)
83+
{
84+
// previous handler expects 3 arguments
85+
prev->sa_sigaction(sig, si, uctx);
86+
}
87+
else if (prev->sa_handler == SIG_DFL || prev->sa_handler == SIG_IGN)
88+
{
89+
// default or ignore: you can reset signal to default and raise
90+
signal(sig, prev->sa_handler);
91+
raise(sig);
92+
}
93+
else
94+
{
95+
// simple handler with 1 argument
96+
prev->sa_handler(sig);
97+
}
98+
}
99+
100+
// re-raise to trigger default handler (and core dump, if enabled)
101+
signal(sig, SIG_DFL);
102+
raise(sig);
103+
}
104+
105+
void installAltStack()
106+
{
107+
static constexpr size_t kAltStackSz = 128 * 1024; // bigger than SIGSTKSZ for safety
108+
altStackMem = mmap(nullptr, kAltStackSz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
109+
if (altStackMem == MAP_FAILED)
110+
altStackMem = std::malloc(kAltStackSz); // fallback to malloc
111+
stack_t ss{};
112+
ss.ss_sp = altStackMem;
113+
ss.ss_size = kAltStackSz;
114+
ss.ss_flags = 0;
115+
if (sigaltstack(&ss, nullptr) != 0)
116+
{
117+
CAGE_LOG(SeverityEnum::Info, "crash-handler", strerror(errno));
118+
CAGE_THROW_ERROR(Exception, "sigaltstack")
119+
}
120+
}
121+
122+
void installHandler(int sig)
123+
{
124+
struct sigaction sa
125+
{};
126+
sa.sa_sigaction = &crashHandler;
127+
sigemptyset(&sa.sa_mask);
128+
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
129+
if (sigaction(sig, &sa, prevHandler(sig)) != 0)
130+
{
131+
CAGE_LOG(SeverityEnum::Info, "crash-handler", strerror(errno));
132+
CAGE_THROW_ERROR(Exception, "sigaction")
133+
}
134+
}
135+
136+
struct SetupHandlers
137+
{
138+
SetupHandlers()
139+
{
140+
installAltStack();
141+
int signals[] = { SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGTRAP };
142+
for (int s : signals)
143+
installHandler(s);
144+
}
145+
} setupHandlers;
146+
}
147+
}
148+
149+
#endif // CAGE_SYSTEM_LINUX

sources/libcore/crashHandler.cpp renamed to sources/libcore/crashHandlerWindows.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
#ifdef CAGE_SYSTEM_WINDOWS
2+
23
#include <mutex>
34
#include "windowsMinimumInclude.h"
45
#include <DbgHelp.h>
6+
57
#pragma comment(lib, "DbgHelp.lib")
68
#define EXCEPTION_CPP 0xE06D7363
79
#define EXCEPTION_DOTNET 0xE0434352

sources/libcore/filesystem/realFiles.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,4 +794,12 @@ namespace cage
794794
#endif
795795
}
796796
}
797+
798+
#ifdef CAGE_SYSTEM_LINUX
799+
int realFileGetFd(File *f)
800+
{
801+
FileRealBase *base = class_cast<FileRealBase *>(f);
802+
return fileno(base->f);
803+
}
804+
#endif
797805
}

sources/libcore/logger.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020

2121
namespace cage
2222
{
23+
#ifdef CAGE_SYSTEM_LINUX
24+
extern int crashHandlerLogFileFd;
25+
int realFileGetFd(File *f);
26+
#endif
27+
2328
Holder<File> realNewFile(const String &path, const FileMode &mode);
2429
void realTryFlushFile(File *f);
2530

@@ -305,7 +310,12 @@ namespace cage
305310
fm.textual = true;
306311
fm.append = append;
307312
if (realFilesystemOnly)
313+
{
308314
f = realNewFile(path, fm);
315+
#ifdef CAGE_SYSTEM_LINUX
316+
crashHandlerLogFileFd = realFileGetFd(+f);
317+
#endif
318+
}
309319
else
310320
f = newFile(path, fm);
311321
}

0 commit comments

Comments
 (0)