mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 19:40:29 +00:00
[vm] Improve crash output from gen_snapshot
* Don't compile it with omit frame pointer even in PRODUCT. * Dump the first frame even if we give up on unwinding. * Dump compiler state even if we give up on unwinding. * Don't abort stack dump if PC for the outermost frame is 0 (can happen when calling pure virtual method for example). TEST=manually tested by making compiler crash during code generation Change-Id: Iddeafbdad8e8588f19197d5dd49af14b8fc63134 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/278341 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Slava Egorov <vegorov@google.com>
This commit is contained in:
parent
792aedec74
commit
15230e41e5
|
@ -83,6 +83,9 @@ config("add_empty_macho_section_config") {
|
||||||
config("dart_precompiler_config") {
|
config("dart_precompiler_config") {
|
||||||
defines = []
|
defines = []
|
||||||
defines += [ "DART_PRECOMPILER" ]
|
defines += [ "DART_PRECOMPILER" ]
|
||||||
|
if (is_clang) {
|
||||||
|
cflags = [ "-fno-omit-frame-pointer" ]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config("dart_os_config") {
|
config("dart_os_config") {
|
||||||
|
|
|
@ -377,9 +377,9 @@ static bool GetAndValidateThreadStackBounds(OSThread* os_thread,
|
||||||
return ValidateThreadStackBounds(fp, sp, *stack_lower, *stack_upper);
|
return ValidateThreadStackBounds(fp, sp, *stack_lower, *stack_upper);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some simple sanity checking of |pc|, |fp|, and |sp|.
|
// Some simple sanity checking of |fp|, and |sp|.
|
||||||
static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) {
|
static bool InitialStackRegistersCheck(uintptr_t fp, uintptr_t sp) {
|
||||||
if ((sp == 0) || (fp == 0) || (pc == 0)) {
|
if ((sp == 0) || (fp == 0)) {
|
||||||
// None of these registers should be zero.
|
// None of these registers should be zero.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -393,6 +393,17 @@ static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(PRODUCT)
|
||||||
|
// Some simple sanity checking of |pc|, |fp|, and |sp|.
|
||||||
|
static bool InitialRegisterCheck(uintptr_t pc, uintptr_t fp, uintptr_t sp) {
|
||||||
|
if (pc == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return InitialStackRegistersCheck(fp, sp);
|
||||||
|
}
|
||||||
|
#endif // !defined(PRODUCT)
|
||||||
|
|
||||||
void Profiler::DumpStackTrace(void* context) {
|
void Profiler::DumpStackTrace(void* context) {
|
||||||
if (context == NULL) {
|
if (context == NULL) {
|
||||||
DumpStackTrace(/*for_crash=*/true);
|
DumpStackTrace(/*for_crash=*/true);
|
||||||
|
@ -444,6 +455,15 @@ void Profiler::DumpStackTrace(bool for_crash) {
|
||||||
DumpStackTrace(sp, fp, pc, for_crash);
|
DumpStackTrace(sp, fp, pc, for_crash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void DumpCompilerState(Thread* thread) {
|
||||||
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||||
|
if (thread != nullptr && thread->execution_state() == Thread::kThreadInVM &&
|
||||||
|
thread->HasCompilerState()) {
|
||||||
|
thread->compiler_state().ReportCrash();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
||||||
if (for_crash) {
|
if (for_crash) {
|
||||||
// Allow only one stack trace to prevent recursively printing stack traces
|
// Allow only one stack trace to prevent recursively printing stack traces
|
||||||
|
@ -496,9 +516,15 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
||||||
vm_source == nullptr
|
vm_source == nullptr
|
||||||
? 0
|
? 0
|
||||||
: reinterpret_cast<uword>(vm_source->snapshot_instructions));
|
: reinterpret_cast<uword>(vm_source->snapshot_instructions));
|
||||||
|
OS::PrintErr("fp=%" Px ", sp=%" Px ", pc=%" Px "\n", fp, sp, pc);
|
||||||
|
|
||||||
if (!InitialRegisterCheck(pc, fp, sp)) {
|
if (!InitialStackRegistersCheck(fp, sp)) {
|
||||||
OS::PrintErr("Stack dump aborted because InitialRegisterCheck failed.\n");
|
OS::PrintErr(
|
||||||
|
"Stack dump aborted because InitialStackRegistersCheck failed.\n");
|
||||||
|
if (pc != 0) { // At the very least dump the top frame.
|
||||||
|
DumpStackFrame(0, pc, fp);
|
||||||
|
}
|
||||||
|
DumpCompilerState(thread);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,6 +534,10 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
||||||
&stack_upper)) {
|
&stack_upper)) {
|
||||||
OS::PrintErr(
|
OS::PrintErr(
|
||||||
"Stack dump aborted because GetAndValidateThreadStackBounds failed.\n");
|
"Stack dump aborted because GetAndValidateThreadStackBounds failed.\n");
|
||||||
|
if (pc != 0) { // At the very least dump the top frame.
|
||||||
|
DumpStackFrame(0, pc, fp);
|
||||||
|
}
|
||||||
|
DumpCompilerState(thread);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,13 +554,10 @@ void Profiler::DumpStackTrace(uword sp, uword fp, uword pc, bool for_crash) {
|
||||||
StackFrame::DumpCurrentTrace();
|
StackFrame::DumpCurrentTrace();
|
||||||
} else if (thread->execution_state() == Thread::kThreadInVM) {
|
} else if (thread->execution_state() == Thread::kThreadInVM) {
|
||||||
StackFrame::DumpCurrentTrace();
|
StackFrame::DumpCurrentTrace();
|
||||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
||||||
if (thread->HasCompilerState()) {
|
|
||||||
thread->compiler_state().ReportCrash();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DumpCompilerState(thread);
|
||||||
}
|
}
|
||||||
#endif // !defined(PRODUCT) || defined(DART_PRECOMPILER)
|
#endif // !defined(PRODUCT) || defined(DART_PRECOMPILER)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue