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