DebuggerAPI.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #ifndef HERMES_DEBUGGERAPI_H
  8. #define HERMES_DEBUGGERAPI_H
  9. #ifdef HERMES_ENABLE_DEBUGGER
  10. #include <hermes/hermes.h>
  11. #include <cassert>
  12. #include <memory>
  13. #include <vector>
  14. #include "hermes/Public/DebuggerTypes.h"
  15. // Forward declarations of internal types.
  16. namespace hermes {
  17. namespace vm {
  18. class CodeBlock;
  19. class Debugger;
  20. struct DebugCommand;
  21. class HermesValue;
  22. } // namespace vm
  23. } // namespace hermes
  24. namespace facebook {
  25. namespace hermes {
  26. class HermesRuntime;
  27. namespace debugger {
  28. class Debugger;
  29. class EventObserver;
  30. /// Represents a variable in the debugger.
  31. struct VariableInfo {
  32. /// Name of the variable in the source.
  33. String name;
  34. /// Value of the variable.
  35. ::facebook::jsi::Value value;
  36. };
  37. /// An EvalResult represents the result of an Eval command.
  38. struct EvalResult {
  39. /// The resulting JavaScript object, or the thrown exception.
  40. ::facebook::jsi::Value value;
  41. /// Indicates that the result was an exception.
  42. bool isException = false;
  43. /// If isException is true, details about the exception.
  44. ExceptionDetails exceptionDetails;
  45. EvalResult(EvalResult &&) = default;
  46. EvalResult() = default;
  47. EvalResult(
  48. ::facebook::jsi::Value value,
  49. bool isException,
  50. ExceptionDetails exceptionDetails)
  51. : value(std::move(value)),
  52. isException(isException),
  53. exceptionDetails(std::move(exceptionDetails)) {}
  54. };
  55. /// ProgramState represents the state of a paused program. An instance of
  56. /// ProgramState is available as the getProgramState() member function of class
  57. /// Debugger.
  58. class ProgramState {
  59. public:
  60. /// \return the reason for the Pause.
  61. PauseReason getPauseReason() const {
  62. return pauseReason_;
  63. }
  64. /// \return the breakpoint if the PauseReason is Breakpoint, otherwise
  65. /// kInvalidBreakpoint.
  66. BreakpointID getBreakpoint() const {
  67. return breakpoint_;
  68. }
  69. /// \return the evaluation result if the PauseReason is due to EvalComplete.
  70. EvalResult getEvalResult() const;
  71. /// \returns a stack trace for the current execution.
  72. const StackTrace &getStackTrace() const {
  73. return stackTrace_;
  74. }
  75. /// \returns lexical information about the state in a given frame.
  76. LexicalInfo getLexicalInfo(uint32_t frameIndex) const;
  77. /// \return information about a variable in a given lexical scope, in a given
  78. /// frame.
  79. VariableInfo getVariableInfo(
  80. uint32_t frameIndex,
  81. ScopeDepth scopeDepth,
  82. uint32_t variableIndexInScope) const;
  83. /// \return information about the `this` value at a given stack depth.
  84. VariableInfo getVariableInfoForThis(uint32_t frameIndex) const;
  85. /// \return the number of variables in a given frame.
  86. /// This is deprecated: prefer using getLexicalInfoInFrame().
  87. uint32_t getVariablesCountInFrame(uint32_t frameIndex) const {
  88. auto info = getLexicalInfo(frameIndex);
  89. uint32_t result = 0;
  90. for (ScopeDepth i = 0, max = info.getScopesCount(); i < max; i++)
  91. result += info.getVariablesCountInScope(i);
  92. return result;
  93. }
  94. /// \return info for a variable at a given index \p variableIndex, in a given
  95. /// frame at index \p frameIndex.
  96. /// This is deprecated. Prefer the getVariableInfo() that takes three
  97. /// parameters.
  98. VariableInfo getVariableInfo(uint32_t frameIndex, uint32_t variableIndex)
  99. const {
  100. LexicalInfo info = getLexicalInfo(frameIndex);
  101. uint32_t remaining = variableIndex;
  102. for (ScopeDepth scope = 0;; scope++) {
  103. assert(scope < info.getScopesCount() && "Index out of bounds");
  104. uint32_t count = info.getVariablesCountInScope(scope);
  105. if (remaining < count) {
  106. return getVariableInfo(frameIndex, scope, remaining);
  107. }
  108. remaining -= count;
  109. }
  110. }
  111. private:
  112. friend Debugger;
  113. /// ProgramState must not be copied, because some of its implementation
  114. /// requires querying the live program state and so the state must not be
  115. /// retained after the pause returns.
  116. /// ProgramState must not be copied.
  117. ProgramState(const ProgramState &) = delete;
  118. ProgramState &operator=(const ProgramState &) = delete;
  119. ::hermes::vm::Debugger *impl() const;
  120. ProgramState(Debugger *dbg) : dbg_(dbg) {}
  121. Debugger *dbg_;
  122. PauseReason pauseReason_{};
  123. StackTrace stackTrace_;
  124. EvalResult evalResult_;
  125. BreakpointID breakpoint_{kInvalidBreakpoint};
  126. };
  127. /// Command represents an action that you can request the debugger to perform
  128. /// when returned from didPause().
  129. class Command {
  130. public:
  131. /// Commands may be moved.
  132. Command(Command &&);
  133. Command &operator=(Command &&);
  134. ~Command();
  135. /// \return a Command that steps with the given StepMode \p mode.
  136. static Command step(StepMode mode);
  137. /// \return a Command that continues execution.
  138. static Command continueExecution();
  139. /// \return a Command that evaluates JavaScript code \p src in the
  140. /// frame at index \p frameIndex.
  141. static Command eval(const String &src, uint32_t frameIndex);
  142. private:
  143. friend Debugger;
  144. explicit Command(::hermes::vm::DebugCommand &&);
  145. std::unique_ptr<::hermes::vm::DebugCommand> debugCommand_;
  146. };
  147. /// Debugger allows access to the Hermes debugging functionality. An instance of
  148. /// Debugger is available from HermesRuntime, and also passed to your
  149. /// EventObserver.
  150. class Debugger {
  151. public:
  152. /// Set the Debugger event observer. The event observer is notified of
  153. /// debugging event, specifically when the program pauses. This is simply a
  154. /// raw pointer: it is the client's responsibility to clear the event observer
  155. /// if the event observer is deallocated before the Debugger.
  156. void setEventObserver(EventObserver *observer);
  157. /// Sets the property %isDebuggerAttached in %DebuggerInternal object.
  158. void setIsDebuggerAttached(bool isAttached);
  159. /// Asynchronously triggers a pause. This may be called from any thread. This
  160. /// is inherently racey and the exact point at which the program pauses is not
  161. /// guaranteed. You can discover when the program has paused through the event
  162. /// observer.
  163. void triggerAsyncPause(AsyncPauseKind kind);
  164. /// \return the ProgramState representing the state of the paused program.
  165. /// This may only be invoked when the program is paused.
  166. const ProgramState &getProgramState() const {
  167. return state_;
  168. }
  169. /// \return the source map URL for the \p fileId.
  170. String getSourceMappingUrl(uint32_t fileId) const;
  171. /// -- Breakpoint Management --
  172. /// Sets a breakpoint on a given SourceLocation.
  173. /// \return the ID of the breakpoint, 0 if it wasn't created.
  174. BreakpointID setBreakpoint(SourceLocation loc);
  175. /// Sets the condition on breakpoint \p breakpoint.
  176. /// The condition will be stored with the breakpoint,
  177. /// and if non-empty, will be executed to determine whether to actually
  178. /// pause on the breakpoint; only if ToBoolean(condition) is true
  179. /// and does not throw will the debugger pause on \p breakpoint.
  180. /// \param condition the code to execute to determine whether to break;
  181. /// if empty, the condition is considered to not be set.
  182. void setBreakpointCondition(BreakpointID breakpoint, const String &condition);
  183. /// Deletes a breakpoint.
  184. void deleteBreakpoint(BreakpointID breakpoint);
  185. /// Deletes all breakpoints.
  186. void deleteAllBreakpoints();
  187. /// Mark a breakpoint as enabled. Breakpoints are by default enabled.
  188. void setBreakpointEnabled(BreakpointID breakpoint, bool enable);
  189. /// \return information on a breakpoint.
  190. BreakpointInfo getBreakpointInfo(BreakpointID breakpoint);
  191. /// \return a list of extant breakpoints.
  192. std::vector<BreakpointID> getBreakpoints();
  193. /// Set whether the debugger should pause when an exception is thrown.
  194. void setPauseOnThrowMode(PauseOnThrowMode mode);
  195. /// \return whether the debugger pauses when an exception is thrown.
  196. PauseOnThrowMode getPauseOnThrowMode() const;
  197. /// Set whether the debugger should pause after a script was loaded.
  198. void setShouldPauseOnScriptLoad(bool flag);
  199. /// \return whether the debugger should pause after a script was loaded.
  200. bool getShouldPauseOnScriptLoad() const;
  201. private:
  202. friend std::unique_ptr<HermesRuntime> hermes::makeHermesRuntime(
  203. const ::hermes::vm::RuntimeConfig &);
  204. friend std::unique_ptr<jsi::ThreadSafeRuntime>
  205. hermes::makeThreadSafeHermesRuntime(const ::hermes::vm::RuntimeConfig &);
  206. friend ProgramState;
  207. /// Debuggers may not be moved or copied.
  208. Debugger(const Debugger &) = delete;
  209. void operator=(const Debugger &) = delete;
  210. Debugger(Debugger &&) = delete;
  211. void operator=(Debugger &&) = delete;
  212. /// Implementation detail used by ProgramState.
  213. ::facebook::jsi::Value jsiValueFromHermesValue(::hermes::vm::HermesValue hv);
  214. explicit Debugger(
  215. ::facebook::hermes::HermesRuntime *runtime,
  216. ::hermes::vm::Debugger *impl);
  217. ::facebook::hermes::HermesRuntime *const runtime_;
  218. EventObserver *eventObserver_ = nullptr;
  219. ::hermes::vm::Debugger *impl_;
  220. ProgramState state_;
  221. };
  222. /// A subclass of EventObserver may be set on the Debugger via
  223. /// setEventObserver(). It receives notifications when the Debugger pauses.
  224. class EventObserver {
  225. public:
  226. /// didPause() is invoked when the JavaScript program has paused. The
  227. /// The Debugger \p debugger can be used to manipulate breakpoints and enqueue
  228. /// debugger commands such as stepping, etc. It can also be used to discover
  229. /// the call stack and variables via debugger.getProgramState().
  230. /// \return a Command for the debugger to perform.
  231. virtual Command didPause(Debugger &debugger) = 0;
  232. /// Invoked when the debugger resolves a previously unresolved breakpoint.
  233. /// Note that the debugger is *not* paused during this,
  234. /// and thus debugger.getProgramState() is not valid.
  235. /// This callback may not invoke JavaScript or enqueue debugger commands.
  236. virtual void breakpointResolved(Debugger &debugger, BreakpointID breakpoint) {
  237. }
  238. virtual ~EventObserver();
  239. };
  240. } // namespace debugger
  241. } // namespace hermes
  242. } // namespace facebook
  243. #endif // HERMES_ENABLE_DEBUGGER
  244. #endif // HERMES_DEBUGGERAPI_H