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 3 // found in the LICENSE file. 4 5 #ifndef V8_DEBUG_DEBUG_H_ 6 #define V8_DEBUG_DEBUG_H_ 7 8 #include "src/allocation.h" 9 #include "src/assembler.h" 10 #include "src/base/atomicops.h" 11 #include "src/base/hashmap.h" 12 #include "src/base/platform/platform.h" 13 #include "src/debug/debug-interface.h" 14 #include "src/debug/interface-types.h" 15 #include "src/execution.h" 16 #include "src/factory.h" 17 #include "src/flags.h" 18 #include "src/frames.h" 19 #include "src/globals.h" 20 #include "src/runtime/runtime.h" 21 #include "src/source-position-table.h" 22 #include "src/string-stream.h" 23 #include "src/v8threads.h" 24 25 #include "include/v8-debug.h" 26 27 namespace v8 { 28 namespace internal { 29 30 31 // Forward declarations. 32 class DebugScope; 33 34 35 // Step actions. NOTE: These values are in macros.py as well. 36 enum StepAction : int8_t { 37 StepNone = -1, // Stepping not prepared. 38 StepOut = 0, // Step out of the current function. 39 StepNext = 1, // Step to the next statement in the current function. 40 StepIn = 2, // Step into new functions invoked or the next statement 41 // in the current function. 42 LastStepAction = StepIn 43 }; 44 45 // Type of exception break. NOTE: These values are in macros.py as well. 46 enum ExceptionBreakType { 47 BreakException = 0, 48 BreakUncaughtException = 1 49 }; 50 51 52 // The different types of breakpoint position alignments. 53 // Must match Debug.BreakPositionAlignment in debug.js 54 enum BreakPositionAlignment { 55 STATEMENT_ALIGNED = 0, 56 BREAK_POSITION_ALIGNED = 1 57 }; 58 59 enum DebugBreakType { 60 NOT_DEBUG_BREAK, 61 DEBUGGER_STATEMENT, 62 DEBUG_BREAK_SLOT, 63 DEBUG_BREAK_SLOT_AT_CALL, 64 DEBUG_BREAK_SLOT_AT_RETURN, 65 DEBUG_BREAK_SLOT_AT_TAIL_CALL, 66 }; 67 68 class BreakLocation { 69 public: 70 static BreakLocation FromFrame(Handle<DebugInfo> debug_info, 71 JavaScriptFrame* frame); 72 73 static void AllAtCurrentStatement(Handle<DebugInfo> debug_info, 74 JavaScriptFrame* frame, 75 List<BreakLocation>* result_out); 76 IsReturn()77 inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; } IsCall()78 inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; } IsTailCall()79 inline bool IsTailCall() const { 80 return type_ == DEBUG_BREAK_SLOT_AT_TAIL_CALL; 81 } IsDebugBreakSlot()82 inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; } IsDebuggerStatement()83 inline bool IsDebuggerStatement() const { 84 return type_ == DEBUGGER_STATEMENT; 85 } 86 87 bool HasBreakPoint(Handle<DebugInfo> debug_info) const; 88 position()89 inline int position() const { return position_; } 90 91 private: BreakLocation(Handle<AbstractCode> abstract_code,DebugBreakType type,int code_offset,int position)92 BreakLocation(Handle<AbstractCode> abstract_code, DebugBreakType type, 93 int code_offset, int position) 94 : abstract_code_(abstract_code), 95 code_offset_(code_offset), 96 type_(type), 97 position_(position) { 98 DCHECK_NE(NOT_DEBUG_BREAK, type_); 99 } 100 101 static int BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, 102 Handle<AbstractCode> abstract_code, 103 int offset); 104 105 void SetDebugBreak(); 106 void ClearDebugBreak(); 107 108 Handle<AbstractCode> abstract_code_; 109 int code_offset_; 110 DebugBreakType type_; 111 int position_; 112 113 friend class CodeBreakIterator; 114 friend class BytecodeArrayBreakIterator; 115 }; 116 117 class BreakIterator { 118 public: 119 static std::unique_ptr<BreakIterator> GetIterator( 120 Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code); 121 ~BreakIterator()122 virtual ~BreakIterator() {} 123 124 virtual BreakLocation GetBreakLocation() = 0; 125 virtual bool Done() const = 0; 126 virtual void Next() = 0; 127 SkipTo(int count)128 void SkipTo(int count) { 129 while (count-- > 0) Next(); 130 } 131 132 virtual int code_offset() = 0; break_index()133 int break_index() const { return break_index_; } position()134 inline int position() const { return position_; } statement_position()135 inline int statement_position() const { return statement_position_; } 136 137 virtual bool IsDebugBreak() = 0; 138 virtual void ClearDebugBreak() = 0; 139 virtual void SetDebugBreak() = 0; 140 141 protected: 142 explicit BreakIterator(Handle<DebugInfo> debug_info); 143 144 int BreakIndexFromPosition(int position, BreakPositionAlignment alignment); 145 isolate()146 Isolate* isolate() { return debug_info_->GetIsolate(); } 147 148 Handle<DebugInfo> debug_info_; 149 int break_index_; 150 int position_; 151 int statement_position_; 152 153 private: 154 DisallowHeapAllocation no_gc_; 155 DISALLOW_COPY_AND_ASSIGN(BreakIterator); 156 }; 157 158 class CodeBreakIterator : public BreakIterator { 159 public: 160 explicit CodeBreakIterator(Handle<DebugInfo> debug_info); ~CodeBreakIterator()161 ~CodeBreakIterator() override {} 162 163 BreakLocation GetBreakLocation() override; Done()164 bool Done() const override { return reloc_iterator_.done(); } 165 void Next() override; 166 167 bool IsDebugBreak() override; 168 void ClearDebugBreak() override; 169 void SetDebugBreak() override; 170 171 void SkipToPosition(int position, BreakPositionAlignment alignment); 172 code_offset()173 int code_offset() override { 174 return static_cast<int>(rinfo()->pc() - 175 debug_info_->DebugCode()->instruction_start()); 176 } 177 178 private: 179 int GetModeMask(); 180 DebugBreakType GetDebugBreakType(); 181 rmode()182 RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); } rinfo()183 RelocInfo* rinfo() { return reloc_iterator_.rinfo(); } 184 185 RelocIterator reloc_iterator_; 186 SourcePositionTableIterator source_position_iterator_; 187 DISALLOW_COPY_AND_ASSIGN(CodeBreakIterator); 188 }; 189 190 class BytecodeArrayBreakIterator : public BreakIterator { 191 public: 192 explicit BytecodeArrayBreakIterator(Handle<DebugInfo> debug_info); ~BytecodeArrayBreakIterator()193 ~BytecodeArrayBreakIterator() override {} 194 195 BreakLocation GetBreakLocation() override; Done()196 bool Done() const override { return source_position_iterator_.done(); } 197 void Next() override; 198 199 bool IsDebugBreak() override; 200 void ClearDebugBreak() override; 201 void SetDebugBreak() override; 202 203 void SkipToPosition(int position, BreakPositionAlignment alignment); 204 code_offset()205 int code_offset() override { return source_position_iterator_.code_offset(); } 206 207 private: 208 DebugBreakType GetDebugBreakType(); 209 210 SourcePositionTableIterator source_position_iterator_; 211 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBreakIterator); 212 }; 213 214 // Linked list holding debug info objects. The debug info objects are kept as 215 // weak handles to avoid a debug info object to keep a function alive. 216 class DebugInfoListNode { 217 public: 218 explicit DebugInfoListNode(DebugInfo* debug_info); 219 ~DebugInfoListNode(); 220 next()221 DebugInfoListNode* next() { return next_; } set_next(DebugInfoListNode * next)222 void set_next(DebugInfoListNode* next) { next_ = next; } debug_info()223 Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); } 224 225 private: 226 // Global (weak) handle to the debug info object. 227 DebugInfo** debug_info_; 228 229 // Next pointer for linked list. 230 DebugInfoListNode* next_; 231 }; 232 233 class DebugFeatureTracker { 234 public: 235 enum Feature { 236 kActive = 1, 237 kBreakPoint = 2, 238 kStepping = 3, 239 kHeapSnapshot = 4, 240 kAllocationTracking = 5, 241 kProfiler = 6, 242 kLiveEdit = 7, 243 }; 244 DebugFeatureTracker(Isolate * isolate)245 explicit DebugFeatureTracker(Isolate* isolate) 246 : isolate_(isolate), bitfield_(0) {} 247 void Track(Feature feature); 248 249 private: 250 Isolate* isolate_; 251 uint32_t bitfield_; 252 }; 253 254 255 // This class contains the debugger support. The main purpose is to handle 256 // setting break points in the code. 257 // 258 // This class controls the debug info for all functions which currently have 259 // active breakpoints in them. This debug info is held in the heap root object 260 // debug_info which is a FixedArray. Each entry in this list is of class 261 // DebugInfo. 262 class Debug { 263 public: 264 // Debug event triggers. 265 void OnDebugBreak(Handle<Object> break_points_hit); 266 267 void OnThrow(Handle<Object> exception); 268 void OnPromiseReject(Handle<Object> promise, Handle<Object> value); 269 void OnCompileError(Handle<Script> script); 270 void OnAfterCompile(Handle<Script> script); 271 void OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id, 272 int parent_id); 273 274 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<Object> fun, 275 Handle<Object> data); 276 Handle<Context> GetDebugContext(); 277 void HandleDebugBreak(); 278 279 // Internal logic 280 bool Load(); 281 void Break(JavaScriptFrame* frame); 282 283 // Scripts handling. 284 Handle<FixedArray> GetLoadedScripts(); 285 286 // Break point handling. 287 bool SetBreakPoint(Handle<JSFunction> function, 288 Handle<Object> break_point_object, 289 int* source_position); 290 bool SetBreakPointForScript(Handle<Script> script, 291 Handle<Object> break_point_object, 292 int* source_position, 293 BreakPositionAlignment alignment); 294 void ClearBreakPoint(Handle<Object> break_point_object); 295 void ChangeBreakOnException(ExceptionBreakType type, bool enable); 296 bool IsBreakOnException(ExceptionBreakType type); 297 298 // The parameter is either a BreakPointInfo object, or a FixedArray of 299 // BreakPointInfo objects. 300 // Returns an empty handle if no breakpoint is hit, or a FixedArray with all 301 // hit breakpoints. 302 MaybeHandle<FixedArray> GetHitBreakPointObjects( 303 Handle<Object> break_point_objects); 304 305 // Stepping handling. 306 void PrepareStep(StepAction step_action); 307 void PrepareStepIn(Handle<JSFunction> function); 308 void PrepareStepInSuspendedGenerator(); 309 void PrepareStepOnThrow(); 310 void ClearStepping(); 311 void ClearStepOut(); 312 313 bool PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared); 314 bool GetPossibleBreakpoints(Handle<Script> script, int start_position, 315 int end_position, std::set<int>* positions); 316 317 void RecordGenerator(Handle<JSGeneratorObject> generator_object); 318 319 void RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise, 320 Handle<Object> parent); 321 322 int NextAsyncTaskId(Handle<JSObject> promise); 323 324 bool IsBlackboxed(Handle<SharedFunctionInfo> shared); 325 326 void SetDebugDelegate(debug::DebugDelegate* delegate, bool pass_ownership); 327 328 // Returns whether the operation succeeded. 329 bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared); 330 void CreateDebugInfo(Handle<SharedFunctionInfo> shared); 331 static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared); 332 333 template <typename C> 334 bool CompileToRevealInnerFunctions(C* compilable); 335 336 // This function is used in FunctionNameUsing* tests. 337 Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script, 338 int position); 339 340 static Handle<Object> GetSourceBreakLocations( 341 Handle<SharedFunctionInfo> shared, 342 BreakPositionAlignment position_aligment); 343 344 // Check whether a global object is the debug global object. 345 bool IsDebugGlobal(JSGlobalObject* global); 346 347 // Check whether this frame is just about to return. 348 bool IsBreakAtReturn(JavaScriptFrame* frame); 349 350 // Support for LiveEdit 351 void ScheduleFrameRestart(StackFrame* frame); 352 353 bool IsFrameBlackboxed(JavaScriptFrame* frame); 354 355 // Threading support. 356 char* ArchiveDebug(char* to); 357 char* RestoreDebug(char* from); 358 static int ArchiveSpacePerThread(); FreeThreadResources()359 void FreeThreadResources() { } 360 void Iterate(ObjectVisitor* v); 361 CheckExecutionState(int id)362 bool CheckExecutionState(int id) { 363 return CheckExecutionState() && break_id() == id; 364 } 365 CheckExecutionState()366 bool CheckExecutionState() { 367 return is_active() && !debug_context().is_null() && break_id() != 0; 368 } 369 370 bool PerformSideEffectCheck(Handle<JSFunction> function); 371 bool PerformSideEffectCheckForCallback(Address function); 372 373 // Flags and states. debugger_entry()374 DebugScope* debugger_entry() { 375 return reinterpret_cast<DebugScope*>( 376 base::NoBarrier_Load(&thread_local_.current_debug_scope_)); 377 } debug_context()378 inline Handle<Context> debug_context() { return debug_context_; } 379 set_live_edit_enabled(bool v)380 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } live_edit_enabled()381 bool live_edit_enabled() const { 382 return FLAG_enable_liveedit && live_edit_enabled_; 383 } 384 is_active()385 inline bool is_active() const { return is_active_; } is_loaded()386 inline bool is_loaded() const { return !debug_context_.is_null(); } in_debug_scope()387 inline bool in_debug_scope() const { 388 return !!base::NoBarrier_Load(&thread_local_.current_debug_scope_); 389 } set_break_points_active(bool v)390 void set_break_points_active(bool v) { break_points_active_ = v; } break_points_active()391 bool break_points_active() const { return break_points_active_; } 392 break_frame_id()393 StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } break_id()394 int break_id() { return thread_local_.break_id_; } 395 return_value_handle()396 Handle<Object> return_value_handle() { 397 return handle(thread_local_.return_value_, isolate_); 398 } return_value()399 Object* return_value() { return thread_local_.return_value_; } set_return_value(Object * value)400 void set_return_value(Object* value) { thread_local_.return_value_ = value; } 401 402 // Support for embedding into generated code. is_active_address()403 Address is_active_address() { 404 return reinterpret_cast<Address>(&is_active_); 405 } 406 hook_on_function_call_address()407 Address hook_on_function_call_address() { 408 return reinterpret_cast<Address>(&hook_on_function_call_); 409 } 410 last_step_action_address()411 Address last_step_action_address() { 412 return reinterpret_cast<Address>(&thread_local_.last_step_action_); 413 } 414 suspended_generator_address()415 Address suspended_generator_address() { 416 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); 417 } 418 restart_fp_address()419 Address restart_fp_address() { 420 return reinterpret_cast<Address>(&thread_local_.restart_fp_); 421 } 422 last_step_action()423 StepAction last_step_action() { return thread_local_.last_step_action_; } 424 feature_tracker()425 DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } 426 427 private: 428 explicit Debug(Isolate* isolate); ~Debug()429 ~Debug() { DCHECK_NULL(debug_delegate_); } 430 431 void UpdateState(); 432 void UpdateHookOnFunctionCall(); 433 void RemoveDebugDelegate(); 434 void Unload(); SetNextBreakId()435 void SetNextBreakId() { 436 thread_local_.break_id_ = ++thread_local_.break_count_; 437 } 438 439 // Return the number of virtual frames below debugger entry. 440 int CurrentFrameCount(); 441 ignore_events()442 inline bool ignore_events() const { 443 return is_suppressed_ || !is_active_ || isolate_->needs_side_effect_check(); 444 } break_disabled()445 inline bool break_disabled() const { return break_disabled_; } 446 clear_suspended_generator()447 void clear_suspended_generator() { 448 thread_local_.suspended_generator_ = Smi::kZero; 449 } 450 has_suspended_generator()451 bool has_suspended_generator() const { 452 return thread_local_.suspended_generator_ != Smi::kZero; 453 } 454 455 bool IsExceptionBlackboxed(bool uncaught); 456 457 void OnException(Handle<Object> exception, Handle<Object> promise); 458 459 // Constructors for debug event objects. 460 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); 461 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( 462 Handle<Object> break_points_hit); 463 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( 464 Handle<Object> exception, 465 bool uncaught, 466 Handle<Object> promise); 467 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( 468 Handle<Script> script, v8::DebugEvent type); 469 MUST_USE_RESULT MaybeHandle<Object> MakeAsyncTaskEvent( 470 v8::debug::PromiseDebugActionType type, int id); 471 472 void ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script); 473 void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data); 474 475 // Find the closest source position for a break point for a given position. 476 int FindBreakablePosition(Handle<DebugInfo> debug_info, int source_position, 477 BreakPositionAlignment alignment); 478 // Instrument code to break at break points. 479 void ApplyBreakPoints(Handle<DebugInfo> debug_info); 480 // Clear code from instrumentation. 481 void ClearBreakPoints(Handle<DebugInfo> debug_info); 482 // Clear all code from instrumentation. 483 void ClearAllBreakPoints(); 484 // Instrument a function with one-shots. 485 void FloodWithOneShot(Handle<SharedFunctionInfo> function); 486 // Clear all one-shot instrumentations, but restore break points. 487 void ClearOneShot(); 488 489 void ActivateStepOut(StackFrame* frame); 490 void RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info); 491 MaybeHandle<FixedArray> CheckBreakPoints(Handle<DebugInfo> debug_info, 492 BreakLocation* location, 493 bool* has_break_points = nullptr); 494 bool IsMutedAtCurrentLocation(JavaScriptFrame* frame); 495 bool CheckBreakPoint(Handle<Object> break_point_object); 496 MaybeHandle<Object> CallFunction(const char* name, int argc, 497 Handle<Object> args[]); 498 AssertDebugContext()499 inline void AssertDebugContext() { 500 DCHECK(isolate_->context() == *debug_context()); 501 DCHECK(in_debug_scope()); 502 } 503 504 void ThreadInit(); 505 506 void PrintBreakLocation(); 507 508 // Global handles. 509 Handle<Context> debug_context_; 510 511 debug::DebugDelegate* debug_delegate_ = nullptr; 512 bool owns_debug_delegate_ = false; 513 514 // Debugger is active, i.e. there is a debug event listener attached. 515 bool is_active_; 516 // Debugger needs to be notified on every new function call. 517 // Used for stepping and read-only checks 518 bool hook_on_function_call_; 519 // Suppress debug events. 520 bool is_suppressed_; 521 // LiveEdit is enabled. 522 bool live_edit_enabled_; 523 // Do not trigger debug break events. 524 bool break_disabled_; 525 // Do not break on break points. 526 bool break_points_active_; 527 // Trigger debug break events for all exceptions. 528 bool break_on_exception_; 529 // Trigger debug break events for uncaught exceptions. 530 bool break_on_uncaught_exception_; 531 // Termination exception because side effect check has failed. 532 bool side_effect_check_failed_; 533 534 // List of active debug info objects. 535 DebugInfoListNode* debug_info_list_; 536 537 // Used to collect histogram data on debugger feature usage. 538 DebugFeatureTracker feature_tracker_; 539 540 // Per-thread data. 541 class ThreadLocal { 542 public: 543 // Top debugger entry. 544 base::AtomicWord current_debug_scope_; 545 546 // Counter for generating next break id. 547 int break_count_; 548 549 // Current break id. 550 int break_id_; 551 552 // Frame id for the frame of the current break. 553 StackFrame::Id break_frame_id_; 554 555 // Step action for last step performed. 556 StepAction last_step_action_; 557 558 // Source statement position from last step next action. 559 int last_statement_position_; 560 561 // Frame pointer from last step next or step frame action. 562 int last_frame_count_; 563 564 // Frame pointer of the target frame we want to arrive at. 565 int target_frame_count_; 566 567 // Value of the accumulator at the point of entering the debugger. 568 Object* return_value_; 569 570 // The suspended generator object to track when stepping. 571 Object* suspended_generator_; 572 573 // The new frame pointer to drop to when restarting a frame. 574 Address restart_fp_; 575 576 int async_task_count_; 577 }; 578 579 // Storage location for registers when handling debug break calls 580 ThreadLocal thread_local_; 581 582 Isolate* isolate_; 583 584 friend class Isolate; 585 friend class DebugScope; 586 friend class DisableBreak; 587 friend class LiveEdit; 588 friend class SuppressDebug; 589 friend class NoSideEffectScope; 590 friend class LegacyDebugDelegate; 591 592 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc 593 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc 594 595 DISALLOW_COPY_AND_ASSIGN(Debug); 596 }; 597 598 class LegacyDebugDelegate : public v8::debug::DebugDelegate { 599 public: LegacyDebugDelegate(Isolate * isolate)600 explicit LegacyDebugDelegate(Isolate* isolate) : isolate_(isolate) {} 601 void PromiseEventOccurred(v8::debug::PromiseDebugActionType type, int id, 602 int parent_id) override; 603 void ScriptCompiled(v8::Local<v8::debug::Script> script, 604 bool has_compile_error) override; 605 void BreakProgramRequested(v8::Local<v8::Context> paused_context, 606 v8::Local<v8::Object> exec_state, 607 v8::Local<v8::Value> break_points_hit) override; 608 void ExceptionThrown(v8::Local<v8::Context> paused_context, 609 v8::Local<v8::Object> exec_state, 610 v8::Local<v8::Value> exception, 611 v8::Local<v8::Value> promise, bool is_uncaught) override; IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,const v8::debug::Location & start,const v8::debug::Location & end)612 bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, 613 const v8::debug::Location& start, 614 const v8::debug::Location& end) override { 615 return false; 616 } 617 618 protected: 619 Isolate* isolate_; 620 621 private: 622 void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data); 623 virtual void ProcessDebugEvent(v8::DebugEvent event, 624 Handle<JSObject> event_data, 625 Handle<JSObject> exec_state) = 0; 626 }; 627 628 class JavaScriptDebugDelegate : public LegacyDebugDelegate { 629 public: 630 JavaScriptDebugDelegate(Isolate* isolate, Handle<JSFunction> listener, 631 Handle<Object> data); 632 virtual ~JavaScriptDebugDelegate(); 633 634 private: 635 void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data, 636 Handle<JSObject> exec_state) override; 637 638 Handle<JSFunction> listener_; 639 Handle<Object> data_; 640 }; 641 642 class NativeDebugDelegate : public LegacyDebugDelegate { 643 public: 644 NativeDebugDelegate(Isolate* isolate, v8::Debug::EventCallback callback, 645 Handle<Object> data); 646 virtual ~NativeDebugDelegate(); 647 648 private: 649 // Details of the debug event delivered to the debug event listener. 650 class EventDetails : public v8::Debug::EventDetails { 651 public: 652 EventDetails(DebugEvent event, Handle<JSObject> exec_state, 653 Handle<JSObject> event_data, Handle<Object> callback_data); 654 virtual DebugEvent GetEvent() const; 655 virtual v8::Local<v8::Object> GetExecutionState() const; 656 virtual v8::Local<v8::Object> GetEventData() const; 657 virtual v8::Local<v8::Context> GetEventContext() const; 658 virtual v8::Local<v8::Value> GetCallbackData() const; GetClientData()659 virtual v8::Debug::ClientData* GetClientData() const { return nullptr; } 660 virtual v8::Isolate* GetIsolate() const; 661 662 private: 663 DebugEvent event_; // Debug event causing the break. 664 Handle<JSObject> exec_state_; // Current execution state. 665 Handle<JSObject> event_data_; // Data associated with the event. 666 Handle<Object> callback_data_; // User data passed with the callback 667 // when it was registered. 668 }; 669 670 void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data, 671 Handle<JSObject> exec_state) override; 672 673 v8::Debug::EventCallback callback_; 674 Handle<Object> data_; 675 }; 676 677 // This scope is used to load and enter the debug context and create a new 678 // break state. Leaving the scope will restore the previous state. 679 // On failure to load, FailedToEnter returns true. 680 class DebugScope BASE_EMBEDDED { 681 public: 682 explicit DebugScope(Debug* debug); 683 ~DebugScope(); 684 685 // Check whether loading was successful. failed()686 inline bool failed() { return failed_; } 687 688 // Get the active context from before entering the debugger. GetContext()689 inline Handle<Context> GetContext() { return save_.context(); } 690 691 private: isolate()692 Isolate* isolate() { return debug_->isolate_; } 693 694 Debug* debug_; 695 DebugScope* prev_; // Previous scope if entered recursively. 696 StackFrame::Id break_frame_id_; // Previous break frame id. 697 int break_id_; // Previous break id. 698 bool failed_; // Did the debug context fail to load? 699 SaveContext save_; // Saves previous context. 700 PostponeInterruptsScope no_termination_exceptons_; 701 }; 702 703 // This scope is used to handle return values in nested debug break points. 704 // When there are nested debug breaks, we use this to restore the return 705 // value to the previous state. This is not merged with DebugScope because 706 // return_value_ will not be cleared when we use DebugScope. 707 class ReturnValueScope { 708 public: 709 explicit ReturnValueScope(Debug* debug); 710 ~ReturnValueScope(); 711 712 private: 713 Debug* debug_; 714 Handle<Object> return_value_; // Previous result. 715 }; 716 717 // Stack allocated class for disabling break. 718 class DisableBreak BASE_EMBEDDED { 719 public: DisableBreak(Debug * debug)720 explicit DisableBreak(Debug* debug) 721 : debug_(debug), previous_break_disabled_(debug->break_disabled_) { 722 debug_->break_disabled_ = true; 723 } ~DisableBreak()724 ~DisableBreak() { 725 debug_->break_disabled_ = previous_break_disabled_; 726 } 727 728 private: 729 Debug* debug_; 730 bool previous_break_disabled_; 731 DISALLOW_COPY_AND_ASSIGN(DisableBreak); 732 }; 733 734 735 class SuppressDebug BASE_EMBEDDED { 736 public: SuppressDebug(Debug * debug)737 explicit SuppressDebug(Debug* debug) 738 : debug_(debug), old_state_(debug->is_suppressed_) { 739 debug_->is_suppressed_ = true; 740 } ~SuppressDebug()741 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } 742 743 private: 744 Debug* debug_; 745 bool old_state_; 746 DISALLOW_COPY_AND_ASSIGN(SuppressDebug); 747 }; 748 749 class NoSideEffectScope { 750 public: NoSideEffectScope(Isolate * isolate,bool disallow_side_effects)751 NoSideEffectScope(Isolate* isolate, bool disallow_side_effects) 752 : isolate_(isolate), 753 old_needs_side_effect_check_(isolate->needs_side_effect_check()) { 754 isolate->set_needs_side_effect_check(old_needs_side_effect_check_ || 755 disallow_side_effects); 756 isolate->debug()->UpdateHookOnFunctionCall(); 757 isolate->debug()->side_effect_check_failed_ = false; 758 } 759 ~NoSideEffectScope(); 760 761 private: 762 Isolate* isolate_; 763 bool old_needs_side_effect_check_; 764 DISALLOW_COPY_AND_ASSIGN(NoSideEffectScope); 765 }; 766 767 // Code generator routines. 768 class DebugCodegen : public AllStatic { 769 public: 770 enum DebugBreakCallHelperMode { 771 SAVE_RESULT_REGISTER, 772 IGNORE_RESULT_REGISTER 773 }; 774 775 static void GenerateDebugBreakStub(MacroAssembler* masm, 776 DebugBreakCallHelperMode mode); 777 778 static void GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode); 779 780 // Builtin to drop frames to restart function. 781 static void GenerateFrameDropperTrampoline(MacroAssembler* masm); 782 783 // Builtin to atomically (wrt deopts) handle debugger statement and 784 // drop frames to restart function if necessary. 785 static void GenerateHandleDebuggerStatement(MacroAssembler* masm); 786 787 static void PatchDebugBreakSlot(Isolate* isolate, Address pc, 788 Handle<Code> code); 789 static bool DebugBreakSlotIsPatched(Address pc); 790 static void ClearDebugBreakSlot(Isolate* isolate, Address pc); 791 }; 792 793 794 } // namespace internal 795 } // namespace v8 796 797 #endif // V8_DEBUG_DEBUG_H_ 798