diff options
Diffstat (limited to 'js/ductwork/debugger')
-rw-r--r-- | js/ductwork/debugger/IJSDebugger.idl | 20 | ||||
-rw-r--r-- | js/ductwork/debugger/JSDebugger.cpp | 56 | ||||
-rw-r--r-- | js/ductwork/debugger/JSDebugger.h | 30 | ||||
-rw-r--r-- | js/ductwork/debugger/components.conf | 14 | ||||
-rw-r--r-- | js/ductwork/debugger/jsdebugger.jsm | 93 | ||||
-rw-r--r-- | js/ductwork/debugger/moz.build | 30 | ||||
-rw-r--r-- | js/ductwork/debugger/tests/head_dbg.js | 13 | ||||
-rw-r--r-- | js/ductwork/debugger/tests/test_nativewrappers.js | 38 | ||||
-rw-r--r-- | js/ductwork/debugger/tests/xpcshell.ini | 7 |
9 files changed, 301 insertions, 0 deletions
diff --git a/js/ductwork/debugger/IJSDebugger.idl b/js/ductwork/debugger/IJSDebugger.idl new file mode 100644 index 0000000000..dc3cd0423a --- /dev/null +++ b/js/ductwork/debugger/IJSDebugger.idl @@ -0,0 +1,20 @@ +/* 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/. */ + +#include "nsISupports.idl" + +/** + * Do not use this interface. Instead, write: + * Components.utils.import("resource://gre/modules/jsdebugger.jsm"); + * addDebuggerToGlobal(global); + */ +[scriptable, uuid(a36fa816-31da-4b23-bc97-6412771f0867)] +interface IJSDebugger : nsISupports +{ + /** + * Define the global Debugger constructor on a given global. + */ + [implicit_jscontext] + void addClass(in jsval global); +}; diff --git a/js/ductwork/debugger/JSDebugger.cpp b/js/ductwork/debugger/JSDebugger.cpp new file mode 100644 index 0000000000..436ab1262e --- /dev/null +++ b/js/ductwork/debugger/JSDebugger.cpp @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- + */ +/* 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/. */ + +#include "JSDebugger.h" +#include "nsThreadUtils.h" +#include "jsapi.h" +#include "jsfriendapi.h" +#include "js/Wrapper.h" +#include "nsServiceManagerUtils.h" +#include "nsMemory.h" + +#define JSDEBUGGER_CONTRACTID "@mozilla.org/jsdebugger;1" + +#define JSDEBUGGER_CID \ + { \ + 0x0365cbd5, 0xd46e, 0x4e94, { \ + 0xa3, 0x9f, 0x83, 0xb6, 0x3c, 0xd1, 0xa9, 0x63 \ + } \ + } + +namespace mozilla::jsdebugger { + +NS_IMPL_ISUPPORTS(JSDebugger, IJSDebugger) + +JSDebugger::JSDebugger() = default; + +JSDebugger::~JSDebugger() = default; + +NS_IMETHODIMP +JSDebugger::AddClass(JS::Handle<JS::Value> global, JSContext* cx) { + if (!global.isObject()) { + return NS_ERROR_INVALID_ARG; + } + + JS::RootedObject obj(cx, &global.toObject()); + obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false); + if (!obj) { + return NS_ERROR_FAILURE; + } + + if (!JS_IsGlobalObject(obj)) { + return NS_ERROR_INVALID_ARG; + } + + JSAutoRealm ar(cx, obj); + if (!JS_DefineDebuggerObject(cx, obj)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +} // namespace mozilla::jsdebugger diff --git a/js/ductwork/debugger/JSDebugger.h b/js/ductwork/debugger/JSDebugger.h new file mode 100644 index 0000000000..830daa3a43 --- /dev/null +++ b/js/ductwork/debugger/JSDebugger.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- + */ +/* 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/. */ + +#ifndef JSDebugger_h +#define JSDebugger_h + +#include "IJSDebugger.h" +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace jsdebugger { + +class JSDebugger final : public IJSDebugger { + public: + NS_DECL_ISUPPORTS + NS_DECL_IJSDEBUGGER + + JSDebugger(); + + private: + ~JSDebugger(); +}; + +} // namespace jsdebugger +} // namespace mozilla + +#endif /* JSDebugger_h */ diff --git a/js/ductwork/debugger/components.conf b/js/ductwork/debugger/components.conf new file mode 100644 index 0000000000..16d3c450dc --- /dev/null +++ b/js/ductwork/debugger/components.conf @@ -0,0 +1,14 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +Classes = [ + { + 'cid': '{0365cbd5-d46e-4e94-a39f-83b63cd1a963}', + 'contract_ids': ['@mozilla.org/jsdebugger;1'], + 'type': 'mozilla::jsdebugger::JSDebugger', + 'headers': ['/js/ductwork/debugger/JSDebugger.h'], + }, +] diff --git a/js/ductwork/debugger/jsdebugger.jsm b/js/ductwork/debugger/jsdebugger.jsm new file mode 100644 index 0000000000..4189594179 --- /dev/null +++ b/js/ductwork/debugger/jsdebugger.jsm @@ -0,0 +1,93 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* 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/. */ + +var EXPORTED_SYMBOLS = [ "addDebuggerToGlobal", "addSandboxedDebuggerToGlobal" ]; + +/* + * This is the js module for Debugger. Import it like so: + * Components.utils.import("resource://gre/modules/jsdebugger.jsm"); + * addDebuggerToGlobal(this); + * + * This will create a 'Debugger' object, which provides an interface to debug + * JavaScript code running in other compartments in the same process, on the + * same thread. + * + * For documentation on the API, see: + * https://developer.mozilla.org/en-US/docs/Tools/Debugger-API + */ + +const init = Cc["@mozilla.org/jsdebugger;1"].createInstance(Ci.IJSDebugger); +function addDebuggerToGlobal(global) { + init.addClass(global); + initPromiseDebugging(global); +} + +// Defines the Debugger in a sandbox global in a separate compartment. This +// ensures the debugger and debuggee are in different compartments. +function addSandboxedDebuggerToGlobal(global) { + var sb = Cu.Sandbox(global, {freshCompartment: true}); + addDebuggerToGlobal(sb); + global.Debugger = sb.Debugger; +} + +function initPromiseDebugging(global) { + if (global.Debugger.Object.prototype.PromiseDebugging) { + return; + } + + // If the PromiseDebugging object doesn't have all legacy functions, we're + // using the new accessors on Debugger.Object already. + if (!PromiseDebugging.getDependentPromises) { + return; + } + + // Otherwise, polyfill them using PromiseDebugging. + global.Debugger.Object.prototype.PromiseDebugging = PromiseDebugging; + global.eval(polyfillSource); +} + +let polyfillSource = ` + Object.defineProperty(Debugger.Object.prototype, "promiseState", { + get() { + const state = this.PromiseDebugging.getState(this.unsafeDereference()); + return { + state: state.state, + value: this.makeDebuggeeValue(state.value), + reason: this.makeDebuggeeValue(state.reason) + }; + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseLifetime", { + get() { + return this.PromiseDebugging.getPromiseLifetime(this.unsafeDereference()); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseTimeToResolution", { + get() { + return this.PromiseDebugging.getTimeToSettle(this.unsafeDereference()); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseDependentPromises", { + get() { + let promises = this.PromiseDebugging.getDependentPromises(this.unsafeDereference()); + return promises.map(p => this.makeDebuggeeValue(p)); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseAllocationSite", { + get() { + return this.PromiseDebugging.getAllocationStack(this.unsafeDereference()); + } + }); + Object.defineProperty(Debugger.Object.prototype, "promiseResolutionSite", { + get() { + let state = this.promiseState.state; + if (state === "fulfilled") { + return this.PromiseDebugging.getFullfillmentStack(this.unsafeDereference()); + } else { + return this.PromiseDebugging.getRejectionStack(this.unsafeDereference()); + } + } + }); +`; diff --git a/js/ductwork/debugger/moz.build b/js/ductwork/debugger/moz.build new file mode 100644 index 0000000000..31b1fc6744 --- /dev/null +++ b/js/ductwork/debugger/moz.build @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +with Files("**"): + BUG_COMPONENT = ("Core", "JavaScript Engine") + +XPIDL_SOURCES += [ + "IJSDebugger.idl", +] + +XPIDL_MODULE = "jsdebugger" + +XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell.ini"] + +SOURCES += [ + "JSDebugger.cpp", +] + +XPCOM_MANIFESTS += [ + "components.conf", +] + +EXTRA_JS_MODULES += [ + "jsdebugger.jsm", +] + +FINAL_LIBRARY = "xul" diff --git a/js/ductwork/debugger/tests/head_dbg.js b/js/ductwork/debugger/tests/head_dbg.js new file mode 100644 index 0000000000..aad37f5f12 --- /dev/null +++ b/js/ductwork/debugger/tests/head_dbg.js @@ -0,0 +1,13 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function testGlobal(aName) { + let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"] + .createInstance(Ci.nsIPrincipal); + + let sandbox = Cu.Sandbox(systemPrincipal); + Cu.evalInSandbox("this.__name = '" + aName + "'", sandbox); + return sandbox; +} diff --git a/js/ductwork/debugger/tests/test_nativewrappers.js b/js/ductwork/debugger/tests/test_nativewrappers.js new file mode 100644 index 0000000000..ccddb1e845 --- /dev/null +++ b/js/ductwork/debugger/tests/test_nativewrappers.js @@ -0,0 +1,38 @@ +function run_test() +{ + const {addDebuggerToGlobal} = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm"); + const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); + + Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true); + registerCleanupFunction(() => { + Services.prefs.clearUserPref("security.allow_eval_with_system_principal"); + }); + + addDebuggerToGlobal(this); + var g = testGlobal("test1"); + + var dbg = new Debugger(); + dbg.addDebuggee(g); + dbg.onDebuggerStatement = function(aFrame) { + let args = aFrame["arguments"]; + try { + args[0]; + Assert.ok(true); + } catch(ex) { + Assert.ok(false); + } + }; + + g.eval("function stopMe(arg) {debugger;}"); + + g2 = testGlobal("test2"); + g2.g = g; + g2.eval("(" + function createBadEvent() { + Cu.importGlobalProperties(["DOMParser"]); + let parser = new DOMParser(); + let doc = parser.parseFromString("<foo></foo>", "text/xml"); + g.stopMe(doc.createEvent("MouseEvent")); + } + ")()"); + + dbg.removeAllDebuggees(); +} diff --git a/js/ductwork/debugger/tests/xpcshell.ini b/js/ductwork/debugger/tests/xpcshell.ini new file mode 100644 index 0000000000..c2a1cd07af --- /dev/null +++ b/js/ductwork/debugger/tests/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = head_dbg.js +skip-if = toolkit == 'android' + +[test_nativewrappers.js] +# Bug 685068 +fail-if = os == "android" |