| 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 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 // Compute column number lazily since it causes scanning of the script. | 189 // Compute column number lazily since it causes scanning of the script. |
| 190 if (column_number_ < 0) { | 190 if (column_number_ < 0) { |
| 191 const Script& script = Script::Handle(this->script()); | 191 const Script& script = Script::Handle(this->script()); |
| 192 script.GetTokenLocation(token_pos_, &line_number_, &column_number_); | 192 script.GetTokenLocation(token_pos_, &line_number_, &column_number_); |
| 193 } | 193 } |
| 194 return column_number_; | 194 return column_number_; |
| 195 } | 195 } |
| 196 | 196 |
| 197 | 197 |
| 198 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { | 198 void Breakpoint::set_bpt_location(BreakpointLocation* new_bpt_location) { |
| 199 ASSERT(bpt_location_->IsLatent()); // Only reason to move. | 199 // Only latent breakpoints can be moved. |
| 200 ASSERT((new_bpt_location == NULL) || bpt_location_->IsLatent()); |
| 200 bpt_location_ = new_bpt_location; | 201 bpt_location_ = new_bpt_location; |
| 201 } | 202 } |
| 202 | 203 |
| 203 | 204 |
| 204 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 205 void Breakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| 205 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); | 206 visitor->VisitPointer(reinterpret_cast<RawObject**>(&closure_)); |
| 206 } | 207 } |
| 207 | 208 |
| 208 | 209 |
| 209 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 210 void BreakpointLocation::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
| (...skipping 1136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1346 resume_action_(kContinue), | 1347 resume_action_(kContinue), |
| 1347 resume_frame_index_(-1), | 1348 resume_frame_index_(-1), |
| 1348 post_deopt_frame_index_(-1), | 1349 post_deopt_frame_index_(-1), |
| 1349 ignore_breakpoints_(false), | 1350 ignore_breakpoints_(false), |
| 1350 pause_event_(NULL), | 1351 pause_event_(NULL), |
| 1351 obj_cache_(NULL), | 1352 obj_cache_(NULL), |
| 1352 stack_trace_(NULL), | 1353 stack_trace_(NULL), |
| 1353 async_causal_stack_trace_(NULL), | 1354 async_causal_stack_trace_(NULL), |
| 1354 stepping_fp_(0), | 1355 stepping_fp_(0), |
| 1355 skip_next_step_(false), | 1356 skip_next_step_(false), |
| 1357 needs_breakpoint_cleanup_(false), |
| 1356 synthetic_async_breakpoint_(NULL), | 1358 synthetic_async_breakpoint_(NULL), |
| 1357 exc_pause_info_(kNoPauseOnExceptions) {} | 1359 exc_pause_info_(kNoPauseOnExceptions) {} |
| 1358 | 1360 |
| 1359 | 1361 |
| 1360 Debugger::~Debugger() { | 1362 Debugger::~Debugger() { |
| 1361 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1363 isolate_id_ = ILLEGAL_ISOLATE_ID; |
| 1362 ASSERT(!IsPaused()); | 1364 ASSERT(!IsPaused()); |
| 1363 ASSERT(latent_locations_ == NULL); | 1365 ASSERT(latent_locations_ == NULL); |
| 1364 ASSERT(breakpoint_locations_ == NULL); | 1366 ASSERT(breakpoint_locations_ == NULL); |
| 1365 ASSERT(code_breakpoints_ == NULL); | 1367 ASSERT(code_breakpoints_ == NULL); |
| (...skipping 1413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2779 error.IsUnhandledException()); | 2781 error.IsUnhandledException()); |
| 2780 | 2782 |
| 2781 // Only send a resume event when the isolate is not unwinding. | 2783 // Only send a resume event when the isolate is not unwinding. |
| 2782 if (!error.IsUnwindError()) { | 2784 if (!error.IsUnwindError()) { |
| 2783 ServiceEvent resume_event(event->isolate(), ServiceEvent::kResume); | 2785 ServiceEvent resume_event(event->isolate(), ServiceEvent::kResume); |
| 2784 resume_event.set_top_frame(event->top_frame()); | 2786 resume_event.set_top_frame(event->top_frame()); |
| 2785 Service::HandleEvent(&resume_event); | 2787 Service::HandleEvent(&resume_event); |
| 2786 } | 2788 } |
| 2787 } | 2789 } |
| 2788 | 2790 |
| 2791 if (needs_breakpoint_cleanup_) { |
| 2792 RemoveUnlinkedCodeBreakpoints(); |
| 2793 } |
| 2789 pause_event_ = NULL; | 2794 pause_event_ = NULL; |
| 2790 obj_cache_ = NULL; // Zone allocated | 2795 obj_cache_ = NULL; // Zone allocated |
| 2791 } | 2796 } |
| 2792 | 2797 |
| 2793 | 2798 |
| 2794 void Debugger::EnterSingleStepMode() { | 2799 void Debugger::EnterSingleStepMode() { |
| 2795 stepping_fp_ = 0; | 2800 stepping_fp_ = 0; |
| 2796 DeoptimizeWorld(); | 2801 DeoptimizeWorld(); |
| 2797 isolate_->set_single_step(true); | 2802 isolate_->set_single_step(true); |
| 2798 } | 2803 } |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3269 // We issue a step over to resume at the point after the await statement. | 3274 // We issue a step over to resume at the point after the await statement. |
| 3270 SetResumeAction(kStepOver); | 3275 SetResumeAction(kStepOver); |
| 3271 // When we single step from a user breakpoint, our next stepping | 3276 // When we single step from a user breakpoint, our next stepping |
| 3272 // point will be at the exact same pc. Skip it. | 3277 // point will be at the exact same pc. Skip it. |
| 3273 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3278 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 3274 ClearCachedStackTraces(); | 3279 ClearCachedStackTraces(); |
| 3275 return Error::null(); | 3280 return Error::null(); |
| 3276 } | 3281 } |
| 3277 | 3282 |
| 3278 if (FLAG_verbose_debug) { | 3283 if (FLAG_verbose_debug) { |
| 3279 OS::Print(">>> hit %s breakpoint at %s:%" Pd | 3284 OS::Print(">>> hit breakpoint at %s:%" Pd " (token %s) (address %#" Px |
| 3280 " " | 3285 ")\n", |
| 3281 "(token %s) (address %#" Px ")\n", | |
| 3282 cbpt->IsInternal() ? "internal" : "user", | |
| 3283 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), | 3286 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), |
| 3284 cbpt->token_pos().ToCString(), top_frame->pc()); | 3287 cbpt->token_pos().ToCString(), top_frame->pc()); |
| 3285 } | 3288 } |
| 3286 | 3289 |
| 3287 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); | 3290 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
| 3288 SignalPausedEvent(top_frame, bpt_hit); | 3291 SignalPausedEvent(top_frame, bpt_hit); |
| 3289 // When we single step from a user breakpoint, our next stepping | 3292 // When we single step from a user breakpoint, our next stepping |
| 3290 // point will be at the exact same pc. Skip it. | 3293 // point will be at the exact same pc. Skip it. |
| 3291 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3294 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 3292 ClearCachedStackTraces(); | 3295 ClearCachedStackTraces(); |
| 3293 if (cbpt->IsInternal()) { | |
| 3294 RemoveInternalBreakpoints(); | |
| 3295 } | |
| 3296 | 3296 |
| 3297 // If any error occurred while in the debug message loop, return it here. | 3297 // If any error occurred while in the debug message loop, return it here. |
| 3298 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3298 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 3299 Thread::Current()->clear_sticky_error(); | 3299 Thread::Current()->clear_sticky_error(); |
| 3300 return error.raw(); | 3300 return error.raw(); |
| 3301 } | 3301 } |
| 3302 | 3302 |
| 3303 | 3303 |
| 3304 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, | 3304 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, |
| 3305 ActivationFrame* top_frame) { | 3305 ActivationFrame* top_frame) { |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3662 Breakpoint* prev_bpt = NULL; | 3662 Breakpoint* prev_bpt = NULL; |
| 3663 Breakpoint* curr_bpt = curr_loc->breakpoints(); | 3663 Breakpoint* curr_bpt = curr_loc->breakpoints(); |
| 3664 while (curr_bpt != NULL) { | 3664 while (curr_bpt != NULL) { |
| 3665 if (curr_bpt->id() == bp_id) { | 3665 if (curr_bpt->id() == bp_id) { |
| 3666 if (prev_bpt == NULL) { | 3666 if (prev_bpt == NULL) { |
| 3667 curr_loc->set_breakpoints(curr_bpt->next()); | 3667 curr_loc->set_breakpoints(curr_bpt->next()); |
| 3668 } else { | 3668 } else { |
| 3669 prev_bpt->set_next(curr_bpt->next()); | 3669 prev_bpt->set_next(curr_bpt->next()); |
| 3670 } | 3670 } |
| 3671 | 3671 |
| 3672 // Send event to client before the breakpoint's fields are |
| 3673 // poisoned and deleted. |
| 3672 SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); | 3674 SendBreakpointEvent(ServiceEvent::kBreakpointRemoved, curr_bpt); |
| 3673 | 3675 |
| 3674 // Remove references from the current debugger pause event. | 3676 curr_bpt->set_next(NULL); |
| 3677 curr_bpt->set_bpt_location(NULL); |
| 3678 // Remove possible references to the breakpoint. |
| 3675 if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) { | 3679 if (pause_event_ != NULL && pause_event_->breakpoint() == curr_bpt) { |
| 3676 pause_event_->set_breakpoint(NULL); | 3680 pause_event_->set_breakpoint(NULL); |
| 3677 } | 3681 } |
| 3678 break; | 3682 if (synthetic_async_breakpoint_ == curr_bpt) { |
| 3683 synthetic_async_breakpoint_ = NULL; |
| 3684 } |
| 3685 delete curr_bpt; |
| 3686 curr_bpt = NULL; |
| 3687 |
| 3688 // Delete the breakpoint location object if there are no more |
| 3689 // breakpoints at that location. |
| 3690 if (curr_loc->breakpoints() == NULL) { |
| 3691 if (prev_loc == NULL) { |
| 3692 breakpoint_locations_ = curr_loc->next(); |
| 3693 } else { |
| 3694 prev_loc->set_next(curr_loc->next()); |
| 3695 } |
| 3696 |
| 3697 // Remove references from code breakpoints to this breakpoint |
| 3698 // location and disable them. |
| 3699 UnlinkCodeBreakpoints(curr_loc); |
| 3700 BreakpointLocation* next_loc = curr_loc->next(); |
| 3701 delete curr_loc; |
| 3702 curr_loc = next_loc; |
| 3703 } |
| 3704 |
| 3705 // The code breakpoints will be deleted when the VM resumes |
| 3706 // after the pause event. |
| 3707 return; |
| 3679 } | 3708 } |
| 3680 | 3709 |
| 3681 prev_bpt = curr_bpt; | 3710 prev_bpt = curr_bpt; |
| 3682 curr_bpt = curr_bpt->next(); | 3711 curr_bpt = curr_bpt->next(); |
| 3683 } | 3712 } |
| 3684 | 3713 prev_loc = curr_loc; |
| 3685 if (curr_loc->breakpoints() == NULL) { | 3714 curr_loc = curr_loc->next(); |
| 3686 if (prev_loc == NULL) { | |
| 3687 breakpoint_locations_ = curr_loc->next(); | |
| 3688 } else { | |
| 3689 prev_loc->set_next(curr_loc->next()); | |
| 3690 } | |
| 3691 | |
| 3692 // Remove references from code breakpoints to this source breakpoint, | |
| 3693 // and disable the code breakpoints. | |
| 3694 UnlinkCodeBreakpoints(curr_loc); | |
| 3695 BreakpointLocation* next_loc = curr_loc->next(); | |
| 3696 delete curr_loc; | |
| 3697 curr_loc = next_loc; | |
| 3698 } else { | |
| 3699 prev_loc = curr_loc; | |
| 3700 curr_loc = curr_loc->next(); | |
| 3701 } | |
| 3702 } | 3715 } |
| 3703 // bpt is not a registered breakpoint, nothing to do. | 3716 // breakpoint with bp_id does not exist, nothing to do. |
| 3704 } | 3717 } |
| 3705 | 3718 |
| 3706 | 3719 |
| 3707 // Turn code breakpoints associated with the given source breakpoint into | 3720 // Unlink code breakpoints from the the given breakpoint location. |
| 3708 // internal breakpoints. They will later be deleted when control | 3721 // They will later be deleted when control returns from the pause event |
| 3709 // returns from the user-defined breakpoint callback. Also, disable the | 3722 // callback. Also, disable the breakpoint so it no longer fires if it |
| 3710 // breakpoint so it no longer fires if it should be hit before it gets | 3723 // should be hit before it gets deleted. |
| 3711 // deleted. | |
| 3712 void Debugger::UnlinkCodeBreakpoints(BreakpointLocation* bpt_location) { | 3724 void Debugger::UnlinkCodeBreakpoints(BreakpointLocation* bpt_location) { |
| 3713 ASSERT(bpt_location != NULL); | 3725 ASSERT(bpt_location != NULL); |
| 3714 CodeBreakpoint* curr_bpt = code_breakpoints_; | 3726 CodeBreakpoint* curr_bpt = code_breakpoints_; |
| 3715 while (curr_bpt != NULL) { | 3727 while (curr_bpt != NULL) { |
| 3716 if (curr_bpt->bpt_location() == bpt_location) { | 3728 if (curr_bpt->bpt_location() == bpt_location) { |
| 3717 curr_bpt->Disable(); | 3729 curr_bpt->Disable(); |
| 3718 curr_bpt->set_bpt_location(NULL); | 3730 curr_bpt->set_bpt_location(NULL); |
| 3731 needs_breakpoint_cleanup_ = true; |
| 3719 } | 3732 } |
| 3720 curr_bpt = curr_bpt->next(); | 3733 curr_bpt = curr_bpt->next(); |
| 3721 } | 3734 } |
| 3722 } | 3735 } |
| 3723 | 3736 |
| 3724 | 3737 |
| 3725 // Remove and delete internal breakpoints, i.e. breakpoints that | 3738 // Remove and delete unlinked code breakpoints, i.e. breakpoints that |
| 3726 // are not associated with a source breakpoint. | 3739 // are not associated with a breakpoint location. |
| 3727 void Debugger::RemoveInternalBreakpoints() { | 3740 void Debugger::RemoveUnlinkedCodeBreakpoints() { |
| 3728 CodeBreakpoint* prev_bpt = NULL; | 3741 CodeBreakpoint* prev_bpt = NULL; |
| 3729 CodeBreakpoint* curr_bpt = code_breakpoints_; | 3742 CodeBreakpoint* curr_bpt = code_breakpoints_; |
| 3730 while (curr_bpt != NULL) { | 3743 while (curr_bpt != NULL) { |
| 3731 if (curr_bpt->bpt_location() == NULL) { | 3744 if (curr_bpt->bpt_location() == NULL) { |
| 3732 if (prev_bpt == NULL) { | 3745 if (prev_bpt == NULL) { |
| 3733 code_breakpoints_ = code_breakpoints_->next(); | 3746 code_breakpoints_ = code_breakpoints_->next(); |
| 3734 } else { | 3747 } else { |
| 3735 prev_bpt->set_next(curr_bpt->next()); | 3748 prev_bpt->set_next(curr_bpt->next()); |
| 3736 } | 3749 } |
| 3737 CodeBreakpoint* temp_bpt = curr_bpt; | 3750 CodeBreakpoint* temp_bpt = curr_bpt; |
| 3738 curr_bpt = curr_bpt->next(); | 3751 curr_bpt = curr_bpt->next(); |
| 3739 temp_bpt->Disable(); | 3752 temp_bpt->Disable(); |
| 3740 delete temp_bpt; | 3753 delete temp_bpt; |
| 3741 } else { | 3754 } else { |
| 3742 prev_bpt = curr_bpt; | 3755 prev_bpt = curr_bpt; |
| 3743 curr_bpt = curr_bpt->next(); | 3756 curr_bpt = curr_bpt->next(); |
| 3744 } | 3757 } |
| 3745 } | 3758 } |
| 3759 needs_breakpoint_cleanup_ = false; |
| 3746 } | 3760 } |
| 3747 | 3761 |
| 3748 | 3762 |
| 3749 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, | 3763 BreakpointLocation* Debugger::GetBreakpointLocation(const Script& script, |
| 3750 TokenPosition token_pos, | 3764 TokenPosition token_pos, |
| 3751 intptr_t requested_column) { | 3765 intptr_t requested_column) { |
| 3752 BreakpointLocation* bpt = breakpoint_locations_; | 3766 BreakpointLocation* bpt = breakpoint_locations_; |
| 3753 while (bpt != NULL) { | 3767 while (bpt != NULL) { |
| 3754 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos) && | 3768 if ((bpt->script_ == script.raw()) && (bpt->token_pos_ == token_pos) && |
| 3755 (bpt->requested_column_number_ == requested_column)) { | 3769 (bpt->requested_column_number_ == requested_column)) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3807 | 3821 |
| 3808 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3822 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 3809 ASSERT(bpt->next() == NULL); | 3823 ASSERT(bpt->next() == NULL); |
| 3810 bpt->set_next(code_breakpoints_); | 3824 bpt->set_next(code_breakpoints_); |
| 3811 code_breakpoints_ = bpt; | 3825 code_breakpoints_ = bpt; |
| 3812 } | 3826 } |
| 3813 | 3827 |
| 3814 #endif // !PRODUCT | 3828 #endif // !PRODUCT |
| 3815 | 3829 |
| 3816 } // namespace dart | 3830 } // namespace dart |
| OLD | NEW |