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