Chromium Code Reviews| 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 "platform/address_sanitizer.h" | 9 #include "platform/address_sanitizer.h" |
| 10 | 10 |
| 11 #include "vm/code_generator.h" | 11 #include "vm/code_generator.h" |
| 12 #include "vm/code_patcher.h" | 12 #include "vm/code_patcher.h" |
| 13 #include "vm/compiler.h" | 13 #include "vm/compiler.h" |
| 14 #include "vm/dart_entry.h" | 14 #include "vm/dart_entry.h" |
| 15 #include "vm/deopt_instructions.h" | 15 #include "vm/deopt_instructions.h" |
| 16 #include "vm/flags.h" | 16 #include "vm/flags.h" |
| 17 #include "vm/globals.h" | 17 #include "vm/globals.h" |
| 18 #include "vm/longjump.h" | 18 #include "vm/longjump.h" |
| 19 #include "vm/json_stream.h" | 19 #include "vm/json_stream.h" |
| 20 #include "vm/message_handler.h" | 20 #include "vm/message_handler.h" |
| 21 #include "vm/object.h" | 21 #include "vm/object.h" |
| 22 #include "vm/object_store.h" | 22 #include "vm/object_store.h" |
| 23 #include "vm/os.h" | 23 #include "vm/os.h" |
| 24 #include "vm/port.h" | 24 #include "vm/port.h" |
| 25 #include "vm/service_event.h" | 25 #include "vm/service_event.h" |
| 26 #include "vm/service_isolate.h" | 26 #include "vm/service_isolate.h" |
| 27 #include "vm/service.h" | 27 #include "vm/service.h" |
| 28 #include "vm/stack_frame.h" | 28 #include "vm/stack_frame.h" |
| 29 #include "vm/stack_trace.h" | |
| 29 #include "vm/stub_code.h" | 30 #include "vm/stub_code.h" |
| 30 #include "vm/symbols.h" | 31 #include "vm/symbols.h" |
| 31 #include "vm/thread_interrupter.h" | 32 #include "vm/thread_interrupter.h" |
| 32 #include "vm/timeline.h" | 33 #include "vm/timeline.h" |
| 33 #include "vm/token_position.h" | 34 #include "vm/token_position.h" |
| 34 #include "vm/visitor.h" | 35 #include "vm/visitor.h" |
| 35 | 36 |
| 36 | 37 |
| 37 namespace dart { | 38 namespace dart { |
| 38 | 39 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 242 visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_)); | 243 visitor->VisitPointer(reinterpret_cast<RawObject**>(&saved_value_)); |
| 243 #endif | 244 #endif |
| 244 } | 245 } |
| 245 | 246 |
| 246 | 247 |
| 247 ActivationFrame::ActivationFrame(uword pc, | 248 ActivationFrame::ActivationFrame(uword pc, |
| 248 uword fp, | 249 uword fp, |
| 249 uword sp, | 250 uword sp, |
| 250 const Code& code, | 251 const Code& code, |
| 251 const Array& deopt_frame, | 252 const Array& deopt_frame, |
| 252 intptr_t deopt_frame_offset) | 253 intptr_t deopt_frame_offset, |
| 254 ActivationFrame::Kind kind) | |
| 253 : pc_(pc), | 255 : pc_(pc), |
| 254 fp_(fp), | 256 fp_(fp), |
| 255 sp_(sp), | 257 sp_(sp), |
| 256 ctx_(Context::ZoneHandle()), | 258 ctx_(Context::ZoneHandle()), |
| 257 code_(Code::ZoneHandle(code.raw())), | 259 code_(Code::ZoneHandle(code.raw())), |
| 258 function_(Function::ZoneHandle(code.function())), | 260 function_(Function::ZoneHandle(code.function())), |
|
rmacnak
2017/01/26 18:05:57
Doesn't mutate, replace slot with an function.
Cutch
2017/01/31 23:45:30
Not entirely sure I understand your comment here.
| |
| 261 live_frame_(kind == kRegular), | |
| 259 token_pos_initialized_(false), | 262 token_pos_initialized_(false), |
| 260 token_pos_(TokenPosition::kNoSource), | 263 token_pos_(TokenPosition::kNoSource), |
| 261 try_index_(-1), | 264 try_index_(-1), |
| 262 line_number_(-1), | 265 line_number_(-1), |
| 263 column_number_(-1), | 266 column_number_(-1), |
| 264 context_level_(-1), | 267 context_level_(-1), |
| 265 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), | 268 deopt_frame_(Array::ZoneHandle(deopt_frame.raw())), |
| 266 deopt_frame_offset_(deopt_frame_offset), | 269 deopt_frame_offset_(deopt_frame_offset), |
| 270 kind_(kind), | |
| 267 vars_initialized_(false), | 271 vars_initialized_(false), |
| 268 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | 272 var_descriptors_(LocalVarDescriptors::ZoneHandle()), |
| 269 desc_indices_(8), | 273 desc_indices_(8), |
| 270 pc_desc_(PcDescriptors::ZoneHandle()) {} | 274 pc_desc_(PcDescriptors::ZoneHandle()) {} |
| 271 | 275 |
| 272 | 276 |
| 277 ActivationFrame::ActivationFrame(Kind kind) | |
| 278 : pc_(0), | |
| 279 fp_(0), | |
| 280 sp_(0), | |
| 281 ctx_(Context::ZoneHandle()), | |
| 282 code_(Code::ZoneHandle()), | |
| 283 function_(Function::ZoneHandle()), | |
| 284 live_frame_(kind == kRegular), | |
| 285 token_pos_initialized_(false), | |
| 286 token_pos_(TokenPosition::kNoSource), | |
| 287 try_index_(-1), | |
| 288 line_number_(-1), | |
| 289 column_number_(-1), | |
| 290 context_level_(-1), | |
| 291 deopt_frame_(Array::ZoneHandle()), | |
| 292 deopt_frame_offset_(0), | |
| 293 kind_(kind), | |
| 294 vars_initialized_(false), | |
| 295 var_descriptors_(LocalVarDescriptors::ZoneHandle()), | |
| 296 desc_indices_(8), | |
| 297 pc_desc_(PcDescriptors::ZoneHandle()) {} | |
| 298 | |
| 273 bool Debugger::NeedsIsolateEvents() { | 299 bool Debugger::NeedsIsolateEvents() { |
| 274 return ((isolate_ != Dart::vm_isolate()) && | 300 return ((isolate_ != Dart::vm_isolate()) && |
| 275 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && | 301 !ServiceIsolate::IsServiceIsolateDescendant(isolate_) && |
| 276 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); | 302 ((event_handler_ != NULL) || Service::isolate_stream.enabled())); |
| 277 } | 303 } |
| 278 | 304 |
| 279 | 305 |
| 280 bool Debugger::NeedsDebugEvents() { | 306 bool Debugger::NeedsDebugEvents() { |
| 281 ASSERT(isolate_ != Dart::vm_isolate() && | 307 ASSERT(isolate_ != Dart::vm_isolate() && |
| 282 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); | 308 !ServiceIsolate::IsServiceIsolateDescendant(isolate_)); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 311 if (ignore_breakpoints_ || IsPaused()) { | 337 if (ignore_breakpoints_ || IsPaused()) { |
| 312 // We don't let the isolate get interrupted if we are already | 338 // We don't let the isolate get interrupted if we are already |
| 313 // paused or ignoring breakpoints. | 339 // paused or ignoring breakpoints. |
| 314 return Error::null(); | 340 return Error::null(); |
| 315 } | 341 } |
| 316 ServiceEvent event(isolate_, kind); | 342 ServiceEvent event(isolate_, kind); |
| 317 DebuggerStackTrace* trace = CollectStackTrace(); | 343 DebuggerStackTrace* trace = CollectStackTrace(); |
| 318 if (trace->Length() > 0) { | 344 if (trace->Length() > 0) { |
| 319 event.set_top_frame(trace->FrameAt(0)); | 345 event.set_top_frame(trace->FrameAt(0)); |
| 320 } | 346 } |
| 321 ASSERT(stack_trace_ == NULL); | 347 CacheStackTraces(trace, CollectAsyncCausalStackTrace()); |
| 322 stack_trace_ = trace; | |
| 323 resume_action_ = kContinue; | 348 resume_action_ = kContinue; |
| 324 Pause(&event); | 349 Pause(&event); |
| 325 HandleSteppingRequest(trace); | 350 HandleSteppingRequest(trace); |
| 326 stack_trace_ = NULL; | 351 ClearCachedStackTraces(); |
| 327 | 352 |
| 328 // If any error occurred while in the debug message loop, return it here. | 353 // If any error occurred while in the debug message loop, return it here. |
| 329 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 354 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 330 ASSERT(error.IsNull() || error.IsUnwindError()); | 355 ASSERT(error.IsNull() || error.IsUnwindError()); |
| 331 Thread::Current()->clear_sticky_error(); | 356 Thread::Current()->clear_sticky_error(); |
| 332 return error.raw(); | 357 return error.raw(); |
| 333 } | 358 } |
| 334 | 359 |
| 335 | 360 |
| 336 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, | 361 void Debugger::SendBreakpointEvent(ServiceEvent::EventKind kind, |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 733 } | 758 } |
| 734 | 759 |
| 735 | 760 |
| 736 void ActivationFrame::GetDescIndices() { | 761 void ActivationFrame::GetDescIndices() { |
| 737 if (vars_initialized_) { | 762 if (vars_initialized_) { |
| 738 return; | 763 return; |
| 739 } | 764 } |
| 740 GetVarDescriptors(); | 765 GetVarDescriptors(); |
| 741 | 766 |
| 742 TokenPosition activation_token_pos = TokenPos(); | 767 TokenPosition activation_token_pos = TokenPos(); |
| 743 if (!activation_token_pos.IsDebugPause()) { | 768 if (!activation_token_pos.IsDebugPause() || !live_frame_) { |
| 744 // We don't have a token position for this frame, so can't determine | 769 // We don't have a token position for this frame, so can't determine |
| 745 // which variables are visible. | 770 // which variables are visible. |
| 746 vars_initialized_ = true; | 771 vars_initialized_ = true; |
| 747 return; | 772 return; |
| 748 } | 773 } |
| 749 | 774 |
| 750 GrowableArray<String*> var_names(8); | 775 GrowableArray<String*> var_names(8); |
| 751 intptr_t var_desc_len = var_descriptors_.Length(); | 776 intptr_t var_desc_len = var_descriptors_.Length(); |
| 752 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { | 777 for (intptr_t cur_idx = 0; cur_idx < var_desc_len; cur_idx++) { |
| 753 ASSERT(var_names.length() == desc_indices_.length()); | 778 ASSERT(var_names.length() == desc_indices_.length()); |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1079 "\tline = %" Pd | 1104 "\tline = %" Pd |
| 1080 "\n" | 1105 "\n" |
| 1081 "\tcontext = %s\n" | 1106 "\tcontext = %s\n" |
| 1082 "\tcontext level = %" Pd " ]\n", | 1107 "\tcontext level = %" Pd " ]\n", |
| 1083 pc(), fp(), sp(), func_name, url.ToCString(), line, ctx_.ToCString(), | 1108 pc(), fp(), sp(), func_name, url.ToCString(), line, ctx_.ToCString(), |
| 1084 ContextLevel()); | 1109 ContextLevel()); |
| 1085 } | 1110 } |
| 1086 | 1111 |
| 1087 | 1112 |
| 1088 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { | 1113 void ActivationFrame::PrintToJSONObject(JSONObject* jsobj, bool full) { |
| 1114 if (kind_ == kRegular) { | |
| 1115 PrintToJSONObjectRegular(jsobj, full); | |
| 1116 } else if (kind_ == kAsyncCausal) { | |
| 1117 PrintToJSONObjectAsyncCausal(jsobj, full); | |
| 1118 } else if (kind_ == kAsyncSuspensionMarker) { | |
| 1119 PrintToJSONObjectAsyncSuspensionMarker(jsobj, full); | |
| 1120 } else { | |
| 1121 UNIMPLEMENTED(); | |
| 1122 } | |
| 1123 } | |
| 1124 | |
| 1125 | |
| 1126 void ActivationFrame::PrintToJSONObjectRegular(JSONObject* jsobj, bool full) { | |
| 1089 const Script& script = Script::Handle(SourceScript()); | 1127 const Script& script = Script::Handle(SourceScript()); |
| 1090 jsobj->AddProperty("type", "Frame"); | 1128 jsobj->AddProperty("type", "Frame"); |
| 1129 jsobj->AddProperty("kind", KindToCString(kind_)); | |
| 1091 TokenPosition pos = TokenPos(); | 1130 TokenPosition pos = TokenPos(); |
| 1092 if (pos.IsSynthetic()) { | 1131 if (pos.IsSynthetic()) { |
| 1093 pos = pos.FromSynthetic(); | 1132 pos = pos.FromSynthetic(); |
| 1094 } | 1133 } |
| 1095 jsobj->AddLocation(script, pos); | 1134 jsobj->AddLocation(script, pos); |
| 1096 jsobj->AddProperty("function", function(), !full); | 1135 jsobj->AddProperty("function", function(), !full); |
| 1097 jsobj->AddProperty("code", code()); | 1136 jsobj->AddProperty("code", code()); |
| 1098 if (full) { | 1137 if (full) { |
| 1099 // TODO(cutch): The old "full" script usage no longer fits | 1138 // TODO(cutch): The old "full" script usage no longer fits |
| 1100 // in the world where we pass the script as part of the | 1139 // in the world where we pass the script as part of the |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1122 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); | 1161 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); |
| 1123 // When the variable becomes visible to the scope. | 1162 // When the variable becomes visible to the scope. |
| 1124 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); | 1163 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); |
| 1125 // When the variable stops being visible to the scope. | 1164 // When the variable stops being visible to the scope. |
| 1126 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); | 1165 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); |
| 1127 } | 1166 } |
| 1128 } | 1167 } |
| 1129 } | 1168 } |
| 1130 } | 1169 } |
| 1131 | 1170 |
| 1171 | |
| 1172 void ActivationFrame::PrintToJSONObjectAsyncCausal(JSONObject* jsobj, | |
| 1173 bool full) { | |
| 1174 jsobj->AddProperty("type", "Frame"); | |
| 1175 jsobj->AddProperty("kind", KindToCString(kind_)); | |
| 1176 const Script& script = Script::Handle(SourceScript()); | |
| 1177 TokenPosition pos = TokenPos(); | |
| 1178 if (pos.IsSynthetic()) { | |
| 1179 pos = pos.FromSynthetic(); | |
| 1180 } | |
| 1181 jsobj->AddLocation(script, pos); | |
| 1182 jsobj->AddProperty("function", function(), !full); | |
| 1183 jsobj->AddProperty("code", code()); | |
| 1184 if (full) { | |
| 1185 // TODO(cutch): The old "full" script usage no longer fits | |
| 1186 // in the world where we pass the script as part of the | |
| 1187 // location. | |
| 1188 jsobj->AddProperty("script", script, !full); | |
| 1189 } | |
| 1190 } | |
| 1191 | |
| 1192 | |
| 1193 void ActivationFrame::PrintToJSONObjectAsyncSuspensionMarker(JSONObject* jsobj, | |
| 1194 bool full) { | |
| 1195 jsobj->AddProperty("type", "Frame"); | |
| 1196 jsobj->AddProperty("kind", KindToCString(kind_)); | |
| 1197 jsobj->AddProperty("marker", "AsynchronousSuspension"); | |
| 1198 } | |
| 1199 | |
| 1200 | |
| 1132 static bool IsFunctionVisible(const Function& function) { | 1201 static bool IsFunctionVisible(const Function& function) { |
| 1133 return FLAG_show_invisible_frames || function.is_visible(); | 1202 return FLAG_show_invisible_frames || function.is_visible(); |
| 1134 } | 1203 } |
| 1135 | 1204 |
| 1136 | 1205 |
| 1137 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { | 1206 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
| 1138 if (IsFunctionVisible(frame->function())) { | 1207 if (IsFunctionVisible(frame->function())) { |
| 1139 trace_.Add(frame); | 1208 trace_.Add(frame); |
| 1140 } | 1209 } |
| 1141 } | 1210 } |
| 1142 | 1211 |
| 1143 | 1212 |
| 1213 void DebuggerStackTrace::AddMarker(ActivationFrame::Kind marker) { | |
| 1214 ASSERT((marker >= ActivationFrame::kAsyncSuspensionMarker) && | |
| 1215 (marker <= ActivationFrame::kAsyncSuspensionMarker)); | |
| 1216 trace_.Add(new ActivationFrame(marker)); | |
| 1217 } | |
| 1218 | |
| 1219 | |
| 1220 void DebuggerStackTrace::AddAsyncCausalFrame(uword pc, const Code& code) { | |
| 1221 trace_.Add(new ActivationFrame(pc, 0, 0, code, Array::Handle(), 0, | |
| 1222 ActivationFrame::kAsyncCausal)); | |
| 1223 } | |
| 1224 | |
| 1225 | |
| 1144 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | | 1226 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | |
| 1145 RawPcDescriptors::kUnoptStaticCall | | 1227 RawPcDescriptors::kUnoptStaticCall | |
| 1146 RawPcDescriptors::kRuntimeCall; | 1228 RawPcDescriptors::kRuntimeCall; |
| 1147 | 1229 |
| 1148 | 1230 |
| 1149 CodeBreakpoint::CodeBreakpoint(const Code& code, | 1231 CodeBreakpoint::CodeBreakpoint(const Code& code, |
| 1150 TokenPosition token_pos, | 1232 TokenPosition token_pos, |
| 1151 uword pc, | 1233 uword pc, |
| 1152 RawPcDescriptors::Kind kind) | 1234 RawPcDescriptors::Kind kind) |
| 1153 : code_(code.raw()), | 1235 : code_(code.raw()), |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1274 exc_pause_info_(kNoPauseOnExceptions) {} | 1356 exc_pause_info_(kNoPauseOnExceptions) {} |
| 1275 | 1357 |
| 1276 | 1358 |
| 1277 Debugger::~Debugger() { | 1359 Debugger::~Debugger() { |
| 1278 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1360 isolate_id_ = ILLEGAL_ISOLATE_ID; |
| 1279 ASSERT(!IsPaused()); | 1361 ASSERT(!IsPaused()); |
| 1280 ASSERT(latent_locations_ == NULL); | 1362 ASSERT(latent_locations_ == NULL); |
| 1281 ASSERT(breakpoint_locations_ == NULL); | 1363 ASSERT(breakpoint_locations_ == NULL); |
| 1282 ASSERT(code_breakpoints_ == NULL); | 1364 ASSERT(code_breakpoints_ == NULL); |
| 1283 ASSERT(stack_trace_ == NULL); | 1365 ASSERT(stack_trace_ == NULL); |
| 1366 ASSERT(async_causal_stack_trace_ == NULL); | |
| 1284 ASSERT(obj_cache_ == NULL); | 1367 ASSERT(obj_cache_ == NULL); |
| 1285 ASSERT(synthetic_async_breakpoint_ == NULL); | 1368 ASSERT(synthetic_async_breakpoint_ == NULL); |
| 1286 } | 1369 } |
| 1287 | 1370 |
| 1288 | 1371 |
| 1289 void Debugger::Shutdown() { | 1372 void Debugger::Shutdown() { |
| 1290 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need | 1373 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need |
| 1291 // them. Then, assert here that isolate_ is not one of those isolates. | 1374 // them. Then, assert here that isolate_ is not one of those isolates. |
| 1292 if ((isolate_ == Dart::vm_isolate()) || | 1375 if ((isolate_ == Dart::vm_isolate()) || |
| 1293 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 1376 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1512 | 1595 |
| 1513 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; | 1596 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
| 1514 frame = iterator.NextFrame()) { | 1597 frame = iterator.NextFrame()) { |
| 1515 ASSERT(frame->IsValid()); | 1598 ASSERT(frame->IsValid()); |
| 1516 if (FLAG_trace_debugger_stacktrace) { | 1599 if (FLAG_trace_debugger_stacktrace) { |
| 1517 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", | 1600 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", |
| 1518 frame->ToCString()); | 1601 frame->ToCString()); |
| 1519 } | 1602 } |
| 1520 if (frame->IsDartFrame()) { | 1603 if (frame->IsDartFrame()) { |
| 1521 code = frame->LookupDartCode(); | 1604 code = frame->LookupDartCode(); |
| 1522 if (code.is_optimized() && !FLAG_precompiled_runtime) { | 1605 AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code, |
| 1523 deopt_frame = DeoptimizeToArray(thread, frame, code); | 1606 &inlined_code, &deopt_frame); |
| 1524 for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); | 1607 } |
| 1525 it.Advance()) { | 1608 } |
| 1609 return stack_trace; | |
| 1610 } | |
| 1611 | |
| 1612 void Debugger::AppendCodeFrames(Thread* thread, | |
| 1613 Isolate* isolate, | |
| 1614 Zone* zone, | |
| 1615 DebuggerStackTrace* stack_trace, | |
| 1616 StackFrame* frame, | |
| 1617 Code* code, | |
| 1618 Code* inlined_code, | |
| 1619 Array* deopt_frame) { | |
| 1620 if (code->is_optimized() && !FLAG_precompiled_runtime) { | |
| 1621 *deopt_frame = DeoptimizeToArray(thread, frame, *code); | |
| 1622 for (InlinedFunctionsIterator it(*code, frame->pc()); !it.Done(); | |
| 1623 it.Advance()) { | |
| 1624 *inlined_code = it.code(); | |
| 1625 if (FLAG_trace_debugger_stacktrace) { | |
| 1626 const Function& function = | |
| 1627 Function::Handle(zone, inlined_code->function()); | |
| 1628 ASSERT(!function.IsNull()); | |
| 1629 OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n", | |
| 1630 function.ToFullyQualifiedCString()); | |
| 1631 } | |
| 1632 intptr_t deopt_frame_offset = it.GetDeoptFpOffset(); | |
| 1633 stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame, | |
| 1634 *inlined_code, *deopt_frame, | |
| 1635 deopt_frame_offset)); | |
| 1636 } | |
| 1637 } else { | |
| 1638 stack_trace->AddActivation(CollectDartFrame( | |
| 1639 isolate, frame->pc(), frame, *code, Object::null_array(), 0)); | |
| 1640 } | |
| 1641 } | |
| 1642 | |
| 1643 | |
| 1644 DebuggerStackTrace* Debugger::CollectAsyncCausalStackTrace() { | |
| 1645 if (!FLAG_sane_async_stacks) { | |
| 1646 return NULL; | |
| 1647 } | |
| 1648 Thread* thread = Thread::Current(); | |
| 1649 Zone* zone = thread->zone(); | |
| 1650 Isolate* isolate = thread->isolate(); | |
| 1651 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | |
| 1652 StackFrameIterator iterator(false); | |
| 1653 Code& code = Code::Handle(zone); | |
| 1654 Smi& offset = Smi::Handle(); | |
| 1655 Code& inlined_code = Code::Handle(zone); | |
| 1656 Array& deopt_frame = Array::Handle(zone); | |
| 1657 | |
| 1658 Function& async_function = Function::Handle(zone); | |
| 1659 Array& async_code_array = Array::Handle(zone); | |
| 1660 Array& async_pc_offset_array = Array::Handle(zone); | |
| 1661 const intptr_t async_stack_trace_length = | |
| 1662 StackTraceUtils::ExtractAsyncStackTraceInfo( | |
| 1663 thread, &async_function, &async_code_array, &async_pc_offset_array); | |
| 1664 | |
| 1665 if (async_function.IsNull()) { | |
| 1666 return NULL; | |
| 1667 } | |
| 1668 | |
| 1669 // Append the top frame from the stack trace. This is the active | |
| 1670 // asynchronous function. We truncate the remainder of the synchronous | |
| 1671 // stack trace because it contains activations that are part of the | |
| 1672 // asynchronous dispatch mechanisms. | |
| 1673 StackFrame* frame = iterator.NextFrame(); | |
| 1674 while ((frame != NULL) && !frame->IsDartFrame()) { | |
| 1675 frame = iterator.NextFrame(); | |
| 1676 } | |
| 1677 ASSERT(frame != NULL); | |
| 1678 ASSERT(frame->IsDartFrame()); | |
| 1679 code = frame->LookupDartCode(); | |
| 1680 AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code, | |
| 1681 &inlined_code, &deopt_frame); | |
| 1682 | |
| 1683 // Now we append the asynchronous causal stack trace. These are not active | |
| 1684 // frames but a historical record of how this asynchronous function was | |
| 1685 // activated. | |
| 1686 for (intptr_t i = 0; i < async_stack_trace_length; i++) { | |
| 1687 if (async_code_array.At(i) == Code::null()) { | |
| 1688 break; | |
| 1689 } | |
| 1690 if (async_code_array.At(i) == | |
| 1691 StubCode::AsynchronousGapMarker_entry()->code()) { | |
| 1692 stack_trace->AddMarker(ActivationFrame::kAsyncSuspensionMarker); | |
| 1693 } else { | |
| 1694 code = Code::RawCast(async_code_array.At(i)); | |
| 1695 offset = Smi::RawCast(async_pc_offset_array.At(i)); | |
| 1696 uword pc = code.PayloadStart() + offset.Value(); | |
| 1697 if (code.is_optimized()) { | |
| 1698 for (InlinedFunctionsIterator it(code, pc); !it.Done(); it.Advance()) { | |
| 1526 inlined_code = it.code(); | 1699 inlined_code = it.code(); |
| 1527 if (FLAG_trace_debugger_stacktrace) { | 1700 stack_trace->AddAsyncCausalFrame(pc, inlined_code); |
| 1528 const Function& function = | |
| 1529 Function::Handle(zone, inlined_code.function()); | |
| 1530 ASSERT(!function.IsNull()); | |
| 1531 OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n", | |
| 1532 function.ToFullyQualifiedCString()); | |
| 1533 } | |
| 1534 intptr_t deopt_frame_offset = it.GetDeoptFpOffset(); | |
| 1535 stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame, | |
| 1536 inlined_code, deopt_frame, | |
| 1537 deopt_frame_offset)); | |
| 1538 } | 1701 } |
| 1539 } else { | 1702 } else { |
| 1540 stack_trace->AddActivation(CollectDartFrame( | 1703 stack_trace->AddAsyncCausalFrame(pc, code); |
| 1541 isolate, frame->pc(), frame, code, Object::null_array(), 0)); | |
| 1542 } | 1704 } |
| 1543 } | 1705 } |
| 1544 } | 1706 } |
| 1545 return stack_trace; | 1707 return stack_trace; |
| 1546 } | 1708 } |
| 1547 | 1709 |
| 1548 | |
| 1549 ActivationFrame* Debugger::TopDartFrame() const { | 1710 ActivationFrame* Debugger::TopDartFrame() const { |
| 1550 StackFrameIterator iterator(false); | 1711 StackFrameIterator iterator(false); |
| 1551 StackFrame* frame = iterator.NextFrame(); | 1712 StackFrame* frame = iterator.NextFrame(); |
| 1552 while ((frame != NULL) && !frame->IsDartFrame()) { | 1713 while ((frame != NULL) && !frame->IsDartFrame()) { |
| 1553 frame = iterator.NextFrame(); | 1714 frame = iterator.NextFrame(); |
| 1554 } | 1715 } |
| 1555 Code& code = Code::Handle(frame->LookupDartCode()); | 1716 Code& code = Code::Handle(frame->LookupDartCode()); |
| 1556 ActivationFrame* activation = new ActivationFrame( | 1717 ActivationFrame* activation = new ActivationFrame( |
| 1557 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); | 1718 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); |
| 1558 return activation; | 1719 return activation; |
| 1559 } | 1720 } |
| 1560 | 1721 |
| 1561 | 1722 |
| 1562 DebuggerStackTrace* Debugger::StackTrace() { | 1723 DebuggerStackTrace* Debugger::StackTrace() { |
| 1563 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); | 1724 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); |
| 1564 } | 1725 } |
| 1565 | 1726 |
| 1727 | |
| 1566 DebuggerStackTrace* Debugger::CurrentStackTrace() { | 1728 DebuggerStackTrace* Debugger::CurrentStackTrace() { |
| 1567 return CollectStackTrace(); | 1729 return CollectStackTrace(); |
| 1568 } | 1730 } |
| 1569 | 1731 |
| 1732 | |
| 1733 DebuggerStackTrace* Debugger::AsyncCausalStackTrace() { | |
| 1734 return (async_causal_stack_trace_ != NULL) ? async_causal_stack_trace_ | |
| 1735 : CollectAsyncCausalStackTrace(); | |
| 1736 } | |
| 1737 | |
| 1738 | |
| 1739 DebuggerStackTrace* Debugger::CurrentAsyncCausalStackTrace() { | |
| 1740 return CollectAsyncCausalStackTrace(); | |
| 1741 } | |
| 1742 | |
| 1743 | |
| 1570 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { | 1744 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { |
| 1571 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 1745 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 1572 Function& function = Function::Handle(); | 1746 Function& function = Function::Handle(); |
| 1573 Code& code = Code::Handle(); | 1747 Code& code = Code::Handle(); |
| 1574 | 1748 |
| 1575 const uword fp = 0; | 1749 const uword fp = 0; |
| 1576 const uword sp = 0; | 1750 const uword sp = 0; |
| 1577 const Array& deopt_frame = Array::Handle(); | 1751 const Array& deopt_frame = Array::Handle(); |
| 1578 const intptr_t deopt_frame_offset = -1; | 1752 const intptr_t deopt_frame_offset = -1; |
| 1579 | 1753 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1660 } | 1834 } |
| 1661 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1835 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 1662 if (!ShouldPauseOnException(stack_trace, exc)) { | 1836 if (!ShouldPauseOnException(stack_trace, exc)) { |
| 1663 return; | 1837 return; |
| 1664 } | 1838 } |
| 1665 ServiceEvent event(isolate_, ServiceEvent::kPauseException); | 1839 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
| 1666 event.set_exception(&exc); | 1840 event.set_exception(&exc); |
| 1667 if (stack_trace->Length() > 0) { | 1841 if (stack_trace->Length() > 0) { |
| 1668 event.set_top_frame(stack_trace->FrameAt(0)); | 1842 event.set_top_frame(stack_trace->FrameAt(0)); |
| 1669 } | 1843 } |
| 1670 ASSERT(stack_trace_ == NULL); | 1844 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
| 1671 stack_trace_ = stack_trace; | |
| 1672 Pause(&event); | 1845 Pause(&event); |
| 1673 HandleSteppingRequest(stack_trace_); // we may get a rewind request | 1846 HandleSteppingRequest(stack_trace_); // we may get a rewind request |
| 1674 stack_trace_ = NULL; | 1847 ClearCachedStackTraces(); |
| 1675 } | 1848 } |
| 1676 | 1849 |
| 1677 | 1850 |
| 1678 static TokenPosition LastTokenOnLine(Zone* zone, | 1851 static TokenPosition LastTokenOnLine(Zone* zone, |
| 1679 const TokenStream& tokens, | 1852 const TokenStream& tokens, |
| 1680 TokenPosition pos) { | 1853 TokenPosition pos) { |
| 1681 TokenStream::Iterator iter(zone, tokens, pos, | 1854 TokenStream::Iterator iter(zone, tokens, pos, |
| 1682 TokenStream::Iterator::kAllTokens); | 1855 TokenStream::Iterator::kAllTokens); |
| 1683 ASSERT(iter.IsValid()); | 1856 ASSERT(iter.IsValid()); |
| 1684 TokenPosition last_pos = pos; | 1857 TokenPosition last_pos = pos; |
| (...skipping 976 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2661 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); | 2834 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); |
| 2662 frame = iterator.NextFrame(); | 2835 frame = iterator.NextFrame(); |
| 2663 } | 2836 } |
| 2664 } | 2837 } |
| 2665 RewindToFrame(resume_frame_index_); | 2838 RewindToFrame(resume_frame_index_); |
| 2666 UNREACHABLE(); | 2839 UNREACHABLE(); |
| 2667 } | 2840 } |
| 2668 } | 2841 } |
| 2669 | 2842 |
| 2670 | 2843 |
| 2844 void Debugger::CacheStackTraces(DebuggerStackTrace* stack_trace, | |
| 2845 DebuggerStackTrace* async_causal_stack_trace) { | |
| 2846 ASSERT(stack_trace_ == NULL); | |
| 2847 stack_trace_ = stack_trace; | |
| 2848 ASSERT(async_causal_stack_trace_ == NULL); | |
| 2849 async_causal_stack_trace_ = async_causal_stack_trace; | |
| 2850 } | |
| 2851 | |
| 2852 | |
| 2853 void Debugger::ClearCachedStackTraces() { | |
| 2854 stack_trace_ = NULL; | |
| 2855 async_causal_stack_trace_ = NULL; | |
| 2856 } | |
| 2857 | |
| 2858 | |
| 2671 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, | 2859 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, |
| 2672 intptr_t frame_index) { | 2860 intptr_t frame_index) { |
| 2673 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { | 2861 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { |
| 2674 ActivationFrame* frame = stack->FrameAt(i); | 2862 ActivationFrame* frame = stack->FrameAt(i); |
| 2675 if (frame->IsRewindable()) { | 2863 if (frame->IsRewindable()) { |
| 2676 return i; | 2864 return i; |
| 2677 } | 2865 } |
| 2678 } | 2866 } |
| 2679 return -1; | 2867 return -1; |
| 2680 } | 2868 } |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2789 } | 2977 } |
| 2790 } | 2978 } |
| 2791 } | 2979 } |
| 2792 UNIMPLEMENTED(); | 2980 UNIMPLEMENTED(); |
| 2793 } | 2981 } |
| 2794 | 2982 |
| 2795 | 2983 |
| 2796 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { | 2984 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { |
| 2797 // We will be jumping out of the debugger rather than exiting this | 2985 // We will be jumping out of the debugger rather than exiting this |
| 2798 // function, so prepare the debugger state. | 2986 // function, so prepare the debugger state. |
| 2799 stack_trace_ = NULL; | 2987 ClearCachedStackTraces(); |
| 2800 resume_action_ = kContinue; | 2988 resume_action_ = kContinue; |
| 2801 resume_frame_index_ = -1; | 2989 resume_frame_index_ = -1; |
| 2802 EnterSingleStepMode(); | 2990 EnterSingleStepMode(); |
| 2803 | 2991 |
| 2804 uword rewind_pc = LookupRewindPc(code, frame->pc()); | 2992 uword rewind_pc = LookupRewindPc(code, frame->pc()); |
| 2805 if (FLAG_trace_rewind && rewind_pc == 0) { | 2993 if (FLAG_trace_rewind && rewind_pc == 0) { |
| 2806 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); | 2994 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); |
| 2807 } | 2995 } |
| 2808 ASSERT(rewind_pc != 0); | 2996 ASSERT(rewind_pc != 0); |
| 2809 if (FLAG_trace_rewind) { | 2997 if (FLAG_trace_rewind) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 2821 } | 3009 } |
| 2822 | 3010 |
| 2823 | 3011 |
| 2824 void Debugger::RewindToOptimizedFrame(StackFrame* frame, | 3012 void Debugger::RewindToOptimizedFrame(StackFrame* frame, |
| 2825 const Code& optimized_code, | 3013 const Code& optimized_code, |
| 2826 intptr_t sub_index) { | 3014 intptr_t sub_index) { |
| 2827 post_deopt_frame_index_ = sub_index; | 3015 post_deopt_frame_index_ = sub_index; |
| 2828 | 3016 |
| 2829 // We will be jumping out of the debugger rather than exiting this | 3017 // We will be jumping out of the debugger rather than exiting this |
| 2830 // function, so prepare the debugger state. | 3018 // function, so prepare the debugger state. |
| 2831 stack_trace_ = NULL; | 3019 ClearCachedStackTraces(); |
| 2832 resume_action_ = kContinue; | 3020 resume_action_ = kContinue; |
| 2833 resume_frame_index_ = -1; | 3021 resume_frame_index_ = -1; |
| 2834 EnterSingleStepMode(); | 3022 EnterSingleStepMode(); |
| 2835 | 3023 |
| 2836 if (FLAG_trace_rewind) { | 3024 if (FLAG_trace_rewind) { |
| 2837 OS::PrintErr( | 3025 OS::PrintErr( |
| 2838 "===============================\n" | 3026 "===============================\n" |
| 2839 "Deoptimizing frame for rewind:\n" | 3027 "Deoptimizing frame for rewind:\n" |
| 2840 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | 3028 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
| 2841 ")\n" | 3029 ")\n" |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2989 ASSERT(!HasActiveBreakpoint(frame->pc())); | 3177 ASSERT(!HasActiveBreakpoint(frame->pc())); |
| 2990 | 3178 |
| 2991 if (FLAG_verbose_debug) { | 3179 if (FLAG_verbose_debug) { |
| 2992 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 3180 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
| 2993 String::Handle(frame->SourceUrl()).ToCString(), | 3181 String::Handle(frame->SourceUrl()).ToCString(), |
| 2994 frame->LineNumber(), | 3182 frame->LineNumber(), |
| 2995 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 3183 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
| 2996 frame->TokenPos().ToCString()); | 3184 frame->TokenPos().ToCString()); |
| 2997 } | 3185 } |
| 2998 | 3186 |
| 2999 ASSERT(stack_trace_ == NULL); | 3187 |
| 3000 stack_trace_ = CollectStackTrace(); | 3188 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace()); |
| 3001 // If this step callback is part of stepping over an await statement, | 3189 // If this step callback is part of stepping over an await statement, |
| 3002 // we saved the synthetic async breakpoint in PauseBreakpoint. We report | 3190 // we saved the synthetic async breakpoint in PauseBreakpoint. We report |
| 3003 // that we are paused at that breakpoint and then delete it after continuing. | 3191 // that we are paused at that breakpoint and then delete it after continuing. |
| 3004 SignalPausedEvent(frame, synthetic_async_breakpoint_); | 3192 SignalPausedEvent(frame, synthetic_async_breakpoint_); |
| 3005 if (synthetic_async_breakpoint_ != NULL) { | 3193 if (synthetic_async_breakpoint_ != NULL) { |
| 3006 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | 3194 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
| 3007 synthetic_async_breakpoint_ = NULL; | 3195 synthetic_async_breakpoint_ = NULL; |
| 3008 } | 3196 } |
| 3009 HandleSteppingRequest(stack_trace_); | 3197 HandleSteppingRequest(stack_trace_); |
| 3010 stack_trace_ = NULL; | 3198 ClearCachedStackTraces(); |
| 3011 | 3199 |
| 3012 // If any error occurred while in the debug message loop, return it here. | 3200 // If any error occurred while in the debug message loop, return it here. |
| 3013 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3201 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 3014 Thread::Current()->clear_sticky_error(); | 3202 Thread::Current()->clear_sticky_error(); |
| 3015 return error.raw(); | 3203 return error.raw(); |
| 3016 } | 3204 } |
| 3017 | 3205 |
| 3018 | 3206 |
| 3019 RawError* Debugger::PauseBreakpoint() { | 3207 RawError* Debugger::PauseBreakpoint() { |
| 3020 // We ignore this breakpoint when the VM is executing code invoked | 3208 // We ignore this breakpoint when the VM is executing code invoked |
| 3021 // by the debugger to evaluate variables values, or when we see a nested | 3209 // by the debugger to evaluate variables values, or when we see a nested |
| 3022 // breakpoint or exception event. | 3210 // breakpoint or exception event. |
| 3023 if (ignore_breakpoints_ || IsPaused()) { | 3211 if (ignore_breakpoints_ || IsPaused()) { |
| 3024 return Error::null(); | 3212 return Error::null(); |
| 3025 } | 3213 } |
| 3026 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3214 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 3027 ASSERT(stack_trace->Length() > 0); | 3215 ASSERT(stack_trace->Length() > 0); |
| 3028 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 3216 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
| 3029 ASSERT(top_frame != NULL); | 3217 ASSERT(top_frame != NULL); |
| 3030 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); | 3218 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); |
| 3031 ASSERT(cbpt != NULL); | 3219 ASSERT(cbpt != NULL); |
| 3032 | 3220 |
| 3033 BreakpointLocation* bpt_location = cbpt->bpt_location_; | 3221 Breakpoint* bpt_hit = FindHitBreakpoint(cbpt->bpt_location_, top_frame); |
| 3034 Breakpoint* bpt_hit = NULL; | |
| 3035 | |
| 3036 // There may be more than one applicable breakpoint at this location, but we | |
| 3037 // will report only one as reached. If there is a single-shot breakpoint, we | |
| 3038 // favor it; then a closure-specific breakpoint ; then an general breakpoint. | |
| 3039 if (bpt_location != NULL) { | |
| 3040 Breakpoint* bpt = bpt_location->breakpoints(); | |
| 3041 while (bpt != NULL) { | |
| 3042 if (bpt->IsSingleShot()) { | |
| 3043 bpt_hit = bpt; | |
| 3044 break; | |
| 3045 } | |
| 3046 bpt = bpt->next(); | |
| 3047 } | |
| 3048 | |
| 3049 if (bpt_hit == NULL) { | |
| 3050 bpt = bpt_location->breakpoints(); | |
| 3051 while (bpt != NULL) { | |
| 3052 if (bpt->IsPerClosure()) { | |
| 3053 Object& closure = Object::Handle(top_frame->GetClosure()); | |
| 3054 ASSERT(closure.IsInstance()); | |
| 3055 ASSERT(Instance::Cast(closure).IsClosure()); | |
| 3056 if (closure.raw() == bpt->closure()) { | |
| 3057 bpt_hit = bpt; | |
| 3058 break; | |
| 3059 } | |
| 3060 } | |
| 3061 bpt = bpt->next(); | |
| 3062 } | |
| 3063 } | |
| 3064 | |
| 3065 if (bpt_hit == NULL) { | |
| 3066 bpt = bpt_location->breakpoints(); | |
| 3067 while (bpt != NULL) { | |
| 3068 if (bpt->IsRepeated()) { | |
| 3069 bpt_hit = bpt; | |
| 3070 break; | |
| 3071 } | |
| 3072 bpt = bpt->next(); | |
| 3073 } | |
| 3074 } | |
| 3075 } | |
| 3076 | |
| 3077 if (bpt_hit == NULL) { | 3222 if (bpt_hit == NULL) { |
| 3078 return Error::null(); | 3223 return Error::null(); |
| 3079 } | 3224 } |
| 3080 | 3225 |
| 3081 if (bpt_hit->is_synthetic_async()) { | 3226 if (bpt_hit->is_synthetic_async()) { |
| 3082 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3227 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 3083 ASSERT(stack_trace->Length() > 0); | 3228 ASSERT(stack_trace->Length() > 0); |
| 3084 ASSERT(stack_trace_ == NULL); | 3229 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
| 3085 stack_trace_ = stack_trace; | |
| 3086 | 3230 |
| 3087 // Hit a synthetic async breakpoint. | 3231 // Hit a synthetic async breakpoint. |
| 3088 if (FLAG_verbose_debug) { | 3232 if (FLAG_verbose_debug) { |
| 3089 OS::Print(">>> hit synthetic breakpoint at %s:%" Pd | 3233 OS::Print(">>> hit synthetic breakpoint at %s:%" Pd |
| 3090 " " | 3234 " " |
| 3091 "(token %s) (address %#" Px ")\n", | 3235 "(token %s) (address %#" Px ")\n", |
| 3092 String::Handle(cbpt->SourceUrl()).ToCString(), | 3236 String::Handle(cbpt->SourceUrl()).ToCString(), |
| 3093 cbpt->LineNumber(), cbpt->token_pos().ToCString(), | 3237 cbpt->LineNumber(), cbpt->token_pos().ToCString(), |
| 3094 top_frame->pc()); | 3238 top_frame->pc()); |
| 3095 } | 3239 } |
| 3096 | 3240 |
| 3097 ASSERT(synthetic_async_breakpoint_ == NULL); | 3241 ASSERT(synthetic_async_breakpoint_ == NULL); |
| 3098 synthetic_async_breakpoint_ = bpt_hit; | 3242 synthetic_async_breakpoint_ = bpt_hit; |
| 3099 bpt_hit = NULL; | 3243 bpt_hit = NULL; |
| 3100 | 3244 |
| 3101 // We are at the entry of an async function. | 3245 // We are at the entry of an async function. |
| 3102 // We issue a step over to resume at the point after the await statement. | 3246 // We issue a step over to resume at the point after the await statement. |
| 3103 SetResumeAction(kStepOver); | 3247 SetResumeAction(kStepOver); |
| 3104 // When we single step from a user breakpoint, our next stepping | 3248 // When we single step from a user breakpoint, our next stepping |
| 3105 // point will be at the exact same pc. Skip it. | 3249 // point will be at the exact same pc. Skip it. |
| 3106 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3250 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 3107 stack_trace_ = NULL; | 3251 ClearCachedStackTraces(); |
| 3108 return Error::null(); | 3252 return Error::null(); |
| 3109 } | 3253 } |
| 3110 | 3254 |
| 3111 if (FLAG_verbose_debug) { | 3255 if (FLAG_verbose_debug) { |
| 3112 OS::Print(">>> hit %s breakpoint at %s:%" Pd | 3256 OS::Print(">>> hit %s breakpoint at %s:%" Pd |
| 3113 " " | 3257 " " |
| 3114 "(token %s) (address %#" Px ")\n", | 3258 "(token %s) (address %#" Px ")\n", |
| 3115 cbpt->IsInternal() ? "internal" : "user", | 3259 cbpt->IsInternal() ? "internal" : "user", |
| 3116 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), | 3260 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), |
| 3117 cbpt->token_pos().ToCString(), top_frame->pc()); | 3261 cbpt->token_pos().ToCString(), top_frame->pc()); |
| 3118 } | 3262 } |
| 3119 | 3263 |
| 3120 ASSERT(stack_trace_ == NULL); | 3264 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
| 3121 stack_trace_ = stack_trace; | |
| 3122 SignalPausedEvent(top_frame, bpt_hit); | 3265 SignalPausedEvent(top_frame, bpt_hit); |
| 3123 // When we single step from a user breakpoint, our next stepping | 3266 // When we single step from a user breakpoint, our next stepping |
| 3124 // point will be at the exact same pc. Skip it. | 3267 // point will be at the exact same pc. Skip it. |
| 3125 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3268 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 3126 stack_trace_ = NULL; | 3269 ClearCachedStackTraces(); |
| 3127 if (cbpt->IsInternal()) { | 3270 if (cbpt->IsInternal()) { |
| 3128 RemoveInternalBreakpoints(); | 3271 RemoveInternalBreakpoints(); |
| 3129 } | 3272 } |
| 3130 | 3273 |
| 3131 // If any error occurred while in the debug message loop, return it here. | 3274 // If any error occurred while in the debug message loop, return it here. |
| 3132 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3275 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
| 3133 Thread::Current()->clear_sticky_error(); | 3276 Thread::Current()->clear_sticky_error(); |
| 3134 return error.raw(); | 3277 return error.raw(); |
| 3135 } | 3278 } |
| 3136 | 3279 |
| 3137 | 3280 |
| 3281 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, | |
| 3282 ActivationFrame* top_frame) { | |
| 3283 if (location == NULL) { | |
| 3284 return NULL; | |
| 3285 } | |
| 3286 // There may be more than one applicable breakpoint at this location, but we | |
| 3287 // will report only one as reached. ; then ; then an general breakpoint. | |
|
rmacnak
2017/01/26 18:05:57
Copy-paste error in comment.
Cutch
2017/01/31 23:45:30
Done.
| |
| 3288 | |
| 3289 // First check for a single-shot breakpoint. | |
| 3290 Breakpoint* bpt = location->breakpoints(); | |
| 3291 while (bpt != NULL) { | |
| 3292 if (bpt->IsSingleShot()) { | |
| 3293 return bpt; | |
| 3294 } | |
| 3295 bpt = bpt->next(); | |
| 3296 } | |
| 3297 | |
| 3298 // Now check for a closure-specific breakpoint. | |
| 3299 bpt = location->breakpoints(); | |
| 3300 while (bpt != NULL) { | |
| 3301 if (bpt->IsPerClosure()) { | |
| 3302 Object& closure = Object::Handle(top_frame->GetClosure()); | |
| 3303 ASSERT(closure.IsInstance()); | |
| 3304 ASSERT(Instance::Cast(closure).IsClosure()); | |
| 3305 if (closure.raw() == bpt->closure()) { | |
| 3306 return bpt; | |
| 3307 } | |
| 3308 } | |
| 3309 bpt = bpt->next(); | |
| 3310 } | |
| 3311 | |
| 3312 // Finally, check for a general breakpoint. | |
| 3313 bpt = location->breakpoints(); | |
| 3314 while (bpt != NULL) { | |
| 3315 if (bpt->IsRepeated()) { | |
| 3316 return bpt; | |
| 3317 } | |
| 3318 bpt = bpt->next(); | |
| 3319 } | |
| 3320 | |
| 3321 return NULL; | |
| 3322 } | |
| 3323 | |
| 3324 | |
| 3138 void Debugger::PauseDeveloper(const String& msg) { | 3325 void Debugger::PauseDeveloper(const String& msg) { |
| 3139 // We ignore this breakpoint when the VM is executing code invoked | 3326 // We ignore this breakpoint when the VM is executing code invoked |
| 3140 // by the debugger to evaluate variables values, or when we see a nested | 3327 // by the debugger to evaluate variables values, or when we see a nested |
| 3141 // breakpoint or exception event. | 3328 // breakpoint or exception event. |
| 3142 if (ignore_breakpoints_ || IsPaused()) { | 3329 if (ignore_breakpoints_ || IsPaused()) { |
| 3143 return; | 3330 return; |
| 3144 } | 3331 } |
| 3145 | 3332 |
| 3146 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3333 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 3147 ASSERT(stack_trace->Length() > 0); | 3334 ASSERT(stack_trace->Length() > 0); |
| 3148 ASSERT(stack_trace_ == NULL); | 3335 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
| 3149 stack_trace_ = stack_trace; | |
| 3150 | |
| 3151 // TODO(johnmccutchan): Send |msg| to Observatory. | 3336 // TODO(johnmccutchan): Send |msg| to Observatory. |
| 3152 | 3337 |
| 3153 // We are in the native call to Developer_debugger. the developer | 3338 // We are in the native call to Developer_debugger. the developer |
| 3154 // gets a better experience by not seeing this call. To accomplish | 3339 // gets a better experience by not seeing this call. To accomplish |
| 3155 // this, we continue execution until the call exits (step out). | 3340 // this, we continue execution until the call exits (step out). |
| 3156 SetResumeAction(kStepOut); | 3341 SetResumeAction(kStepOut); |
| 3157 HandleSteppingRequest(stack_trace_); | 3342 HandleSteppingRequest(stack_trace_); |
| 3158 | 3343 ClearCachedStackTraces(); |
| 3159 stack_trace_ = NULL; | |
| 3160 } | 3344 } |
| 3161 | 3345 |
| 3162 | 3346 |
| 3163 void Debugger::Initialize(Isolate* isolate) { | 3347 void Debugger::Initialize(Isolate* isolate) { |
| 3164 if (initialized_) { | 3348 if (initialized_) { |
| 3165 return; | 3349 return; |
| 3166 } | 3350 } |
| 3167 isolate_ = isolate; | 3351 isolate_ = isolate; |
| 3168 | 3352 |
| 3169 // Use the isolate's control port as the isolate_id for debugging. | 3353 // Use the isolate's control port as the isolate_id for debugging. |
| (...skipping 429 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3599 | 3783 |
| 3600 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3784 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 3601 ASSERT(bpt->next() == NULL); | 3785 ASSERT(bpt->next() == NULL); |
| 3602 bpt->set_next(code_breakpoints_); | 3786 bpt->set_next(code_breakpoints_); |
| 3603 code_breakpoints_ = bpt; | 3787 code_breakpoints_ = bpt; |
| 3604 } | 3788 } |
| 3605 | 3789 |
| 3606 #endif // !PRODUCT | 3790 #endif // !PRODUCT |
| 3607 | 3791 |
| 3608 } // namespace dart | 3792 } // namespace dart |
| OLD | NEW |