// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_DEBUG_H_ #define V8_DEBUG_H_ #include "src/allocation.h" #include "src/arguments.h" #include "src/assembler.h" #include "src/base/atomicops.h" #include "src/base/platform/platform.h" #include "src/execution.h" #include "src/factory.h" #include "src/flags.h" #include "src/frames-inl.h" #include "src/hashmap.h" #include "src/liveedit.h" #include "src/string-stream.h" #include "src/v8threads.h" #include "include/v8-debug.h" namespace v8 { namespace internal { // Forward declarations. class DebugScope; // Step actions. NOTE: These values are in macros.py as well. enum StepAction { StepNone = -1, // Stepping not prepared. StepOut = 0, // Step out of the current function. StepNext = 1, // Step to the next statement in the current function. StepIn = 2, // Step into new functions invoked or the next statement // in the current function. StepMin = 3, // Perform a minimum step in the current function. StepInMin = 4, // Step into new functions invoked or perform a minimum step // in the current function. StepFrame = 5 // Step into a new frame or return to previous frame. }; // Type of exception break. NOTE: These values are in macros.py as well. enum ExceptionBreakType { BreakException = 0, BreakUncaughtException = 1 }; // Type of exception break. enum BreakLocatorType { ALL_BREAK_LOCATIONS = 0, SOURCE_BREAK_LOCATIONS = 1, CALLS_AND_RETURNS = 2 }; // The different types of breakpoint position alignments. // Must match Debug.BreakPositionAlignment in debug-debugger.js enum BreakPositionAlignment { STATEMENT_ALIGNED = 0, BREAK_POSITION_ALIGNED = 1 }; class BreakLocation { public: // Find the break point at the supplied address, or the closest one before // the address. static BreakLocation FromAddress(Handle debug_info, BreakLocatorType type, Address pc); static void FromAddressSameStatement(Handle debug_info, BreakLocatorType type, Address pc, List* result_out); static BreakLocation FromPosition(Handle debug_info, BreakLocatorType type, int position, BreakPositionAlignment alignment); bool IsDebugBreak() const; inline bool IsExit() const { return RelocInfo::IsJSReturn(rmode_); } inline bool IsConstructCall() const { return RelocInfo::IsConstructCall(rmode_); } inline bool IsCodeTarget() const { return RelocInfo::IsCodeTarget(rmode_); } Handle CodeTarget() const; Handle OriginalCodeTarget() const; bool IsStepInLocation() const; inline bool HasBreakPoint() const { return debug_info_->HasBreakPoint(pc_offset_); } Handle BreakPointObjects() const; void SetBreakPoint(Handle break_point_object); void ClearBreakPoint(Handle break_point_object); void SetOneShot(); void ClearOneShot(); inline RelocInfo rinfo() const { return RelocInfo(pc(), rmode(), data_, code()); } inline RelocInfo original_rinfo() const { return RelocInfo(original_pc(), original_rmode(), original_data_, original_code()); } inline int position() const { return position_; } inline int statement_position() const { return statement_position_; } inline Address pc() const { return code()->entry() + pc_offset_; } inline Address original_pc() const { return original_code()->entry() + original_pc_offset_; } inline RelocInfo::Mode rmode() const { return rmode_; } inline RelocInfo::Mode original_rmode() const { return original_rmode_; } inline Code* code() const { return debug_info_->code(); } inline Code* original_code() const { return debug_info_->original_code(); } private: BreakLocation(Handle debug_info, RelocInfo* rinfo, RelocInfo* original_rinfo, int position, int statement_position) : debug_info_(debug_info), pc_offset_(static_cast(rinfo->pc() - debug_info->code()->entry())), original_pc_offset_(static_cast( original_rinfo->pc() - debug_info->original_code()->entry())), rmode_(rinfo->rmode()), original_rmode_(original_rinfo->rmode()), data_(rinfo->data()), original_data_(original_rinfo->data()), position_(position), statement_position_(statement_position) {} class Iterator { public: Iterator(Handle debug_info, BreakLocatorType type); BreakLocation GetBreakLocation() { return BreakLocation(debug_info_, rinfo(), original_rinfo(), position(), statement_position()); } inline bool Done() const { return RinfoDone(); } void Next(); void SkipTo(int count) { while (count-- > 0) Next(); } inline RelocInfo::Mode rmode() { return reloc_iterator_.rinfo()->rmode(); } inline RelocInfo::Mode original_rmode() { return reloc_iterator_.rinfo()->rmode(); } inline RelocInfo* rinfo() { return reloc_iterator_.rinfo(); } inline RelocInfo* original_rinfo() { return reloc_iterator_original_.rinfo(); } inline Address pc() { return rinfo()->pc(); } inline Address original_pc() { return original_rinfo()->pc(); } int break_index() const { return break_index_; } inline int position() const { return position_; } inline int statement_position() const { return statement_position_; } private: bool RinfoDone() const; void RinfoNext(); Handle debug_info_; BreakLocatorType type_; RelocIterator reloc_iterator_; RelocIterator reloc_iterator_original_; int break_index_; int position_; int statement_position_; DisallowHeapAllocation no_gc_; DISALLOW_COPY_AND_ASSIGN(Iterator); }; friend class Debug; static int BreakIndexFromAddress(Handle debug_info, BreakLocatorType type, Address pc); void ClearDebugBreak(); void RestoreFromOriginal(int length_in_bytes); void SetDebugBreak(); void SetDebugBreakAtReturn(); void SetDebugBreakAtSlot(); void SetDebugBreakAtIC(); inline bool IsDebuggerStatement() const { return RelocInfo::IsDebuggerStatement(rmode_); } inline bool IsDebugBreakSlot() const { return RelocInfo::IsDebugBreakSlot(rmode_); } Handle debug_info_; int pc_offset_; int original_pc_offset_; RelocInfo::Mode rmode_; RelocInfo::Mode original_rmode_; intptr_t data_; intptr_t original_data_; int position_; int statement_position_; }; // Cache of all script objects in the heap. When a script is added a weak handle // to it is created and that weak handle is stored in the cache. The weak handle // callback takes care of removing the script from the cache. The key used in // the cache is the script id. class ScriptCache : private HashMap { public: explicit ScriptCache(Isolate* isolate); virtual ~ScriptCache() { Clear(); } // Add script to the cache. void Add(Handle