Dump stack trace on segfault in the VM.

Install a signal handler in the standalone VM that dumps a backtrace
similar to what we already do on assertion failures.

For now only Linux and MacOS are supported.

BUG=
R=asiva@google.com

Review URL: https://codereview.chromium.org/2514113002 .
This commit is contained in:
Florian Schneider 2016-11-23 10:29:07 -08:00
parent 7d287b232b
commit 6cd141def5
6 changed files with 81 additions and 6 deletions

View file

@ -22,6 +22,12 @@ char* Platform::resolved_executable_name_ = NULL;
int Platform::script_index_ = 1;
char** Platform::argv_ = NULL;
static void segv_handler(int signal, siginfo_t* siginfo, void* context) {
Dart_DumpNativeStackTrace(context);
abort();
}
bool Platform::Initialize() {
// Turn off the signal handler for SIGPIPE as it causes the process
// to terminate on writing to a closed pipe. Without the signal
@ -33,6 +39,21 @@ bool Platform::Initialize() {
perror("Setting signal handler failed");
return false;
}
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = &segv_handler;
if (sigemptyset(&act.sa_mask) != 0) {
perror("sigemptyset() failed.");
return false;
}
if (sigaddset(&act.sa_mask, SIGPROF) != 0) {
perror("sigaddset() failed");
return false;
}
if (sigaction(SIGSEGV, &act, NULL) != 0) {
perror("sigaction() failed.");
return false;
}
return true;
}

View file

@ -39,6 +39,20 @@ bool Platform::Initialize() {
perror("Setting signal handler failed");
return false;
}
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = &segv_handler;
if (sigemptyset(&act.sa_mask) != 0) {
perror("sigemptyset() failed.");
return false;
}
if (sigaddset(&act.sa_mask, SIGPROF) != 0) {
perror("sigaddset() failed");
return false;
}
if (sigaction(SIGSEGV, &act, NULL) != 0) {
perror("sigaction() failed.");
return false;
}
return true;
}

View file

@ -3281,4 +3281,10 @@ Dart_CreateAppJITSnapshot(uint8_t** vm_isolate_snapshot_buffer,
*/
DART_EXPORT bool Dart_IsPrecompiledRuntime();
/**
* Print a native stack trace. Used for crash handling.
*/
DART_EXPORT void Dart_DumpNativeStackTrace(void* context);
#endif /* INCLUDE_DART_API_H_ */ /* NOLINT */

View file

@ -6671,4 +6671,9 @@ DART_EXPORT bool Dart_IsPrecompiledRuntime() {
#endif
}
DART_EXPORT void Dart_DumpNativeStackTrace(void* context) {
Profiler::DumpStackTrace(context);
}
} // namespace dart

View file

@ -944,7 +944,36 @@ static uintptr_t __attribute__((noinline)) GetProgramCounter() {
#endif
void Profiler::DumpStackTrace(void* context) {
#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS)
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t mcontext = ucontext->uc_mcontext;
uword pc = SignalHandler::GetProgramCounter(mcontext);
uword fp = SignalHandler::GetFramePointer(mcontext);
uword sp = SignalHandler::GetCStackPointer(mcontext);
DumpStackTrace(/* native_stack_trace = */ true, sp, fp, pc);
#else
// TODO(fschneider): Add support for more platforms.
// Do nothing on unsupported platforms.
#endif
}
void Profiler::DumpStackTrace(bool native_stack_trace) {
uintptr_t sp = Thread::GetCurrentStackPointer();
uintptr_t fp = 0;
uintptr_t pc = GetProgramCounter();
COPY_FP_REGISTER(fp);
DumpStackTrace(native_stack_trace, sp, fp, pc);
}
void Profiler::DumpStackTrace(bool native_stack_trace,
uword sp,
uword fp,
uword pc) {
// Allow only one stack trace to prevent recursively printing stack traces if
// we hit an assert while printing the stack.
static uintptr_t started_dump = 0;
@ -970,12 +999,6 @@ void Profiler::DumpStackTrace(bool native_stack_trace) {
native_stack_trace ? "native" : "dart-only",
OSThread::ThreadIdToIntPtr(os_thread->trace_id()));
uintptr_t sp = Thread::GetCurrentStackPointer();
uintptr_t fp = 0;
uintptr_t pc = GetProgramCounter();
COPY_FP_REGISTER(fp);
uword stack_lower = 0;
uword stack_upper = 0;

View file

@ -54,6 +54,7 @@ class Profiler : public AllStatic {
static SampleBuffer* sample_buffer() { return sample_buffer_; }
static void DumpStackTrace(void* context);
static void DumpStackTrace(bool native_stack_trace = true);
static void SampleAllocation(Thread* thread, intptr_t cid);
@ -74,6 +75,11 @@ class Profiler : public AllStatic {
}
private:
static void DumpStackTrace(bool native_stack_trace,
uword sp,
uword fp,
uword pc);
// Does not walk the thread's stack.
static void SampleThreadSingleFrame(Thread* thread, uintptr_t pc);
static bool initialized_;