OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/debugger.h" | 5 #include "vm/debugger.h" |
6 | 6 |
7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
8 | 8 |
9 #include "platform/address_sanitizer.h" | 9 #include "platform/address_sanitizer.h" |
10 | 10 |
(...skipping 891 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
902 if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) { | 902 if (iter.TryIndex() != CatchClauseNode::kInvalidTryIndex) { |
903 if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) { | 903 if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) { |
904 try_index_ = iter.TryIndex(); | 904 try_index_ = iter.TryIndex(); |
905 } | 905 } |
906 } | 906 } |
907 } | 907 } |
908 } | 908 } |
909 } | 909 } |
910 | 910 |
911 | 911 |
| 912 bool ActivationFrame::IsAsyncMachinery() const { |
| 913 Isolate* isolate = Isolate::Current(); |
| 914 if (function_.raw() == isolate->object_store()->complete_on_async_return()) { |
| 915 // We are completing an async function's completer. |
| 916 return true; |
| 917 } |
| 918 if (function_.Owner() == |
| 919 isolate->object_store()->async_star_stream_controller()) { |
| 920 // We are inside the async* stream controller code. |
| 921 return true; |
| 922 } |
| 923 return false; |
| 924 } |
| 925 |
| 926 |
912 // Get the saved current context of this activation. | 927 // Get the saved current context of this activation. |
913 const Context& ActivationFrame::GetSavedCurrentContext() { | 928 const Context& ActivationFrame::GetSavedCurrentContext() { |
914 if (!ctx_.IsNull()) return ctx_; | 929 if (!ctx_.IsNull()) return ctx_; |
915 GetVarDescriptors(); | 930 GetVarDescriptors(); |
916 intptr_t var_desc_len = var_descriptors_.Length(); | 931 intptr_t var_desc_len = var_descriptors_.Length(); |
917 for (intptr_t i = 0; i < var_desc_len; i++) { | 932 for (intptr_t i = 0; i < var_desc_len; i++) { |
918 RawLocalVarDescriptors::VarInfo var_info; | 933 RawLocalVarDescriptors::VarInfo var_info; |
919 var_descriptors_.GetInfo(i, &var_info); | 934 var_descriptors_.GetInfo(i, &var_info); |
920 const int8_t kind = var_info.kind(); | 935 const int8_t kind = var_info.kind(); |
921 if (kind == RawLocalVarDescriptors::kSavedCurrentContext) { | 936 if (kind == RawLocalVarDescriptors::kSavedCurrentContext) { |
(...skipping 646 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1568 resume_action_(kContinue), | 1583 resume_action_(kContinue), |
1569 resume_frame_index_(-1), | 1584 resume_frame_index_(-1), |
1570 post_deopt_frame_index_(-1), | 1585 post_deopt_frame_index_(-1), |
1571 ignore_breakpoints_(false), | 1586 ignore_breakpoints_(false), |
1572 pause_event_(NULL), | 1587 pause_event_(NULL), |
1573 obj_cache_(NULL), | 1588 obj_cache_(NULL), |
1574 stack_trace_(NULL), | 1589 stack_trace_(NULL), |
1575 async_causal_stack_trace_(NULL), | 1590 async_causal_stack_trace_(NULL), |
1576 awaiter_stack_trace_(NULL), | 1591 awaiter_stack_trace_(NULL), |
1577 stepping_fp_(0), | 1592 stepping_fp_(0), |
| 1593 async_stepping_fp_(0), |
| 1594 top_frame_awaiter_(Object::null()), |
1578 skip_next_step_(false), | 1595 skip_next_step_(false), |
1579 needs_breakpoint_cleanup_(false), | 1596 needs_breakpoint_cleanup_(false), |
1580 synthetic_async_breakpoint_(NULL), | 1597 synthetic_async_breakpoint_(NULL), |
1581 exc_pause_info_(kNoPauseOnExceptions) {} | 1598 exc_pause_info_(kNoPauseOnExceptions) {} |
1582 | 1599 |
1583 | 1600 |
1584 Debugger::~Debugger() { | 1601 Debugger::~Debugger() { |
1585 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1602 isolate_id_ = ILLEGAL_ISOLATE_ID; |
1586 ASSERT(!IsPaused()); | 1603 ASSERT(!IsPaused()); |
1587 ASSERT(latent_locations_ == NULL); | 1604 ASSERT(latent_locations_ == NULL); |
(...skipping 1542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3130 bpt = latent_locations_; | 3147 bpt = latent_locations_; |
3131 while (bpt != NULL) { | 3148 while (bpt != NULL) { |
3132 bpt->VisitObjectPointers(visitor); | 3149 bpt->VisitObjectPointers(visitor); |
3133 bpt = bpt->next(); | 3150 bpt = bpt->next(); |
3134 } | 3151 } |
3135 CodeBreakpoint* cbpt = code_breakpoints_; | 3152 CodeBreakpoint* cbpt = code_breakpoints_; |
3136 while (cbpt != NULL) { | 3153 while (cbpt != NULL) { |
3137 cbpt->VisitObjectPointers(visitor); | 3154 cbpt->VisitObjectPointers(visitor); |
3138 cbpt = cbpt->next(); | 3155 cbpt = cbpt->next(); |
3139 } | 3156 } |
| 3157 visitor->VisitPointer(reinterpret_cast<RawObject**>(&top_frame_awaiter_)); |
3140 } | 3158 } |
3141 | 3159 |
3142 | 3160 |
3143 // static | 3161 // static |
3144 void Debugger::SetEventHandler(EventHandler* handler) { | 3162 void Debugger::SetEventHandler(EventHandler* handler) { |
3145 event_handler_ = handler; | 3163 event_handler_ = handler; |
3146 } | 3164 } |
3147 | 3165 |
3148 | 3166 |
3149 void Debugger::Pause(ServiceEvent* event) { | 3167 void Debugger::Pause(ServiceEvent* event) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3193 | 3211 |
3194 if (needs_breakpoint_cleanup_) { | 3212 if (needs_breakpoint_cleanup_) { |
3195 RemoveUnlinkedCodeBreakpoints(); | 3213 RemoveUnlinkedCodeBreakpoints(); |
3196 } | 3214 } |
3197 pause_event_ = NULL; | 3215 pause_event_ = NULL; |
3198 obj_cache_ = NULL; // Zone allocated | 3216 obj_cache_ = NULL; // Zone allocated |
3199 } | 3217 } |
3200 | 3218 |
3201 | 3219 |
3202 void Debugger::EnterSingleStepMode() { | 3220 void Debugger::EnterSingleStepMode() { |
3203 stepping_fp_ = 0; | 3221 ResetSteppingFramePointers(); |
3204 DeoptimizeWorld(); | 3222 DeoptimizeWorld(); |
3205 isolate_->set_single_step(true); | 3223 isolate_->set_single_step(true); |
3206 } | 3224 } |
3207 | 3225 |
3208 | 3226 |
| 3227 void Debugger::ResetSteppingFramePointers() { |
| 3228 stepping_fp_ = 0; |
| 3229 async_stepping_fp_ = 0; |
| 3230 } |
| 3231 |
| 3232 |
| 3233 bool Debugger::SteppedForSyntheticAsyncBreakpoint() const { |
| 3234 return synthetic_async_breakpoint_ != NULL; |
| 3235 } |
| 3236 |
| 3237 |
| 3238 void Debugger::CleanupSyntheticAsyncBreakpoint() { |
| 3239 if (synthetic_async_breakpoint_ != NULL) { |
| 3240 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
| 3241 synthetic_async_breakpoint_ = NULL; |
| 3242 } |
| 3243 } |
| 3244 |
| 3245 |
| 3246 void Debugger::RememberTopFrameAwaiter() { |
| 3247 if (!FLAG_async_debugger_stepping) { |
| 3248 return; |
| 3249 } |
| 3250 if (stack_trace_->Length() > 0) { |
| 3251 top_frame_awaiter_ = stack_trace_->FrameAt(0)->GetAsyncAwaiter(); |
| 3252 } else { |
| 3253 top_frame_awaiter_ = Object::null(); |
| 3254 } |
| 3255 } |
| 3256 |
| 3257 |
| 3258 void Debugger::SetAsyncSteppingFramePointer() { |
| 3259 if (!FLAG_async_debugger_stepping) { |
| 3260 return; |
| 3261 } |
| 3262 if (stack_trace_->FrameAt(0)->function().IsAsyncClosure() || |
| 3263 stack_trace_->FrameAt(0)->function().IsAsyncGenClosure()) { |
| 3264 async_stepping_fp_ = stack_trace_->FrameAt(0)->fp(); |
| 3265 } else { |
| 3266 async_stepping_fp_ = 0; |
| 3267 } |
| 3268 } |
| 3269 |
| 3270 |
3209 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, | 3271 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
3210 bool skip_next_step) { | 3272 bool skip_next_step) { |
3211 stepping_fp_ = 0; | 3273 ResetSteppingFramePointers(); |
| 3274 RememberTopFrameAwaiter(); |
3212 if (resume_action_ == kStepInto) { | 3275 if (resume_action_ == kStepInto) { |
3213 // When single stepping, we need to deoptimize because we might be | 3276 // When single stepping, we need to deoptimize because we might be |
3214 // stepping into optimized code. This happens in particular if | 3277 // stepping into optimized code. This happens in particular if |
3215 // the isolate has been interrupted, but can happen in other cases | 3278 // the isolate has been interrupted, but can happen in other cases |
3216 // as well. We need to deoptimize the world in case we are about | 3279 // as well. We need to deoptimize the world in case we are about |
3217 // to call an optimized function. | 3280 // to call an optimized function. |
3218 DeoptimizeWorld(); | 3281 DeoptimizeWorld(); |
3219 isolate_->set_single_step(true); | 3282 isolate_->set_single_step(true); |
3220 skip_next_step_ = skip_next_step; | 3283 skip_next_step_ = skip_next_step; |
| 3284 SetAsyncSteppingFramePointer(); |
3221 if (FLAG_verbose_debug) { | 3285 if (FLAG_verbose_debug) { |
3222 OS::Print("HandleSteppingRequest- kStepInto\n"); | 3286 OS::Print("HandleSteppingRequest- kStepInto\n"); |
3223 } | 3287 } |
3224 } else if (resume_action_ == kStepOver) { | 3288 } else if (resume_action_ == kStepOver) { |
3225 DeoptimizeWorld(); | 3289 DeoptimizeWorld(); |
3226 isolate_->set_single_step(true); | 3290 isolate_->set_single_step(true); |
3227 skip_next_step_ = skip_next_step; | 3291 skip_next_step_ = skip_next_step; |
3228 ASSERT(stack_trace->Length() > 0); | 3292 ASSERT(stack_trace->Length() > 0); |
3229 stepping_fp_ = stack_trace->FrameAt(0)->fp(); | 3293 stepping_fp_ = stack_trace->FrameAt(0)->fp(); |
| 3294 SetAsyncSteppingFramePointer(); |
3230 if (FLAG_verbose_debug) { | 3295 if (FLAG_verbose_debug) { |
3231 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); | 3296 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); |
3232 } | 3297 } |
3233 } else if (resume_action_ == kStepOut) { | 3298 } else if (resume_action_ == kStepOut) { |
3234 if (FLAG_async_debugger_stepping) { | 3299 if (FLAG_async_debugger_stepping) { |
3235 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() || | 3300 if (stack_trace->FrameAt(0)->function().IsAsyncClosure() || |
3236 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) { | 3301 stack_trace->FrameAt(0)->function().IsAsyncGenClosure()) { |
3237 // Request to step out of an async/async* closure. | 3302 // Request to step out of an async/async* closure. |
3238 const Object& async_op = | 3303 const Object& async_op = |
3239 Object::Handle(stack_trace->FrameAt(0)->GetAsyncAwaiter()); | 3304 Object::Handle(stack_trace->FrameAt(0)->GetAsyncAwaiter()); |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3526 return false; | 3591 return false; |
3527 } | 3592 } |
3528 const Class& cls = Class::Handle(func.Owner()); | 3593 const Class& cls = Class::Handle(func.Owner()); |
3529 const Library& lib = Library::Handle(cls.library()); | 3594 const Library& lib = Library::Handle(cls.library()); |
3530 return lib.IsDebuggable(); | 3595 return lib.IsDebuggable(); |
3531 } | 3596 } |
3532 | 3597 |
3533 | 3598 |
3534 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { | 3599 void Debugger::SignalPausedEvent(ActivationFrame* top_frame, Breakpoint* bpt) { |
3535 resume_action_ = kContinue; | 3600 resume_action_ = kContinue; |
3536 stepping_fp_ = 0; | 3601 ResetSteppingFramePointers(); |
3537 isolate_->set_single_step(false); | 3602 isolate_->set_single_step(false); |
3538 ASSERT(!IsPaused()); | 3603 ASSERT(!IsPaused()); |
3539 ASSERT(obj_cache_ == NULL); | 3604 ASSERT(obj_cache_ == NULL); |
3540 if ((bpt != NULL) && bpt->IsSingleShot()) { | 3605 if ((bpt != NULL) && bpt->IsSingleShot()) { |
3541 RemoveBreakpoint(bpt->id()); | 3606 RemoveBreakpoint(bpt->id()); |
3542 bpt = NULL; | 3607 bpt = NULL; |
3543 } | 3608 } |
3544 | 3609 |
3545 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); | 3610 ServiceEvent event(isolate_, ServiceEvent::kPauseBreakpoint); |
3546 event.set_top_frame(top_frame); | 3611 event.set_top_frame(top_frame); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3592 } | 3657 } |
3593 | 3658 |
3594 // Check whether we are in a Dart function that the user is | 3659 // Check whether we are in a Dart function that the user is |
3595 // interested in. If we saved the frame pointer of a stack frame | 3660 // interested in. If we saved the frame pointer of a stack frame |
3596 // the user is interested in, we ignore the single step if we are | 3661 // the user is interested in, we ignore the single step if we are |
3597 // in a callee of that frame. Note that we assume that the stack | 3662 // in a callee of that frame. Note that we assume that the stack |
3598 // grows towards lower addresses. | 3663 // grows towards lower addresses. |
3599 ActivationFrame* frame = TopDartFrame(); | 3664 ActivationFrame* frame = TopDartFrame(); |
3600 ASSERT(frame != NULL); | 3665 ASSERT(frame != NULL); |
3601 | 3666 |
| 3667 if (FLAG_async_debugger_stepping) { |
| 3668 if ((async_stepping_fp_ != 0) && (top_frame_awaiter_ != Object::null())) { |
| 3669 // Check if the user has single stepped out of an async function with |
| 3670 // an awaiter. The first check handles the case of calling into the |
| 3671 // async machinery as we finish the async function. The second check |
| 3672 // handles the case of returning from an async function. |
| 3673 const bool exited_async_function = |
| 3674 (IsCalleeFrameOf(async_stepping_fp_, frame->fp()) && |
| 3675 frame->IsAsyncMachinery()) || |
| 3676 IsCalleeFrameOf(frame->fp(), async_stepping_fp_); |
| 3677 if (exited_async_function) { |
| 3678 // Step to the top frame awaiter. |
| 3679 const Object& async_op = Object::Handle(top_frame_awaiter_); |
| 3680 top_frame_awaiter_ = Object::null(); |
| 3681 AsyncStepInto(Closure::Cast(async_op)); |
| 3682 return Error::null(); |
| 3683 } |
| 3684 } |
| 3685 } |
| 3686 |
3602 if (stepping_fp_ != 0) { | 3687 if (stepping_fp_ != 0) { |
3603 // There is an "interesting frame" set. Only pause at appropriate | 3688 // There is an "interesting frame" set. Only pause at appropriate |
3604 // locations in this frame. | 3689 // locations in this frame. |
3605 if (IsCalleeFrameOf(stepping_fp_, frame->fp())) { | 3690 if (IsCalleeFrameOf(stepping_fp_, frame->fp())) { |
3606 // We are in a callee of the frame we're interested in. | 3691 // We are in a callee of the frame we're interested in. |
3607 // Ignore this stepping break. | 3692 // Ignore this stepping break. |
3608 return Error::null(); | 3693 return Error::null(); |
3609 } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) { | 3694 } else if (IsCalleeFrameOf(frame->fp(), stepping_fp_)) { |
3610 // We returned from the "interesting frame", there can be no more | 3695 // We returned from the "interesting frame", there can be no more |
3611 // stepping breaks for it. Pause at the next appropriate location | 3696 // stepping breaks for it. Pause at the next appropriate location |
3612 // and let the user set the "interesting" frame again. | 3697 // and let the user set the "interesting" frame again. |
3613 stepping_fp_ = 0; | 3698 ResetSteppingFramePointers(); |
3614 } | 3699 } |
3615 } | 3700 } |
3616 | 3701 |
3617 if (!frame->IsDebuggable()) { | 3702 if (!frame->IsDebuggable()) { |
3618 return Error::null(); | 3703 return Error::null(); |
3619 } | 3704 } |
3620 if (!frame->TokenPos().IsDebugPause()) { | 3705 if (!frame->TokenPos().IsDebugPause()) { |
3621 return Error::null(); | 3706 return Error::null(); |
3622 } | 3707 } |
3623 | 3708 |
3624 // If there is an active breakpoint at this pc, then we should have | 3709 // If there is an active breakpoint at this pc, then we should have |
3625 // already bailed out of this function in the skip_next_step_ test | 3710 // already bailed out of this function in the skip_next_step_ test |
3626 // above. | 3711 // above. |
3627 ASSERT(!HasActiveBreakpoint(frame->pc())); | 3712 ASSERT(!HasActiveBreakpoint(frame->pc())); |
3628 | 3713 |
3629 if (FLAG_verbose_debug) { | 3714 if (FLAG_verbose_debug) { |
3630 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 3715 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
3631 String::Handle(frame->SourceUrl()).ToCString(), | 3716 String::Handle(frame->SourceUrl()).ToCString(), |
3632 frame->LineNumber(), | 3717 frame->LineNumber(), |
3633 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 3718 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
3634 frame->TokenPos().ToCString()); | 3719 frame->TokenPos().ToCString()); |
3635 } | 3720 } |
3636 | 3721 |
3637 | 3722 |
3638 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace(), | 3723 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace(), |
3639 CollectAwaiterReturnStackTrace()); | 3724 CollectAwaiterReturnStackTrace()); |
3640 // If this step callback is part of stepping over an await statement, | 3725 if (SteppedForSyntheticAsyncBreakpoint()) { |
3641 // we saved the synthetic async breakpoint in PauseBreakpoint. We report | 3726 CleanupSyntheticAsyncBreakpoint(); |
3642 // that we are paused at that breakpoint and then delete it after continuing. | |
3643 SignalPausedEvent(frame, synthetic_async_breakpoint_); | |
3644 if (synthetic_async_breakpoint_ != NULL) { | |
3645 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | |
3646 synthetic_async_breakpoint_ = NULL; | |
3647 } | 3727 } |
| 3728 SignalPausedEvent(frame, NULL); |
3648 HandleSteppingRequest(stack_trace_); | 3729 HandleSteppingRequest(stack_trace_); |
3649 ClearCachedStackTraces(); | 3730 ClearCachedStackTraces(); |
3650 | 3731 |
3651 // If any error occurred while in the debug message loop, return it here. | 3732 // If any error occurred while in the debug message loop, return it here. |
3652 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3733 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
3653 Thread::Current()->clear_sticky_error(); | 3734 Thread::Current()->clear_sticky_error(); |
3654 return error.raw(); | 3735 return error.raw(); |
3655 } | 3736 } |
3656 | 3737 |
3657 | 3738 |
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4230 | 4311 |
4231 void Debugger::AsyncStepInto(const Closure& async_op) { | 4312 void Debugger::AsyncStepInto(const Closure& async_op) { |
4232 SetBreakpointAtActivation(async_op, true); | 4313 SetBreakpointAtActivation(async_op, true); |
4233 Continue(); | 4314 Continue(); |
4234 } | 4315 } |
4235 | 4316 |
4236 | 4317 |
4237 void Debugger::Continue() { | 4318 void Debugger::Continue() { |
4238 SetResumeAction(kContinue); | 4319 SetResumeAction(kContinue); |
4239 stepping_fp_ = 0; | 4320 stepping_fp_ = 0; |
| 4321 async_stepping_fp_ = 0; |
4240 isolate_->set_single_step(false); | 4322 isolate_->set_single_step(false); |
4241 } | 4323 } |
4242 | 4324 |
4243 | 4325 |
4244 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, | 4326 BreakpointLocation* Debugger::GetLatentBreakpoint(const String& url, |
4245 intptr_t line, | 4327 intptr_t line, |
4246 intptr_t column) { | 4328 intptr_t column) { |
4247 BreakpointLocation* bpt = latent_locations_; | 4329 BreakpointLocation* bpt = latent_locations_; |
4248 String& bpt_url = String::Handle(); | 4330 String& bpt_url = String::Handle(); |
4249 while (bpt != NULL) { | 4331 while (bpt != NULL) { |
(...skipping 21 matching lines...) Expand all Loading... |
4271 | 4353 |
4272 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 4354 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
4273 ASSERT(bpt->next() == NULL); | 4355 ASSERT(bpt->next() == NULL); |
4274 bpt->set_next(code_breakpoints_); | 4356 bpt->set_next(code_breakpoints_); |
4275 code_breakpoints_ = bpt; | 4357 code_breakpoints_ = bpt; |
4276 } | 4358 } |
4277 | 4359 |
4278 #endif // !PRODUCT | 4360 #endif // !PRODUCT |
4279 | 4361 |
4280 } // namespace dart | 4362 } // namespace dart |
OLD | NEW |