summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/utils/make-debugger.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/utils/make-debugger.js')
-rw-r--r--devtools/server/actors/utils/make-debugger.js122
1 files changed, 122 insertions, 0 deletions
diff --git a/devtools/server/actors/utils/make-debugger.js b/devtools/server/actors/utils/make-debugger.js
new file mode 100644
index 0000000000..40c28f01b2
--- /dev/null
+++ b/devtools/server/actors/utils/make-debugger.js
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const EventEmitter = require("resource://devtools/shared/event-emitter.js");
+const Debugger = require("Debugger");
+
+const {
+ reportException,
+} = require("resource://devtools/shared/DevToolsUtils.js");
+
+/**
+ * Multiple actors that use a |Debugger| instance come in a few versions, each
+ * with a different set of debuggees. One version for content tabs (globals
+ * within a tab), one version for chrome debugging (all globals), and sometimes
+ * a third version for addon debugging (chrome globals the addon is loaded in
+ * and content globals the addon injects scripts into). The |makeDebugger|
+ * function helps us avoid repeating the logic for finding and maintaining the
+ * correct set of globals for a given |Debugger| instance across each version of
+ * all of our actors.
+ *
+ * The |makeDebugger| function expects a single object parameter with the
+ * following properties:
+ *
+ * @param Function findDebuggees
+ * Called with one argument: a |Debugger| instance. This function should
+ * return an iterable of globals to be added to the |Debugger|
+ * instance. The globals are the actual global objects and aren't wrapped
+ * in in a |Debugger.Object|.
+ *
+ * @param Function shouldAddNewGlobalAsDebuggee
+ * Called with one argument: a |Debugger.Object| wrapping a global
+ * object. This function must return |true| if the global object should
+ * be added as debuggee, and |false| otherwise.
+ *
+ * @returns Debugger
+ * Returns a |Debugger| instance that can manage its set of debuggee
+ * globals itself and is decorated with the |EventEmitter| class.
+ *
+ * Existing |Debugger| properties set on the returned |Debugger|
+ * instance:
+ *
+ * - onNewGlobalObject: The |Debugger| will automatically add new
+ * globals as debuggees if calling |shouldAddNewGlobalAsDebuggee|
+ * with the global returns true.
+ *
+ * - uncaughtExceptionHook: The |Debugger| already has an error
+ * reporter attached to |uncaughtExceptionHook|, so if any
+ * |Debugger| hooks fail, the error will be reported.
+ *
+ * New properties set on the returned |Debugger| instance:
+ *
+ * - addDebuggees: A function which takes no arguments. It adds all
+ * current globals that should be debuggees (as determined by
+ * |findDebuggees|) to the |Debugger| instance.
+ */
+module.exports = function makeDebugger({
+ findDebuggees,
+ shouldAddNewGlobalAsDebuggee,
+} = {}) {
+ const dbg = new Debugger();
+ EventEmitter.decorate(dbg);
+
+ // By default, we disable asm.js and WASM debugging because of performance reason.
+ // Enabling asm.js debugging (allowUnobservedAsmJS=false) will make asm.js fallback to JS compiler
+ // and be debugging as a regular JS script.
+ dbg.allowUnobservedAsmJS = true;
+ // Enabling WASM debugging (allowUnobservedWasm=false) will make the engine compile WASM scripts
+ // into different machine code with debugging instructions. This significantly increase the memory usage of it.
+ dbg.allowUnobservedWasm = true;
+
+ dbg.uncaughtExceptionHook = reportDebuggerHookException;
+
+ const onNewGlobalObject = function (global) {
+ if (shouldAddNewGlobalAsDebuggee(global)) {
+ safeAddDebuggee(this, global);
+ }
+ };
+
+ dbg.onNewGlobalObject = onNewGlobalObject;
+ dbg.addDebuggees = function () {
+ for (const global of findDebuggees(this)) {
+ safeAddDebuggee(this, global);
+ }
+ };
+
+ dbg.disable = function () {
+ dbg.removeAllDebuggees();
+ dbg.onNewGlobalObject = undefined;
+ };
+
+ dbg.enable = function () {
+ dbg.addDebuggees();
+ dbg.onNewGlobalObject = onNewGlobalObject;
+ };
+ dbg.findDebuggees = function () {
+ return findDebuggees(dbg);
+ };
+
+ return dbg;
+};
+
+const reportDebuggerHookException = e => reportException("DBG-SERVER", e);
+
+/**
+ * Add |global| as a debuggee to |dbg|, handling error cases.
+ */
+function safeAddDebuggee(dbg, global) {
+ let globalDO;
+ try {
+ globalDO = dbg.addDebuggee(global);
+ } catch (e) {
+ // Ignoring attempt to add the debugger's compartment as a debuggee.
+ return;
+ }
+
+ if (dbg.onNewDebuggee) {
+ dbg.onNewDebuggee(globalDO);
+ }
+}