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 <vector> 9 10 #include "src/allocation.h" 11 #include "src/base/atomicops.h" 12 #include "src/base/hashmap.h" 13 #include "src/base/platform/platform.h" 14 #include "src/debug/debug-interface.h" 15 #include "src/debug/interface-types.h" 16 #include "src/execution.h" 17 #include "src/flags.h" 18 #include "src/frames.h" 19 #include "src/globals.h" 20 #include "src/heap/factory.h" 21 #include "src/objects/debug-objects.h" 22 #include "src/runtime/runtime.h" 23 #include "src/source-position-table.h" 24 #include "src/string-stream.h" 25 #include "src/v8threads.h" 26 27 namespace v8 { 28 namespace internal { 29 30 // Forward declarations. 31 class DebugScope; 32 class JSGeneratorObject; 33 34 // Step actions. NOTE: These values are in macros.py as well. 35 enum StepAction : int8_t { 36 StepNone = -1, // Stepping not prepared. 37 StepOut = 0, // Step out of the current function. 38 StepNext = 1, // Step to the next statement in the current function. 39 StepIn = 2, // Step into new functions invoked or the next statement 40 // in the current function. 41 LastStepAction = StepIn 42 }; 43 44 // Type of exception break. NOTE: These values are in macros.py as well. 45 enum ExceptionBreakType { 46 BreakException = 0, 47 BreakUncaughtException = 1 48 }; 49 50 enum DebugBreakType { 51 NOT_DEBUG_BREAK, 52 DEBUGGER_STATEMENT, 53 DEBUG_BREAK_SLOT, 54 DEBUG_BREAK_SLOT_AT_CALL, 55 DEBUG_BREAK_SLOT_AT_RETURN, 56 DEBUG_BREAK_SLOT_AT_SUSPEND, 57 DEBUG_BREAK_AT_ENTRY, 58 }; 59 60 enum IgnoreBreakMode { 61 kIgnoreIfAllFramesBlackboxed, 62 kIgnoreIfTopFrameBlackboxed 63 }; 64 65 class BreakLocation { 66 public: 67 static BreakLocation FromFrame(Handle<DebugInfo> debug_info, 68 JavaScriptFrame* frame); 69 70 static void AllAtCurrentStatement(Handle<DebugInfo> debug_info, 71 JavaScriptFrame* frame, 72 std::vector<BreakLocation>* result_out); 73 IsSuspend()74 inline bool IsSuspend() const { return type_ == DEBUG_BREAK_SLOT_AT_SUSPEND; } IsReturn()75 inline bool IsReturn() const { return type_ == DEBUG_BREAK_SLOT_AT_RETURN; } IsReturnOrSuspend()76 inline bool IsReturnOrSuspend() const { 77 return type_ >= DEBUG_BREAK_SLOT_AT_RETURN; 78 } IsCall()79 inline bool IsCall() const { return type_ == DEBUG_BREAK_SLOT_AT_CALL; } IsDebugBreakSlot()80 inline bool IsDebugBreakSlot() const { return type_ >= DEBUG_BREAK_SLOT; } IsDebuggerStatement()81 inline bool IsDebuggerStatement() const { 82 return type_ == DEBUGGER_STATEMENT; 83 } IsDebugBreakAtEntry()84 inline bool IsDebugBreakAtEntry() const { 85 bool result = type_ == DEBUG_BREAK_AT_ENTRY; 86 return result; 87 } 88 89 bool HasBreakPoint(Isolate* isolate, Handle<DebugInfo> debug_info) const; 90 position()91 inline int position() const { return position_; } 92 93 debug::BreakLocationType type() const; 94 95 JSGeneratorObject* GetGeneratorObjectForSuspendedFrame( 96 JavaScriptFrame* frame) const; 97 98 private: BreakLocation(Handle<AbstractCode> abstract_code,DebugBreakType type,int code_offset,int position,int generator_obj_reg_index)99 BreakLocation(Handle<AbstractCode> abstract_code, DebugBreakType type, 100 int code_offset, int position, int generator_obj_reg_index) 101 : abstract_code_(abstract_code), 102 code_offset_(code_offset), 103 type_(type), 104 position_(position), 105 generator_obj_reg_index_(generator_obj_reg_index) { 106 DCHECK_NE(NOT_DEBUG_BREAK, type_); 107 } 108 BreakLocation(int position,DebugBreakType type)109 BreakLocation(int position, DebugBreakType type) 110 : code_offset_(0), 111 type_(type), 112 position_(position), 113 generator_obj_reg_index_(0) {} 114 115 static int BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info, 116 Handle<AbstractCode> abstract_code, 117 int offset); 118 119 void SetDebugBreak(); 120 void ClearDebugBreak(); 121 122 Handle<AbstractCode> abstract_code_; 123 int code_offset_; 124 DebugBreakType type_; 125 int position_; 126 int generator_obj_reg_index_; 127 128 friend class BreakIterator; 129 }; 130 131 class BreakIterator { 132 public: 133 explicit BreakIterator(Handle<DebugInfo> debug_info); 134 135 BreakLocation GetBreakLocation(); Done()136 bool Done() const { return source_position_iterator_.done(); } 137 void Next(); 138 139 void SkipToPosition(int position); SkipTo(int count)140 void SkipTo(int count) { 141 while (count-- > 0) Next(); 142 } 143 code_offset()144 int code_offset() { return source_position_iterator_.code_offset(); } break_index()145 int break_index() const { return break_index_; } position()146 inline int position() const { return position_; } statement_position()147 inline int statement_position() const { return statement_position_; } 148 149 void ClearDebugBreak(); 150 void SetDebugBreak(); 151 152 private: 153 int BreakIndexFromPosition(int position); 154 155 Isolate* isolate(); 156 157 DebugBreakType GetDebugBreakType(); 158 159 Handle<DebugInfo> debug_info_; 160 int break_index_; 161 int position_; 162 int statement_position_; 163 SourcePositionTableIterator source_position_iterator_; 164 DisallowHeapAllocation no_gc_; 165 166 DISALLOW_COPY_AND_ASSIGN(BreakIterator); 167 }; 168 169 // Linked list holding debug info objects. The debug info objects are kept as 170 // weak handles to avoid a debug info object to keep a function alive. 171 class DebugInfoListNode { 172 public: 173 DebugInfoListNode(Isolate* isolate, DebugInfo* debug_info); 174 ~DebugInfoListNode(); 175 next()176 DebugInfoListNode* next() { return next_; } set_next(DebugInfoListNode * next)177 void set_next(DebugInfoListNode* next) { next_ = next; } debug_info()178 Handle<DebugInfo> debug_info() { return Handle<DebugInfo>(debug_info_); } 179 180 private: 181 // Global (weak) handle to the debug info object. 182 DebugInfo** debug_info_; 183 184 // Next pointer for linked list. 185 DebugInfoListNode* next_; 186 }; 187 188 class DebugFeatureTracker { 189 public: 190 enum Feature { 191 kActive = 1, 192 kBreakPoint = 2, 193 kStepping = 3, 194 kHeapSnapshot = 4, 195 kAllocationTracking = 5, 196 kProfiler = 6, 197 kLiveEdit = 7, 198 }; 199 DebugFeatureTracker(Isolate * isolate)200 explicit DebugFeatureTracker(Isolate* isolate) 201 : isolate_(isolate), bitfield_(0) {} 202 void Track(Feature feature); 203 204 private: 205 Isolate* isolate_; 206 uint32_t bitfield_; 207 }; 208 209 210 // This class contains the debugger support. The main purpose is to handle 211 // setting break points in the code. 212 // 213 // This class controls the debug info for all functions which currently have 214 // active breakpoints in them. This debug info is held in the heap root object 215 // debug_info which is a FixedArray. Each entry in this list is of class 216 // DebugInfo. 217 class Debug { 218 public: 219 // Debug event triggers. 220 void OnDebugBreak(Handle<FixedArray> break_points_hit); 221 222 void OnThrow(Handle<Object> exception); 223 void OnPromiseReject(Handle<Object> promise, Handle<Object> value); 224 void OnCompileError(Handle<Script> script); 225 void OnAfterCompile(Handle<Script> script); 226 227 void HandleDebugBreak(IgnoreBreakMode ignore_break_mode); 228 229 // The break target may not be the top-most frame, since we may be 230 // breaking before entering a function that cannot contain break points. 231 void Break(JavaScriptFrame* frame, Handle<JSFunction> break_target); 232 233 // Scripts handling. 234 Handle<FixedArray> GetLoadedScripts(); 235 236 // Break point handling. 237 bool SetBreakPoint(Handle<JSFunction> function, 238 Handle<BreakPoint> break_point, int* source_position); 239 void ClearBreakPoint(Handle<BreakPoint> break_point); 240 void ChangeBreakOnException(ExceptionBreakType type, bool enable); 241 bool IsBreakOnException(ExceptionBreakType type); 242 243 bool SetBreakPointForScript(Handle<Script> script, Handle<String> condition, 244 int* source_position, int* id); 245 bool SetBreakpointForFunction(Handle<JSFunction> function, 246 Handle<String> condition, int* id); 247 void RemoveBreakpoint(int id); 248 249 // Find breakpoints from the debug info and the break location and check 250 // whether they are hit. Return an empty handle if not, or a FixedArray with 251 // hit BreakPoint objects. 252 MaybeHandle<FixedArray> GetHitBreakPoints(Handle<DebugInfo> debug_info, 253 int position); 254 255 // Stepping handling. 256 void PrepareStep(StepAction step_action); 257 void PrepareStepIn(Handle<JSFunction> function); 258 void PrepareStepInSuspendedGenerator(); 259 void PrepareStepOnThrow(); 260 void ClearStepping(); 261 262 void SetBreakOnNextFunctionCall(); 263 void ClearBreakOnNextFunctionCall(); 264 265 void DeoptimizeFunction(Handle<SharedFunctionInfo> shared); 266 void PrepareFunctionForDebugExecution(Handle<SharedFunctionInfo> shared); 267 void InstallDebugBreakTrampoline(); 268 bool GetPossibleBreakpoints(Handle<Script> script, int start_position, 269 int end_position, bool restrict_to_function, 270 std::vector<BreakLocation>* locations); 271 272 bool IsBlackboxed(Handle<SharedFunctionInfo> shared); 273 274 bool CanBreakAtEntry(Handle<SharedFunctionInfo> shared); 275 276 void SetDebugDelegate(debug::DebugDelegate* delegate); 277 278 // Returns whether the operation succeeded. 279 bool EnsureBreakInfo(Handle<SharedFunctionInfo> shared); 280 void CreateBreakInfo(Handle<SharedFunctionInfo> shared); 281 Handle<DebugInfo> GetOrCreateDebugInfo(Handle<SharedFunctionInfo> shared); 282 283 void InstallCoverageInfo(Handle<SharedFunctionInfo> shared, 284 Handle<CoverageInfo> coverage_info); 285 void RemoveAllCoverageInfos(); 286 287 // This function is used in FunctionNameUsing* tests. 288 Handle<Object> FindSharedFunctionInfoInScript(Handle<Script> script, 289 int position); 290 291 static Handle<Object> GetSourceBreakLocations( 292 Isolate* isolate, Handle<SharedFunctionInfo> shared); 293 294 // Check whether this frame is just about to return. 295 bool IsBreakAtReturn(JavaScriptFrame* frame); 296 297 // Support for LiveEdit 298 void ScheduleFrameRestart(StackFrame* frame); 299 300 bool AllFramesOnStackAreBlackboxed(); 301 302 // Set new script source, throw an exception if error occurred. When preview 303 // is true: try to set source, throw exception if any without actual script 304 // change. stack_changed is true if after editing script on pause stack is 305 // changed and client should request stack trace again. 306 bool SetScriptSource(Handle<Script> script, Handle<String> source, 307 bool preview, debug::LiveEditResult* result); 308 309 int GetFunctionDebuggingId(Handle<JSFunction> function); 310 311 // Threading support. 312 char* ArchiveDebug(char* to); 313 char* RestoreDebug(char* from); 314 static int ArchiveSpacePerThread(); FreeThreadResources()315 void FreeThreadResources() { } 316 void Iterate(RootVisitor* v); InitThread(const ExecutionAccess & lock)317 void InitThread(const ExecutionAccess& lock) { ThreadInit(); } 318 CheckExecutionState()319 bool CheckExecutionState() { return is_active(); } 320 321 void StartSideEffectCheckMode(); 322 void StopSideEffectCheckMode(); 323 324 void ApplySideEffectChecks(Handle<DebugInfo> debug_info); 325 void ClearSideEffectChecks(Handle<DebugInfo> debug_info); 326 327 bool PerformSideEffectCheck(Handle<JSFunction> function, 328 Handle<Object> receiver); 329 bool PerformSideEffectCheckForCallback(Handle<Object> callback_info); 330 bool PerformSideEffectCheckAtBytecode(InterpretedFrame* frame); 331 bool PerformSideEffectCheckForObject(Handle<Object> object); 332 333 // Flags and states. is_active()334 inline bool is_active() const { return is_active_; } in_debug_scope()335 inline bool in_debug_scope() const { 336 return !!base::Relaxed_Load(&thread_local_.current_debug_scope_); 337 } needs_check_on_function_call()338 inline bool needs_check_on_function_call() const { 339 return hook_on_function_call_; 340 } 341 set_break_points_active(bool v)342 void set_break_points_active(bool v) { break_points_active_ = v; } break_points_active()343 bool break_points_active() const { return break_points_active_; } 344 break_frame_id()345 StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; } 346 347 Handle<Object> return_value_handle(); return_value()348 Object* return_value() { return thread_local_.return_value_; } set_return_value(Object * value)349 void set_return_value(Object* value) { thread_local_.return_value_ = value; } 350 351 // Support for embedding into generated code. is_active_address()352 Address is_active_address() { 353 return reinterpret_cast<Address>(&is_active_); 354 } 355 hook_on_function_call_address()356 Address hook_on_function_call_address() { 357 return reinterpret_cast<Address>(&hook_on_function_call_); 358 } 359 suspended_generator_address()360 Address suspended_generator_address() { 361 return reinterpret_cast<Address>(&thread_local_.suspended_generator_); 362 } 363 restart_fp_address()364 Address restart_fp_address() { 365 return reinterpret_cast<Address>(&thread_local_.restart_fp_); 366 } 367 last_step_action()368 StepAction last_step_action() { return thread_local_.last_step_action_; } break_on_next_function_call()369 bool break_on_next_function_call() const { 370 return thread_local_.break_on_next_function_call_; 371 } 372 feature_tracker()373 DebugFeatureTracker* feature_tracker() { return &feature_tracker_; } 374 375 // For functions in which we cannot set a break point, use a canonical 376 // source position for break points. 377 static const int kBreakAtEntryPosition = 0; 378 379 void RemoveBreakInfoAndMaybeFree(Handle<DebugInfo> debug_info); 380 381 private: 382 explicit Debug(Isolate* isolate); 383 ~Debug(); 384 385 void UpdateDebugInfosForExecutionMode(); 386 void UpdateState(); 387 void UpdateHookOnFunctionCall(); 388 void Unload(); 389 390 // Return the number of virtual frames below debugger entry. 391 int CurrentFrameCount(); 392 ignore_events()393 inline bool ignore_events() const { 394 return is_suppressed_ || !is_active_ || 395 isolate_->debug_execution_mode() == DebugInfo::kSideEffects; 396 } break_disabled()397 inline bool break_disabled() const { return break_disabled_; } 398 clear_suspended_generator()399 void clear_suspended_generator() { 400 thread_local_.suspended_generator_ = Smi::kZero; 401 } 402 has_suspended_generator()403 bool has_suspended_generator() const { 404 return thread_local_.suspended_generator_ != Smi::kZero; 405 } 406 407 bool IsExceptionBlackboxed(bool uncaught); 408 409 void OnException(Handle<Object> exception, Handle<Object> promise); 410 411 void ProcessCompileEvent(bool has_compile_error, Handle<Script> script); 412 413 // Find the closest source position for a break point for a given position. 414 int FindBreakablePosition(Handle<DebugInfo> debug_info, int source_position); 415 // Instrument code to break at break points. 416 void ApplyBreakPoints(Handle<DebugInfo> debug_info); 417 // Clear code from instrumentation. 418 void ClearBreakPoints(Handle<DebugInfo> debug_info); 419 // Clear all code from instrumentation. 420 void ClearAllBreakPoints(); 421 // Instrument a function with one-shots. 422 void FloodWithOneShot(Handle<SharedFunctionInfo> function, 423 bool returns_only = false); 424 // Clear all one-shot instrumentations, but restore break points. 425 void ClearOneShot(); 426 427 bool IsFrameBlackboxed(JavaScriptFrame* frame); 428 429 void ActivateStepOut(StackFrame* frame); 430 MaybeHandle<FixedArray> CheckBreakPoints(Handle<DebugInfo> debug_info, 431 BreakLocation* location, 432 bool* has_break_points = nullptr); 433 bool IsMutedAtCurrentLocation(JavaScriptFrame* frame); 434 // Check whether a BreakPoint object is hit. Evaluate condition depending 435 // on whether this is a regular break location or a break at function entry. 436 bool CheckBreakPoint(Handle<BreakPoint> break_point, bool is_break_at_entry); 437 AssertDebugContext()438 inline void AssertDebugContext() { 439 DCHECK(in_debug_scope()); 440 } 441 442 void ThreadInit(); 443 444 void PrintBreakLocation(); 445 446 void ClearAllDebuggerHints(); 447 448 // Wraps logic for clearing and maybe freeing all debug infos. 449 typedef std::function<void(Handle<DebugInfo>)> DebugInfoClearFunction; 450 void ClearAllDebugInfos(DebugInfoClearFunction clear_function); 451 452 void FindDebugInfo(Handle<DebugInfo> debug_info, DebugInfoListNode** prev, 453 DebugInfoListNode** curr); 454 void FreeDebugInfoListNode(DebugInfoListNode* prev, DebugInfoListNode* node); 455 456 debug::DebugDelegate* debug_delegate_ = nullptr; 457 458 // Debugger is active, i.e. there is a debug event listener attached. 459 bool is_active_; 460 // Debugger needs to be notified on every new function call. 461 // Used for stepping and read-only checks 462 bool hook_on_function_call_; 463 // Suppress debug events. 464 bool is_suppressed_; 465 // Running liveedit. 466 bool running_live_edit_ = false; 467 // Do not trigger debug break events. 468 bool break_disabled_; 469 // Do not break on break points. 470 bool break_points_active_; 471 // Trigger debug break events for all exceptions. 472 bool break_on_exception_; 473 // Trigger debug break events for uncaught exceptions. 474 bool break_on_uncaught_exception_; 475 // Termination exception because side effect check has failed. 476 bool side_effect_check_failed_; 477 478 // List of active debug info objects. 479 DebugInfoListNode* debug_info_list_; 480 481 // Used for side effect check to mark temporary objects. 482 class TemporaryObjectsTracker; 483 std::unique_ptr<TemporaryObjectsTracker> temporary_objects_; 484 485 Handle<RegExpMatchInfo> regexp_match_info_; 486 487 // Used to collect histogram data on debugger feature usage. 488 DebugFeatureTracker feature_tracker_; 489 490 // Per-thread data. 491 class ThreadLocal { 492 public: 493 // Top debugger entry. 494 base::AtomicWord current_debug_scope_; 495 496 // Frame id for the frame of the current break. 497 StackFrame::Id break_frame_id_; 498 499 // Step action for last step performed. 500 StepAction last_step_action_; 501 502 // If set, next PrepareStepIn will ignore this function until stepped into 503 // another function, at which point this will be cleared. 504 Object* ignore_step_into_function_; 505 506 // If set then we need to repeat StepOut action at return. 507 bool fast_forward_to_return_; 508 509 // Source statement position from last step next action. 510 int last_statement_position_; 511 512 // Frame pointer from last step next or step frame action. 513 int last_frame_count_; 514 515 // Frame pointer of the target frame we want to arrive at. 516 int target_frame_count_; 517 518 // Value of the accumulator at the point of entering the debugger. 519 Object* return_value_; 520 521 // The suspended generator object to track when stepping. 522 Object* suspended_generator_; 523 524 // The new frame pointer to drop to when restarting a frame. 525 Address restart_fp_; 526 527 // Last used inspector breakpoint id. 528 int last_breakpoint_id_; 529 530 // This flag is true when SetBreakOnNextFunctionCall is called and it forces 531 // debugger to break on next function call. 532 bool break_on_next_function_call_; 533 }; 534 535 // Storage location for registers when handling debug break calls 536 ThreadLocal thread_local_; 537 538 Isolate* isolate_; 539 540 friend class Isolate; 541 friend class DebugScope; 542 friend class DisableBreak; 543 friend class LiveEdit; 544 friend class SuppressDebug; 545 546 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc 547 friend void CheckDebuggerUnloaded(); // In test-debug.cc 548 549 DISALLOW_COPY_AND_ASSIGN(Debug); 550 }; 551 552 // This scope is used to load and enter the debug context and create a new 553 // break state. Leaving the scope will restore the previous state. 554 class DebugScope BASE_EMBEDDED { 555 public: 556 explicit DebugScope(Debug* debug); 557 ~DebugScope(); 558 559 private: isolate()560 Isolate* isolate() { return debug_->isolate_; } 561 562 Debug* debug_; 563 DebugScope* prev_; // Previous scope if entered recursively. 564 StackFrame::Id break_frame_id_; // Previous break frame id. 565 PostponeInterruptsScope no_interrupts_; 566 }; 567 568 // This scope is used to handle return values in nested debug break points. 569 // When there are nested debug breaks, we use this to restore the return 570 // value to the previous state. This is not merged with DebugScope because 571 // return_value_ will not be cleared when we use DebugScope. 572 class ReturnValueScope { 573 public: 574 explicit ReturnValueScope(Debug* debug); 575 ~ReturnValueScope(); 576 577 private: 578 Debug* debug_; 579 Handle<Object> return_value_; // Previous result. 580 }; 581 582 // Stack allocated class for disabling break. 583 class DisableBreak BASE_EMBEDDED { 584 public: 585 explicit DisableBreak(Debug* debug, bool disable = true) debug_(debug)586 : debug_(debug), previous_break_disabled_(debug->break_disabled_) { 587 debug_->break_disabled_ = disable; 588 } ~DisableBreak()589 ~DisableBreak() { 590 debug_->break_disabled_ = previous_break_disabled_; 591 } 592 593 private: 594 Debug* debug_; 595 bool previous_break_disabled_; 596 DISALLOW_COPY_AND_ASSIGN(DisableBreak); 597 }; 598 599 600 class SuppressDebug BASE_EMBEDDED { 601 public: SuppressDebug(Debug * debug)602 explicit SuppressDebug(Debug* debug) 603 : debug_(debug), old_state_(debug->is_suppressed_) { 604 debug_->is_suppressed_ = true; 605 } ~SuppressDebug()606 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; } 607 608 private: 609 Debug* debug_; 610 bool old_state_; 611 DISALLOW_COPY_AND_ASSIGN(SuppressDebug); 612 }; 613 614 // Code generator routines. 615 class DebugCodegen : public AllStatic { 616 public: 617 enum DebugBreakCallHelperMode { 618 SAVE_RESULT_REGISTER, 619 IGNORE_RESULT_REGISTER 620 }; 621 622 // Builtin to drop frames to restart function. 623 static void GenerateFrameDropperTrampoline(MacroAssembler* masm); 624 625 // Builtin to atomically (wrt deopts) handle debugger statement and 626 // drop frames to restart function if necessary. 627 static void GenerateHandleDebuggerStatement(MacroAssembler* masm); 628 629 // Builtin to trigger a debug break before entering the function. 630 static void GenerateDebugBreakTrampoline(MacroAssembler* masm); 631 }; 632 633 634 } // namespace internal 635 } // namespace v8 636 637 #endif // V8_DEBUG_DEBUG_H_ 638