| 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 565 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); | 576 OS::SNPrint(chars, len, kFormat, func_name, url.ToCString(), line); |
| 577 return chars; | 577 return chars; |
| 578 } | 578 } |
| 579 | 579 |
| 580 | 580 |
| 581 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { | 581 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
| 582 trace_.Add(frame); | 582 trace_.Add(frame); |
| 583 } | 583 } |
| 584 | 584 |
| 585 | 585 |
| 586 static bool IsSafePoint(PcDescriptors::Kind kind) { |
| 587 return ((kind == PcDescriptors::kIcCall) || |
| 588 (kind == PcDescriptors::kFuncCall) || |
| 589 (kind == PcDescriptors::kClosureCall) || |
| 590 (kind == PcDescriptors::kReturn) || |
| 591 (kind == PcDescriptors::kEqualNull)); |
| 592 } |
| 593 |
| 594 |
| 586 CodeBreakpoint::CodeBreakpoint(const Function& func, intptr_t pc_desc_index) | 595 CodeBreakpoint::CodeBreakpoint(const Function& func, intptr_t pc_desc_index) |
| 587 : function_(func.raw()), | 596 : function_(func.raw()), |
| 588 pc_desc_index_(pc_desc_index), | 597 pc_desc_index_(pc_desc_index), |
| 589 pc_(0), | 598 pc_(0), |
| 590 line_number_(-1), | 599 line_number_(-1), |
| 591 is_enabled_(false), | 600 is_enabled_(false), |
| 592 src_bpt_(NULL), | 601 src_bpt_(NULL), |
| 593 next_(NULL) { | 602 next_(NULL) { |
| 594 ASSERT(!func.HasOptimizedCode()); | 603 ASSERT(!func.HasOptimizedCode()); |
| 595 Code& code = Code::Handle(func.unoptimized_code()); | 604 Code& code = Code::Handle(func.unoptimized_code()); |
| 596 ASSERT(!code.IsNull()); // Function must be compiled. | 605 ASSERT(!code.IsNull()); // Function must be compiled. |
| 597 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 606 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 598 ASSERT(pc_desc_index < desc.Length()); | 607 ASSERT(pc_desc_index < desc.Length()); |
| 599 token_pos_ = desc.TokenPos(pc_desc_index); | 608 token_pos_ = desc.TokenPos(pc_desc_index); |
| 600 ASSERT(token_pos_ >= 0); | 609 ASSERT(token_pos_ >= 0); |
| 601 pc_ = desc.PC(pc_desc_index); | 610 pc_ = desc.PC(pc_desc_index); |
| 602 ASSERT(pc_ != 0); | 611 ASSERT(pc_ != 0); |
| 603 breakpoint_kind_ = desc.DescriptorKind(pc_desc_index); | 612 breakpoint_kind_ = desc.DescriptorKind(pc_desc_index); |
| 604 ASSERT((breakpoint_kind_ == PcDescriptors::kIcCall) || | 613 ASSERT(IsSafePoint(breakpoint_kind_)); |
| 605 (breakpoint_kind_ == PcDescriptors::kFuncCall) || | |
| 606 (breakpoint_kind_ == PcDescriptors::kClosureCall) || | |
| 607 (breakpoint_kind_ == PcDescriptors::kReturn)); | |
| 608 } | 614 } |
| 609 | 615 |
| 610 | 616 |
| 611 CodeBreakpoint::~CodeBreakpoint() { | 617 CodeBreakpoint::~CodeBreakpoint() { |
| 612 // Make sure we don't leave patched code behind. | 618 // Make sure we don't leave patched code behind. |
| 613 ASSERT(!IsEnabled()); | 619 ASSERT(!IsEnabled()); |
| 614 // Poison the data so we catch use after free errors. | 620 // Poison the data so we catch use after free errors. |
| 615 #ifdef DEBUG | 621 #ifdef DEBUG |
| 616 function_ = Function::null(); | 622 function_ = Function::null(); |
| 617 pc_ = 0ul; | 623 pc_ = 0ul; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 } | 674 } |
| 669 case PcDescriptors::kClosureCall: { | 675 case PcDescriptors::kClosureCall: { |
| 670 const Code& code = | 676 const Code& code = |
| 671 Code::Handle(Function::Handle(function_).unoptimized_code()); | 677 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 672 saved_bytes_.target_address_ = | 678 saved_bytes_.target_address_ = |
| 673 CodePatcher::GetStaticCallTargetAt(pc_, code); | 679 CodePatcher::GetStaticCallTargetAt(pc_, code); |
| 674 CodePatcher::PatchStaticCallAt(pc_, code, | 680 CodePatcher::PatchStaticCallAt(pc_, code, |
| 675 StubCode::BreakpointClosureEntryPoint()); | 681 StubCode::BreakpointClosureEntryPoint()); |
| 676 break; | 682 break; |
| 677 } | 683 } |
| 684 case PcDescriptors::kEqualNull: { |
| 685 const Code& code = |
| 686 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 687 saved_bytes_.target_address_ = |
| 688 CodePatcher::GetStaticCallTargetAt(pc_, code); |
| 689 CodePatcher::PatchStaticCallAt(pc_, code, |
| 690 StubCode::BreakpointEqNullEntryPoint()); |
| 691 break; |
| 692 } |
| 678 case PcDescriptors::kReturn: | 693 case PcDescriptors::kReturn: |
| 679 PatchFunctionReturn(); | 694 PatchFunctionReturn(); |
| 680 break; | 695 break; |
| 681 default: | 696 default: |
| 682 UNREACHABLE(); | 697 UNREACHABLE(); |
| 683 } | 698 } |
| 684 is_enabled_ = true; | 699 is_enabled_ = true; |
| 685 } | 700 } |
| 686 | 701 |
| 687 | 702 |
| 688 void CodeBreakpoint::RestoreCode() { | 703 void CodeBreakpoint::RestoreCode() { |
| 689 ASSERT(is_enabled_); | 704 ASSERT(is_enabled_); |
| 690 switch (breakpoint_kind_) { | 705 switch (breakpoint_kind_) { |
| 691 case PcDescriptors::kIcCall: { | 706 case PcDescriptors::kIcCall: { |
| 692 const Code& code = | 707 const Code& code = |
| 693 Code::Handle(Function::Handle(function_).unoptimized_code()); | 708 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 694 CodePatcher::PatchInstanceCallAt(pc_, code, | 709 CodePatcher::PatchInstanceCallAt(pc_, code, |
| 695 saved_bytes_.target_address_); | 710 saved_bytes_.target_address_); |
| 696 break; | 711 break; |
| 697 } | 712 } |
| 698 case PcDescriptors::kFuncCall: | 713 case PcDescriptors::kFuncCall: |
| 699 case PcDescriptors::kClosureCall: { | 714 case PcDescriptors::kClosureCall: |
| 715 case PcDescriptors::kEqualNull: { |
| 700 const Code& code = | 716 const Code& code = |
| 701 Code::Handle(Function::Handle(function_).unoptimized_code()); | 717 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 702 CodePatcher::PatchStaticCallAt(pc_, code, | 718 CodePatcher::PatchStaticCallAt(pc_, code, |
| 703 saved_bytes_.target_address_); | 719 saved_bytes_.target_address_); |
| 704 break; | 720 break; |
| 705 } | 721 } |
| 706 case PcDescriptors::kReturn: | 722 case PcDescriptors::kReturn: |
| 707 RestoreFunctionReturn(); | 723 RestoreFunctionReturn(); |
| 708 break; | 724 break; |
| 709 default: | 725 default: |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 ASSERT(!function.IsNull()); | 869 ASSERT(!function.IsNull()); |
| 854 if (function.HasOptimizedCode()) { | 870 if (function.HasOptimizedCode()) { |
| 855 function.SwitchToUnoptimizedCode(); | 871 function.SwitchToUnoptimizedCode(); |
| 856 } | 872 } |
| 857 } | 873 } |
| 858 } | 874 } |
| 859 } | 875 } |
| 860 } | 876 } |
| 861 | 877 |
| 862 | 878 |
| 863 static bool IsSafePoint(PcDescriptors::Kind kind) { | |
| 864 return ((kind == PcDescriptors::kIcCall) || | |
| 865 (kind == PcDescriptors::kFuncCall) || | |
| 866 (kind == PcDescriptors::kClosureCall) || | |
| 867 (kind == PcDescriptors::kReturn)); | |
| 868 } | |
| 869 | |
| 870 | |
| 871 void Debugger::InstrumentForStepping(const Function& target_function) { | 879 void Debugger::InstrumentForStepping(const Function& target_function) { |
| 872 if (!target_function.HasCode()) { | 880 if (!target_function.HasCode()) { |
| 873 Compiler::CompileFunction(target_function); | 881 Compiler::CompileFunction(target_function); |
| 874 // If there were any errors, ignore them silently and return without | 882 // If there were any errors, ignore them silently and return without |
| 875 // adding breakpoints to target. | 883 // adding breakpoints to target. |
| 876 if (!target_function.HasCode()) { | 884 if (!target_function.HasCode()) { |
| 877 return; | 885 return; |
| 878 } | 886 } |
| 879 } | 887 } |
| 880 DeoptimizeWorld(); | 888 DeoptimizeWorld(); |
| (...skipping 727 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1608 ArgumentsDescriptor args_desc(Array::Handle( | 1616 ArgumentsDescriptor args_desc(Array::Handle( |
| 1609 CodePatcher::GetClosureArgDescAt(bpt->pc_, code))); | 1617 CodePatcher::GetClosureArgDescAt(bpt->pc_, code))); |
| 1610 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); | 1618 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); |
| 1611 const Object& receiver = | 1619 const Object& receiver = |
| 1612 Object::Handle(top_frame->GetClosureObject(args_desc.Count())); | 1620 Object::Handle(top_frame->GetClosureObject(args_desc.Count())); |
| 1613 if (!receiver.IsNull()) { | 1621 if (!receiver.IsNull()) { |
| 1614 // Verify that the class of receiver is a closure class | 1622 // Verify that the class of receiver is a closure class |
| 1615 // by checking that signature_function() is not null. | 1623 // by checking that signature_function() is not null. |
| 1616 const Class& receiver_class = Class::Handle(receiver.clazz()); | 1624 const Class& receiver_class = Class::Handle(receiver.clazz()); |
| 1617 if (receiver_class.IsSignatureClass()) { | 1625 if (receiver_class.IsSignatureClass()) { |
| 1618 func_to_instrument = Closure::function(Instance::Cast(receiver)); | 1626 Function& closure_func = |
| 1627 Function::Handle(Closure::function(Instance::Cast(receiver))); |
| 1628 if (IsDebuggable(closure_func)) { |
| 1629 func_to_instrument = closure_func.raw(); |
| 1630 } |
| 1619 } | 1631 } |
| 1620 // If the receiver is not a closure, then the runtime will attempt | 1632 // If the receiver is not a closure, then the runtime will attempt |
| 1621 // to invoke the "call" method on the object if one exists. | 1633 // to invoke the "call" method on the object if one exists. |
| 1622 // TODO(hausner): find call method and intrument it for stepping. | 1634 // TODO(hausner): find call method and intrument it for stepping. |
| 1623 } | 1635 } |
| 1636 } else if (bpt->breakpoint_kind_ == PcDescriptors::kEqualNull) { |
| 1637 // This is just a call to the runtime, not Dart code. Stepping |
| 1638 // into not possible, just treat like StepOver. |
| 1639 func_to_instrument = bpt->function(); |
| 1624 } else { | 1640 } else { |
| 1625 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); | 1641 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); |
| 1626 // Treat like stepping out to caller. | 1642 // Treat like stepping out to caller. |
| 1627 if (stack_trace->Length() > 1) { | 1643 if (stack_trace->Length() > 1) { |
| 1628 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1); | 1644 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1); |
| 1629 func_to_instrument = caller_frame->function().raw(); | 1645 func_to_instrument = caller_frame->function().raw(); |
| 1630 } | 1646 } |
| 1631 } | 1647 } |
| 1632 } else { | 1648 } else { |
| 1633 ASSERT(resume_action_ == kStepOut); | 1649 ASSERT(resume_action_ == kStepOut); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1825 } | 1841 } |
| 1826 | 1842 |
| 1827 | 1843 |
| 1828 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1844 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1829 ASSERT(bpt->next() == NULL); | 1845 ASSERT(bpt->next() == NULL); |
| 1830 bpt->set_next(code_breakpoints_); | 1846 bpt->set_next(code_breakpoints_); |
| 1831 code_breakpoints_ = bpt; | 1847 code_breakpoints_ = bpt; |
| 1832 } | 1848 } |
| 1833 | 1849 |
| 1834 } // namespace dart | 1850 } // namespace dart |
| OLD | NEW |