OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/debug.h" | 5 #include "src/debug/debug.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 // Get the debug info (create it if it does not exist). | 437 // Get the debug info (create it if it does not exist). |
438 Handle<JSFunction> function(frame->function()); | 438 Handle<JSFunction> function(frame->function()); |
439 Handle<SharedFunctionInfo> shared(function->shared()); | 439 Handle<SharedFunctionInfo> shared(function->shared()); |
440 if (!EnsureDebugInfo(shared, function)) { | 440 if (!EnsureDebugInfo(shared, function)) { |
441 // Return if we failed to retrieve the debug info. | 441 // Return if we failed to retrieve the debug info. |
442 return; | 442 return; |
443 } | 443 } |
444 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 444 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
445 | 445 |
446 // Find the break location where execution has stopped. | 446 // Find the break location where execution has stopped. |
447 // PC points to the instruction after the current one, possibly a break | 447 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
448 // location as well. So the "- 1" to exclude it from the search. | |
449 Address call_pc = frame->pc() - 1; | |
450 BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc); | |
451 | 448 |
452 // Find actual break points, if any, and trigger debug break event. | 449 // Find actual break points, if any, and trigger debug break event. |
453 if (break_points_active_ && location.HasBreakPoint()) { | 450 Handle<Object> break_points_hit = CheckBreakPoints(&location); |
454 Handle<Object> break_point_objects = location.BreakPointObjects(); | 451 if (!break_points_hit->IsUndefined()) { |
455 Handle<Object> break_points_hit = CheckBreakPoints(break_point_objects); | 452 // Clear all current stepping setup. |
456 if (!break_points_hit->IsUndefined()) { | 453 ClearStepping(); |
457 // Clear all current stepping setup. | 454 // Notify the debug event listeners. |
458 ClearStepping(); | 455 OnDebugBreak(break_points_hit, false); |
459 // Notify the debug event listeners. | 456 return; |
460 OnDebugBreak(break_points_hit, false); | |
461 return; | |
462 } | |
463 } | 457 } |
464 | 458 |
465 // No break point. Check for stepping. | 459 // No break point. Check for stepping. |
466 StepAction step_action = last_step_action(); | 460 StepAction step_action = last_step_action(); |
467 Address current_fp = frame->UnpaddedFP(); | 461 Address current_fp = frame->UnpaddedFP(); |
468 Address target_fp = thread_local_.target_fp_; | 462 Address target_fp = thread_local_.target_fp_; |
469 Address last_fp = thread_local_.last_fp_; | 463 Address last_fp = thread_local_.last_fp_; |
470 | 464 |
471 bool step_break = true; | 465 bool step_break = true; |
472 switch (step_action) { | 466 switch (step_action) { |
(...skipping 23 matching lines...) Expand all Loading... |
496 if (step_break) { | 490 if (step_break) { |
497 // Notify the debug event listeners. | 491 // Notify the debug event listeners. |
498 OnDebugBreak(isolate_->factory()->undefined_value(), false); | 492 OnDebugBreak(isolate_->factory()->undefined_value(), false); |
499 } else { | 493 } else { |
500 // Re-prepare to continue. | 494 // Re-prepare to continue. |
501 PrepareStep(step_action); | 495 PrepareStep(step_action); |
502 } | 496 } |
503 } | 497 } |
504 | 498 |
505 | 499 |
506 // Check the break point objects for whether one or more are actually | 500 // Find break point objects for this location, if any, and evaluate them. |
507 // triggered. This function returns a JSArray with the break point objects | 501 // Return an array of break point objects that evaluated true. |
508 // which is triggered. | 502 Handle<Object> Debug::CheckBreakPoints(BreakLocation* location, |
509 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { | 503 bool* has_break_points) { |
510 Factory* factory = isolate_->factory(); | 504 Factory* factory = isolate_->factory(); |
| 505 bool has_break_points_to_check = |
| 506 break_points_active_ && location->HasBreakPoint(); |
| 507 if (has_break_points) *has_break_points = has_break_points_to_check; |
| 508 if (!has_break_points_to_check) return factory->undefined_value(); |
511 | 509 |
| 510 Handle<Object> break_point_objects = location->BreakPointObjects(); |
512 // Count the number of break points hit. If there are multiple break points | 511 // Count the number of break points hit. If there are multiple break points |
513 // they are in a FixedArray. | 512 // they are in a FixedArray. |
514 Handle<FixedArray> break_points_hit; | 513 Handle<FixedArray> break_points_hit; |
515 int break_points_hit_count = 0; | 514 int break_points_hit_count = 0; |
516 DCHECK(!break_point_objects->IsUndefined()); | 515 DCHECK(!break_point_objects->IsUndefined()); |
517 if (break_point_objects->IsFixedArray()) { | 516 if (break_point_objects->IsFixedArray()) { |
518 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); | 517 Handle<FixedArray> array(FixedArray::cast(*break_point_objects)); |
519 break_points_hit = factory->NewFixedArray(array->length()); | 518 break_points_hit = factory->NewFixedArray(array->length()); |
520 for (int i = 0; i < array->length(); i++) { | 519 for (int i = 0; i < array->length(); i++) { |
521 Handle<Object> o(array->get(i), isolate_); | 520 Handle<Object> break_point_object(array->get(i), isolate_); |
522 if (CheckBreakPoint(o)) { | 521 if (CheckBreakPoint(break_point_object)) { |
523 break_points_hit->set(break_points_hit_count++, *o); | 522 break_points_hit->set(break_points_hit_count++, *break_point_object); |
524 } | 523 } |
525 } | 524 } |
526 } else { | 525 } else { |
527 break_points_hit = factory->NewFixedArray(1); | 526 break_points_hit = factory->NewFixedArray(1); |
528 if (CheckBreakPoint(break_point_objects)) { | 527 if (CheckBreakPoint(break_point_objects)) { |
529 break_points_hit->set(break_points_hit_count++, *break_point_objects); | 528 break_points_hit->set(break_points_hit_count++, *break_point_objects); |
530 } | 529 } |
531 } | 530 } |
532 | 531 if (break_points_hit_count == 0) return factory->undefined_value(); |
533 // Return undefined if no break points were triggered. | |
534 if (break_points_hit_count == 0) { | |
535 return factory->undefined_value(); | |
536 } | |
537 // Return break points hit as a JSArray. | |
538 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit); | 532 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit); |
539 result->set_length(Smi::FromInt(break_points_hit_count)); | 533 result->set_length(Smi::FromInt(break_points_hit_count)); |
540 return result; | 534 return result; |
541 } | 535 } |
542 | 536 |
543 | 537 |
| 538 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { |
| 539 // A break location is considered muted if the break location has break |
| 540 // points, but their conditions all evaluate to false. |
| 541 // Aside from not triggering a debug break event at the break location, |
| 542 // we also do not trigger one for debugger statements, nor an exception event |
| 543 // on exception at this location. |
| 544 Object* fun = frame->function(); |
| 545 if (!fun->IsJSFunction()) return false; |
| 546 JSFunction* function = JSFunction::cast(fun); |
| 547 if (!function->shared()->HasDebugInfo()) return false; |
| 548 HandleScope scope(isolate_); |
| 549 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); |
| 550 // Enter the debugger. |
| 551 DebugScope debug_scope(this); |
| 552 if (debug_scope.failed()) return false; |
| 553 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
| 554 bool has_break_points; |
| 555 Handle<Object> check_result = CheckBreakPoints(&location, &has_break_points); |
| 556 return has_break_points && check_result->IsUndefined(); |
| 557 } |
| 558 |
| 559 |
544 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, | 560 MaybeHandle<Object> Debug::CallFunction(const char* name, int argc, |
545 Handle<Object> args[]) { | 561 Handle<Object> args[]) { |
546 PostponeInterruptsScope no_interrupts(isolate_); | 562 PostponeInterruptsScope no_interrupts(isolate_); |
547 AssertDebugContext(); | 563 AssertDebugContext(); |
548 Handle<Object> holder = isolate_->natives_utils_object(); | 564 Handle<Object> holder = isolate_->natives_utils_object(); |
549 Handle<JSFunction> fun = Handle<JSFunction>::cast( | 565 Handle<JSFunction> fun = Handle<JSFunction>::cast( |
550 Object::GetProperty(isolate_, holder, name, STRICT).ToHandleChecked()); | 566 Object::GetProperty(isolate_, holder, name, STRICT).ToHandleChecked()); |
551 Handle<Object> undefined = isolate_->factory()->undefined_value(); | 567 Handle<Object> undefined = isolate_->factory()->undefined_value(); |
552 return Execution::TryCall(isolate_, fun, undefined, argc, args); | 568 return Execution::TryCall(isolate_, fun, undefined, argc, args); |
553 } | 569 } |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
840 // Return if ensuring debug info failed. | 856 // Return if ensuring debug info failed. |
841 return; | 857 return; |
842 } | 858 } |
843 | 859 |
844 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 860 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
845 // Refresh frame summary if the code has been recompiled for debugging. | 861 // Refresh frame summary if the code has been recompiled for debugging. |
846 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); | 862 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame); |
847 | 863 |
848 // PC points to the instruction after the current one, possibly a break | 864 // PC points to the instruction after the current one, possibly a break |
849 // location as well. So the "- 1" to exclude it from the search. | 865 // location as well. So the "- 1" to exclude it from the search. |
850 Address call_pc = summary.pc() - 1; | 866 BreakLocation location = BreakLocation::FromFrame(debug_info, &summary); |
851 BreakLocation location = BreakLocation::FromAddress(debug_info, call_pc); | |
852 | 867 |
853 // At a return statement we will step out either way. | 868 // At a return statement we will step out either way. |
854 if (location.IsReturn()) step_action = StepOut; | 869 if (location.IsReturn()) step_action = StepOut; |
855 | 870 |
856 thread_local_.last_statement_position_ = | 871 thread_local_.last_statement_position_ = |
857 debug_info->code()->SourceStatementPosition(summary.pc()); | 872 debug_info->code()->SourceStatementPosition(summary.pc()); |
858 thread_local_.last_fp_ = frame->UnpaddedFP(); | 873 thread_local_.last_fp_ = frame->UnpaddedFP(); |
859 | 874 |
860 switch (step_action) { | 875 switch (step_action) { |
861 case StepNone: | 876 case StepNone: |
(...skipping 750 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1612 } | 1627 } |
1613 // Bail out if exception breaks are not active | 1628 // Bail out if exception breaks are not active |
1614 if (uncaught) { | 1629 if (uncaught) { |
1615 // Uncaught exceptions are reported by either flags. | 1630 // Uncaught exceptions are reported by either flags. |
1616 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; | 1631 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; |
1617 } else { | 1632 } else { |
1618 // Caught exceptions are reported is activated. | 1633 // Caught exceptions are reported is activated. |
1619 if (!break_on_exception_) return; | 1634 if (!break_on_exception_) return; |
1620 } | 1635 } |
1621 | 1636 |
| 1637 { |
| 1638 // Check whether the break location is muted. |
| 1639 JavaScriptFrameIterator it(isolate_); |
| 1640 if (!it.done() && IsMutedAtCurrentLocation(it.frame())) return; |
| 1641 } |
| 1642 |
1622 DebugScope debug_scope(this); | 1643 DebugScope debug_scope(this); |
1623 if (debug_scope.failed()) return; | 1644 if (debug_scope.failed()) return; |
1624 | 1645 |
1625 // Create the event data object. | 1646 // Create the event data object. |
1626 Handle<Object> event_data; | 1647 Handle<Object> event_data; |
1627 // Bail out and don't call debugger if exception. | 1648 // Bail out and don't call debugger if exception. |
1628 if (!MakeExceptionEvent( | 1649 if (!MakeExceptionEvent( |
1629 exception, uncaught, promise).ToHandle(&event_data)) { | 1650 exception, uncaught, promise).ToHandle(&event_data)) { |
1630 return; | 1651 return; |
1631 } | 1652 } |
1632 | 1653 |
1633 // Process debug event. | 1654 // Process debug event. |
1634 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); | 1655 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); |
1635 // Return to continue execution from where the exception was thrown. | 1656 // Return to continue execution from where the exception was thrown. |
1636 } | 1657 } |
1637 | 1658 |
1638 | 1659 |
1639 void Debug::OnDebugBreak(Handle<Object> break_points_hit, | 1660 void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) { |
1640 bool auto_continue) { | |
1641 // The caller provided for DebugScope. | 1661 // The caller provided for DebugScope. |
1642 AssertDebugContext(); | 1662 AssertDebugContext(); |
1643 // Bail out if there is no listener for this event | 1663 // Bail out if there is no listener for this event |
1644 if (ignore_events()) return; | 1664 if (ignore_events()) return; |
1645 | 1665 |
1646 HandleScope scope(isolate_); | 1666 HandleScope scope(isolate_); |
1647 // Create the event data object. | 1667 // Create the event data object. |
1648 Handle<Object> event_data; | 1668 Handle<Object> event_data; |
1649 // Bail out and don't call debugger if exception. | 1669 // Bail out and don't call debugger if exception. |
1650 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; | 1670 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; |
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2064 { JavaScriptFrameIterator it(isolate_); | 2084 { JavaScriptFrameIterator it(isolate_); |
2065 DCHECK(!it.done()); | 2085 DCHECK(!it.done()); |
2066 Object* fun = it.frame()->function(); | 2086 Object* fun = it.frame()->function(); |
2067 if (fun && fun->IsJSFunction()) { | 2087 if (fun && fun->IsJSFunction()) { |
2068 // Don't stop in builtin functions. | 2088 // Don't stop in builtin functions. |
2069 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; | 2089 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; |
2070 JSGlobalObject* global = | 2090 JSGlobalObject* global = |
2071 JSFunction::cast(fun)->context()->global_object(); | 2091 JSFunction::cast(fun)->context()->global_object(); |
2072 // Don't stop in debugger functions. | 2092 // Don't stop in debugger functions. |
2073 if (IsDebugGlobal(global)) return; | 2093 if (IsDebugGlobal(global)) return; |
| 2094 // Don't stop if the break location is muted. |
| 2095 if (IsMutedAtCurrentLocation(it.frame())) return; |
2074 } | 2096 } |
2075 } | 2097 } |
2076 | 2098 |
2077 // Collect the break state before clearing the flags. | 2099 // Collect the break state before clearing the flags. |
2078 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && | 2100 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && |
2079 !isolate_->stack_guard()->CheckDebugBreak(); | 2101 !isolate_->stack_guard()->CheckDebugBreak(); |
2080 | 2102 |
2081 isolate_->stack_guard()->ClearDebugBreak(); | 2103 isolate_->stack_guard()->ClearDebugBreak(); |
2082 | 2104 |
2083 // Clear stepping to avoid duplicate breaks. | 2105 // Clear stepping to avoid duplicate breaks. |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2405 } | 2427 } |
2406 | 2428 |
2407 | 2429 |
2408 void LockingCommandMessageQueue::Clear() { | 2430 void LockingCommandMessageQueue::Clear() { |
2409 base::LockGuard<base::Mutex> lock_guard(&mutex_); | 2431 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
2410 queue_.Clear(); | 2432 queue_.Clear(); |
2411 } | 2433 } |
2412 | 2434 |
2413 } // namespace internal | 2435 } // namespace internal |
2414 } // namespace v8 | 2436 } // namespace v8 |
OLD | NEW |