debug-interface.h 16.6 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2016 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_DEBUG_INTERFACE_H_
#define V8_DEBUG_DEBUG_INTERFACE_H_

8
#include "include/v8-inspector.h"
9
#include "include/v8-util.h"
10 11
#include "include/v8.h"

12
#include "src/debug/interface-types.h"
13
#include "src/globals.h"
14

15
namespace v8 {
16 17

namespace internal {
18
struct CoverageBlock;
19 20
struct CoverageFunction;
struct CoverageScript;
21 22
struct TypeProfileEntry;
struct TypeProfileScript;
23 24
class Coverage;
class Script;
25 26
class TypeProfile;
}  // namespace internal
27

28
namespace debug {
29

30 31 32
void SetContextId(Local<Context> context, int id);
int GetContextId(Local<Context> context);

33 34 35
void SetInspector(Isolate* isolate, v8_inspector::V8Inspector*);
v8_inspector::V8Inspector* GetInspector(Isolate* isolate);

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
/**
 * Debugger is running in its own context which is entered while debugger
 * messages are being dispatched. This is an explicit getter for this
 * debugger context. Note that the content of the debugger context is subject
 * to change. The Context exists only when the debugger is active, i.e. at
 * least one DebugEventListener or MessageHandler is set.
 */
Local<Context> GetDebugContext(Isolate* isolate);

/**
 * Run a JavaScript function in the debugger.
 * \param fun the function to call
 * \param data passed as second argument to the function
 * With this call the debugger is entered and the function specified is called
 * with the execution state as the first argument. This makes it possible to
 * get access to information otherwise not available during normal JavaScript
 * execution e.g. details on stack frames. Receiver of the function call will
 * be the debugger context global object, however this is a subject to change.
 * The following example shows a JavaScript function which when passed to
 * v8::Debug::Call will return the current line of JavaScript execution.
 *
 * \code
 *   function frame_source_line(exec_state) {
 *     return exec_state.frame(0).sourceLine();
 *   }
 * \endcode
 */
// TODO(dcarney): data arg should be a MaybeLocal
MaybeLocal<Value> Call(Local<Context> context, v8::Local<v8::Function> fun,
                       Local<Value> data = Local<Value>());

/**
 * Enable/disable LiveEdit functionality for the given Isolate
 * (default Isolate if not provided). V8 will abort if LiveEdit is
 * unexpectedly used. LiveEdit is enabled by default.
 */
72
V8_EXPORT_PRIVATE void SetLiveEditEnabled(Isolate* isolate, bool enable);
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93

// Schedule a debugger break to happen when JavaScript code is run
// in the given isolate.
void DebugBreak(Isolate* isolate);

// Remove scheduled debugger break in given isolate if it has not
// happened yet.
void CancelDebugBreak(Isolate* isolate);

/**
 * Returns array of internal properties specific to the value type. Result has
 * the following format: [<name>, <value>,...,<name>, <value>]. Result array
 * will be allocated in the current context.
 */
MaybeLocal<Array> GetInternalProperties(Isolate* isolate, Local<Value> value);

enum ExceptionBreakState {
  NoBreakOnException = 0,
  BreakOnUncaughtException = 1,
  BreakOnAnyException = 2
};
94

95 96 97 98 99 100 101 102
/**
 * Defines if VM will pause on exceptions or not.
 * If BreakOnAnyExceptions is set then VM will pause on caught and uncaught
 * exception, if BreakOnUncaughtException is set then VM will pause only on
 * uncaught exception, otherwise VM won't stop on any exception.
 */
void ChangeBreakOnException(Isolate* isolate, ExceptionBreakState state);

103
void RemoveBreakpoint(Isolate* isolate, BreakpointId id);
104 105
void SetBreakPointsActive(Isolate* isolate, bool is_active);

106 107 108
enum StepAction {
  StepOut = 0,   // Step out of the current function.
  StepNext = 1,  // Step to the next statement in the current function.
109
  StepIn = 2     // Step into new functions invoked or the next statement
110 111
                 // in the current function.
};
112

113
void PrepareStep(Isolate* isolate, StepAction action);
114
void ClearStepping(Isolate* isolate);
115
void BreakRightNow(Isolate* isolate);
116

117
bool AllFramesOnStackAreBlackboxed(Isolate* isolate);
118

119 120 121 122 123 124 125
/**
 * Out-of-memory callback function.
 * The function is invoked when the heap size is close to the hard limit.
 *
 * \param data the parameter provided during callback installation.
 */
typedef void (*OutOfMemoryCallback)(void* data);
126 127 128 129 130

V8_DEPRECATED("Use v8::Isolate::AddNearHeapLimitCallback",
              void SetOutOfMemoryCallback(Isolate* isolate,
                                          OutOfMemoryCallback callback,
                                          void* data));
131

132 133 134
/**
 * Native wrapper around v8::internal::Script object.
 */
135
class V8_EXPORT_PRIVATE Script {
136 137 138 139 140
 public:
  v8::Isolate* GetIsolate() const;

  ScriptOriginOptions OriginOptions() const;
  bool WasCompiled() const;
141
  bool IsEmbedded() const;
142 143 144 145 146 147 148
  int Id() const;
  int LineOffset() const;
  int ColumnOffset() const;
  std::vector<int> LineEnds() const;
  MaybeLocal<String> Name() const;
  MaybeLocal<String> SourceURL() const;
  MaybeLocal<String> SourceMappingURL() const;
149
  Maybe<int> ContextId() const;
150 151
  MaybeLocal<String> Source() const;
  bool IsWasm() const;
152
  bool IsModule() const;
153 154 155 156
  bool GetPossibleBreakpoints(
      const debug::Location& start, const debug::Location& end,
      bool restrict_to_function,
      std::vector<debug::BreakLocation>* locations) const;
157 158
  int GetSourceOffset(const debug::Location& location) const;
  v8::debug::Location GetSourceLocation(int offset) const;
159 160
  bool SetScriptSource(v8::Local<v8::String> newSource, bool preview,
                       bool* stack_changed) const;
161 162
  bool SetBreakpoint(v8::Local<v8::String> condition, debug::Location* location,
                     BreakpointId* id) const;
163
};
164

165 166 167 168
// Specialization for wasm Scripts.
class WasmScript : public Script {
 public:
  static WasmScript* Cast(Script* script);
169

170 171 172
  int NumFunctions() const;
  int NumImportedFunctions() const;

173 174
  std::pair<int, int> GetFunctionRange(int function_index) const;

175
  debug::WasmDisassembly DisassembleFunction(int function_index) const;
176
  uint32_t GetFunctionHash(int function_index);
177 178 179
};

void GetLoadedScripts(Isolate* isolate, PersistentValueVector<Script>& scripts);
180

181 182
MaybeLocal<UnboundScript> CompileInspectorScript(Isolate* isolate,
                                                 Local<String> source);
183

184
class DebugDelegate {
185
 public:
186
  virtual ~DebugDelegate() {}
187
  virtual void PromiseEventOccurred(debug::PromiseDebugActionType type, int id,
188
                                    bool is_blackboxed) {}
189
  virtual void ScriptCompiled(v8::Local<Script> script, bool is_live_edited,
190
                              bool has_compile_error) {}
191 192 193 194 195
  // |inspector_break_points_hit| contains id of breakpoints installed with
  // debug::Script::SetBreakpoint API.
  virtual void BreakProgramRequested(
      v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state,
      const std::vector<debug::BreakpointId>& inspector_break_points_hit) {}
196 197 198
  virtual void ExceptionThrown(v8::Local<v8::Context> paused_context,
                               v8::Local<v8::Object> exec_state,
                               v8::Local<v8::Value> exception,
199 200
                               v8::Local<v8::Value> promise, bool is_uncaught) {
  }
201 202 203 204 205
  virtual bool IsFunctionBlackboxed(v8::Local<debug::Script> script,
                                    const debug::Location& start,
                                    const debug::Location& end) {
    return false;
  }
206 207
};

208 209 210 211
void SetDebugDelegate(Isolate* isolate, DebugDelegate* listener);

void ResetBlackboxedStateCache(Isolate* isolate,
                               v8::Local<debug::Script> script);
212

213 214
int EstimatedValueSize(Isolate* isolate, v8::Local<v8::Value> value);

215 216 217 218
v8::MaybeLocal<v8::Array> EntriesPreview(Isolate* isolate,
                                         v8::Local<v8::Value> value,
                                         bool* is_key_value);

219 220 221 222 223 224 225 226 227 228
enum Builtin {
  kObjectKeys,
  kObjectGetPrototypeOf,
  kObjectGetOwnPropertyDescriptor,
  kObjectGetOwnPropertyNames,
  kObjectGetOwnPropertySymbols,
};

Local<Function> GetBuiltin(Isolate* isolate, Builtin builtin);

229 230
V8_EXPORT_PRIVATE void SetConsoleDelegate(Isolate* isolate,
                                          ConsoleDelegate* delegate);
231

232 233
int GetStackFrameId(v8::Local<v8::StackFrame> frame);

234 235 236
v8::Local<v8::StackTrace> GetDetailedStackTrace(Isolate* isolate,
                                                v8::Local<v8::Object> error);

237 238 239 240 241 242 243 244 245 246 247 248 249
/**
 * Native wrapper around v8::internal::JSGeneratorObject object.
 */
class GeneratorObject {
 public:
  v8::MaybeLocal<debug::Script> Script();
  v8::Local<v8::Function> Function();
  debug::Location SuspendedLocation();
  bool IsSuspended();

  static v8::Local<debug::GeneratorObject> Cast(v8::Local<v8::Value> value);
};

250 251 252 253 254
/*
 * Provide API layer between inspector and code coverage.
 */
class V8_EXPORT_PRIVATE Coverage {
 public:
255 256
  MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Coverage);

257 258
  enum Mode {
    // Make use of existing information in feedback vectors on the heap.
259 260
    // Only return a yes/no result. Optimization and GC are not affected.
    // Collecting best effort coverage does not reset counters.
261 262
    kBestEffort,
    // Disable optimization and prevent feedback vectors from being garbage
263 264
    // collected in order to preserve precise invocation counts. Collecting
    // precise count coverage resets counters to get incremental updates.
265
    kPreciseCount,
266 267 268
    // We are only interested in a yes/no result for the function. Optimization
    // and GC can be allowed once a function has been invoked. Collecting
    // precise binary coverage resets counters for incremental updates.
269 270 271 272
    kPreciseBinary,
    // Similar to the precise coverage modes but provides coverage at a
    // lower granularity. Design doc: goo.gl/lA2swZ.
    kBlockCount,
273
    kBlockBinary,
274 275
  };

276 277 278 279 280 281
  // Forward declarations.
  class ScriptData;
  class FunctionData;

  class V8_EXPORT_PRIVATE BlockData {
   public:
282 283
    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(BlockData);

284 285 286 287 288
    int StartOffset() const;
    int EndOffset() const;
    uint32_t Count() const;

   private:
289 290 291 292
    explicit BlockData(i::CoverageBlock* block,
                       std::shared_ptr<i::Coverage> coverage)
        : block_(block), coverage_(std::move(coverage)) {}

293
    i::CoverageBlock* block_;
294
    std::shared_ptr<i::Coverage> coverage_;
295 296 297

    friend class v8::debug::Coverage::FunctionData;
  };
298 299

  class V8_EXPORT_PRIVATE FunctionData {
300
   public:
301 302
    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(FunctionData);

303 304 305 306
    int StartOffset() const;
    int EndOffset() const;
    uint32_t Count() const;
    MaybeLocal<String> Name() const;
307
    size_t BlockCount() const;
308
    bool HasBlockCoverage() const;
309
    BlockData GetBlockData(size_t i) const;
310 311

   private:
312 313 314 315
    explicit FunctionData(i::CoverageFunction* function,
                          std::shared_ptr<i::Coverage> coverage)
        : function_(function), coverage_(std::move(coverage)) {}

316
    i::CoverageFunction* function_;
317
    std::shared_ptr<i::Coverage> coverage_;
318

319 320 321 322 323
    friend class v8::debug::Coverage::ScriptData;
  };

  class V8_EXPORT_PRIVATE ScriptData {
   public:
324 325
    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ScriptData);

326 327 328
    Local<debug::Script> GetScript() const;
    size_t FunctionCount() const;
    FunctionData GetFunctionData(size_t i) const;
329 330

   private:
331 332
    explicit ScriptData(size_t index, std::shared_ptr<i::Coverage> c);

333
    i::CoverageScript* script_;
334
    std::shared_ptr<i::Coverage> coverage_;
335 336

    friend class v8::debug::Coverage;
337 338
  };

339 340
  static Coverage CollectPrecise(Isolate* isolate);
  static Coverage CollectBestEffort(Isolate* isolate);
341

342
  static void SelectMode(Isolate* isolate, Mode mode);
343

344 345 346
  size_t ScriptCount() const;
  ScriptData GetScriptData(size_t i) const;
  bool IsEmpty() const { return coverage_ == nullptr; }
347 348

 private:
349 350
  explicit Coverage(std::shared_ptr<i::Coverage> coverage)
      : coverage_(std::move(coverage)) {}
351
  std::shared_ptr<i::Coverage> coverage_;
352
};
353

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
/*
 * Provide API layer between inspector and type profile.
 */
class V8_EXPORT_PRIVATE TypeProfile {
 public:
  MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(TypeProfile);

  enum Mode {
    kNone,
    kCollect,
  };
  class ScriptData;  // Forward declaration.

  class V8_EXPORT_PRIVATE Entry {
   public:
    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(Entry);

    int SourcePosition() const;
    std::vector<MaybeLocal<String>> Types() const;

   private:
375 376 377 378
    explicit Entry(const i::TypeProfileEntry* entry,
                   std::shared_ptr<i::TypeProfile> type_profile)
        : entry_(entry), type_profile_(std::move(type_profile)) {}

379
    const i::TypeProfileEntry* entry_;
380
    std::shared_ptr<i::TypeProfile> type_profile_;
381 382 383 384 385 386 387 388 389 390 391 392

    friend class v8::debug::TypeProfile::ScriptData;
  };

  class V8_EXPORT_PRIVATE ScriptData {
   public:
    MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ScriptData);

    Local<debug::Script> GetScript() const;
    std::vector<Entry> Entries() const;

   private:
393 394 395
    explicit ScriptData(size_t index,
                        std::shared_ptr<i::TypeProfile> type_profile);

396
    i::TypeProfileScript* script_;
397
    std::shared_ptr<i::TypeProfile> type_profile_;
398 399 400 401 402 403 404 405 406 407 408 409

    friend class v8::debug::TypeProfile;
  };

  static TypeProfile Collect(Isolate* isolate);

  static void SelectMode(Isolate* isolate, Mode mode);

  size_t ScriptCount() const;
  ScriptData GetScriptData(size_t i) const;

 private:
410 411 412 413
  explicit TypeProfile(std::shared_ptr<i::TypeProfile> type_profile)
      : type_profile_(std::move(type_profile)) {}

  std::shared_ptr<i::TypeProfile> type_profile_;
414 415
};

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
class ScopeIterator {
 public:
  static std::unique_ptr<ScopeIterator> CreateForFunction(
      v8::Isolate* isolate, v8::Local<v8::Function> func);
  static std::unique_ptr<ScopeIterator> CreateForGeneratorObject(
      v8::Isolate* isolate, v8::Local<v8::Object> generator);

  ScopeIterator() = default;
  virtual ~ScopeIterator() = default;

  enum ScopeType {
    ScopeTypeGlobal = 0,
    ScopeTypeLocal,
    ScopeTypeWith,
    ScopeTypeClosure,
    ScopeTypeCatch,
    ScopeTypeBlock,
    ScopeTypeScript,
    ScopeTypeEval,
    ScopeTypeModule
  };

  virtual bool Done() = 0;
  virtual void Advance() = 0;
  virtual ScopeType GetType() = 0;
  virtual v8::Local<v8::Object> GetObject() = 0;
  virtual v8::Local<v8::Function> GetFunction() = 0;
  virtual debug::Location GetStartLocation() = 0;
  virtual debug::Location GetEndLocation() = 0;

  virtual bool SetVariableValue(v8::Local<v8::String> name,
                                v8::Local<v8::Value> value) = 0;

 private:
  DISALLOW_COPY_AND_ASSIGN(ScopeIterator);
};

class StackTraceIterator {
 public:
  static std::unique_ptr<StackTraceIterator> Create(Isolate* isolate,
                                                    int index = 0);
  StackTraceIterator() = default;
  virtual ~StackTraceIterator() = default;

  virtual bool Done() const = 0;
  virtual void Advance() = 0;

  virtual int GetContextId() const = 0;
464
  virtual v8::MaybeLocal<v8::Value> GetReceiver() const = 0;
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
  virtual v8::Local<v8::Value> GetReturnValue() const = 0;
  virtual v8::Local<v8::String> GetFunctionName() const = 0;
  virtual v8::Local<v8::debug::Script> GetScript() const = 0;
  virtual debug::Location GetSourceLocation() const = 0;
  virtual v8::Local<v8::Function> GetFunction() const = 0;
  virtual std::unique_ptr<ScopeIterator> GetScopeIterator() const = 0;

  virtual bool Restart() = 0;
  virtual v8::MaybeLocal<v8::Value> Evaluate(v8::Local<v8::String> source,
                                             bool throw_on_side_effect) = 0;

 private:
  DISALLOW_COPY_AND_ASSIGN(StackTraceIterator);
};

480 481 482 483 484 485 486 487 488 489
class QueryObjectPredicate {
 public:
  virtual ~QueryObjectPredicate() = default;
  virtual bool Filter(v8::Local<v8::Object> object) = 0;
};

void QueryObjects(v8::Local<v8::Context> context,
                  QueryObjectPredicate* predicate,
                  v8::PersistentValueVector<v8::Object>* objects);

490 491 492
void GlobalLexicalScopeNames(v8::Local<v8::Context> context,
                             v8::PersistentValueVector<v8::String>* names);

493 494
void SetReturnValue(v8::Isolate* isolate, v8::Local<v8::Value> value);

495 496 497 498 499 500 501 502 503 504 505
enum class NativeAccessorType {
  None = 0,
  HasGetter = 1 << 0,
  HasSetter = 1 << 1,
  IsBuiltin = 1 << 2
};

int GetNativeAccessorDescriptor(v8::Local<v8::Context> context,
                                v8::Local<v8::Object> object,
                                v8::Local<v8::Name> name);

506 507
int64_t GetNextRandomInt64(v8::Isolate* isolate);

508
v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
509 510
                                         v8::Local<v8::String> source,
                                         bool throw_on_side_effect);
511

512 513 514 515 516
int GetDebuggingId(v8::Local<v8::Function> function);

bool SetFunctionBreakpoint(v8::Local<v8::Function> function,
                           v8::Local<v8::String> condition, BreakpointId* id);

517
}  // namespace debug
518 519 520
}  // namespace v8

#endif  // V8_DEBUG_DEBUG_INTERFACE_H_