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 |