| 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 "vm/code_generator.h" | 7 #include "vm/code_generator.h" |
| 8 #include "vm/code_patcher.h" | 8 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 11 #include "vm/flags.h" | 11 #include "vm/flags.h" |
| 12 #include "vm/globals.h" | 12 #include "vm/globals.h" |
| 13 #include "vm/longjump.h" | 13 #include "vm/longjump.h" |
| 14 #include "vm/object.h" | 14 #include "vm/object.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/os.h" | 16 #include "vm/os.h" |
| 17 #include "vm/stack_frame.h" | 17 #include "vm/stack_frame.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/visitor.h" | 19 #include "vm/visitor.h" |
| 20 | 20 |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 static const bool verbose = false; | 24 static const bool verbose = false; |
| 25 | 25 |
| 26 | 26 |
| 27 SourceBreakpoint::SourceBreakpoint(const Function& func, intptr_t token_index) | 27 SourceBreakpoint::SourceBreakpoint(intptr_t id, |
| 28 : function_(func.raw()), | 28 const Function& func, |
| 29 intptr_t token_index) |
| 30 : id_(id), |
| 31 function_(func.raw()), |
| 29 token_index_(token_index), | 32 token_index_(token_index), |
| 30 line_number_(-1), | 33 line_number_(-1), |
| 31 is_enabled_(false), | 34 is_enabled_(false), |
| 32 next_(NULL) { | 35 next_(NULL) { |
| 33 ASSERT(!func.IsNull()); | 36 ASSERT(!func.IsNull()); |
| 34 ASSERT((func.token_index() <= token_index_) && | 37 ASSERT((func.token_index() <= token_index_) && |
| 35 (token_index_ < func.end_token_index())); | 38 (token_index_ < func.end_token_index())); |
| 36 } | 39 } |
| 37 | 40 |
| 38 | 41 |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 RestoreCode(); | 423 RestoreCode(); |
| 421 } | 424 } |
| 422 ASSERT(!is_enabled_); | 425 ASSERT(!is_enabled_); |
| 423 } | 426 } |
| 424 | 427 |
| 425 | 428 |
| 426 Debugger::Debugger() | 429 Debugger::Debugger() |
| 427 : isolate_(NULL), | 430 : isolate_(NULL), |
| 428 initialized_(false), | 431 initialized_(false), |
| 429 bp_handler_(NULL), | 432 bp_handler_(NULL), |
| 433 event_handler_(NULL), |
| 434 next_id_(1), |
| 435 stack_trace_(NULL), |
| 430 src_breakpoints_(NULL), | 436 src_breakpoints_(NULL), |
| 431 code_breakpoints_(NULL), | 437 code_breakpoints_(NULL), |
| 432 resume_action_(kContinue), | 438 resume_action_(kContinue), |
| 433 ignore_breakpoints_(false) { | 439 ignore_breakpoints_(false) { |
| 434 } | 440 } |
| 435 | 441 |
| 436 | 442 |
| 437 Debugger::~Debugger() { | 443 Debugger::~Debugger() { |
| 438 ASSERT(src_breakpoints_ == NULL); | 444 ASSERT(src_breakpoints_ == NULL); |
| 439 ASSERT(code_breakpoints_ == NULL); | 445 ASSERT(code_breakpoints_ == NULL); |
| 446 ASSERT(stack_trace_ == NULL); |
| 440 } | 447 } |
| 441 | 448 |
| 442 | 449 |
| 443 void Debugger::Shutdown() { | 450 void Debugger::Shutdown() { |
| 444 while (src_breakpoints_ != NULL) { | 451 while (src_breakpoints_ != NULL) { |
| 445 SourceBreakpoint* bpt = src_breakpoints_; | 452 SourceBreakpoint* bpt = src_breakpoints_; |
| 446 src_breakpoints_ = src_breakpoints_->next(); | 453 src_breakpoints_ = src_breakpoints_->next(); |
| 447 delete bpt; | 454 delete bpt; |
| 448 } | 455 } |
| 449 while (code_breakpoints_ != NULL) { | 456 while (code_breakpoints_ != NULL) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 541 (kind == PcDescriptors::kFuncCall) || | 548 (kind == PcDescriptors::kFuncCall) || |
| 542 (kind == PcDescriptors::kReturn)) { | 549 (kind == PcDescriptors::kReturn)) { |
| 543 bpt = new CodeBreakpoint(target_function, i); | 550 bpt = new CodeBreakpoint(target_function, i); |
| 544 RegisterCodeBreakpoint(bpt); | 551 RegisterCodeBreakpoint(bpt); |
| 545 bpt->Enable(); | 552 bpt->Enable(); |
| 546 } | 553 } |
| 547 } | 554 } |
| 548 } | 555 } |
| 549 | 556 |
| 550 | 557 |
| 558 void Debugger::SignalBpResolved(SourceBreakpoint* bpt) { |
| 559 if (event_handler_ != NULL) { |
| 560 DebuggerEvent event; |
| 561 event.type = kBreakpointResolved; |
| 562 event.breakpoint = bpt; |
| 563 (*event_handler_)(&event); |
| 564 } |
| 565 } |
| 566 |
| 567 |
| 551 CodeBreakpoint* Debugger::MakeCodeBreakpoint(const Function& func, | 568 CodeBreakpoint* Debugger::MakeCodeBreakpoint(const Function& func, |
| 552 intptr_t token_index) { | 569 intptr_t token_index) { |
| 553 ASSERT(func.HasCode()); | 570 ASSERT(func.HasCode()); |
| 554 ASSERT(!func.HasOptimizedCode()); | 571 ASSERT(!func.HasOptimizedCode()); |
| 555 Code& code = Code::Handle(func.unoptimized_code()); | 572 Code& code = Code::Handle(func.unoptimized_code()); |
| 556 ASSERT(!code.IsNull()); | 573 ASSERT(!code.IsNull()); |
| 557 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 574 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 558 intptr_t best_fit_index = -1; | 575 intptr_t best_fit_index = -1; |
| 559 intptr_t best_fit = INT_MAX; | 576 intptr_t best_fit = INT_MAX; |
| 560 for (int i = 0; i < desc.Length(); i++) { | 577 for (int i = 0; i < desc.Length(); i++) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 604 (target_function.end_token_index() <= token_index)) { | 621 (target_function.end_token_index() <= token_index)) { |
| 605 // The given token position is not within the target function. | 622 // The given token position is not within the target function. |
| 606 return NULL; | 623 return NULL; |
| 607 } | 624 } |
| 608 EnsureFunctionIsDeoptimized(target_function); | 625 EnsureFunctionIsDeoptimized(target_function); |
| 609 SourceBreakpoint* bpt = GetSourceBreakpoint(target_function, token_index); | 626 SourceBreakpoint* bpt = GetSourceBreakpoint(target_function, token_index); |
| 610 if (bpt != NULL) { | 627 if (bpt != NULL) { |
| 611 // A breakpoint for this location already exists, return it. | 628 // A breakpoint for this location already exists, return it. |
| 612 return bpt; | 629 return bpt; |
| 613 } | 630 } |
| 614 bpt = new SourceBreakpoint(target_function, token_index); | 631 bpt = new SourceBreakpoint(nextId(), target_function, token_index); |
| 615 RegisterSourceBreakpoint(bpt); | 632 RegisterSourceBreakpoint(bpt); |
| 616 if (verbose && !target_function.HasCode()) { | 633 if (verbose && !target_function.HasCode()) { |
| 617 OS::Print("Registering breakpoint for uncompiled function '%s'" | 634 OS::Print("Registering breakpoint for uncompiled function '%s'" |
| 618 " (%s:%d)\n", | 635 " (%s:%d)\n", |
| 619 String::Handle(target_function.name()).ToCString(), | 636 String::Handle(target_function.name()).ToCString(), |
| 620 String::Handle(bpt->SourceUrl()).ToCString(), | 637 String::Handle(bpt->SourceUrl()).ToCString(), |
| 621 bpt->LineNumber()); | 638 bpt->LineNumber()); |
| 622 } | 639 } |
| 623 | 640 |
| 624 if (target_function.HasCode()) { | 641 if (target_function.HasCode()) { |
| 625 CodeBreakpoint* cbpt = MakeCodeBreakpoint(target_function, token_index); | 642 CodeBreakpoint* cbpt = MakeCodeBreakpoint(target_function, token_index); |
| 626 if (cbpt != NULL) { | 643 if (cbpt != NULL) { |
| 627 ASSERT(cbpt->src_bpt() == NULL); | 644 ASSERT(cbpt->src_bpt() == NULL); |
| 628 cbpt->set_src_bpt(bpt); | 645 cbpt->set_src_bpt(bpt); |
| 646 SignalBpResolved(bpt); |
| 629 } else { | 647 } else { |
| 630 if (verbose) { | 648 if (verbose) { |
| 631 OS::Print("Failed to set breakpoint at '%s' line %d\n", | 649 OS::Print("Failed to set breakpoint at '%s' line %d\n", |
| 632 String::Handle(bpt->SourceUrl()).ToCString(), | 650 String::Handle(bpt->SourceUrl()).ToCString(), |
| 633 bpt->LineNumber()); | 651 bpt->LineNumber()); |
| 634 } | 652 } |
| 635 } | 653 } |
| 636 } | 654 } |
| 637 bpt->Enable(); | 655 bpt->Enable(); |
| 638 return bpt; | 656 return bpt; |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 853 | 871 |
| 854 | 872 |
| 855 void Debugger::SetBreakpointHandler(BreakpointHandler* handler) { | 873 void Debugger::SetBreakpointHandler(BreakpointHandler* handler) { |
| 856 bp_handler_ = handler; | 874 bp_handler_ = handler; |
| 857 if (bp_handler_ == NULL) { | 875 if (bp_handler_ == NULL) { |
| 858 bp_handler_ = &DefaultBreakpointHandler; | 876 bp_handler_ = &DefaultBreakpointHandler; |
| 859 } | 877 } |
| 860 } | 878 } |
| 861 | 879 |
| 862 | 880 |
| 881 void Debugger::SetEventHandler(EventHandler* handler) { |
| 882 event_handler_ = handler; |
| 883 } |
| 884 |
| 885 |
| 863 void Debugger::BreakpointCallback() { | 886 void Debugger::BreakpointCallback() { |
| 864 ASSERT(initialized_); | 887 ASSERT(initialized_); |
| 865 | 888 |
| 866 if (ignore_breakpoints_) { | 889 if (ignore_breakpoints_) { |
| 867 return; | 890 return; |
| 868 } | 891 } |
| 869 DartFrameIterator iterator; | 892 DartFrameIterator iterator; |
| 870 StackFrame* frame = iterator.NextFrame(); | 893 StackFrame* frame = iterator.NextFrame(); |
| 871 ASSERT(frame != NULL && frame->IsDartFrame()); | 894 ASSERT(frame != NULL && frame->IsDartFrame()); |
| 872 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc()); | 895 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc()); |
| 873 ASSERT(bpt != NULL); | 896 ASSERT(bpt != NULL); |
| 874 if (verbose) { | 897 if (verbose) { |
| 875 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", | 898 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", |
| 876 bpt->IsInternal() ? "hit internal" : "hit user", | 899 bpt->IsInternal() ? "hit internal" : "hit user", |
| 877 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", | 900 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", |
| 878 bpt ? bpt->LineNumber() : 0, | 901 bpt ? bpt->LineNumber() : 0, |
| 879 frame->pc()); | 902 frame->pc()); |
| 880 } | 903 } |
| 904 |
| 881 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 905 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 882 while (frame != NULL) { | 906 while (frame != NULL) { |
| 883 ASSERT(frame->IsValid()); | 907 ASSERT(frame->IsValid()); |
| 884 ASSERT(frame->IsDartFrame()); | 908 ASSERT(frame->IsDartFrame()); |
| 885 ActivationFrame* activation = | 909 ActivationFrame* activation = |
| 886 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); | 910 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); |
| 887 stack_trace->AddActivation(activation); | 911 stack_trace->AddActivation(activation); |
| 888 frame = iterator.NextFrame(); | 912 frame = iterator.NextFrame(); |
| 889 } | 913 } |
| 890 | 914 |
| 891 resume_action_ = kContinue; | 915 resume_action_ = kContinue; |
| 892 if (bp_handler_ != NULL) { | 916 if (bp_handler_ != NULL) { |
| 893 SourceBreakpoint* src_bpt = bpt->src_bpt(); | 917 SourceBreakpoint* src_bpt = bpt->src_bpt(); |
| 918 ASSERT(stack_trace_ == NULL); |
| 919 stack_trace_ = stack_trace; |
| 894 (*bp_handler_)(src_bpt, stack_trace); | 920 (*bp_handler_)(src_bpt, stack_trace); |
| 921 stack_trace_ = NULL; |
| 895 } | 922 } |
| 896 | 923 |
| 897 if (resume_action_ == kContinue) { | 924 if (resume_action_ == kContinue) { |
| 898 RemoveInternalBreakpoints(); | 925 RemoveInternalBreakpoints(); |
| 899 } else if (resume_action_ == kStepOver) { | 926 } else if (resume_action_ == kStepOver) { |
| 900 Function& func = Function::Handle(bpt->function()); | 927 Function& func = Function::Handle(bpt->function()); |
| 901 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { | 928 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { |
| 902 // If we are at the function return, do a StepOut action. | 929 // If we are at the function return, do a StepOut action. |
| 903 if (stack_trace->Length() > 1) { | 930 if (stack_trace->Length() > 1) { |
| 904 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); | 931 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 991 bpt->set_function(closure); | 1018 bpt->set_function(closure); |
| 992 } else { | 1019 } else { |
| 993 if (verbose) { | 1020 if (verbose) { |
| 994 OS::Print("Enable pending breakpoint for function '%s'\n", | 1021 OS::Print("Enable pending breakpoint for function '%s'\n", |
| 995 String::Handle(lookup_function.name()).ToCString()); | 1022 String::Handle(lookup_function.name()).ToCString()); |
| 996 } | 1023 } |
| 997 // Set breakpoint in newly compiled code of function func. | 1024 // Set breakpoint in newly compiled code of function func. |
| 998 CodeBreakpoint* cbpt = MakeCodeBreakpoint(func, bpt->token_index()); | 1025 CodeBreakpoint* cbpt = MakeCodeBreakpoint(func, bpt->token_index()); |
| 999 if (cbpt != NULL) { | 1026 if (cbpt != NULL) { |
| 1000 cbpt->set_src_bpt(bpt); | 1027 cbpt->set_src_bpt(bpt); |
| 1028 SignalBpResolved(bpt); |
| 1001 } | 1029 } |
| 1002 } | 1030 } |
| 1003 bpt->Enable(); // Enables the code breakpoint as well. | 1031 bpt->Enable(); // Enables the code breakpoint as well. |
| 1004 } | 1032 } |
| 1005 bpt = bpt->next(); | 1033 bpt = bpt->next(); |
| 1006 } | 1034 } |
| 1007 } | 1035 } |
| 1008 | 1036 |
| 1009 | 1037 |
| 1010 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { | 1038 CodeBreakpoint* Debugger::GetCodeBreakpoint(uword breakpoint_address) { |
| 1011 CodeBreakpoint* bpt = code_breakpoints_; | 1039 CodeBreakpoint* bpt = code_breakpoints_; |
| 1012 while (bpt != NULL) { | 1040 while (bpt != NULL) { |
| 1013 if (bpt->pc() == breakpoint_address) { | 1041 if (bpt->pc() == breakpoint_address) { |
| 1014 return bpt; | 1042 return bpt; |
| 1015 } | 1043 } |
| 1016 bpt = bpt->next(); | 1044 bpt = bpt->next(); |
| 1017 } | 1045 } |
| 1018 return NULL; | 1046 return NULL; |
| 1019 } | 1047 } |
| 1020 | 1048 |
| 1021 | 1049 |
| 1022 // Remove and delete the source breakpoint bpt and its associated | 1050 // Remove and delete the source breakpoint bpt and its associated |
| 1023 // code breakpoints. | 1051 // code breakpoints. |
| 1024 void Debugger::RemoveBreakpoint(SourceBreakpoint* bpt) { | 1052 void Debugger::RemoveBreakpoint(intptr_t bp_id) { |
| 1025 ASSERT(src_breakpoints_ != NULL); | 1053 ASSERT(src_breakpoints_ != NULL); |
| 1026 SourceBreakpoint* prev_bpt = NULL; | 1054 SourceBreakpoint* prev_bpt = NULL; |
| 1027 SourceBreakpoint* curr_bpt = src_breakpoints_; | 1055 SourceBreakpoint* curr_bpt = src_breakpoints_; |
| 1028 while (curr_bpt != NULL) { | 1056 while (curr_bpt != NULL) { |
| 1029 if (bpt == curr_bpt) { | 1057 if (curr_bpt->id() == bp_id) { |
| 1030 if (prev_bpt == NULL) { | 1058 if (prev_bpt == NULL) { |
| 1031 src_breakpoints_ = src_breakpoints_->next(); | 1059 src_breakpoints_ = src_breakpoints_->next(); |
| 1032 } else { | 1060 } else { |
| 1033 prev_bpt->set_next(curr_bpt->next()); | 1061 prev_bpt->set_next(curr_bpt->next()); |
| 1034 } | 1062 } |
| 1035 // Remove the code breakpoints associated with the source breakpoint. | 1063 // Remove the code breakpoints associated with the source breakpoint. |
| 1036 RemoveCodeBreakpoints(bpt); | 1064 RemoveCodeBreakpoints(curr_bpt); |
| 1037 delete bpt; | 1065 delete curr_bpt; |
| 1038 return; | 1066 return; |
| 1039 } | 1067 } |
| 1040 prev_bpt = curr_bpt; | 1068 prev_bpt = curr_bpt; |
| 1041 curr_bpt = curr_bpt->next(); | 1069 curr_bpt = curr_bpt->next(); |
| 1042 } | 1070 } |
| 1043 // bpt is not a registered breakpoint, nothing to do. | 1071 // bpt is not a registered breakpoint, nothing to do. |
| 1044 } | 1072 } |
| 1045 | 1073 |
| 1046 | 1074 |
| 1047 // Remove and delete the code breakpoints that are associated with given | 1075 // Remove and delete the code breakpoints that are associated with given |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1082 if ((bpt->function() == func.raw()) && | 1110 if ((bpt->function() == func.raw()) && |
| 1083 (bpt->token_index() == token_index)) { | 1111 (bpt->token_index() == token_index)) { |
| 1084 return bpt; | 1112 return bpt; |
| 1085 } | 1113 } |
| 1086 bpt = bpt->next(); | 1114 bpt = bpt->next(); |
| 1087 } | 1115 } |
| 1088 return NULL; | 1116 return NULL; |
| 1089 } | 1117 } |
| 1090 | 1118 |
| 1091 | 1119 |
| 1120 SourceBreakpoint* Debugger::GetBreakpointById(intptr_t id) { |
| 1121 SourceBreakpoint* bpt = src_breakpoints_; |
| 1122 while (bpt != NULL) { |
| 1123 if (bpt->id() == id) { |
| 1124 return bpt; |
| 1125 } |
| 1126 bpt = bpt->next(); |
| 1127 } |
| 1128 return NULL; |
| 1129 } |
| 1130 |
| 1131 |
| 1092 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { | 1132 void Debugger::RegisterSourceBreakpoint(SourceBreakpoint* bpt) { |
| 1093 ASSERT(bpt->next() == NULL); | 1133 ASSERT(bpt->next() == NULL); |
| 1094 bpt->set_next(src_breakpoints_); | 1134 bpt->set_next(src_breakpoints_); |
| 1095 src_breakpoints_ = bpt; | 1135 src_breakpoints_ = bpt; |
| 1096 } | 1136 } |
| 1097 | 1137 |
| 1098 | 1138 |
| 1099 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1139 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1100 ASSERT(bpt->next() == NULL); | 1140 ASSERT(bpt->next() == NULL); |
| 1101 bpt->set_next(code_breakpoints_); | 1141 bpt->set_next(code_breakpoints_); |
| 1102 code_breakpoints_ = bpt; | 1142 code_breakpoints_ = bpt; |
| 1103 } | 1143 } |
| 1104 | 1144 |
| 1105 } // namespace dart | 1145 } // namespace dart |
| OLD | NEW |