BreakEventHandler.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. var convert = require('./convert'),
  2. CallFramesProvider = require('./CallFramesProvider').CallFramesProvider;
  3. /**
  4. * @param {Object} config
  5. * @param {FrontendClient} frontendClient
  6. * @param {DebuggerClient} debuggerClient
  7. * @param {ScriptManager} scriptManager
  8. * @constructor
  9. */
  10. function BreakEventHandler(config, frontendClient, debuggerClient, scriptManager) {
  11. this._config = config;
  12. this._frontendClient = frontendClient;
  13. this._debuggerClient = debuggerClient;
  14. this._scriptManager = scriptManager;
  15. this._callFramesProvider = new CallFramesProvider(config, debuggerClient);
  16. this._registerDebuggerEventHandlers();
  17. }
  18. var callbackForNextBreak;
  19. Object.defineProperties(BreakEventHandler.prototype, {
  20. /** @type {Number} */
  21. continueToLocationBreakpointId: {
  22. writable: true,
  23. value: null
  24. },
  25. /** @type {function(eventData)} */
  26. callbackForNextBreak: {
  27. get: function() { return callbackForNextBreak; },
  28. set: function(value) {
  29. if (value && callbackForNextBreak)
  30. throw new Error('Cannot set multiple callbacks for the next break.');
  31. callbackForNextBreak = value;
  32. }
  33. }
  34. });
  35. BreakEventHandler.prototype._registerDebuggerEventHandlers = function() {
  36. this._debuggerClient.on('break', this._onBreak.bind(this));
  37. this._debuggerClient.on('exception', this._onBreak.bind(this));
  38. };
  39. BreakEventHandler.prototype._onBreak = function(obj) {
  40. var scriptId = obj.script.id,
  41. hitBreakpoints = obj.breakpoints,
  42. source = this._scriptManager.findScriptByID(scriptId);
  43. // Source is undefined when the breakpoint was in code eval()-ed via
  44. // console or eval()-ed internally by node inspector.
  45. // We could send backtrace in such case, but that isn't working well now.
  46. // V8 is reusing the same scriptId for multiple eval() calls and DevTools
  47. // front-end does not update the displayed source code when a content
  48. // of a script changes.
  49. // The following solution - ignore the breakpoint and resume the
  50. // execution - should be good enough in most cases.
  51. if (!source || source.hidden) {
  52. this._debuggerClient.request('continue', { stepaction: 'out' });
  53. return;
  54. }
  55. if (this.callbackForNextBreak) {
  56. var callback = this.callbackForNextBreak;
  57. this.callbackForNextBreak = null;
  58. callback(obj);
  59. return;
  60. }
  61. if (this.continueToLocationBreakpointId !== null) {
  62. this._debuggerClient.clearBreakpoint(
  63. this.continueToLocationBreakpointId,
  64. function(err, result) {
  65. if (err)
  66. this._frontendClient.sendLogToConsole('warning', err);
  67. else
  68. this.continueToLocationBreakpointId = null;
  69. }.bind(this)
  70. );
  71. }
  72. this.sendBacktraceToFrontend(obj.exception, hitBreakpoints);
  73. };
  74. /**
  75. * @param {function(error, response)} callback
  76. */
  77. BreakEventHandler.prototype.fetchCallFrames = function(callback) {
  78. this._callFramesProvider.fetchCallFrames(callback);
  79. };
  80. /**
  81. * @param {Object} exception
  82. * @param {Array.<number>} hitBreakpoints
  83. */
  84. BreakEventHandler.prototype.sendBacktraceToFrontend = function(exception, hitBreakpoints) {
  85. this.fetchCallFrames(function(error, result) {
  86. if (error)
  87. this._frontendClient.sendLogToConsole('error', error);
  88. else
  89. this._frontendClient.sendEvent(
  90. 'Debugger.paused',
  91. {
  92. callFrames: result,
  93. reason: exception ? 'exception' : 'other',
  94. data: exception ? convert.v8RefToInspectorObject(exception) : null,
  95. hitBreakpoints: hitBreakpoints
  96. });
  97. }.bind(this));
  98. };
  99. exports.BreakEventHandler = BreakEventHandler;