| 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 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 ASSERT(!code.IsNull()); // Function must be compiled. | 596 ASSERT(!code.IsNull()); // Function must be compiled. |
| 597 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 597 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 598 ASSERT(pc_desc_index < desc.Length()); | 598 ASSERT(pc_desc_index < desc.Length()); |
| 599 token_pos_ = desc.TokenPos(pc_desc_index); | 599 token_pos_ = desc.TokenPos(pc_desc_index); |
| 600 ASSERT(token_pos_ >= 0); | 600 ASSERT(token_pos_ >= 0); |
| 601 pc_ = desc.PC(pc_desc_index); | 601 pc_ = desc.PC(pc_desc_index); |
| 602 ASSERT(pc_ != 0); | 602 ASSERT(pc_ != 0); |
| 603 breakpoint_kind_ = desc.DescriptorKind(pc_desc_index); | 603 breakpoint_kind_ = desc.DescriptorKind(pc_desc_index); |
| 604 ASSERT((breakpoint_kind_ == PcDescriptors::kIcCall) || | 604 ASSERT((breakpoint_kind_ == PcDescriptors::kIcCall) || |
| 605 (breakpoint_kind_ == PcDescriptors::kFuncCall) || | 605 (breakpoint_kind_ == PcDescriptors::kFuncCall) || |
| 606 (breakpoint_kind_ == PcDescriptors::kClosureCall) || |
| 606 (breakpoint_kind_ == PcDescriptors::kReturn)); | 607 (breakpoint_kind_ == PcDescriptors::kReturn)); |
| 607 } | 608 } |
| 608 | 609 |
| 609 | 610 |
| 610 CodeBreakpoint::~CodeBreakpoint() { | 611 CodeBreakpoint::~CodeBreakpoint() { |
| 611 // Make sure we don't leave patched code behind. | 612 // Make sure we don't leave patched code behind. |
| 612 ASSERT(!IsEnabled()); | 613 ASSERT(!IsEnabled()); |
| 613 // Poison the data so we catch use after free errors. | 614 // Poison the data so we catch use after free errors. |
| 614 #ifdef DEBUG | 615 #ifdef DEBUG |
| 615 function_ = Function::null(); | 616 function_ = Function::null(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 658 } | 659 } |
| 659 case PcDescriptors::kFuncCall: { | 660 case PcDescriptors::kFuncCall: { |
| 660 const Code& code = | 661 const Code& code = |
| 661 Code::Handle(Function::Handle(function_).unoptimized_code()); | 662 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 662 saved_bytes_.target_address_ = | 663 saved_bytes_.target_address_ = |
| 663 CodePatcher::GetStaticCallTargetAt(pc_, code); | 664 CodePatcher::GetStaticCallTargetAt(pc_, code); |
| 664 CodePatcher::PatchStaticCallAt(pc_, code, | 665 CodePatcher::PatchStaticCallAt(pc_, code, |
| 665 StubCode::BreakpointStaticEntryPoint()); | 666 StubCode::BreakpointStaticEntryPoint()); |
| 666 break; | 667 break; |
| 667 } | 668 } |
| 669 case PcDescriptors::kClosureCall: { |
| 670 const Code& code = |
| 671 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 672 saved_bytes_.target_address_ = |
| 673 CodePatcher::GetStaticCallTargetAt(pc_, code); |
| 674 CodePatcher::PatchStaticCallAt(pc_, code, |
| 675 StubCode::BreakpointClosureEntryPoint()); |
| 676 break; |
| 677 } |
| 668 case PcDescriptors::kReturn: | 678 case PcDescriptors::kReturn: |
| 669 PatchFunctionReturn(); | 679 PatchFunctionReturn(); |
| 670 break; | 680 break; |
| 671 default: | 681 default: |
| 672 UNREACHABLE(); | 682 UNREACHABLE(); |
| 673 } | 683 } |
| 674 is_enabled_ = true; | 684 is_enabled_ = true; |
| 675 } | 685 } |
| 676 | 686 |
| 677 | 687 |
| 678 void CodeBreakpoint::RestoreCode() { | 688 void CodeBreakpoint::RestoreCode() { |
| 679 ASSERT(is_enabled_); | 689 ASSERT(is_enabled_); |
| 680 switch (breakpoint_kind_) { | 690 switch (breakpoint_kind_) { |
| 681 case PcDescriptors::kIcCall: { | 691 case PcDescriptors::kIcCall: { |
| 682 const Code& code = | 692 const Code& code = |
| 683 Code::Handle(Function::Handle(function_).unoptimized_code()); | 693 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 684 CodePatcher::PatchInstanceCallAt(pc_, code, | 694 CodePatcher::PatchInstanceCallAt(pc_, code, |
| 685 saved_bytes_.target_address_); | 695 saved_bytes_.target_address_); |
| 686 break; | 696 break; |
| 687 } | 697 } |
| 688 case PcDescriptors::kFuncCall: { | 698 case PcDescriptors::kFuncCall: |
| 699 case PcDescriptors::kClosureCall: { |
| 689 const Code& code = | 700 const Code& code = |
| 690 Code::Handle(Function::Handle(function_).unoptimized_code()); | 701 Code::Handle(Function::Handle(function_).unoptimized_code()); |
| 691 CodePatcher::PatchStaticCallAt(pc_, code, | 702 CodePatcher::PatchStaticCallAt(pc_, code, |
| 692 saved_bytes_.target_address_); | 703 saved_bytes_.target_address_); |
| 693 break; | 704 break; |
| 694 } | 705 } |
| 695 case PcDescriptors::kReturn: | 706 case PcDescriptors::kReturn: |
| 696 RestoreFunctionReturn(); | 707 RestoreFunctionReturn(); |
| 697 break; | 708 break; |
| 698 default: | 709 default: |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 867 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i)); | 878 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(i)); |
| 868 if (bpt != NULL) { | 879 if (bpt != NULL) { |
| 869 // There is already a breakpoint for this address. Make sure | 880 // There is already a breakpoint for this address. Make sure |
| 870 // it is enabled. | 881 // it is enabled. |
| 871 bpt->Enable(); | 882 bpt->Enable(); |
| 872 continue; | 883 continue; |
| 873 } | 884 } |
| 874 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 885 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 875 if ((kind == PcDescriptors::kIcCall) || | 886 if ((kind == PcDescriptors::kIcCall) || |
| 876 (kind == PcDescriptors::kFuncCall) || | 887 (kind == PcDescriptors::kFuncCall) || |
| 888 (kind == PcDescriptors::kClosureCall) || |
| 877 (kind == PcDescriptors::kReturn)) { | 889 (kind == PcDescriptors::kReturn)) { |
| 878 bpt = new CodeBreakpoint(target_function, i); | 890 bpt = new CodeBreakpoint(target_function, i); |
| 879 RegisterCodeBreakpoint(bpt); | 891 RegisterCodeBreakpoint(bpt); |
| 880 bpt->Enable(); | 892 bpt->Enable(); |
| 881 } | 893 } |
| 882 } | 894 } |
| 883 } | 895 } |
| 884 | 896 |
| 885 | 897 |
| 886 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { | 898 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1034 intptr_t lowest_pc_index = -1; | 1046 intptr_t lowest_pc_index = -1; |
| 1035 for (int i = 0; i < desc.Length(); i++) { | 1047 for (int i = 0; i < desc.Length(); i++) { |
| 1036 intptr_t desc_token_pos = desc.TokenPos(i); | 1048 intptr_t desc_token_pos = desc.TokenPos(i); |
| 1037 ASSERT(desc_token_pos >= 0); | 1049 ASSERT(desc_token_pos >= 0); |
| 1038 if (desc_token_pos < first_token_pos) { | 1050 if (desc_token_pos < first_token_pos) { |
| 1039 continue; | 1051 continue; |
| 1040 } | 1052 } |
| 1041 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 1053 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 1042 if ((kind == PcDescriptors::kIcCall) || | 1054 if ((kind == PcDescriptors::kIcCall) || |
| 1043 (kind == PcDescriptors::kFuncCall) || | 1055 (kind == PcDescriptors::kFuncCall) || |
| 1056 (kind == PcDescriptors::kClosureCall) || |
| 1044 (kind == PcDescriptors::kReturn)) { | 1057 (kind == PcDescriptors::kReturn)) { |
| 1045 if ((desc_token_pos - first_token_pos) < best_fit) { | 1058 if ((desc_token_pos - first_token_pos) < best_fit) { |
| 1046 best_fit = desc_token_pos - first_token_pos; | 1059 best_fit = desc_token_pos - first_token_pos; |
| 1047 ASSERT(best_fit >= 0); | 1060 ASSERT(best_fit >= 0); |
| 1048 best_fit_index = i; | 1061 best_fit_index = i; |
| 1049 } | 1062 } |
| 1050 if ((first_token_pos <= desc_token_pos) && | 1063 if ((first_token_pos <= desc_token_pos) && |
| 1051 (desc_token_pos <= last_token_pos) && | 1064 (desc_token_pos <= last_token_pos) && |
| 1052 (desc.PC(i) < lowest_pc)) { | 1065 (desc.PC(i) < lowest_pc)) { |
| 1053 lowest_pc = desc.PC(i); | 1066 lowest_pc = desc.PC(i); |
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1566 } | 1579 } |
| 1567 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) { | 1580 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) { |
| 1568 func_to_instrument = bpt->function(); | 1581 func_to_instrument = bpt->function(); |
| 1569 const Code& code = Code::Handle(func_to_instrument.CurrentCode()); | 1582 const Code& code = Code::Handle(func_to_instrument.CurrentCode()); |
| 1570 const Function& callee = | 1583 const Function& callee = |
| 1571 Function::Handle(code.GetStaticCallTargetFunctionAt(bpt->pc_)); | 1584 Function::Handle(code.GetStaticCallTargetFunctionAt(bpt->pc_)); |
| 1572 ASSERT(!callee.IsNull()); | 1585 ASSERT(!callee.IsNull()); |
| 1573 if (IsDebuggable(callee)) { | 1586 if (IsDebuggable(callee)) { |
| 1574 func_to_instrument = callee.raw(); | 1587 func_to_instrument = callee.raw(); |
| 1575 } | 1588 } |
| 1589 } else if (bpt->breakpoint_kind_ == PcDescriptors::kClosureCall) { |
| 1590 func_to_instrument = bpt->function(); |
| 1591 const Code& code = Code::Handle(func_to_instrument.CurrentCode()); |
| 1592 ArgumentsDescriptor args_desc(Array::Handle( |
| 1593 CodePatcher::GetClosureArgDescAt(bpt->pc_, code))); |
| 1594 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); |
| 1595 const Object& receiver = |
| 1596 Object::Handle(top_frame->GetClosureObject(args_desc.Count())); |
| 1597 if (!receiver.IsNull()) { |
| 1598 // Verify that the class of receiver is a closure class |
| 1599 // by checking that signature_function() is not null. |
| 1600 const Class& receiver_class = Class::Handle(receiver.clazz()); |
| 1601 if (receiver_class.IsSignatureClass()) { |
| 1602 func_to_instrument = Closure::function(Instance::Cast(receiver)); |
| 1603 } |
| 1604 // If the receiver is not a closure, then the runtime will attempt |
| 1605 // to invoke the "call" method on the object if one exists. |
| 1606 // TODO(hausner): find call method and intrument it for stepping. |
| 1607 } |
| 1576 } else { | 1608 } else { |
| 1577 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); | 1609 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); |
| 1578 // Treat like stepping out to caller. | 1610 // Treat like stepping out to caller. |
| 1579 if (stack_trace->Length() > 1) { | 1611 if (stack_trace->Length() > 1) { |
| 1580 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1); | 1612 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1); |
| 1581 func_to_instrument = caller_frame->function().raw(); | 1613 func_to_instrument = caller_frame->function().raw(); |
| 1582 } | 1614 } |
| 1583 } | 1615 } |
| 1584 } else { | 1616 } else { |
| 1585 ASSERT(resume_action_ == kStepOut); | 1617 ASSERT(resume_action_ == kStepOut); |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1779 } | 1811 } |
| 1780 | 1812 |
| 1781 | 1813 |
| 1782 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1814 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1783 ASSERT(bpt->next() == NULL); | 1815 ASSERT(bpt->next() == NULL); |
| 1784 bpt->set_next(code_breakpoints_); | 1816 bpt->set_next(code_breakpoints_); |
| 1785 code_breakpoints_ = bpt; | 1817 code_breakpoints_ = bpt; |
| 1786 } | 1818 } |
| 1787 | 1819 |
| 1788 } // namespace dart | 1820 } // namespace dart |
| OLD | NEW |