| Index: runtime/vm/debugger.cc
|
| diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
|
| index 5c54271bc56aefaeca52be2ef11e299e17a169e9..3cdf810c8d678527f68328de0fa065be6d01b0e1 100644
|
| --- a/runtime/vm/debugger.cc
|
| +++ b/runtime/vm/debugger.cc
|
| @@ -6,8 +6,6 @@
|
|
|
| #include "include/dart_api.h"
|
|
|
| -#include "platform/address_sanitizer.h"
|
| -
|
| #include "vm/code_generator.h"
|
| #include "vm/code_patcher.h"
|
| #include "vm/compiler.h"
|
| @@ -44,7 +42,6 @@ DEFINE_FLAG(bool,
|
| trace_debugger_stacktrace,
|
| false,
|
| "Trace debugger stacktrace collection");
|
| -DEFINE_FLAG(bool, trace_rewind, false, "Trace frame rewind");
|
| DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages");
|
| DEFINE_FLAG(bool,
|
| steal_breakpoints,
|
| @@ -853,24 +850,6 @@ RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) {
|
| }
|
|
|
|
|
| -bool ActivationFrame::IsRewindable() const {
|
| - if (deopt_frame_.IsNull()) {
|
| - return true;
|
| - }
|
| - // TODO(turnidge): This is conservative. It looks at all values in
|
| - // the deopt_frame_ even though some of them may correspond to other
|
| - // inlined frames.
|
| - Object& obj = Object::Handle();
|
| - for (int i = 0; i < deopt_frame_.Length(); i++) {
|
| - obj = deopt_frame_.At(i);
|
| - if (obj.raw() == Symbols::OptimizedOut().raw()) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot,
|
| intptr_t frame_ctx_level,
|
| intptr_t var_ctx_level) {
|
| @@ -1129,13 +1108,9 @@ void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) {
|
| }
|
| }
|
|
|
| -static bool IsFunctionVisible(const Function& function) {
|
| - return FLAG_show_invisible_frames || function.is_visible();
|
| -}
|
| -
|
|
|
| void DebuggerStackTrace::AddActivation(ActivationFrame* frame) {
|
| - if (IsFunctionVisible(frame->function())) {
|
| + if (FLAG_show_invisible_frames || frame->function().is_visible()) {
|
| trace_.Add(frame);
|
| }
|
| }
|
| @@ -1262,8 +1237,6 @@ Debugger::Debugger()
|
| breakpoint_locations_(NULL),
|
| code_breakpoints_(NULL),
|
| resume_action_(kContinue),
|
| - resume_frame_index_(-1),
|
| - post_deopt_frame_index_(-1),
|
| ignore_breakpoints_(false),
|
| pause_event_(NULL),
|
| obj_cache_(NULL),
|
| @@ -1327,13 +1300,10 @@ static RawFunction* ResolveLibraryFunction(const Library& library,
|
| }
|
|
|
|
|
| -bool Debugger::SetupStepOverAsyncSuspension(const char** error) {
|
| +bool Debugger::SetupStepOverAsyncSuspension() {
|
| ActivationFrame* top_frame = TopDartFrame();
|
| if (!IsAtAsyncJump(top_frame)) {
|
| // Not at an async operation.
|
| - if (error) {
|
| - *error = "Isolate must be paused at an async suspension point";
|
| - }
|
| return false;
|
| }
|
| Object& closure = Object::Handle(top_frame->GetAsyncOperation());
|
| @@ -1343,42 +1313,24 @@ bool Debugger::SetupStepOverAsyncSuspension(const char** error) {
|
| Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true);
|
| if (bpt == NULL) {
|
| // Unable to set the breakpoint.
|
| - if (error) {
|
| - *error = "Unable to set breakpoint at async suspension point";
|
| - }
|
| return false;
|
| }
|
| return true;
|
| }
|
|
|
|
|
| -bool Debugger::SetResumeAction(ResumeAction action,
|
| - intptr_t frame_index,
|
| - const char** error) {
|
| - if (error) {
|
| - *error = NULL;
|
| - }
|
| - resume_frame_index_ = -1;
|
| - switch (action) {
|
| - case kStepInto:
|
| - case kStepOver:
|
| - case kStepOut:
|
| - case kContinue:
|
| - resume_action_ = action;
|
| - return true;
|
| - case kStepRewind:
|
| - if (!CanRewindFrame(frame_index, error)) {
|
| - return false;
|
| - }
|
| - resume_action_ = kStepRewind;
|
| - resume_frame_index_ = frame_index;
|
| - return true;
|
| - case kStepOverAsyncSuspension:
|
| - return SetupStepOverAsyncSuspension(error);
|
| - default:
|
| - UNREACHABLE();
|
| - return false;
|
| - }
|
| +void Debugger::SetSingleStep() {
|
| + resume_action_ = kSingleStep;
|
| +}
|
| +
|
| +
|
| +void Debugger::SetStepOver() {
|
| + resume_action_ = kStepOver;
|
| +}
|
| +
|
| +
|
| +void Debugger::SetStepOut() {
|
| + resume_action_ = kStepOut;
|
| }
|
|
|
|
|
| @@ -1670,7 +1622,6 @@ void Debugger::PauseException(const Instance& exc) {
|
| ASSERT(stack_trace_ == NULL);
|
| stack_trace_ = stack_trace;
|
| Pause(&event);
|
| - HandleSteppingRequest(stack_trace_); // we may get a rewind request
|
| stack_trace_ = NULL;
|
| }
|
|
|
| @@ -2596,7 +2547,7 @@ void Debugger::EnterSingleStepMode() {
|
| void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace,
|
| bool skip_next_step) {
|
| stepping_fp_ = 0;
|
| - if (resume_action_ == kStepInto) {
|
| + if (resume_action_ == kSingleStep) {
|
| // When single stepping, we need to deoptimize because we might be
|
| // stepping into optimized code. This happens in particular if
|
| // the isolate has been interrupted, but can happen in other cases
|
| @@ -2606,7 +2557,7 @@ void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace,
|
| isolate_->set_single_step(true);
|
| skip_next_step_ = skip_next_step;
|
| if (FLAG_verbose_debug) {
|
| - OS::Print("HandleSteppingRequest- kStepInto\n");
|
| + OS::Print("HandleSteppingRequest- kSingleStep\n");
|
| }
|
| } else if (resume_action_ == kStepOver) {
|
| DeoptimizeWorld();
|
| @@ -2631,244 +2582,6 @@ void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace,
|
| if (FLAG_verbose_debug) {
|
| OS::Print("HandleSteppingRequest- kStepOut %" Px "\n", stepping_fp_);
|
| }
|
| - } else if (resume_action_ == kStepRewind) {
|
| - if (FLAG_trace_rewind) {
|
| - OS::PrintErr("Rewinding to frame %" Pd "\n", resume_frame_index_);
|
| - OS::PrintErr(
|
| - "-------------------------\n"
|
| - "All frames...\n\n");
|
| - StackFrameIterator iterator(false);
|
| - StackFrame* frame = iterator.NextFrame();
|
| - intptr_t num = 0;
|
| - while ((frame != NULL)) {
|
| - OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString());
|
| - frame = iterator.NextFrame();
|
| - }
|
| - }
|
| - RewindToFrame(resume_frame_index_);
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| -static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack,
|
| - intptr_t frame_index) {
|
| - for (intptr_t i = frame_index + 1; i < stack->Length(); i++) {
|
| - ActivationFrame* frame = stack->FrameAt(i);
|
| - if (frame->IsRewindable()) {
|
| - return i;
|
| - }
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -
|
| -// Can the top frame be rewound?
|
| -bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const {
|
| - // check rewind pc is found
|
| - DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace();
|
| - intptr_t num_frames = stack->Length();
|
| - if (frame_index < 1 || frame_index >= num_frames) {
|
| - if (error) {
|
| - *error = Thread::Current()->zone()->PrintToString(
|
| - "Frame must be in bounds [1..%" Pd
|
| - "]: "
|
| - "saw %" Pd "",
|
| - num_frames - 1, frame_index);
|
| - }
|
| - return false;
|
| - }
|
| - ActivationFrame* frame = stack->FrameAt(frame_index);
|
| - if (!frame->IsRewindable()) {
|
| - intptr_t next_index = FindNextRewindFrameIndex(stack, frame_index);
|
| - if (next_index > 0) {
|
| - *error = Thread::Current()->zone()->PrintToString(
|
| - "Cannot rewind to frame %" Pd
|
| - " due to conflicting compiler "
|
| - "optimizations. "
|
| - "Run the vm with --no-prune-dead-locals to disallow these "
|
| - "optimizations. "
|
| - "Next valid rewind frame is %" Pd ".",
|
| - frame_index, next_index);
|
| - } else {
|
| - *error = Thread::Current()->zone()->PrintToString(
|
| - "Cannot rewind to frame %" Pd
|
| - " due to conflicting compiler "
|
| - "optimizations. "
|
| - "Run the vm with --no-prune-dead-locals to disallow these "
|
| - "optimizations.",
|
| - frame_index);
|
| - }
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| -// Given a return address pc, find the "rewind" pc, which is the pc
|
| -// before the corresponding call.
|
| -static uword LookupRewindPc(const Code& code, uword pc) {
|
| - ASSERT(!code.is_optimized());
|
| - ASSERT(code.ContainsInstructionAt(pc));
|
| -
|
| - uword pc_offset = pc - code.PayloadStart();
|
| - const PcDescriptors& descriptors =
|
| - PcDescriptors::Handle(code.pc_descriptors());
|
| - PcDescriptors::Iterator iter(
|
| - descriptors, RawPcDescriptors::kRewind | RawPcDescriptors::kIcCall |
|
| - RawPcDescriptors::kUnoptStaticCall);
|
| - intptr_t rewind_deopt_id = -1;
|
| - uword rewind_pc = 0;
|
| - while (iter.MoveNext()) {
|
| - if (iter.Kind() == RawPcDescriptors::kRewind) {
|
| - // Remember the last rewind so we don't need to iterator twice.
|
| - rewind_pc = code.PayloadStart() + iter.PcOffset();
|
| - rewind_deopt_id = iter.DeoptId();
|
| - }
|
| - if ((pc_offset == iter.PcOffset()) && (iter.DeoptId() == rewind_deopt_id)) {
|
| - return rewind_pc;
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -
|
| -void Debugger::RewindToFrame(intptr_t frame_index) {
|
| - Thread* thread = Thread::Current();
|
| - Zone* zone = thread->zone();
|
| - Code& code = Code::Handle(zone);
|
| - Function& function = Function::Handle(zone);
|
| -
|
| - // Find the requested frame.
|
| - StackFrameIterator iterator(false);
|
| - intptr_t current_frame = 0;
|
| - for (StackFrame* frame = iterator.NextFrame(); frame != NULL;
|
| - frame = iterator.NextFrame()) {
|
| - ASSERT(frame->IsValid());
|
| - if (frame->IsDartFrame()) {
|
| - code = frame->LookupDartCode();
|
| - function = code.function();
|
| - if (!IsFunctionVisible(function)) {
|
| - continue;
|
| - }
|
| - if (code.is_optimized()) {
|
| - intptr_t sub_index = 0;
|
| - for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done();
|
| - it.Advance()) {
|
| - if (current_frame == frame_index) {
|
| - RewindToOptimizedFrame(frame, code, sub_index);
|
| - UNREACHABLE();
|
| - }
|
| - current_frame++;
|
| - sub_index++;
|
| - }
|
| - } else {
|
| - if (current_frame == frame_index) {
|
| - // We are rewinding to an unoptimized frame.
|
| - RewindToUnoptimizedFrame(frame, code);
|
| - UNREACHABLE();
|
| - }
|
| - current_frame++;
|
| - }
|
| - }
|
| - }
|
| - UNIMPLEMENTED();
|
| -}
|
| -
|
| -
|
| -void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) {
|
| - // We will be jumping out of the debugger rather than exiting this
|
| - // function, so prepare the debugger state.
|
| - stack_trace_ = NULL;
|
| - resume_action_ = kContinue;
|
| - resume_frame_index_ = -1;
|
| - EnterSingleStepMode();
|
| -
|
| - uword rewind_pc = LookupRewindPc(code, frame->pc());
|
| - if (FLAG_trace_rewind && rewind_pc == 0) {
|
| - OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc());
|
| - }
|
| - ASSERT(rewind_pc != 0);
|
| - if (FLAG_trace_rewind) {
|
| - OS::PrintErr(
|
| - "===============================\n"
|
| - "Rewinding to unoptimized frame:\n"
|
| - " rewind_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px
|
| - ")\n"
|
| - "===============================\n",
|
| - rewind_pc, frame->sp(), frame->fp());
|
| - }
|
| - Exceptions::JumpToFrame(Thread::Current(), rewind_pc, frame->sp(),
|
| - frame->fp(), true /* clear lazy deopt at target */);
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| -void Debugger::RewindToOptimizedFrame(StackFrame* frame,
|
| - const Code& optimized_code,
|
| - intptr_t sub_index) {
|
| - post_deopt_frame_index_ = sub_index;
|
| -
|
| - // We will be jumping out of the debugger rather than exiting this
|
| - // function, so prepare the debugger state.
|
| - stack_trace_ = NULL;
|
| - resume_action_ = kContinue;
|
| - resume_frame_index_ = -1;
|
| - EnterSingleStepMode();
|
| -
|
| - if (FLAG_trace_rewind) {
|
| - OS::PrintErr(
|
| - "===============================\n"
|
| - "Deoptimizing frame for rewind:\n"
|
| - " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px
|
| - ")\n"
|
| - "===============================\n",
|
| - frame->pc(), frame->sp(), frame->fp());
|
| - }
|
| - Thread* thread = Thread::Current();
|
| - thread->set_resume_pc(frame->pc());
|
| - uword deopt_stub_pc = StubCode::DeoptForRewind_entry()->EntryPoint();
|
| - Exceptions::JumpToFrame(thread, deopt_stub_pc, frame->sp(), frame->fp(),
|
| - true /* clear lazy deopt at target */);
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| -void Debugger::RewindPostDeopt() {
|
| - intptr_t rewind_frame = post_deopt_frame_index_;
|
| - post_deopt_frame_index_ = -1;
|
| - if (FLAG_trace_rewind) {
|
| - OS::PrintErr("Post deopt, jumping to frame %" Pd "\n", rewind_frame);
|
| - OS::PrintErr(
|
| - "-------------------------\n"
|
| - "All frames...\n\n");
|
| - StackFrameIterator iterator(false);
|
| - StackFrame* frame = iterator.NextFrame();
|
| - intptr_t num = 0;
|
| - while ((frame != NULL)) {
|
| - OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString());
|
| - frame = iterator.NextFrame();
|
| - }
|
| - }
|
| -
|
| - Thread* thread = Thread::Current();
|
| - Zone* zone = thread->zone();
|
| - Code& code = Code::Handle(zone);
|
| -
|
| - StackFrameIterator iterator(false);
|
| - intptr_t current_frame = 0;
|
| - for (StackFrame* frame = iterator.NextFrame(); frame != NULL;
|
| - frame = iterator.NextFrame()) {
|
| - ASSERT(frame->IsValid());
|
| - if (frame->IsDartFrame()) {
|
| - code = frame->LookupDartCode();
|
| - ASSERT(!code.is_optimized());
|
| - if (current_frame == rewind_frame) {
|
| - RewindToUnoptimizedFrame(frame, code);
|
| - UNREACHABLE();
|
| - }
|
| - current_frame++;
|
| - }
|
| }
|
| }
|
|
|
| @@ -3080,7 +2793,7 @@ RawError* Debugger::PauseBreakpoint() {
|
|
|
| // We are at the entry of an async function.
|
| // We issue a step over to resume at the point after the await statement.
|
| - SetResumeAction(kStepOver);
|
| + SetStepOver();
|
| // When we single step from a user breakpoint, our next stepping
|
| // point will be at the exact same pc. Skip it.
|
| HandleSteppingRequest(stack_trace_, true /* skip next step */);
|
| @@ -3133,7 +2846,7 @@ void Debugger::PauseDeveloper(const String& msg) {
|
| // We are in the native call to Developer_debugger. the developer
|
| // gets a better experience by not seeing this call. To accomplish
|
| // this, we continue execution until the call exits (step out).
|
| - SetResumeAction(kStepOut);
|
| + SetStepOut();
|
| HandleSteppingRequest(stack_trace_);
|
|
|
| stack_trace_ = NULL;
|
|
|