| 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" | |
| 10 | |
| 11 #include "vm/code_generator.h" | 9 #include "vm/code_generator.h" |
| 12 #include "vm/code_patcher.h" | 10 #include "vm/code_patcher.h" |
| 13 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
| 14 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 15 #include "vm/deopt_instructions.h" | 13 #include "vm/deopt_instructions.h" |
| 16 #include "vm/flags.h" | 14 #include "vm/flags.h" |
| 17 #include "vm/globals.h" | 15 #include "vm/globals.h" |
| 18 #include "vm/longjump.h" | 16 #include "vm/longjump.h" |
| 19 #include "vm/json_stream.h" | 17 #include "vm/json_stream.h" |
| 20 #include "vm/message_handler.h" | 18 #include "vm/message_handler.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 37 namespace dart { | 35 namespace dart { |
| 38 | 36 |
| 39 DEFINE_FLAG(bool, | 37 DEFINE_FLAG(bool, |
| 40 show_invisible_frames, | 38 show_invisible_frames, |
| 41 false, | 39 false, |
| 42 "Show invisible frames in debugger stack traces"); | 40 "Show invisible frames in debugger stack traces"); |
| 43 DEFINE_FLAG(bool, | 41 DEFINE_FLAG(bool, |
| 44 trace_debugger_stacktrace, | 42 trace_debugger_stacktrace, |
| 45 false, | 43 false, |
| 46 "Trace debugger stacktrace collection"); | 44 "Trace debugger stacktrace collection"); |
| 47 DEFINE_FLAG(bool, trace_rewind, false, "Trace frame rewind"); | |
| 48 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); | 45 DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages"); |
| 49 DEFINE_FLAG(bool, | 46 DEFINE_FLAG(bool, |
| 50 steal_breakpoints, | 47 steal_breakpoints, |
| 51 false, | 48 false, |
| 52 "Intercept breakpoints and other pause events before they " | 49 "Intercept breakpoints and other pause events before they " |
| 53 "are sent to the embedder and use a generic VM breakpoint " | 50 "are sent to the embedder and use a generic VM breakpoint " |
| 54 "handler instead. This handler dispatches breakpoints to " | 51 "handler instead. This handler dispatches breakpoints to " |
| 55 "the VM service."); | 52 "the VM service."); |
| 56 | 53 |
| 57 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger); | 54 DECLARE_FLAG(bool, warn_on_pause_with_no_debugger); |
| (...skipping 788 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 846 | 843 |
| 847 RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) { | 844 RawObject* ActivationFrame::GetStackVar(intptr_t slot_index) { |
| 848 if (deopt_frame_.IsNull()) { | 845 if (deopt_frame_.IsNull()) { |
| 849 return GetVariableValue(LocalVarAddress(fp(), slot_index)); | 846 return GetVariableValue(LocalVarAddress(fp(), slot_index)); |
| 850 } else { | 847 } else { |
| 851 return deopt_frame_.At(LocalVarIndex(deopt_frame_offset_, slot_index)); | 848 return deopt_frame_.At(LocalVarIndex(deopt_frame_offset_, slot_index)); |
| 852 } | 849 } |
| 853 } | 850 } |
| 854 | 851 |
| 855 | 852 |
| 856 bool ActivationFrame::IsRewindable() const { | |
| 857 if (deopt_frame_.IsNull()) { | |
| 858 return true; | |
| 859 } | |
| 860 // TODO(turnidge): This is conservative. It looks at all values in | |
| 861 // the deopt_frame_ even though some of them may correspond to other | |
| 862 // inlined frames. | |
| 863 Object& obj = Object::Handle(); | |
| 864 for (int i = 0; i < deopt_frame_.Length(); i++) { | |
| 865 obj = deopt_frame_.At(i); | |
| 866 if (obj.raw() == Symbols::OptimizedOut().raw()) { | |
| 867 return false; | |
| 868 } | |
| 869 } | |
| 870 return true; | |
| 871 } | |
| 872 | |
| 873 | |
| 874 void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, | 853 void ActivationFrame::PrintContextMismatchError(intptr_t ctx_slot, |
| 875 intptr_t frame_ctx_level, | 854 intptr_t frame_ctx_level, |
| 876 intptr_t var_ctx_level) { | 855 intptr_t var_ctx_level) { |
| 877 OS::PrintErr( | 856 OS::PrintErr( |
| 878 "-------------------------\n" | 857 "-------------------------\n" |
| 879 "Encountered context mismatch\n" | 858 "Encountered context mismatch\n" |
| 880 "\tctx_slot: %" Pd | 859 "\tctx_slot: %" Pd |
| 881 "\n" | 860 "\n" |
| 882 "\tframe_ctx_level: %" Pd | 861 "\tframe_ctx_level: %" Pd |
| 883 "\n" | 862 "\n" |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); | 1101 jsvar.AddProperty("declarationTokenPos", declaration_token_pos); |
| 1123 // When the variable becomes visible to the scope. | 1102 // When the variable becomes visible to the scope. |
| 1124 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); | 1103 jsvar.AddProperty("scopeStartTokenPos", visible_start_token_pos); |
| 1125 // When the variable stops being visible to the scope. | 1104 // When the variable stops being visible to the scope. |
| 1126 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); | 1105 jsvar.AddProperty("scopeEndTokenPos", visible_end_token_pos); |
| 1127 } | 1106 } |
| 1128 } | 1107 } |
| 1129 } | 1108 } |
| 1130 } | 1109 } |
| 1131 | 1110 |
| 1132 static bool IsFunctionVisible(const Function& function) { | |
| 1133 return FLAG_show_invisible_frames || function.is_visible(); | |
| 1134 } | |
| 1135 | |
| 1136 | 1111 |
| 1137 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { | 1112 void DebuggerStackTrace::AddActivation(ActivationFrame* frame) { |
| 1138 if (IsFunctionVisible(frame->function())) { | 1113 if (FLAG_show_invisible_frames || frame->function().is_visible()) { |
| 1139 trace_.Add(frame); | 1114 trace_.Add(frame); |
| 1140 } | 1115 } |
| 1141 } | 1116 } |
| 1142 | 1117 |
| 1143 | 1118 |
| 1144 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | | 1119 const uint8_t kSafepointKind = RawPcDescriptors::kIcCall | |
| 1145 RawPcDescriptors::kUnoptStaticCall | | 1120 RawPcDescriptors::kUnoptStaticCall | |
| 1146 RawPcDescriptors::kRuntimeCall; | 1121 RawPcDescriptors::kRuntimeCall; |
| 1147 | 1122 |
| 1148 | 1123 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1255 | 1230 |
| 1256 Debugger::Debugger() | 1231 Debugger::Debugger() |
| 1257 : isolate_(NULL), | 1232 : isolate_(NULL), |
| 1258 isolate_id_(ILLEGAL_ISOLATE_ID), | 1233 isolate_id_(ILLEGAL_ISOLATE_ID), |
| 1259 initialized_(false), | 1234 initialized_(false), |
| 1260 next_id_(1), | 1235 next_id_(1), |
| 1261 latent_locations_(NULL), | 1236 latent_locations_(NULL), |
| 1262 breakpoint_locations_(NULL), | 1237 breakpoint_locations_(NULL), |
| 1263 code_breakpoints_(NULL), | 1238 code_breakpoints_(NULL), |
| 1264 resume_action_(kContinue), | 1239 resume_action_(kContinue), |
| 1265 resume_frame_index_(-1), | |
| 1266 post_deopt_frame_index_(-1), | |
| 1267 ignore_breakpoints_(false), | 1240 ignore_breakpoints_(false), |
| 1268 pause_event_(NULL), | 1241 pause_event_(NULL), |
| 1269 obj_cache_(NULL), | 1242 obj_cache_(NULL), |
| 1270 stack_trace_(NULL), | 1243 stack_trace_(NULL), |
| 1271 stepping_fp_(0), | 1244 stepping_fp_(0), |
| 1272 skip_next_step_(false), | 1245 skip_next_step_(false), |
| 1273 synthetic_async_breakpoint_(NULL), | 1246 synthetic_async_breakpoint_(NULL), |
| 1274 exc_pause_info_(kNoPauseOnExceptions) {} | 1247 exc_pause_info_(kNoPauseOnExceptions) {} |
| 1275 | 1248 |
| 1276 | 1249 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 const String& fname) { | 1293 const String& fname) { |
| 1321 ASSERT(!library.IsNull()); | 1294 ASSERT(!library.IsNull()); |
| 1322 const Object& object = Object::Handle(library.ResolveName(fname)); | 1295 const Object& object = Object::Handle(library.ResolveName(fname)); |
| 1323 if (!object.IsNull() && object.IsFunction()) { | 1296 if (!object.IsNull() && object.IsFunction()) { |
| 1324 return Function::Cast(object).raw(); | 1297 return Function::Cast(object).raw(); |
| 1325 } | 1298 } |
| 1326 return Function::null(); | 1299 return Function::null(); |
| 1327 } | 1300 } |
| 1328 | 1301 |
| 1329 | 1302 |
| 1330 bool Debugger::SetupStepOverAsyncSuspension(const char** error) { | 1303 bool Debugger::SetupStepOverAsyncSuspension() { |
| 1331 ActivationFrame* top_frame = TopDartFrame(); | 1304 ActivationFrame* top_frame = TopDartFrame(); |
| 1332 if (!IsAtAsyncJump(top_frame)) { | 1305 if (!IsAtAsyncJump(top_frame)) { |
| 1333 // Not at an async operation. | 1306 // Not at an async operation. |
| 1334 if (error) { | |
| 1335 *error = "Isolate must be paused at an async suspension point"; | |
| 1336 } | |
| 1337 return false; | 1307 return false; |
| 1338 } | 1308 } |
| 1339 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); | 1309 Object& closure = Object::Handle(top_frame->GetAsyncOperation()); |
| 1340 ASSERT(!closure.IsNull()); | 1310 ASSERT(!closure.IsNull()); |
| 1341 ASSERT(closure.IsInstance()); | 1311 ASSERT(closure.IsInstance()); |
| 1342 ASSERT(Instance::Cast(closure).IsClosure()); | 1312 ASSERT(Instance::Cast(closure).IsClosure()); |
| 1343 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); | 1313 Breakpoint* bpt = SetBreakpointAtActivation(Instance::Cast(closure), true); |
| 1344 if (bpt == NULL) { | 1314 if (bpt == NULL) { |
| 1345 // Unable to set the breakpoint. | 1315 // Unable to set the breakpoint. |
| 1346 if (error) { | |
| 1347 *error = "Unable to set breakpoint at async suspension point"; | |
| 1348 } | |
| 1349 return false; | 1316 return false; |
| 1350 } | 1317 } |
| 1351 return true; | 1318 return true; |
| 1352 } | 1319 } |
| 1353 | 1320 |
| 1354 | 1321 |
| 1355 bool Debugger::SetResumeAction(ResumeAction action, | 1322 void Debugger::SetSingleStep() { |
| 1356 intptr_t frame_index, | 1323 resume_action_ = kSingleStep; |
| 1357 const char** error) { | |
| 1358 if (error) { | |
| 1359 *error = NULL; | |
| 1360 } | |
| 1361 resume_frame_index_ = -1; | |
| 1362 switch (action) { | |
| 1363 case kStepInto: | |
| 1364 case kStepOver: | |
| 1365 case kStepOut: | |
| 1366 case kContinue: | |
| 1367 resume_action_ = action; | |
| 1368 return true; | |
| 1369 case kStepRewind: | |
| 1370 if (!CanRewindFrame(frame_index, error)) { | |
| 1371 return false; | |
| 1372 } | |
| 1373 resume_action_ = kStepRewind; | |
| 1374 resume_frame_index_ = frame_index; | |
| 1375 return true; | |
| 1376 case kStepOverAsyncSuspension: | |
| 1377 return SetupStepOverAsyncSuspension(error); | |
| 1378 default: | |
| 1379 UNREACHABLE(); | |
| 1380 return false; | |
| 1381 } | |
| 1382 } | 1324 } |
| 1383 | 1325 |
| 1384 | 1326 |
| 1327 void Debugger::SetStepOver() { |
| 1328 resume_action_ = kStepOver; |
| 1329 } |
| 1330 |
| 1331 |
| 1332 void Debugger::SetStepOut() { |
| 1333 resume_action_ = kStepOut; |
| 1334 } |
| 1335 |
| 1336 |
| 1385 RawFunction* Debugger::ResolveFunction(const Library& library, | 1337 RawFunction* Debugger::ResolveFunction(const Library& library, |
| 1386 const String& class_name, | 1338 const String& class_name, |
| 1387 const String& function_name) { | 1339 const String& function_name) { |
| 1388 ASSERT(!library.IsNull()); | 1340 ASSERT(!library.IsNull()); |
| 1389 ASSERT(!class_name.IsNull()); | 1341 ASSERT(!class_name.IsNull()); |
| 1390 ASSERT(!function_name.IsNull()); | 1342 ASSERT(!function_name.IsNull()); |
| 1391 if (class_name.Length() == 0) { | 1343 if (class_name.Length() == 0) { |
| 1392 return ResolveLibraryFunction(library, function_name); | 1344 return ResolveLibraryFunction(library, function_name); |
| 1393 } | 1345 } |
| 1394 const Class& cls = Class::Handle(library.LookupClass(class_name)); | 1346 const Class& cls = Class::Handle(library.LookupClass(class_name)); |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1663 return; | 1615 return; |
| 1664 } | 1616 } |
| 1665 ServiceEvent event(isolate_, ServiceEvent::kPauseException); | 1617 ServiceEvent event(isolate_, ServiceEvent::kPauseException); |
| 1666 event.set_exception(&exc); | 1618 event.set_exception(&exc); |
| 1667 if (stack_trace->Length() > 0) { | 1619 if (stack_trace->Length() > 0) { |
| 1668 event.set_top_frame(stack_trace->FrameAt(0)); | 1620 event.set_top_frame(stack_trace->FrameAt(0)); |
| 1669 } | 1621 } |
| 1670 ASSERT(stack_trace_ == NULL); | 1622 ASSERT(stack_trace_ == NULL); |
| 1671 stack_trace_ = stack_trace; | 1623 stack_trace_ = stack_trace; |
| 1672 Pause(&event); | 1624 Pause(&event); |
| 1673 HandleSteppingRequest(stack_trace_); // we may get a rewind request | |
| 1674 stack_trace_ = NULL; | 1625 stack_trace_ = NULL; |
| 1675 } | 1626 } |
| 1676 | 1627 |
| 1677 | 1628 |
| 1678 static TokenPosition LastTokenOnLine(Zone* zone, | 1629 static TokenPosition LastTokenOnLine(Zone* zone, |
| 1679 const TokenStream& tokens, | 1630 const TokenStream& tokens, |
| 1680 TokenPosition pos) { | 1631 TokenPosition pos) { |
| 1681 TokenStream::Iterator iter(zone, tokens, pos, | 1632 TokenStream::Iterator iter(zone, tokens, pos, |
| 1682 TokenStream::Iterator::kAllTokens); | 1633 TokenStream::Iterator::kAllTokens); |
| 1683 ASSERT(iter.IsValid()); | 1634 ASSERT(iter.IsValid()); |
| (...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2589 void Debugger::EnterSingleStepMode() { | 2540 void Debugger::EnterSingleStepMode() { |
| 2590 stepping_fp_ = 0; | 2541 stepping_fp_ = 0; |
| 2591 DeoptimizeWorld(); | 2542 DeoptimizeWorld(); |
| 2592 isolate_->set_single_step(true); | 2543 isolate_->set_single_step(true); |
| 2593 } | 2544 } |
| 2594 | 2545 |
| 2595 | 2546 |
| 2596 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, | 2547 void Debugger::HandleSteppingRequest(DebuggerStackTrace* stack_trace, |
| 2597 bool skip_next_step) { | 2548 bool skip_next_step) { |
| 2598 stepping_fp_ = 0; | 2549 stepping_fp_ = 0; |
| 2599 if (resume_action_ == kStepInto) { | 2550 if (resume_action_ == kSingleStep) { |
| 2600 // When single stepping, we need to deoptimize because we might be | 2551 // When single stepping, we need to deoptimize because we might be |
| 2601 // stepping into optimized code. This happens in particular if | 2552 // stepping into optimized code. This happens in particular if |
| 2602 // the isolate has been interrupted, but can happen in other cases | 2553 // the isolate has been interrupted, but can happen in other cases |
| 2603 // as well. We need to deoptimize the world in case we are about | 2554 // as well. We need to deoptimize the world in case we are about |
| 2604 // to call an optimized function. | 2555 // to call an optimized function. |
| 2605 DeoptimizeWorld(); | 2556 DeoptimizeWorld(); |
| 2606 isolate_->set_single_step(true); | 2557 isolate_->set_single_step(true); |
| 2607 skip_next_step_ = skip_next_step; | 2558 skip_next_step_ = skip_next_step; |
| 2608 if (FLAG_verbose_debug) { | 2559 if (FLAG_verbose_debug) { |
| 2609 OS::Print("HandleSteppingRequest- kStepInto\n"); | 2560 OS::Print("HandleSteppingRequest- kSingleStep\n"); |
| 2610 } | 2561 } |
| 2611 } else if (resume_action_ == kStepOver) { | 2562 } else if (resume_action_ == kStepOver) { |
| 2612 DeoptimizeWorld(); | 2563 DeoptimizeWorld(); |
| 2613 isolate_->set_single_step(true); | 2564 isolate_->set_single_step(true); |
| 2614 skip_next_step_ = skip_next_step; | 2565 skip_next_step_ = skip_next_step; |
| 2615 ASSERT(stack_trace->Length() > 0); | 2566 ASSERT(stack_trace->Length() > 0); |
| 2616 stepping_fp_ = stack_trace->FrameAt(0)->fp(); | 2567 stepping_fp_ = stack_trace->FrameAt(0)->fp(); |
| 2617 if (FLAG_verbose_debug) { | 2568 if (FLAG_verbose_debug) { |
| 2618 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); | 2569 OS::Print("HandleSteppingRequest- kStepOver %" Px "\n", stepping_fp_); |
| 2619 } | 2570 } |
| 2620 } else if (resume_action_ == kStepOut) { | 2571 } else if (resume_action_ == kStepOut) { |
| 2621 DeoptimizeWorld(); | 2572 DeoptimizeWorld(); |
| 2622 isolate_->set_single_step(true); | 2573 isolate_->set_single_step(true); |
| 2623 // Find topmost caller that is debuggable. | 2574 // Find topmost caller that is debuggable. |
| 2624 for (intptr_t i = 1; i < stack_trace->Length(); i++) { | 2575 for (intptr_t i = 1; i < stack_trace->Length(); i++) { |
| 2625 ActivationFrame* frame = stack_trace->FrameAt(i); | 2576 ActivationFrame* frame = stack_trace->FrameAt(i); |
| 2626 if (frame->IsDebuggable()) { | 2577 if (frame->IsDebuggable()) { |
| 2627 stepping_fp_ = frame->fp(); | 2578 stepping_fp_ = frame->fp(); |
| 2628 break; | 2579 break; |
| 2629 } | 2580 } |
| 2630 } | 2581 } |
| 2631 if (FLAG_verbose_debug) { | 2582 if (FLAG_verbose_debug) { |
| 2632 OS::Print("HandleSteppingRequest- kStepOut %" Px "\n", stepping_fp_); | 2583 OS::Print("HandleSteppingRequest- kStepOut %" Px "\n", stepping_fp_); |
| 2633 } | 2584 } |
| 2634 } else if (resume_action_ == kStepRewind) { | |
| 2635 if (FLAG_trace_rewind) { | |
| 2636 OS::PrintErr("Rewinding to frame %" Pd "\n", resume_frame_index_); | |
| 2637 OS::PrintErr( | |
| 2638 "-------------------------\n" | |
| 2639 "All frames...\n\n"); | |
| 2640 StackFrameIterator iterator(false); | |
| 2641 StackFrame* frame = iterator.NextFrame(); | |
| 2642 intptr_t num = 0; | |
| 2643 while ((frame != NULL)) { | |
| 2644 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); | |
| 2645 frame = iterator.NextFrame(); | |
| 2646 } | |
| 2647 } | |
| 2648 RewindToFrame(resume_frame_index_); | |
| 2649 UNREACHABLE(); | |
| 2650 } | |
| 2651 } | |
| 2652 | |
| 2653 | |
| 2654 static intptr_t FindNextRewindFrameIndex(DebuggerStackTrace* stack, | |
| 2655 intptr_t frame_index) { | |
| 2656 for (intptr_t i = frame_index + 1; i < stack->Length(); i++) { | |
| 2657 ActivationFrame* frame = stack->FrameAt(i); | |
| 2658 if (frame->IsRewindable()) { | |
| 2659 return i; | |
| 2660 } | |
| 2661 } | |
| 2662 return -1; | |
| 2663 } | |
| 2664 | |
| 2665 | |
| 2666 // Can the top frame be rewound? | |
| 2667 bool Debugger::CanRewindFrame(intptr_t frame_index, const char** error) const { | |
| 2668 // check rewind pc is found | |
| 2669 DebuggerStackTrace* stack = Isolate::Current()->debugger()->StackTrace(); | |
| 2670 intptr_t num_frames = stack->Length(); | |
| 2671 if (frame_index < 1 || frame_index >= num_frames) { | |
| 2672 if (error) { | |
| 2673 *error = Thread::Current()->zone()->PrintToString( | |
| 2674 "Frame must be in bounds [1..%" Pd | |
| 2675 "]: " | |
| 2676 "saw %" Pd "", | |
| 2677 num_frames - 1, frame_index); | |
| 2678 } | |
| 2679 return false; | |
| 2680 } | |
| 2681 ActivationFrame* frame = stack->FrameAt(frame_index); | |
| 2682 if (!frame->IsRewindable()) { | |
| 2683 intptr_t next_index = FindNextRewindFrameIndex(stack, frame_index); | |
| 2684 if (next_index > 0) { | |
| 2685 *error = Thread::Current()->zone()->PrintToString( | |
| 2686 "Cannot rewind to frame %" Pd | |
| 2687 " due to conflicting compiler " | |
| 2688 "optimizations. " | |
| 2689 "Run the vm with --no-prune-dead-locals to disallow these " | |
| 2690 "optimizations. " | |
| 2691 "Next valid rewind frame is %" Pd ".", | |
| 2692 frame_index, next_index); | |
| 2693 } else { | |
| 2694 *error = Thread::Current()->zone()->PrintToString( | |
| 2695 "Cannot rewind to frame %" Pd | |
| 2696 " due to conflicting compiler " | |
| 2697 "optimizations. " | |
| 2698 "Run the vm with --no-prune-dead-locals to disallow these " | |
| 2699 "optimizations.", | |
| 2700 frame_index); | |
| 2701 } | |
| 2702 return false; | |
| 2703 } | |
| 2704 return true; | |
| 2705 } | |
| 2706 | |
| 2707 | |
| 2708 // Given a return address pc, find the "rewind" pc, which is the pc | |
| 2709 // before the corresponding call. | |
| 2710 static uword LookupRewindPc(const Code& code, uword pc) { | |
| 2711 ASSERT(!code.is_optimized()); | |
| 2712 ASSERT(code.ContainsInstructionAt(pc)); | |
| 2713 | |
| 2714 uword pc_offset = pc - code.PayloadStart(); | |
| 2715 const PcDescriptors& descriptors = | |
| 2716 PcDescriptors::Handle(code.pc_descriptors()); | |
| 2717 PcDescriptors::Iterator iter( | |
| 2718 descriptors, RawPcDescriptors::kRewind | RawPcDescriptors::kIcCall | | |
| 2719 RawPcDescriptors::kUnoptStaticCall); | |
| 2720 intptr_t rewind_deopt_id = -1; | |
| 2721 uword rewind_pc = 0; | |
| 2722 while (iter.MoveNext()) { | |
| 2723 if (iter.Kind() == RawPcDescriptors::kRewind) { | |
| 2724 // Remember the last rewind so we don't need to iterator twice. | |
| 2725 rewind_pc = code.PayloadStart() + iter.PcOffset(); | |
| 2726 rewind_deopt_id = iter.DeoptId(); | |
| 2727 } | |
| 2728 if ((pc_offset == iter.PcOffset()) && (iter.DeoptId() == rewind_deopt_id)) { | |
| 2729 return rewind_pc; | |
| 2730 } | |
| 2731 } | |
| 2732 return 0; | |
| 2733 } | |
| 2734 | |
| 2735 | |
| 2736 void Debugger::RewindToFrame(intptr_t frame_index) { | |
| 2737 Thread* thread = Thread::Current(); | |
| 2738 Zone* zone = thread->zone(); | |
| 2739 Code& code = Code::Handle(zone); | |
| 2740 Function& function = Function::Handle(zone); | |
| 2741 | |
| 2742 // Find the requested frame. | |
| 2743 StackFrameIterator iterator(false); | |
| 2744 intptr_t current_frame = 0; | |
| 2745 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; | |
| 2746 frame = iterator.NextFrame()) { | |
| 2747 ASSERT(frame->IsValid()); | |
| 2748 if (frame->IsDartFrame()) { | |
| 2749 code = frame->LookupDartCode(); | |
| 2750 function = code.function(); | |
| 2751 if (!IsFunctionVisible(function)) { | |
| 2752 continue; | |
| 2753 } | |
| 2754 if (code.is_optimized()) { | |
| 2755 intptr_t sub_index = 0; | |
| 2756 for (InlinedFunctionsIterator it(code, frame->pc()); !it.Done(); | |
| 2757 it.Advance()) { | |
| 2758 if (current_frame == frame_index) { | |
| 2759 RewindToOptimizedFrame(frame, code, sub_index); | |
| 2760 UNREACHABLE(); | |
| 2761 } | |
| 2762 current_frame++; | |
| 2763 sub_index++; | |
| 2764 } | |
| 2765 } else { | |
| 2766 if (current_frame == frame_index) { | |
| 2767 // We are rewinding to an unoptimized frame. | |
| 2768 RewindToUnoptimizedFrame(frame, code); | |
| 2769 UNREACHABLE(); | |
| 2770 } | |
| 2771 current_frame++; | |
| 2772 } | |
| 2773 } | |
| 2774 } | |
| 2775 UNIMPLEMENTED(); | |
| 2776 } | |
| 2777 | |
| 2778 | |
| 2779 void Debugger::RewindToUnoptimizedFrame(StackFrame* frame, const Code& code) { | |
| 2780 // We will be jumping out of the debugger rather than exiting this | |
| 2781 // function, so prepare the debugger state. | |
| 2782 stack_trace_ = NULL; | |
| 2783 resume_action_ = kContinue; | |
| 2784 resume_frame_index_ = -1; | |
| 2785 EnterSingleStepMode(); | |
| 2786 | |
| 2787 uword rewind_pc = LookupRewindPc(code, frame->pc()); | |
| 2788 if (FLAG_trace_rewind && rewind_pc == 0) { | |
| 2789 OS::PrintErr("Unable to find rewind pc for pc(%" Px ")\n", frame->pc()); | |
| 2790 } | |
| 2791 ASSERT(rewind_pc != 0); | |
| 2792 if (FLAG_trace_rewind) { | |
| 2793 OS::PrintErr( | |
| 2794 "===============================\n" | |
| 2795 "Rewinding to unoptimized frame:\n" | |
| 2796 " rewind_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | |
| 2797 ")\n" | |
| 2798 "===============================\n", | |
| 2799 rewind_pc, frame->sp(), frame->fp()); | |
| 2800 } | |
| 2801 Exceptions::JumpToFrame(Thread::Current(), rewind_pc, frame->sp(), | |
| 2802 frame->fp(), true /* clear lazy deopt at target */); | |
| 2803 UNREACHABLE(); | |
| 2804 } | |
| 2805 | |
| 2806 | |
| 2807 void Debugger::RewindToOptimizedFrame(StackFrame* frame, | |
| 2808 const Code& optimized_code, | |
| 2809 intptr_t sub_index) { | |
| 2810 post_deopt_frame_index_ = sub_index; | |
| 2811 | |
| 2812 // We will be jumping out of the debugger rather than exiting this | |
| 2813 // function, so prepare the debugger state. | |
| 2814 stack_trace_ = NULL; | |
| 2815 resume_action_ = kContinue; | |
| 2816 resume_frame_index_ = -1; | |
| 2817 EnterSingleStepMode(); | |
| 2818 | |
| 2819 if (FLAG_trace_rewind) { | |
| 2820 OS::PrintErr( | |
| 2821 "===============================\n" | |
| 2822 "Deoptimizing frame for rewind:\n" | |
| 2823 " deopt_pc(0x%" Px ") sp(0x%" Px ") fp(0x%" Px | |
| 2824 ")\n" | |
| 2825 "===============================\n", | |
| 2826 frame->pc(), frame->sp(), frame->fp()); | |
| 2827 } | |
| 2828 Thread* thread = Thread::Current(); | |
| 2829 thread->set_resume_pc(frame->pc()); | |
| 2830 uword deopt_stub_pc = StubCode::DeoptForRewind_entry()->EntryPoint(); | |
| 2831 Exceptions::JumpToFrame(thread, deopt_stub_pc, frame->sp(), frame->fp(), | |
| 2832 true /* clear lazy deopt at target */); | |
| 2833 UNREACHABLE(); | |
| 2834 } | |
| 2835 | |
| 2836 | |
| 2837 void Debugger::RewindPostDeopt() { | |
| 2838 intptr_t rewind_frame = post_deopt_frame_index_; | |
| 2839 post_deopt_frame_index_ = -1; | |
| 2840 if (FLAG_trace_rewind) { | |
| 2841 OS::PrintErr("Post deopt, jumping to frame %" Pd "\n", rewind_frame); | |
| 2842 OS::PrintErr( | |
| 2843 "-------------------------\n" | |
| 2844 "All frames...\n\n"); | |
| 2845 StackFrameIterator iterator(false); | |
| 2846 StackFrame* frame = iterator.NextFrame(); | |
| 2847 intptr_t num = 0; | |
| 2848 while ((frame != NULL)) { | |
| 2849 OS::PrintErr("#%04" Pd " %s\n", num++, frame->ToCString()); | |
| 2850 frame = iterator.NextFrame(); | |
| 2851 } | |
| 2852 } | |
| 2853 | |
| 2854 Thread* thread = Thread::Current(); | |
| 2855 Zone* zone = thread->zone(); | |
| 2856 Code& code = Code::Handle(zone); | |
| 2857 | |
| 2858 StackFrameIterator iterator(false); | |
| 2859 intptr_t current_frame = 0; | |
| 2860 for (StackFrame* frame = iterator.NextFrame(); frame != NULL; | |
| 2861 frame = iterator.NextFrame()) { | |
| 2862 ASSERT(frame->IsValid()); | |
| 2863 if (frame->IsDartFrame()) { | |
| 2864 code = frame->LookupDartCode(); | |
| 2865 ASSERT(!code.is_optimized()); | |
| 2866 if (current_frame == rewind_frame) { | |
| 2867 RewindToUnoptimizedFrame(frame, code); | |
| 2868 UNREACHABLE(); | |
| 2869 } | |
| 2870 current_frame++; | |
| 2871 } | |
| 2872 } | 2585 } |
| 2873 } | 2586 } |
| 2874 | 2587 |
| 2875 | 2588 |
| 2876 // static | 2589 // static |
| 2877 bool Debugger::IsDebuggable(const Function& func) { | 2590 bool Debugger::IsDebuggable(const Function& func) { |
| 2878 if (!func.is_debuggable()) { | 2591 if (!func.is_debuggable()) { |
| 2879 return false; | 2592 return false; |
| 2880 } | 2593 } |
| 2881 const Class& cls = Class::Handle(func.Owner()); | 2594 const Class& cls = Class::Handle(func.Owner()); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3073 cbpt->LineNumber(), cbpt->token_pos().ToCString(), | 2786 cbpt->LineNumber(), cbpt->token_pos().ToCString(), |
| 3074 top_frame->pc()); | 2787 top_frame->pc()); |
| 3075 } | 2788 } |
| 3076 | 2789 |
| 3077 ASSERT(synthetic_async_breakpoint_ == NULL); | 2790 ASSERT(synthetic_async_breakpoint_ == NULL); |
| 3078 synthetic_async_breakpoint_ = bpt_hit; | 2791 synthetic_async_breakpoint_ = bpt_hit; |
| 3079 bpt_hit = NULL; | 2792 bpt_hit = NULL; |
| 3080 | 2793 |
| 3081 // We are at the entry of an async function. | 2794 // We are at the entry of an async function. |
| 3082 // We issue a step over to resume at the point after the await statement. | 2795 // We issue a step over to resume at the point after the await statement. |
| 3083 SetResumeAction(kStepOver); | 2796 SetStepOver(); |
| 3084 // When we single step from a user breakpoint, our next stepping | 2797 // When we single step from a user breakpoint, our next stepping |
| 3085 // point will be at the exact same pc. Skip it. | 2798 // point will be at the exact same pc. Skip it. |
| 3086 HandleSteppingRequest(stack_trace_, true /* skip next step */); | 2799 HandleSteppingRequest(stack_trace_, true /* skip next step */); |
| 3087 stack_trace_ = NULL; | 2800 stack_trace_ = NULL; |
| 3088 return Error::null(); | 2801 return Error::null(); |
| 3089 } | 2802 } |
| 3090 | 2803 |
| 3091 if (FLAG_verbose_debug) { | 2804 if (FLAG_verbose_debug) { |
| 3092 OS::Print(">>> hit %s breakpoint at %s:%" Pd | 2805 OS::Print(">>> hit %s breakpoint at %s:%" Pd |
| 3093 " " | 2806 " " |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3126 DebuggerStackTrace* stack_trace = CollectStackTrace(); | 2839 DebuggerStackTrace* stack_trace = CollectStackTrace(); |
| 3127 ASSERT(stack_trace->Length() > 0); | 2840 ASSERT(stack_trace->Length() > 0); |
| 3128 ASSERT(stack_trace_ == NULL); | 2841 ASSERT(stack_trace_ == NULL); |
| 3129 stack_trace_ = stack_trace; | 2842 stack_trace_ = stack_trace; |
| 3130 | 2843 |
| 3131 // TODO(johnmccutchan): Send |msg| to Observatory. | 2844 // TODO(johnmccutchan): Send |msg| to Observatory. |
| 3132 | 2845 |
| 3133 // We are in the native call to Developer_debugger. the developer | 2846 // We are in the native call to Developer_debugger. the developer |
| 3134 // gets a better experience by not seeing this call. To accomplish | 2847 // gets a better experience by not seeing this call. To accomplish |
| 3135 // this, we continue execution until the call exits (step out). | 2848 // this, we continue execution until the call exits (step out). |
| 3136 SetResumeAction(kStepOut); | 2849 SetStepOut(); |
| 3137 HandleSteppingRequest(stack_trace_); | 2850 HandleSteppingRequest(stack_trace_); |
| 3138 | 2851 |
| 3139 stack_trace_ = NULL; | 2852 stack_trace_ = NULL; |
| 3140 } | 2853 } |
| 3141 | 2854 |
| 3142 | 2855 |
| 3143 void Debugger::Initialize(Isolate* isolate) { | 2856 void Debugger::Initialize(Isolate* isolate) { |
| 3144 if (initialized_) { | 2857 if (initialized_) { |
| 3145 return; | 2858 return; |
| 3146 } | 2859 } |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3579 | 3292 |
| 3580 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 3293 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 3581 ASSERT(bpt->next() == NULL); | 3294 ASSERT(bpt->next() == NULL); |
| 3582 bpt->set_next(code_breakpoints_); | 3295 bpt->set_next(code_breakpoints_); |
| 3583 code_breakpoints_ = bpt; | 3296 code_breakpoints_ = bpt; |
| 3584 } | 3297 } |
| 3585 | 3298 |
| 3586 #endif // !PRODUCT | 3299 #endif // !PRODUCT |
| 3587 | 3300 |
| 3588 } // namespace dart | 3301 } // namespace dart |
| OLD | NEW |