| // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "lib/stacktrace.h" |
| #include "vm/heap/safepoint.h" |
| #include "vm/object.h" |
| #include "vm/stack_frame.h" |
| |
| namespace dart { |
| |
| #if !defined(PRODUCT) |
| |
| DART_EXPORT |
| void _printRawObject(ObjectPtr object) { |
| OS::PrintErr("%s\n", Object::Handle(object).ToCString()); |
| } |
| |
| DART_EXPORT |
| Object* _handle(ObjectPtr object) { |
| return &Object::Handle(object); |
| } |
| |
| // An utility method for convenient printing of dart stack traces when |
| // inside 'gdb'. Note: This function will only work when there is a |
| // valid exit frame information. It will not work when a breakpoint is |
| // set in dart code and control is got inside 'gdb' without going through |
| // the runtime or native transition stub. |
| DART_EXPORT |
| void _printDartStackTrace() { |
| const StackTrace& stacktrace = GetCurrentStackTrace(0); |
| OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString()); |
| } |
| |
| // Like _printDartStackTrace, but works in a NoSafepointScope. Use it if you're |
| // in the middle of a GC or interested in stub frames. |
| DART_EXPORT |
| void _printStackTrace() { |
| StackFrame::DumpCurrentTrace(); |
| } |
| |
| // Like _printDartStackTrace, but works when stopped in generated code. |
| // Must be called with the current fp, sp, and pc. |
| DART_EXPORT |
| void _printGeneratedStackTrace(uword fp, uword sp, uword pc) { |
| StackFrameIterator frames(fp, sp, pc, ValidationPolicy::kDontValidateFrames, |
| Thread::Current(), |
| StackFrameIterator::kNoCrossThreadIteration); |
| StackFrame* frame = frames.NextFrame(); |
| while (frame != nullptr) { |
| OS::PrintErr("%s\n", frame->ToCString()); |
| frame = frames.NextFrame(); |
| } |
| } |
| |
| // Like _printDartStackTrace, but works in the interpreter loop. |
| // Must be called with the current interpreter fp, sp, and pc. |
| // Note that sp[0] is not modified, but sp[1] will be trashed. |
| DART_EXPORT |
| void _printInterpreterStackTrace(ObjectPtr* fp, |
| ObjectPtr* sp, |
| const KBCInstr* pc) { |
| Thread* thread = Thread::Current(); |
| sp[1] = Function::null(); |
| sp[2] = Bytecode::null(); |
| sp[3] = static_cast<ObjectPtr>(reinterpret_cast<uword>(pc)); |
| sp[4] = static_cast<ObjectPtr>(reinterpret_cast<uword>(fp)); |
| ObjectPtr* exit_fp = sp + 1 + kKBCDartFrameFixedSize; |
| thread->set_top_exit_frame_info(reinterpret_cast<uword>(exit_fp)); |
| thread->set_execution_state(Thread::kThreadInVM); |
| _printDartStackTrace(); |
| thread->set_execution_state(Thread::kThreadInGenerated); |
| thread->set_top_exit_frame_info(0); |
| } |
| |
| class PrintObjectPointersVisitor : public ObjectPointerVisitor { |
| public: |
| PrintObjectPointersVisitor() |
| : ObjectPointerVisitor(IsolateGroup::Current()) {} |
| |
| void VisitPointers(ObjectPtr* first, ObjectPtr* last) { |
| for (ObjectPtr* p = first; p <= last; p++) { |
| Object& obj = Object::Handle(*p); |
| OS::PrintErr("%p: %s\n", p, obj.ToCString()); |
| } |
| } |
| }; |
| |
| DART_EXPORT |
| void _printStackTraceWithLocals() { |
| PrintObjectPointersVisitor visitor; |
| StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, |
| Thread::Current(), |
| StackFrameIterator::kNoCrossThreadIteration); |
| StackFrame* frame = frames.NextFrame(); |
| while (frame != nullptr) { |
| OS::PrintErr("%s\n", frame->ToCString()); |
| frame->VisitObjectPointers(&visitor); |
| frame = frames.NextFrame(); |
| } |
| } |
| |
| #endif // !PRODUCT |
| |
| } // namespace dart |