Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(267)

Side by Side Diff: runtime/vm/debugger.cc

Issue 10442088: Bigger stepping granularity in debugging (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
(...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 : isolate_(NULL), 468 : isolate_(NULL),
469 initialized_(false), 469 initialized_(false),
470 bp_handler_(NULL), 470 bp_handler_(NULL),
471 event_handler_(NULL), 471 event_handler_(NULL),
472 next_id_(1), 472 next_id_(1),
473 stack_trace_(NULL), 473 stack_trace_(NULL),
474 obj_cache_(NULL), 474 obj_cache_(NULL),
475 src_breakpoints_(NULL), 475 src_breakpoints_(NULL),
476 code_breakpoints_(NULL), 476 code_breakpoints_(NULL),
477 resume_action_(kContinue), 477 resume_action_(kContinue),
478 last_bpt_line_(-1),
478 ignore_breakpoints_(false) { 479 ignore_breakpoints_(false) {
479 } 480 }
480 481
481 482
482 Debugger::~Debugger() { 483 Debugger::~Debugger() {
483 ASSERT(src_breakpoints_ == NULL); 484 ASSERT(src_breakpoints_ == NULL);
484 ASSERT(code_breakpoints_ == NULL); 485 ASSERT(code_breakpoints_ == NULL);
485 ASSERT(stack_trace_ == NULL); 486 ASSERT(stack_trace_ == NULL);
486 ASSERT(obj_cache_ == NULL); 487 ASSERT(obj_cache_ == NULL);
487 } 488 }
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 bp_handler_ = &DefaultBreakpointHandler; 960 bp_handler_ = &DefaultBreakpointHandler;
960 } 961 }
961 } 962 }
962 963
963 964
964 void Debugger::SetEventHandler(EventHandler* handler) { 965 void Debugger::SetEventHandler(EventHandler* handler) {
965 event_handler_ = handler; 966 event_handler_ = handler;
966 } 967 }
967 968
968 969
970 bool Debugger::IsDebuggable(const Function& func) {
971 RawFunction::Kind fkind = func.kind();
972 if ((fkind == RawFunction::kImplicitGetter) ||
973 (fkind == RawFunction::kImplicitSetter) ||
974 (fkind == RawFunction::kConstImplicitGetter)) {
975 return false;
976 }
977 const Class& cls = Class::Handle(func.owner());
978 const Library& lib = Library::Handle(cls.library());
979 return lib.IsDebuggable();
980 }
981
982
969 void Debugger::BreakpointCallback() { 983 void Debugger::BreakpointCallback() {
970 ASSERT(initialized_); 984 ASSERT(initialized_);
971 985
972 if (ignore_breakpoints_) { 986 if (ignore_breakpoints_) {
973 return; 987 return;
974 } 988 }
975 DartFrameIterator iterator; 989 DartFrameIterator iterator;
976 StackFrame* frame = iterator.NextFrame(); 990 StackFrame* frame = iterator.NextFrame();
977 ASSERT(frame != NULL && frame->IsDartFrame()); 991 ASSERT(frame != NULL && frame->IsDartFrame());
978 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc()); 992 CodeBreakpoint* bpt = GetCodeBreakpoint(frame->pc());
979 ASSERT(bpt != NULL); 993 ASSERT(bpt != NULL);
980 if (verbose) { 994 if (verbose) {
981 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n", 995 OS::Print(">>> %s breakpoint at %s:%d (Address %p)\n",
982 bpt->IsInternal() ? "hit internal" : "hit user", 996 bpt->IsInternal() ? "hit internal" : "hit user",
983 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?", 997 bpt ? String::Handle(bpt->SourceUrl()).ToCString() : "?",
984 bpt ? bpt->LineNumber() : 0, 998 bpt ? bpt->LineNumber() : 0,
985 frame->pc()); 999 frame->pc());
986 } 1000 }
987 1001
1002 if (!bpt->IsInternal()) {
1003 // This is a user-defined breakpoint, so we call the breakpoint callback
1004 // even if it is on the same line as the previous breakpoint.
1005 last_bpt_line_ = -1;
1006 }
1007
1008 bool notify_frontend =
1009 (last_bpt_line_ < 0) || (last_bpt_line_ != bpt->LineNumber());
1010
988 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); 1011 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
989 while (frame != NULL) { 1012 while (frame != NULL) {
990 ASSERT(frame->IsValid()); 1013 ASSERT(frame->IsValid());
991 ASSERT(frame->IsDartFrame()); 1014 ASSERT(frame->IsDartFrame());
992 ActivationFrame* activation = 1015 ActivationFrame* activation =
993 new ActivationFrame(frame->pc(), frame->fp(), frame->sp()); 1016 new ActivationFrame(frame->pc(), frame->fp(), frame->sp());
994 stack_trace->AddActivation(activation); 1017 stack_trace->AddActivation(activation);
995 frame = iterator.NextFrame(); 1018 frame = iterator.NextFrame();
996 } 1019 }
997 1020
998 resume_action_ = kContinue; 1021 if (notify_frontend) {
999 if (bp_handler_ != NULL) { 1022 resume_action_ = kContinue;
1000 SourceBreakpoint* src_bpt = bpt->src_bpt(); 1023 if (bp_handler_ != NULL) {
1001 ASSERT(stack_trace_ == NULL); 1024 SourceBreakpoint* src_bpt = bpt->src_bpt();
1002 ASSERT(obj_cache_ == NULL); 1025 ASSERT(stack_trace_ == NULL);
1003 obj_cache_ = new RemoteObjectCache(64); 1026 ASSERT(obj_cache_ == NULL);
1004 stack_trace_ = stack_trace; 1027 obj_cache_ = new RemoteObjectCache(64);
1005 (*bp_handler_)(src_bpt, stack_trace); 1028 stack_trace_ = stack_trace;
1006 stack_trace_ = NULL; 1029 (*bp_handler_)(src_bpt, stack_trace);
1007 obj_cache_ = NULL; // Remote object cache is zone allocated. 1030 stack_trace_ = NULL;
1031 obj_cache_ = NULL; // Remote object cache is zone allocated.
1032 last_bpt_line_ = bpt->LineNumber();
1033 }
1008 } 1034 }
1009 1035
1036 Function& currently_instrumented_func = Function::Handle();
1037 if (bpt->IsInternal()) {
1038 currently_instrumented_func = bpt->function();
1039 }
1040 Function& func_to_instrument = Function::Handle();
1010 if (resume_action_ == kContinue) { 1041 if (resume_action_ == kContinue) {
1011 RemoveInternalBreakpoints(); 1042 // Nothing to do here, any potential instrumentation will be removed
1043 // below.
1012 } else if (resume_action_ == kStepOver) { 1044 } else if (resume_action_ == kStepOver) {
1013 Function& func = Function::Handle(bpt->function()); 1045 func_to_instrument = bpt->function();
siva 2012/05/31 19:11:15 This will be an issue if we have resursive calls r
hausner 2012/05/31 20:04:14 We don't have recursive calls. Breakpoints are ign
siva 2012/05/31 20:26:56 I didn't mean recursive calls to the breakpoint ha
1014 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) { 1046 if (bpt->breakpoint_kind_ == PcDescriptors::kReturn) {
1015 // If we are at the function return, do a StepOut action. 1047 // If we are at the function return, do a StepOut action.
1016 if (stack_trace->Length() > 1) { 1048 if (stack_trace->Length() > 1) {
1017 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); 1049 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
1018 func = caller->DartFunction().raw(); 1050 func_to_instrument = caller_frame->DartFunction().raw();
1019 } 1051 }
1020 } 1052 }
1021 RemoveInternalBreakpoints(); // *bpt is now invalid.
1022 InstrumentForStepping(func);
1023 } else if (resume_action_ == kStepInto) { 1053 } else if (resume_action_ == kStepInto) {
1054 // If the call target is not debuggable, we treat StepInto like
1055 // a StepOver, that is we instrument the current function.
1024 if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) { 1056 if (bpt->breakpoint_kind_ == PcDescriptors::kIcCall) {
1057 func_to_instrument = bpt->function();
1025 int num_args, num_named_args; 1058 int num_args, num_named_args;
1026 uword target; 1059 uword target;
1027 CodePatcher::GetInstanceCallAt(bpt->pc_, NULL, 1060 CodePatcher::GetInstanceCallAt(bpt->pc_, NULL,
1028 &num_args, &num_named_args, &target); 1061 &num_args, &num_named_args, &target);
1029 RemoveInternalBreakpoints(); // *bpt is now invalid.
1030 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0); 1062 ActivationFrame* top_frame = stack_trace->ActivationFrameAt(0);
1031 Instance& receiver = Instance::Handle( 1063 Instance& receiver = Instance::Handle(
1032 top_frame->GetInstanceCallReceiver(num_args)); 1064 top_frame->GetInstanceCallReceiver(num_args));
1033 Code& code = Code::Handle( 1065 Code& code = Code::Handle(
1034 ResolveCompileInstanceCallTarget(isolate_, receiver)); 1066 ResolveCompileInstanceCallTarget(isolate_, receiver));
1035 if (!code.IsNull()) { 1067 if (!code.IsNull()) {
1036 Function& callee = Function::Handle(code.function()); 1068 Function& callee = Function::Handle(code.function());
1037 InstrumentForStepping(callee); 1069 if (IsDebuggable(callee)) {
1070 func_to_instrument = callee.raw();
1071 }
1038 } 1072 }
1039 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) { 1073 } else if (bpt->breakpoint_kind_ == PcDescriptors::kFuncCall) {
1074 func_to_instrument = bpt->function();
1040 Function& callee = Function::Handle(); 1075 Function& callee = Function::Handle();
1041 uword target; 1076 uword target;
1042 CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target); 1077 CodePatcher::GetStaticCallAt(bpt->pc_, &callee, &target);
1043 RemoveInternalBreakpoints(); // *bpt is now invalid. 1078 if (IsDebuggable(callee)) {
1044 InstrumentForStepping(callee); 1079 func_to_instrument = callee.raw();
1080 }
1045 } else { 1081 } else {
1046 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn); 1082 ASSERT(bpt->breakpoint_kind_ == PcDescriptors::kReturn);
1047 RemoveInternalBreakpoints(); // *bpt is now invalid.
1048 // Treat like stepping out to caller. 1083 // Treat like stepping out to caller.
1049 if (stack_trace->Length() > 1) { 1084 if (stack_trace->Length() > 1) {
1050 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); 1085 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
1051 InstrumentForStepping(caller->DartFunction()); 1086 func_to_instrument = caller_frame->DartFunction().raw();
1052 } 1087 }
1053 } 1088 }
1054 } else { 1089 } else {
1055 ASSERT(resume_action_ == kStepOut); 1090 ASSERT(resume_action_ == kStepOut);
1056 RemoveInternalBreakpoints(); // *bpt is now invalid.
1057 // Set stepping breakpoints in the caller. 1091 // Set stepping breakpoints in the caller.
1058 if (stack_trace->Length() > 1) { 1092 if (stack_trace->Length() > 1) {
1059 ActivationFrame* caller = stack_trace->ActivationFrameAt(1); 1093 ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
1060 InstrumentForStepping(caller->DartFunction()); 1094 func_to_instrument = caller_frame->DartFunction().raw();
siva 2012/05/31 19:11:15 How does this work if we have recursive calls i.e
hausner 2012/05/31 20:04:14 Recursive functions are not properly treated yet.
siva 2012/05/31 20:26:56 Actually we won't step out to the previous activat
hausner 2012/05/31 20:32:28 Ah, you are right. I will put this on my todo list
1095 }
1096 }
1097
1098 if (func_to_instrument.raw() != currently_instrumented_func.raw()) {
1099 last_bpt_line_ = -1;
1100 RemoveInternalBreakpoints(); // *bpt is now invalid.
1101 if (!func_to_instrument.IsNull()) {
1102 InstrumentForStepping(func_to_instrument);
1061 } 1103 }
1062 } 1104 }
1063 } 1105 }
1064 1106
1065 1107
1066 void Debugger::Initialize(Isolate* isolate) { 1108 void Debugger::Initialize(Isolate* isolate) {
1067 if (initialized_) { 1109 if (initialized_) {
1068 return; 1110 return;
1069 } 1111 }
1070 isolate_ = isolate; 1112 isolate_ = isolate;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1139 ASSERT(src_breakpoints_ != NULL); 1181 ASSERT(src_breakpoints_ != NULL);
1140 SourceBreakpoint* prev_bpt = NULL; 1182 SourceBreakpoint* prev_bpt = NULL;
1141 SourceBreakpoint* curr_bpt = src_breakpoints_; 1183 SourceBreakpoint* curr_bpt = src_breakpoints_;
1142 while (curr_bpt != NULL) { 1184 while (curr_bpt != NULL) {
1143 if (curr_bpt->id() == bp_id) { 1185 if (curr_bpt->id() == bp_id) {
1144 if (prev_bpt == NULL) { 1186 if (prev_bpt == NULL) {
1145 src_breakpoints_ = src_breakpoints_->next(); 1187 src_breakpoints_ = src_breakpoints_->next();
1146 } else { 1188 } else {
1147 prev_bpt->set_next(curr_bpt->next()); 1189 prev_bpt->set_next(curr_bpt->next());
1148 } 1190 }
1149 // Remove the code breakpoints associated with the source breakpoint. 1191 // Remove references from code breakpoints to this source breakpoint.
1150 RemoveCodeBreakpoints(curr_bpt); 1192 UnlinkCodeBreakpoints(curr_bpt);
1151 delete curr_bpt; 1193 delete curr_bpt;
1152 return; 1194 return;
1153 } 1195 }
1154 prev_bpt = curr_bpt; 1196 prev_bpt = curr_bpt;
1155 curr_bpt = curr_bpt->next(); 1197 curr_bpt = curr_bpt->next();
1156 } 1198 }
1157 // bpt is not a registered breakpoint, nothing to do. 1199 // bpt is not a registered breakpoint, nothing to do.
1158 } 1200 }
1159 1201
1160 1202
1161 // Remove and delete the code breakpoints that are associated with given 1203 // Turn code breakpoints associated with the given source breakpoint into
1162 // source breakpoint bpt. If bpt is null, remove the internal breakpoints. 1204 // internal breakpoints. They will later be deleted when control
1163 void Debugger::RemoveCodeBreakpoints(SourceBreakpoint* src_bpt) { 1205 // returns from the user-defined breakpoint callback.
siva 2012/05/31 19:11:15 Can you add a comment stating that breakpoints can
hausner 2012/05/31 20:04:14 Done.
1206 void Debugger::UnlinkCodeBreakpoints(SourceBreakpoint* src_bpt) {
1207 ASSERT(src_bpt != NULL);
1208 CodeBreakpoint* curr_bpt = code_breakpoints_;
1209 while (curr_bpt != NULL) {
1210 if (curr_bpt->src_bpt() == src_bpt) {
1211 curr_bpt->set_src_bpt(NULL);
siva 2012/05/31 19:11:15 can you break out from here instead of looping til
hausner 2012/05/31 20:04:14 There can be multiple code breakpoints pointing to
1212 }
1213 curr_bpt = curr_bpt->next();
1214 }
1215 }
1216
1217
1218 // Remove and delete internal breakpoints, i.e. breakpoints that
1219 // are not associated with a source breakpoint.
1220 void Debugger::RemoveInternalBreakpoints() {
1164 CodeBreakpoint* prev_bpt = NULL; 1221 CodeBreakpoint* prev_bpt = NULL;
1165 CodeBreakpoint* curr_bpt = code_breakpoints_; 1222 CodeBreakpoint* curr_bpt = code_breakpoints_;
1166 while (curr_bpt != NULL) { 1223 while (curr_bpt != NULL) {
1167 if (curr_bpt->src_bpt() == src_bpt) { 1224 if (curr_bpt->src_bpt() == NULL) {
1168 if (prev_bpt == NULL) { 1225 if (prev_bpt == NULL) {
1169 code_breakpoints_ = code_breakpoints_->next(); 1226 code_breakpoints_ = code_breakpoints_->next();
1170 } else { 1227 } else {
1171 prev_bpt->set_next(curr_bpt->next()); 1228 prev_bpt->set_next(curr_bpt->next());
1172 } 1229 }
1173 CodeBreakpoint* temp_bpt = curr_bpt; 1230 CodeBreakpoint* temp_bpt = curr_bpt;
1174 curr_bpt = curr_bpt->next(); 1231 curr_bpt = curr_bpt->next();
1175 temp_bpt->Disable(); 1232 temp_bpt->Disable();
1176 delete temp_bpt; 1233 delete temp_bpt;
1177 } else { 1234 } else {
1178 prev_bpt = curr_bpt; 1235 prev_bpt = curr_bpt;
1179 curr_bpt = curr_bpt->next(); 1236 curr_bpt = curr_bpt->next();
1180 } 1237 }
1181 } 1238 }
1182 } 1239 }
1183 1240
1184 1241
1185 // Remove and delete all breakpoints that are not associated with a
1186 // user-defined source breakpoint.
1187 void Debugger::RemoveInternalBreakpoints() {
1188 RemoveCodeBreakpoints(NULL);
1189 }
1190
1191
1192 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func, 1242 SourceBreakpoint* Debugger::GetSourceBreakpoint(const Function& func,
1193 intptr_t token_index) { 1243 intptr_t token_index) {
1194 SourceBreakpoint* bpt = src_breakpoints_; 1244 SourceBreakpoint* bpt = src_breakpoints_;
1195 while (bpt != NULL) { 1245 while (bpt != NULL) {
1196 if ((bpt->function() == func.raw()) && 1246 if ((bpt->function() == func.raw()) &&
1197 (bpt->token_index() == token_index)) { 1247 (bpt->token_index() == token_index)) {
1198 return bpt; 1248 return bpt;
1199 } 1249 }
1200 bpt = bpt->next(); 1250 bpt = bpt->next();
1201 } 1251 }
(...skipping 20 matching lines...) Expand all
1222 } 1272 }
1223 1273
1224 1274
1225 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { 1275 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) {
1226 ASSERT(bpt->next() == NULL); 1276 ASSERT(bpt->next() == NULL);
1227 bpt->set_next(code_breakpoints_); 1277 bpt->set_next(code_breakpoints_);
1228 code_breakpoints_ = bpt; 1278 code_breakpoints_ = bpt;
1229 } 1279 }
1230 1280
1231 } // namespace dart 1281 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/debugger.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698