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 "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
10 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
(...skipping 24 matching lines...) Expand all Loading... | |
35 "Show invisible frames in debugger stack traces"); | 35 "Show invisible frames in debugger stack traces"); |
36 DEFINE_FLAG(bool, trace_debugger_stacktrace, false, | 36 DEFINE_FLAG(bool, trace_debugger_stacktrace, false, |
37 "Trace debugger stacktrace collection"); | 37 "Trace debugger stacktrace collection"); |
38 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); | 38 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); |
39 DEFINE_FLAG(bool, steal_breakpoints, false, | 39 DEFINE_FLAG(bool, steal_breakpoints, false, |
40 "Intercept breakpoints and other pause events before they " | 40 "Intercept breakpoints and other pause events before they " |
41 "are sent to the embedder and use a generic VM breakpoint " | 41 "are sent to the embedder and use a generic VM breakpoint " |
42 "handler instead. This handler dispatches breakpoints to " | 42 "handler instead. This handler dispatches breakpoints to " |
43 "the VM service."); | 43 "the VM service."); |
44 | 44 |
45 DECLARE_FLAG(bool, trace_isolates); | |
46 | |
45 | 47 |
46 Debugger::EventHandler* Debugger::event_handler_ = NULL; | 48 Debugger::EventHandler* Debugger::event_handler_ = NULL; |
47 | 49 |
48 | 50 |
49 class RemoteObjectCache : public ZoneAllocated { | 51 class RemoteObjectCache : public ZoneAllocated { |
50 public: | 52 public: |
51 explicit RemoteObjectCache(intptr_t initial_size); | 53 explicit RemoteObjectCache(intptr_t initial_size); |
52 intptr_t AddObject(const Object& obj); | 54 intptr_t AddObject(const Object& obj); |
53 RawObject* GetObj(intptr_t obj_id) const; | 55 RawObject* GetObj(intptr_t obj_id) const; |
54 bool IsValidId(intptr_t obj_id) const { | 56 bool IsValidId(intptr_t obj_id) const { |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
312 } | 314 } |
313 } | 315 } |
314 | 316 |
315 | 317 |
316 void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) { | 318 void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) { |
317 if (HasEventHandler()) { | 319 if (HasEventHandler()) { |
318 DebuggerEvent event(isolate_, type); | 320 DebuggerEvent event(isolate_, type); |
319 ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID); | 321 ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID); |
320 if (type == DebuggerEvent::kIsolateInterrupted) { | 322 if (type == DebuggerEvent::kIsolateInterrupted) { |
321 DebuggerStackTrace* trace = CollectStackTrace(); | 323 DebuggerStackTrace* trace = CollectStackTrace(); |
322 ASSERT(trace->Length() > 0); | 324 if (trace->Length() > 0) { |
323 event.set_top_frame(trace->FrameAt(0)); | 325 event.set_top_frame(trace->FrameAt(0)); |
326 } | |
324 ASSERT(stack_trace_ == NULL); | 327 ASSERT(stack_trace_ == NULL); |
325 stack_trace_ = trace; | 328 stack_trace_ = trace; |
326 resume_action_ = kContinue; | 329 resume_action_ = kContinue; |
327 Pause(&event); | 330 Pause(&event); |
328 HandleSteppingRequest(trace); | 331 HandleSteppingRequest(trace); |
329 stack_trace_ = NULL; | 332 stack_trace_ = NULL; |
330 } else { | 333 } else { |
331 InvokeEventHandler(&event); | 334 InvokeEventHandler(&event); |
332 } | 335 } |
333 } | 336 } |
334 } | 337 } |
335 | 338 |
336 | 339 |
337 void Debugger::SignalIsolateInterrupted() { | 340 RawError* Debugger::SignalIsolateInterrupted() { |
338 if (HasEventHandler()) { | 341 if (HasEventHandler()) { |
339 Debugger* debugger = Isolate::Current()->debugger(); | 342 SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); |
340 debugger->SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted); | |
341 } | 343 } |
344 Dart_IsolateInterruptCallback callback = isolate_->InterruptCallback(); | |
345 if (callback) { | |
346 if (!(*callback)()) { | |
347 if (FLAG_trace_isolates) { | |
348 OS::Print("[!] Embedder api: terminating isolate:\n" | |
349 "\tisolate: %s\n", isolate_->name()); | |
350 } | |
351 const String& msg = String::Handle(String::New("isolate terminated")); | |
352 return UnwindError::New(msg); | |
353 } | |
354 } | |
355 | |
356 // If any error occurred while in the debug message loop, return it here. | |
turnidge
2015/09/15 22:14:10
This could happen, for example, if the isolate rec
| |
357 const Error& error = | |
358 Error::Handle(isolate_, isolate_->object_store()->sticky_error()); | |
359 isolate_->object_store()->clear_sticky_error(); | |
360 return error.raw(); | |
342 } | 361 } |
343 | 362 |
344 | 363 |
345 // The vm service handles breakpoint notifications in a different way | 364 // The vm service handles breakpoint notifications in a different way |
346 // than the regular debugger breakpoint notifications. | 365 // than the regular debugger breakpoint notifications. |
347 static void SendServiceBreakpointEvent(ServiceEvent::EventKind kind, | 366 static void SendServiceBreakpointEvent(ServiceEvent::EventKind kind, |
348 Breakpoint* bpt) { | 367 Breakpoint* bpt) { |
349 if (Service::debug_stream.enabled()) { | 368 if (Service::debug_stream.enabled()) { |
350 ServiceEvent service_event(Isolate::Current(), kind); | 369 ServiceEvent service_event(Isolate::Current(), kind); |
351 service_event.set_breakpoint(bpt); | 370 service_event.set_breakpoint(bpt); |
(...skipping 2191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2543 if ((iter.CurrentTokenKind() == Token::kIDENT) && | 2562 if ((iter.CurrentTokenKind() == Token::kIDENT) && |
2544 ((iter.CurrentLiteral() == Symbols::Await().raw()) || | 2563 ((iter.CurrentLiteral() == Symbols::Await().raw()) || |
2545 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { | 2564 (iter.CurrentLiteral() == Symbols::YieldKw().raw()))) { |
2546 event.set_at_async_jump(true); | 2565 event.set_at_async_jump(true); |
2547 } | 2566 } |
2548 } | 2567 } |
2549 Pause(&event); | 2568 Pause(&event); |
2550 } | 2569 } |
2551 | 2570 |
2552 | 2571 |
2553 void Debugger::DebuggerStepCallback() { | 2572 RawError* Debugger::DebuggerStepCallback() { |
2554 ASSERT(isolate_->single_step()); | 2573 ASSERT(isolate_->single_step()); |
2555 // We can't get here unless the debugger event handler enabled | 2574 // We can't get here unless the debugger event handler enabled |
2556 // single stepping. | 2575 // single stepping. |
2557 ASSERT(HasEventHandler()); | 2576 ASSERT(HasEventHandler()); |
2558 // Don't pause recursively. | 2577 // Don't pause recursively. |
2559 if (IsPaused()) return; | 2578 if (IsPaused()) { |
2579 return Error::null(); | |
2580 } | |
2560 | 2581 |
2561 // Check whether we are in a Dart function that the user is | 2582 // Check whether we are in a Dart function that the user is |
2562 // interested in. If we saved the frame pointer of a stack frame | 2583 // interested in. If we saved the frame pointer of a stack frame |
2563 // the user is interested in, we ignore the single step if we are | 2584 // the user is interested in, we ignore the single step if we are |
2564 // in a callee of that frame. Note that we assume that the stack | 2585 // in a callee of that frame. Note that we assume that the stack |
2565 // grows towards lower addresses. | 2586 // grows towards lower addresses. |
2566 ActivationFrame* frame = TopDartFrame(); | 2587 ActivationFrame* frame = TopDartFrame(); |
2567 ASSERT(frame != NULL); | 2588 ASSERT(frame != NULL); |
2568 | 2589 |
2569 if (stepping_fp_ != 0) { | 2590 if (stepping_fp_ != 0) { |
2570 // There is an "interesting frame" set. Only pause at appropriate | 2591 // There is an "interesting frame" set. Only pause at appropriate |
2571 // locations in this frame. | 2592 // locations in this frame. |
2572 if (stepping_fp_ > frame->fp()) { | 2593 if (stepping_fp_ > frame->fp()) { |
2573 // We are in a callee of the frame we're interested in. | 2594 // We are in a callee of the frame we're interested in. |
2574 // Ignore this stepping break. | 2595 // Ignore this stepping break. |
2575 return; | 2596 return Error::null(); |
2576 } else if (frame->fp() > stepping_fp_) { | 2597 } else if (frame->fp() > stepping_fp_) { |
2577 // We returned from the "interesting frame", there can be no more | 2598 // We returned from the "interesting frame", there can be no more |
2578 // stepping breaks for it. Pause at the next appropriate location | 2599 // stepping breaks for it. Pause at the next appropriate location |
2579 // and let the user set the "interesting" frame again. | 2600 // and let the user set the "interesting" frame again. |
2580 stepping_fp_ = 0; | 2601 stepping_fp_ = 0; |
2581 } | 2602 } |
2582 } | 2603 } |
2583 | 2604 |
2584 if (!frame->IsDebuggable()) { | 2605 if (!frame->IsDebuggable()) { |
2585 return; | 2606 return Error::null(); |
2586 } | 2607 } |
2587 if (frame->TokenPos() == Scanner::kNoSourcePos) { | 2608 if (frame->TokenPos() == Scanner::kNoSourcePos) { |
2588 return; | 2609 return Error::null(); |
2589 } | 2610 } |
2590 | 2611 |
2591 // Don't pause for a single step if there is a breakpoint set | 2612 // Don't pause for a single step if there is a breakpoint set |
2592 // at this location. | 2613 // at this location. |
2593 if (HasActiveBreakpoint(frame->pc())) { | 2614 if (HasActiveBreakpoint(frame->pc())) { |
2594 return; | 2615 return Error::null(); |
2595 } | 2616 } |
2596 | 2617 |
2597 if (FLAG_verbose_debug) { | 2618 if (FLAG_verbose_debug) { |
2598 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", | 2619 OS::Print(">>> single step break at %s:%" Pd " (func %s token %" Pd ")\n", |
2599 String::Handle(frame->SourceUrl()).ToCString(), | 2620 String::Handle(frame->SourceUrl()).ToCString(), |
2600 frame->LineNumber(), | 2621 frame->LineNumber(), |
2601 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 2622 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
2602 frame->TokenPos()); | 2623 frame->TokenPos()); |
2603 } | 2624 } |
2604 | 2625 |
2605 ASSERT(stack_trace_ == NULL); | 2626 ASSERT(stack_trace_ == NULL); |
2606 stack_trace_ = CollectStackTrace(); | 2627 stack_trace_ = CollectStackTrace(); |
2607 SignalPausedEvent(frame, NULL); | 2628 SignalPausedEvent(frame, NULL); |
2608 HandleSteppingRequest(stack_trace_); | 2629 HandleSteppingRequest(stack_trace_); |
2609 stack_trace_ = NULL; | 2630 stack_trace_ = NULL; |
2631 | |
2632 // If any error occurred while in the debug message loop, return it here. | |
2633 const Error& error = | |
2634 Error::Handle(isolate_, isolate_->object_store()->sticky_error()); | |
2635 isolate_->object_store()->clear_sticky_error(); | |
2636 return error.raw(); | |
2610 } | 2637 } |
2611 | 2638 |
2612 | 2639 |
2613 void Debugger::SignalBpReached() { | 2640 RawError* Debugger::SignalBpReached() { |
2614 // We ignore this breakpoint when the VM is executing code invoked | 2641 // We ignore this breakpoint when the VM is executing code invoked |
2615 // by the debugger to evaluate variables values, or when we see a nested | 2642 // by the debugger to evaluate variables values, or when we see a nested |
2616 // breakpoint or exception event. | 2643 // breakpoint or exception event. |
2617 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { | 2644 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { |
2618 return; | 2645 return Error::null(); |
2619 } | 2646 } |
2620 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2647 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
2621 ASSERT(stack_trace->Length() > 0); | 2648 ASSERT(stack_trace->Length() > 0); |
2622 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 2649 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
2623 ASSERT(top_frame != NULL); | 2650 ASSERT(top_frame != NULL); |
2624 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); | 2651 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); |
2625 ASSERT(cbpt != NULL); | 2652 ASSERT(cbpt != NULL); |
2626 | 2653 |
2627 BreakpointLocation* bpt_location = cbpt->bpt_location_; | 2654 BreakpointLocation* bpt_location = cbpt->bpt_location_; |
2628 Breakpoint* bpt_hit = NULL; | 2655 Breakpoint* bpt_hit = NULL; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2662 if (bpt->IsRepeated()) { | 2689 if (bpt->IsRepeated()) { |
2663 bpt_hit = bpt; | 2690 bpt_hit = bpt; |
2664 break; | 2691 break; |
2665 } | 2692 } |
2666 bpt = bpt->next(); | 2693 bpt = bpt->next(); |
2667 } | 2694 } |
2668 } | 2695 } |
2669 } | 2696 } |
2670 | 2697 |
2671 if (bpt_hit == NULL) { | 2698 if (bpt_hit == NULL) { |
2672 return; | 2699 return Error::null(); |
2673 } | 2700 } |
2674 | 2701 |
2675 if (FLAG_verbose_debug) { | 2702 if (FLAG_verbose_debug) { |
2676 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " | 2703 OS::Print(">>> hit %s breakpoint at %s:%" Pd " " |
2677 "(token %" Pd ") (address %#" Px ")\n", | 2704 "(token %" Pd ") (address %#" Px ")\n", |
2678 cbpt->IsInternal() ? "internal" : "user", | 2705 cbpt->IsInternal() ? "internal" : "user", |
2679 String::Handle(cbpt->SourceUrl()).ToCString(), | 2706 String::Handle(cbpt->SourceUrl()).ToCString(), |
2680 cbpt->LineNumber(), | 2707 cbpt->LineNumber(), |
2681 cbpt->token_pos(), | 2708 cbpt->token_pos(), |
2682 top_frame->pc()); | 2709 top_frame->pc()); |
2683 } | 2710 } |
2684 | 2711 |
2685 ASSERT(stack_trace_ == NULL); | 2712 ASSERT(stack_trace_ == NULL); |
2686 stack_trace_ = stack_trace; | 2713 stack_trace_ = stack_trace; |
2687 SignalPausedEvent(top_frame, bpt_hit); | 2714 SignalPausedEvent(top_frame, bpt_hit); |
2688 HandleSteppingRequest(stack_trace_); | 2715 HandleSteppingRequest(stack_trace_); |
2689 stack_trace_ = NULL; | 2716 stack_trace_ = NULL; |
2690 if (cbpt->IsInternal()) { | 2717 if (cbpt->IsInternal()) { |
2691 RemoveInternalBreakpoints(); | 2718 RemoveInternalBreakpoints(); |
2692 } | 2719 } |
2720 | |
2721 // If any error occurred while in the debug message loop, return it here. | |
2722 const Error& error = | |
2723 Error::Handle(isolate_, isolate_->object_store()->sticky_error()); | |
2724 isolate_->object_store()->clear_sticky_error(); | |
2725 return error.raw(); | |
2693 } | 2726 } |
2694 | 2727 |
2695 | 2728 |
2696 void Debugger::BreakHere(const String& msg) { | 2729 void Debugger::BreakHere(const String& msg) { |
2697 // We ignore this breakpoint when the VM is executing code invoked | 2730 // We ignore this breakpoint when the VM is executing code invoked |
2698 // by the debugger to evaluate variables values, or when we see a nested | 2731 // by the debugger to evaluate variables values, or when we see a nested |
2699 // breakpoint or exception event. | 2732 // breakpoint or exception event. |
2700 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { | 2733 if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) { |
2701 return; | 2734 return; |
2702 } | 2735 } |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3172 } | 3205 } |
3173 | 3206 |
3174 | 3207 |
3175 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3208 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
3176 ASSERT(bpt->next() == NULL); | 3209 ASSERT(bpt->next() == NULL); |
3177 bpt->set_next(code_breakpoints_); | 3210 bpt->set_next(code_breakpoints_); |
3178 code_breakpoints_ = bpt; | 3211 code_breakpoints_ = bpt; |
3179 } | 3212 } |
3180 | 3213 |
3181 } // namespace dart | 3214 } // namespace dart |
OLD | NEW |