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())), |
| 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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1261 latent_locations_(NULL), | 1343 latent_locations_(NULL), |
1262 breakpoint_locations_(NULL), | 1344 breakpoint_locations_(NULL), |
1263 code_breakpoints_(NULL), | 1345 code_breakpoints_(NULL), |
1264 resume_action_(kContinue), | 1346 resume_action_(kContinue), |
1265 resume_frame_index_(-1), | 1347 resume_frame_index_(-1), |
1266 post_deopt_frame_index_(-1), | 1348 post_deopt_frame_index_(-1), |
1267 ignore_breakpoints_(false), | 1349 ignore_breakpoints_(false), |
1268 pause_event_(NULL), | 1350 pause_event_(NULL), |
1269 obj_cache_(NULL), | 1351 obj_cache_(NULL), |
1270 stack_trace_(NULL), | 1352 stack_trace_(NULL), |
| 1353 async_causal_stack_trace_(NULL), |
1271 stepping_fp_(0), | 1354 stepping_fp_(0), |
1272 skip_next_step_(false), | 1355 skip_next_step_(false), |
1273 synthetic_async_breakpoint_(NULL), | 1356 synthetic_async_breakpoint_(NULL), |
1274 exc_pause_info_(kNoPauseOnExceptions) {} | 1357 exc_pause_info_(kNoPauseOnExceptions) {} |
1275 | 1358 |
1276 | 1359 |
1277 Debugger::~Debugger() { | 1360 Debugger::~Debugger() { |
1278 isolate_id_ = ILLEGAL_ISOLATE_ID; | 1361 isolate_id_ = ILLEGAL_ISOLATE_ID; |
1279 ASSERT(!IsPaused()); | 1362 ASSERT(!IsPaused()); |
1280 ASSERT(latent_locations_ == NULL); | 1363 ASSERT(latent_locations_ == NULL); |
1281 ASSERT(breakpoint_locations_ == NULL); | 1364 ASSERT(breakpoint_locations_ == NULL); |
1282 ASSERT(code_breakpoints_ == NULL); | 1365 ASSERT(code_breakpoints_ == NULL); |
1283 ASSERT(stack_trace_ == NULL); | 1366 ASSERT(stack_trace_ == NULL); |
| 1367 ASSERT(async_causal_stack_trace_ == NULL); |
1284 ASSERT(obj_cache_ == NULL); | 1368 ASSERT(obj_cache_ == NULL); |
1285 ASSERT(synthetic_async_breakpoint_ == NULL); | 1369 ASSERT(synthetic_async_breakpoint_ == NULL); |
1286 } | 1370 } |
1287 | 1371 |
1288 | 1372 |
1289 void Debugger::Shutdown() { | 1373 void Debugger::Shutdown() { |
1290 // TODO(johnmccutchan): Do not create a debugger for isolates that don't need | 1374 // 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. | 1375 // them. Then, assert here that isolate_ is not one of those isolates. |
1292 if ((isolate_ == Dart::vm_isolate()) || | 1376 if ((isolate_ == Dart::vm_isolate()) || |
1293 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { | 1377 ServiceIsolate::IsServiceIsolateDescendant(isolate_)) { |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1512 | 1596 |
1513 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; | 1597 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; |
1514 frame = iterator.NextFrame()) { | 1598 frame = iterator.NextFrame()) { |
1515 ASSERT(frame->IsValid()); | 1599 ASSERT(frame->IsValid()); |
1516 if (FLAG_trace_debugger_stacktrace) { | 1600 if (FLAG_trace_debugger_stacktrace) { |
1517 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", | 1601 OS::PrintErr("CollectStackTrace: visiting frame:\n\t%s\n", |
1518 frame->ToCString()); | 1602 frame->ToCString()); |
1519 } | 1603 } |
1520 if (frame->IsDartFrame()) { | 1604 if (frame->IsDartFrame()) { |
1521 code = frame->LookupDartCode(); | 1605 code = frame->LookupDartCode(); |
1522 if (code.is_optimized() && !FLAG_precompiled_runtime) { | 1606 AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code, |
1523 deopt_frame = DeoptimizeToArray(thread, frame, code); | 1607 &inlined_code, &deopt_frame); |
1524 for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); | |
1525 it.Advance()) { | |
1526 inlined_code = it.code(); | |
1527 if (FLAG_trace_debugger_stacktrace) { | |
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 } | |
1539 } else { | |
1540 stack_trace->AddActivation(CollectDartFrame( | |
1541 isolate, frame->pc(), frame, code, Object::null_array(), 0)); | |
1542 } | |
1543 } | 1608 } |
1544 } | 1609 } |
1545 return stack_trace; | 1610 return stack_trace; |
1546 } | 1611 } |
1547 | 1612 |
| 1613 void Debugger::AppendCodeFrames(Thread* thread, |
| 1614 Isolate* isolate, |
| 1615 Zone* zone, |
| 1616 DebuggerStackTrace* stack_trace, |
| 1617 StackFrame* frame, |
| 1618 Code* code, |
| 1619 Code* inlined_code, |
| 1620 Array* deopt_frame) { |
| 1621 if (code->is_optimized() && !FLAG_precompiled_runtime) { |
| 1622 // TODO(rmacnak): Use CodeSourceMap |
| 1623 *deopt_frame = DeoptimizeToArray(thread, frame, *code); |
| 1624 for (InlinedFunctionsIterator it(*code, frame->pc()); !it.Done(); |
| 1625 it.Advance()) { |
| 1626 *inlined_code = it.code(); |
| 1627 if (FLAG_trace_debugger_stacktrace) { |
| 1628 const Function& function = |
| 1629 Function::Handle(zone, inlined_code->function()); |
| 1630 ASSERT(!function.IsNull()); |
| 1631 OS::PrintErr("CollectStackTrace: visiting inlined function: %s\n", |
| 1632 function.ToFullyQualifiedCString()); |
| 1633 } |
| 1634 intptr_t deopt_frame_offset = it.GetDeoptFpOffset(); |
| 1635 stack_trace->AddActivation(CollectDartFrame(isolate, it.pc(), frame, |
| 1636 *inlined_code, *deopt_frame, |
| 1637 deopt_frame_offset)); |
| 1638 } |
| 1639 } else { |
| 1640 stack_trace->AddActivation(CollectDartFrame( |
| 1641 isolate, frame->pc(), frame, *code, Object::null_array(), 0)); |
| 1642 } |
| 1643 } |
| 1644 |
| 1645 |
| 1646 DebuggerStackTrace* Debugger::CollectAsyncCausalStackTrace() { |
| 1647 if (!FLAG_causal_async_stacks) { |
| 1648 return NULL; |
| 1649 } |
| 1650 Thread* thread = Thread::Current(); |
| 1651 Zone* zone = thread->zone(); |
| 1652 Isolate* isolate = thread->isolate(); |
| 1653 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
| 1654 |
| 1655 Code& code = Code::Handle(zone); |
| 1656 Smi& offset = Smi::Handle(); |
| 1657 Code& inlined_code = Code::Handle(zone); |
| 1658 Array& deopt_frame = Array::Handle(zone); |
| 1659 |
| 1660 Function& async_function = Function::Handle(zone); |
| 1661 class StackTrace& async_stack_trace = StackTrace::Handle(zone); |
| 1662 Array& async_code_array = Array::Handle(zone); |
| 1663 Array& async_pc_offset_array = Array::Handle(zone); |
| 1664 StackTraceUtils::ExtractAsyncStackTraceInfo( |
| 1665 thread, &async_function, &async_stack_trace, &async_code_array, |
| 1666 &async_pc_offset_array); |
| 1667 |
| 1668 if (async_function.IsNull()) { |
| 1669 return NULL; |
| 1670 } |
| 1671 |
| 1672 intptr_t synchronous_stack_trace_length = |
| 1673 StackTraceUtils::CountFrames(thread, 0, async_function); |
| 1674 |
| 1675 // Append the top frames from the synchronous stack trace, up until the active |
| 1676 // asynchronous function. We truncate the remainder of the synchronous |
| 1677 // stack trace because it contains activations that are part of the |
| 1678 // asynchronous dispatch mechanisms. |
| 1679 StackFrameIterator iterator(false); |
| 1680 StackFrame* frame = iterator.NextFrame(); |
| 1681 while (synchronous_stack_trace_length >= 0) { |
| 1682 ASSERT(frame != NULL); |
| 1683 if (frame->IsDartFrame()) { |
| 1684 code = frame->LookupDartCode(); |
| 1685 AppendCodeFrames(thread, isolate, zone, stack_trace, frame, &code, |
| 1686 &inlined_code, &deopt_frame); |
| 1687 synchronous_stack_trace_length--; |
| 1688 } |
| 1689 frame = iterator.NextFrame(); |
| 1690 } |
| 1691 |
| 1692 // Now we append the asynchronous causal stack trace. These are not active |
| 1693 // frames but a historical record of how this asynchronous function was |
| 1694 // activated. |
| 1695 while (!async_stack_trace.IsNull()) { |
| 1696 for (intptr_t i = 0; i < async_stack_trace.Length(); i++) { |
| 1697 if (async_stack_trace.CodeAtFrame(i) == Code::null()) { |
| 1698 break; |
| 1699 } |
| 1700 if (async_stack_trace.CodeAtFrame(i) == |
| 1701 StubCode::AsynchronousGapMarker_entry()->code()) { |
| 1702 stack_trace->AddMarker(ActivationFrame::kAsyncSuspensionMarker); |
| 1703 } else { |
| 1704 code = Code::RawCast(async_stack_trace.CodeAtFrame(i)); |
| 1705 offset = Smi::RawCast(async_stack_trace.PcOffsetAtFrame(i)); |
| 1706 uword pc = code.PayloadStart() + offset.Value(); |
| 1707 if (code.is_optimized()) { |
| 1708 for (InlinedFunctionsIterator it(code, pc); !it.Done(); |
| 1709 it.Advance()) { |
| 1710 inlined_code = it.code(); |
| 1711 stack_trace->AddAsyncCausalFrame(pc, inlined_code); |
| 1712 } |
| 1713 } else { |
| 1714 stack_trace->AddAsyncCausalFrame(pc, code); |
| 1715 } |
| 1716 } |
| 1717 } |
| 1718 // Follow the link. |
| 1719 async_stack_trace = async_stack_trace.async_link(); |
| 1720 } |
| 1721 |
| 1722 return stack_trace; |
| 1723 } |
1548 | 1724 |
1549 ActivationFrame* Debugger::TopDartFrame() const { | 1725 ActivationFrame* Debugger::TopDartFrame() const { |
1550 StackFrameIterator iterator(false); | 1726 StackFrameIterator iterator(false); |
1551 StackFrame* frame = iterator.NextFrame(); | 1727 StackFrame* frame = iterator.NextFrame(); |
1552 while ((frame != NULL) && !frame->IsDartFrame()) { | 1728 while ((frame != NULL) && !frame->IsDartFrame()) { |
1553 frame = iterator.NextFrame(); | 1729 frame = iterator.NextFrame(); |
1554 } | 1730 } |
1555 Code& code = Code::Handle(frame->LookupDartCode()); | 1731 Code& code = Code::Handle(frame->LookupDartCode()); |
1556 ActivationFrame* activation = new ActivationFrame( | 1732 ActivationFrame* activation = new ActivationFrame( |
1557 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); | 1733 frame->pc(), frame->fp(), frame->sp(), code, Object::null_array(), 0); |
1558 return activation; | 1734 return activation; |
1559 } | 1735 } |
1560 | 1736 |
1561 | 1737 |
1562 DebuggerStackTrace* Debugger::StackTrace() { | 1738 DebuggerStackTrace* Debugger::StackTrace() { |
1563 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); | 1739 return (stack_trace_ != NULL) ? stack_trace_ : CollectStackTrace(); |
1564 } | 1740 } |
1565 | 1741 |
| 1742 |
1566 DebuggerStackTrace* Debugger::CurrentStackTrace() { | 1743 DebuggerStackTrace* Debugger::CurrentStackTrace() { |
1567 return CollectStackTrace(); | 1744 return CollectStackTrace(); |
1568 } | 1745 } |
1569 | 1746 |
| 1747 |
| 1748 DebuggerStackTrace* Debugger::AsyncCausalStackTrace() { |
| 1749 return (async_causal_stack_trace_ != NULL) ? async_causal_stack_trace_ |
| 1750 : CollectAsyncCausalStackTrace(); |
| 1751 } |
| 1752 |
| 1753 |
| 1754 DebuggerStackTrace* Debugger::CurrentAsyncCausalStackTrace() { |
| 1755 return CollectAsyncCausalStackTrace(); |
| 1756 } |
| 1757 |
| 1758 |
1570 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { | 1759 DebuggerStackTrace* Debugger::StackTraceFrom(const class StackTrace& ex_trace) { |
1571 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); | 1760 DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8); |
1572 Function& function = Function::Handle(); | 1761 Function& function = Function::Handle(); |
1573 Code& code = Code::Handle(); | 1762 Code& code = Code::Handle(); |
1574 | 1763 |
1575 const uword fp = 0; | 1764 const uword fp = 0; |
1576 const uword sp = 0; | 1765 const uword sp = 0; |
1577 const Array& deopt_frame = Array::Handle(); | 1766 const Array& deopt_frame = Array::Handle(); |
1578 const intptr_t deopt_frame_offset = -1; | 1767 const intptr_t deopt_frame_offset = -1; |
1579 | 1768 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1660 } | 1849 } |
1661 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 1850 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
1662 if (!ShouldPauseOnException(stack_trace, exc)) { | 1851 if (!ShouldPauseOnException(stack_trace, exc)) { |
1663 return; | 1852 return; |
1664 } | 1853 } |
1665 ServiceEvent event(isolate_, ServiceEvent::kPauseException); | 1854 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
1666 event.set_exception(&exc); | 1855 event.set_exception(&exc); |
1667 if (stack_trace->Length() > 0) { | 1856 if (stack_trace->Length() > 0) { |
1668 event.set_top_frame(stack_trace->FrameAt(0)); | 1857 event.set_top_frame(stack_trace->FrameAt(0)); |
1669 } | 1858 } |
1670 ASSERT(stack_trace_ == NULL); | 1859 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
1671 stack_trace_ = stack_trace; | |
1672 Pause(&event); | 1860 Pause(&event); |
1673 HandleSteppingRequest(stack_trace_); // we may get a rewind request | 1861 HandleSteppingRequest(stack_trace_); // we may get a rewind request |
1674 stack_trace_ = NULL; | 1862 ClearCachedStackTraces(); |
1675 } | 1863 } |
1676 | 1864 |
1677 | 1865 |
1678 static TokenPosition LastTokenOnLine(Zone* zone, | 1866 static TokenPosition LastTokenOnLine(Zone* zone, |
1679 const TokenStream& tokens, | 1867 const TokenStream& tokens, |
1680 TokenPosition pos) { | 1868 TokenPosition pos) { |
1681 TokenStream::Iterator iter(zone, tokens, pos, | 1869 TokenStream::Iterator iter(zone, tokens, pos, |
1682 TokenStream::Iterator::kAllTokens); | 1870 TokenStream::Iterator::kAllTokens); |
1683 ASSERT(iter.IsValid()); | 1871 ASSERT(iter.IsValid()); |
1684 TokenPosition last_pos = pos; | 1872 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()); | 2849 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); |
2662 frame = iterator.NextFrame(); | 2850 frame = iterator.NextFrame(); |
2663 } | 2851 } |
2664 } | 2852 } |
2665 RewindToFrame(resume_frame_index_); | 2853 RewindToFrame(resume_frame_index_); |
2666 UNREACHABLE(); | 2854 UNREACHABLE(); |
2667 } | 2855 } |
2668 } | 2856 } |
2669 | 2857 |
2670 | 2858 |
| 2859 void Debugger::CacheStackTraces(DebuggerStackTrace* stack_trace, |
| 2860 DebuggerStackTrace* async_causal_stack_trace) { |
| 2861 ASSERT(stack_trace_ == NULL); |
| 2862 stack_trace_ = stack_trace; |
| 2863 ASSERT(async_causal_stack_trace_ == NULL); |
| 2864 async_causal_stack_trace_ = async_causal_stack_trace; |
| 2865 } |
| 2866 |
| 2867 |
| 2868 void Debugger::ClearCachedStackTraces() { |
| 2869 stack_trace_ = NULL; |
| 2870 async_causal_stack_trace_ = NULL; |
| 2871 } |
| 2872 |
| 2873 |
2671 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, | 2874 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, |
2672 intptr_t frame_index) { | 2875 intptr_t frame_index) { |
2673 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { | 2876 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { |
2674 ActivationFrame* frame = stack->FrameAt(i); | 2877 ActivationFrame* frame = stack->FrameAt(i); |
2675 if (frame->IsRewindable()) { | 2878 if (frame->IsRewindable()) { |
2676 return i; | 2879 return i; |
2677 } | 2880 } |
2678 } | 2881 } |
2679 return -1; | 2882 return -1; |
2680 } | 2883 } |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2789 } | 2992 } |
2790 } | 2993 } |
2791 } | 2994 } |
2792 UNIMPLEMENTED(); | 2995 UNIMPLEMENTED(); |
2793 } | 2996 } |
2794 | 2997 |
2795 | 2998 |
2796 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { | 2999 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { |
2797 // We will be jumping out of the debugger rather than exiting this | 3000 // We will be jumping out of the debugger rather than exiting this |
2798 // function, so prepare the debugger state. | 3001 // function, so prepare the debugger state. |
2799 stack_trace_ = NULL; | 3002 ClearCachedStackTraces(); |
2800 resume_action_ = kContinue; | 3003 resume_action_ = kContinue; |
2801 resume_frame_index_ = -1; | 3004 resume_frame_index_ = -1; |
2802 EnterSingleStepMode(); | 3005 EnterSingleStepMode(); |
2803 | 3006 |
2804 uword rewind_pc = LookupRewindPc(code, frame->pc()); | 3007 uword rewind_pc = LookupRewindPc(code, frame->pc()); |
2805 if (FLAG_trace_rewind && rewind_pc == 0) { | 3008 if (FLAG_trace_rewind && rewind_pc == 0) { |
2806 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); | 3009 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); |
2807 } | 3010 } |
2808 ASSERT(rewind_pc != 0); | 3011 ASSERT(rewind_pc != 0); |
2809 if (FLAG_trace_rewind) { | 3012 if (FLAG_trace_rewind) { |
(...skipping 11 matching lines...) Expand all Loading... |
2821 } | 3024 } |
2822 | 3025 |
2823 | 3026 |
2824 void Debugger::RewindToOptimizedFrame(StackFrame* frame, | 3027 void Debugger::RewindToOptimizedFrame(StackFrame* frame, |
2825 const Code& optimized_code, | 3028 const Code& optimized_code, |
2826 intptr_t sub_index) { | 3029 intptr_t sub_index) { |
2827 post_deopt_frame_index_ = sub_index; | 3030 post_deopt_frame_index_ = sub_index; |
2828 | 3031 |
2829 // We will be jumping out of the debugger rather than exiting this | 3032 // We will be jumping out of the debugger rather than exiting this |
2830 // function, so prepare the debugger state. | 3033 // function, so prepare the debugger state. |
2831 stack_trace_ = NULL; | 3034 ClearCachedStackTraces(); |
2832 resume_action_ = kContinue; | 3035 resume_action_ = kContinue; |
2833 resume_frame_index_ = -1; | 3036 resume_frame_index_ = -1; |
2834 EnterSingleStepMode(); | 3037 EnterSingleStepMode(); |
2835 | 3038 |
2836 if (FLAG_trace_rewind) { | 3039 if (FLAG_trace_rewind) { |
2837 OS::PrintErr( | 3040 OS::PrintErr( |
2838 "===============================\n" | 3041 "===============================\n" |
2839 "Deoptimizing frame for rewind:\n" | 3042 "Deoptimizing frame for rewind:\n" |
2840 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | 3043 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px |
2841 ")\n" | 3044 ")\n" |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2997 ASSERT(!HasActiveBreakpoint(frame->pc())); | 3200 ASSERT(!HasActiveBreakpoint(frame->pc())); |
2998 | 3201 |
2999 if (FLAG_verbose_debug) { | 3202 if (FLAG_verbose_debug) { |
3000 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", | 3203 OS::Print(">>> single step break at %s:%" Pd " (func %s token %s)\n", |
3001 String::Handle(frame->SourceUrl()).ToCString(), | 3204 String::Handle(frame->SourceUrl()).ToCString(), |
3002 frame->LineNumber(), | 3205 frame->LineNumber(), |
3003 String::Handle(frame->QualifiedFunctionName()).ToCString(), | 3206 String::Handle(frame->QualifiedFunctionName()).ToCString(), |
3004 frame->TokenPos().ToCString()); | 3207 frame->TokenPos().ToCString()); |
3005 } | 3208 } |
3006 | 3209 |
3007 ASSERT(stack_trace_ == NULL); | 3210 |
3008 stack_trace_ = CollectStackTrace(); | 3211 CacheStackTraces(CollectStackTrace(), CollectAsyncCausalStackTrace()); |
3009 // If this step callback is part of stepping over an await statement, | 3212 // If this step callback is part of stepping over an await statement, |
3010 // we saved the synthetic async breakpoint in PauseBreakpoint. We report | 3213 // we saved the synthetic async breakpoint in PauseBreakpoint. We report |
3011 // that we are paused at that breakpoint and then delete it after continuing. | 3214 // that we are paused at that breakpoint and then delete it after continuing. |
3012 SignalPausedEvent(frame, synthetic_async_breakpoint_); | 3215 SignalPausedEvent(frame, synthetic_async_breakpoint_); |
3013 if (synthetic_async_breakpoint_ != NULL) { | 3216 if (synthetic_async_breakpoint_ != NULL) { |
3014 RemoveBreakpoint(synthetic_async_breakpoint_->id()); | 3217 RemoveBreakpoint(synthetic_async_breakpoint_->id()); |
3015 synthetic_async_breakpoint_ = NULL; | 3218 synthetic_async_breakpoint_ = NULL; |
3016 } | 3219 } |
3017 HandleSteppingRequest(stack_trace_); | 3220 HandleSteppingRequest(stack_trace_); |
3018 stack_trace_ = NULL; | 3221 ClearCachedStackTraces(); |
3019 | 3222 |
3020 // If any error occurred while in the debug message loop, return it here. | 3223 // If any error occurred while in the debug message loop, return it here. |
3021 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3224 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
3022 Thread::Current()->clear_sticky_error(); | 3225 Thread::Current()->clear_sticky_error(); |
3023 return error.raw(); | 3226 return error.raw(); |
3024 } | 3227 } |
3025 | 3228 |
3026 | 3229 |
3027 RawError* Debugger::PauseBreakpoint() { | 3230 RawError* Debugger::PauseBreakpoint() { |
3028 // We ignore this breakpoint when the VM is executing code invoked | 3231 // We ignore this breakpoint when the VM is executing code invoked |
3029 // by the debugger to evaluate variables values, or when we see a nested | 3232 // by the debugger to evaluate variables values, or when we see a nested |
3030 // breakpoint or exception event. | 3233 // breakpoint or exception event. |
3031 if (ignore_breakpoints_ || IsPaused()) { | 3234 if (ignore_breakpoints_ || IsPaused()) { |
3032 return Error::null(); | 3235 return Error::null(); |
3033 } | 3236 } |
3034 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3237 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
3035 ASSERT(stack_trace->Length() > 0); | 3238 ASSERT(stack_trace->Length() > 0); |
3036 ActivationFrame* top_frame = stack_trace->FrameAt(0); | 3239 ActivationFrame* top_frame = stack_trace->FrameAt(0); |
3037 ASSERT(top_frame != NULL); | 3240 ASSERT(top_frame != NULL); |
3038 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); | 3241 CodeBreakpoint* cbpt = GetCodeBreakpoint(top_frame->pc()); |
3039 ASSERT(cbpt != NULL); | 3242 ASSERT(cbpt != NULL); |
3040 | 3243 |
3041 BreakpointLocation* bpt_location = cbpt->bpt_location_; | 3244 Breakpoint* bpt_hit = FindHitBreakpoint(cbpt->bpt_location_, top_frame); |
3042 Breakpoint* bpt_hit = NULL; | |
3043 | |
3044 // There may be more than one applicable breakpoint at this location, but we | |
3045 // will report only one as reached. If there is a single-shot breakpoint, we | |
3046 // favor it; then a closure-specific breakpoint ; then an general breakpoint. | |
3047 if (bpt_location != NULL) { | |
3048 Breakpoint* bpt = bpt_location->breakpoints(); | |
3049 while (bpt != NULL) { | |
3050 if (bpt->IsSingleShot()) { | |
3051 bpt_hit = bpt; | |
3052 break; | |
3053 } | |
3054 bpt = bpt->next(); | |
3055 } | |
3056 | |
3057 if (bpt_hit == NULL) { | |
3058 bpt = bpt_location->breakpoints(); | |
3059 while (bpt != NULL) { | |
3060 if (bpt->IsPerClosure()) { | |
3061 Object& closure = Object::Handle(top_frame->GetClosure()); | |
3062 ASSERT(closure.IsInstance()); | |
3063 ASSERT(Instance::Cast(closure).IsClosure()); | |
3064 if (closure.raw() == bpt->closure()) { | |
3065 bpt_hit = bpt; | |
3066 break; | |
3067 } | |
3068 } | |
3069 bpt = bpt->next(); | |
3070 } | |
3071 } | |
3072 | |
3073 if (bpt_hit == NULL) { | |
3074 bpt = bpt_location->breakpoints(); | |
3075 while (bpt != NULL) { | |
3076 if (bpt->IsRepeated()) { | |
3077 bpt_hit = bpt; | |
3078 break; | |
3079 } | |
3080 bpt = bpt->next(); | |
3081 } | |
3082 } | |
3083 } | |
3084 | |
3085 if (bpt_hit == NULL) { | 3245 if (bpt_hit == NULL) { |
3086 return Error::null(); | 3246 return Error::null(); |
3087 } | 3247 } |
3088 | 3248 |
3089 if (bpt_hit->is_synthetic_async()) { | 3249 if (bpt_hit->is_synthetic_async()) { |
3090 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3250 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
3091 ASSERT(stack_trace->Length() > 0); | 3251 ASSERT(stack_trace->Length() > 0); |
3092 ASSERT(stack_trace_ == NULL); | 3252 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
3093 stack_trace_ = stack_trace; | |
3094 | 3253 |
3095 // Hit a synthetic async breakpoint. | 3254 // Hit a synthetic async breakpoint. |
3096 if (FLAG_verbose_debug) { | 3255 if (FLAG_verbose_debug) { |
3097 OS::Print(">>> hit synthetic breakpoint at %s:%" Pd | 3256 OS::Print(">>> hit synthetic breakpoint at %s:%" Pd |
3098 " " | 3257 " " |
3099 "(token %s) (address %#" Px ")\n", | 3258 "(token %s) (address %#" Px ")\n", |
3100 String::Handle(cbpt->SourceUrl()).ToCString(), | 3259 String::Handle(cbpt->SourceUrl()).ToCString(), |
3101 cbpt->LineNumber(), cbpt->token_pos().ToCString(), | 3260 cbpt->LineNumber(), cbpt->token_pos().ToCString(), |
3102 top_frame->pc()); | 3261 top_frame->pc()); |
3103 } | 3262 } |
3104 | 3263 |
3105 ASSERT(synthetic_async_breakpoint_ == NULL); | 3264 ASSERT(synthetic_async_breakpoint_ == NULL); |
3106 synthetic_async_breakpoint_ = bpt_hit; | 3265 synthetic_async_breakpoint_ = bpt_hit; |
3107 bpt_hit = NULL; | 3266 bpt_hit = NULL; |
3108 | 3267 |
3109 // We are at the entry of an async function. | 3268 // We are at the entry of an async function. |
3110 // We issue a step over to resume at the point after the await statement. | 3269 // We issue a step over to resume at the point after the await statement. |
3111 SetResumeAction(kStepOver); | 3270 SetResumeAction(kStepOver); |
3112 // When we single step from a user breakpoint, our next stepping | 3271 // When we single step from a user breakpoint, our next stepping |
3113 // point will be at the exact same pc. Skip it. | 3272 // point will be at the exact same pc. Skip it. |
3114 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3273 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
3115 stack_trace_ = NULL; | 3274 ClearCachedStackTraces(); |
3116 return Error::null(); | 3275 return Error::null(); |
3117 } | 3276 } |
3118 | 3277 |
3119 if (FLAG_verbose_debug) { | 3278 if (FLAG_verbose_debug) { |
3120 OS::Print(">>> hit %s breakpoint at %s:%" Pd | 3279 OS::Print(">>> hit %s breakpoint at %s:%" Pd |
3121 " " | 3280 " " |
3122 "(token %s) (address %#" Px ")\n", | 3281 "(token %s) (address %#" Px ")\n", |
3123 cbpt->IsInternal() ? "internal" : "user", | 3282 cbpt->IsInternal() ? "internal" : "user", |
3124 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), | 3283 String::Handle(cbpt->SourceUrl()).ToCString(), cbpt->LineNumber(), |
3125 cbpt->token_pos().ToCString(), top_frame->pc()); | 3284 cbpt->token_pos().ToCString(), top_frame->pc()); |
3126 } | 3285 } |
3127 | 3286 |
3128 ASSERT(stack_trace_ == NULL); | 3287 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
3129 stack_trace_ = stack_trace; | |
3130 SignalPausedEvent(top_frame, bpt_hit); | 3288 SignalPausedEvent(top_frame, bpt_hit); |
3131 // When we single step from a user breakpoint, our next stepping | 3289 // When we single step from a user breakpoint, our next stepping |
3132 // point will be at the exact same pc. Skip it. | 3290 // point will be at the exact same pc. Skip it. |
3133 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 3291 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
3134 stack_trace_ = NULL; | 3292 ClearCachedStackTraces(); |
3135 if (cbpt->IsInternal()) { | 3293 if (cbpt->IsInternal()) { |
3136 RemoveInternalBreakpoints(); | 3294 RemoveInternalBreakpoints(); |
3137 } | 3295 } |
3138 | 3296 |
3139 // If any error occurred while in the debug message loop, return it here. | 3297 // If any error occurred while in the debug message loop, return it here. |
3140 const Error& error = Error::Handle(Thread::Current()->sticky_error()); | 3298 const Error& error = Error::Handle(Thread::Current()->sticky_error()); |
3141 Thread::Current()->clear_sticky_error(); | 3299 Thread::Current()->clear_sticky_error(); |
3142 return error.raw(); | 3300 return error.raw(); |
3143 } | 3301 } |
3144 | 3302 |
3145 | 3303 |
| 3304 Breakpoint* Debugger::FindHitBreakpoint(BreakpointLocation* location, |
| 3305 ActivationFrame* top_frame) { |
| 3306 if (location == NULL) { |
| 3307 return NULL; |
| 3308 } |
| 3309 // There may be more than one applicable breakpoint at this location, but we |
| 3310 // will report only one as reached. If there is a single-shot breakpoint, we |
| 3311 // favor it; then a closure-specific breakpoint ; then an general breakpoint. |
| 3312 |
| 3313 // First check for a single-shot breakpoint. |
| 3314 Breakpoint* bpt = location->breakpoints(); |
| 3315 while (bpt != NULL) { |
| 3316 if (bpt->IsSingleShot()) { |
| 3317 return bpt; |
| 3318 } |
| 3319 bpt = bpt->next(); |
| 3320 } |
| 3321 |
| 3322 // Now check for a closure-specific breakpoint. |
| 3323 bpt = location->breakpoints(); |
| 3324 while (bpt != NULL) { |
| 3325 if (bpt->IsPerClosure()) { |
| 3326 Object& closure = Object::Handle(top_frame->GetClosure()); |
| 3327 ASSERT(closure.IsInstance()); |
| 3328 ASSERT(Instance::Cast(closure).IsClosure()); |
| 3329 if (closure.raw() == bpt->closure()) { |
| 3330 return bpt; |
| 3331 } |
| 3332 } |
| 3333 bpt = bpt->next(); |
| 3334 } |
| 3335 |
| 3336 // Finally, check for a general breakpoint. |
| 3337 bpt = location->breakpoints(); |
| 3338 while (bpt != NULL) { |
| 3339 if (bpt->IsRepeated()) { |
| 3340 return bpt; |
| 3341 } |
| 3342 bpt = bpt->next(); |
| 3343 } |
| 3344 |
| 3345 return NULL; |
| 3346 } |
| 3347 |
| 3348 |
3146 void Debugger::PauseDeveloper(const String& msg) { | 3349 void Debugger::PauseDeveloper(const String& msg) { |
3147 // We ignore this breakpoint when the VM is executing code invoked | 3350 // We ignore this breakpoint when the VM is executing code invoked |
3148 // by the debugger to evaluate variables values, or when we see a nested | 3351 // by the debugger to evaluate variables values, or when we see a nested |
3149 // breakpoint or exception event. | 3352 // breakpoint or exception event. |
3150 if (ignore_breakpoints_ || IsPaused()) { | 3353 if (ignore_breakpoints_ || IsPaused()) { |
3151 return; | 3354 return; |
3152 } | 3355 } |
3153 | 3356 |
3154 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 3357 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
3155 ASSERT(stack_trace->Length() > 0); | 3358 ASSERT(stack_trace->Length() > 0); |
3156 ASSERT(stack_trace_ == NULL); | 3359 CacheStackTraces(stack_trace, CollectAsyncCausalStackTrace()); |
3157 stack_trace_ = stack_trace; | |
3158 | |
3159 // TODO(johnmccutchan): Send |msg| to Observatory. | 3360 // TODO(johnmccutchan): Send |msg| to Observatory. |
3160 | 3361 |
3161 // We are in the native call to Developer_debugger. the developer | 3362 // We are in the native call to Developer_debugger. the developer |
3162 // gets a better experience by not seeing this call. To accomplish | 3363 // gets a better experience by not seeing this call. To accomplish |
3163 // this, we continue execution until the call exits (step out). | 3364 // this, we continue execution until the call exits (step out). |
3164 SetResumeAction(kStepOut); | 3365 SetResumeAction(kStepOut); |
3165 HandleSteppingRequest(stack_trace_); | 3366 HandleSteppingRequest(stack_trace_); |
3166 | 3367 ClearCachedStackTraces(); |
3167 stack_trace_ = NULL; | |
3168 } | 3368 } |
3169 | 3369 |
3170 | 3370 |
3171 void Debugger::Initialize(Isolate* isolate) { | 3371 void Debugger::Initialize(Isolate* isolate) { |
3172 if (initialized_) { | 3372 if (initialized_) { |
3173 return; | 3373 return; |
3174 } | 3374 } |
3175 isolate_ = isolate; | 3375 isolate_ = isolate; |
3176 | 3376 |
3177 // Use the isolate's control port as the isolate_id for debugging. | 3377 // 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... |
3607 | 3807 |
3608 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3808 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
3609 ASSERT(bpt->next() == NULL); | 3809 ASSERT(bpt->next() == NULL); |
3610 bpt->set_next(code_breakpoints_); | 3810 bpt->set_next(code_breakpoints_); |
3611 code_breakpoints_ = bpt; | 3811 code_breakpoints_ = bpt; |
3612 } | 3812 } |
3613 | 3813 |
3614 #endif // !PRODUCT | 3814 #endif // !PRODUCT |
3615 | 3815 |
3616 } // namespace dart | 3816 } // namespace dart |
OLD | NEW |