/* 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 may be wrapped in a |Debugger.Object|, or * unwrapped. * * @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; }; 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); } }