michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const { Cc, Ci, Cu } = require("chrome"); michael@0: const TargetFactory = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.TargetFactory; michael@0: const gcli = require("gcli/index"); michael@0: michael@0: loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm"); michael@0: michael@0: loader.lazyGetter(this, "Debugger", () => { michael@0: let global = Cu.getGlobalForObject({}); michael@0: let JsDebugger = Cu.import("resource://gre/modules/jsdebugger.jsm", {}); michael@0: JsDebugger.addDebuggerToGlobal(global); michael@0: return global.Debugger; michael@0: }); michael@0: michael@0: let debuggers = []; michael@0: let chromeDebuggers = []; michael@0: let sandboxes = []; michael@0: michael@0: exports.items = [ michael@0: { michael@0: name: "calllog", michael@0: description: gcli.lookup("calllogDesc") michael@0: }, michael@0: { michael@0: name: "calllog start", michael@0: description: gcli.lookup("calllogStartDesc"), michael@0: michael@0: exec: function(args, context) { michael@0: let contentWindow = context.environment.window; michael@0: michael@0: let dbg = new Debugger(contentWindow); michael@0: dbg.onEnterFrame = function(frame) { michael@0: // BUG 773652 - Make the output from the GCLI calllog command nicer michael@0: contentWindow.console.log("Method call: " + this.callDescription(frame)); michael@0: }.bind(this); michael@0: michael@0: debuggers.push(dbg); michael@0: michael@0: let gBrowser = context.environment.chromeDocument.defaultView.gBrowser; michael@0: let target = TargetFactory.forTab(gBrowser.selectedTab); michael@0: gDevTools.showToolbox(target, "webconsole"); michael@0: michael@0: return gcli.lookup("calllogStartReply"); michael@0: }, michael@0: michael@0: callDescription: function(frame) { michael@0: let name = ""; michael@0: if (frame.callee.name) { michael@0: name = frame.callee.name; michael@0: } michael@0: else { michael@0: let desc = frame.callee.getOwnPropertyDescriptor("displayName"); michael@0: if (desc && desc.value && typeof desc.value == "string") { michael@0: name = desc.value; michael@0: } michael@0: } michael@0: michael@0: let args = frame.arguments.map(this.valueToString).join(", "); michael@0: return name + "(" + args + ")"; michael@0: }, michael@0: michael@0: valueToString: function(value) { michael@0: if (typeof value !== "object" || value === null) { michael@0: return uneval(value); michael@0: } michael@0: return "[object " + value.class + "]"; michael@0: } michael@0: }, michael@0: { michael@0: name: "calllog stop", michael@0: description: gcli.lookup("calllogStopDesc"), michael@0: michael@0: exec: function(args, context) { michael@0: let numDebuggers = debuggers.length; michael@0: if (numDebuggers == 0) { michael@0: return gcli.lookup("calllogStopNoLogging"); michael@0: } michael@0: michael@0: for (let dbg of debuggers) { michael@0: dbg.onEnterFrame = undefined; michael@0: } michael@0: debuggers = []; michael@0: michael@0: return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]); michael@0: } michael@0: }, michael@0: { michael@0: name: "calllog chromestart", michael@0: description: gcli.lookup("calllogChromeStartDesc"), michael@0: get hidden() gcli.hiddenByChromePref(), michael@0: params: [ michael@0: { michael@0: name: "sourceType", michael@0: type: { michael@0: name: "selection", michael@0: data: ["content-variable", "chrome-variable", "jsm", "javascript"] michael@0: } michael@0: }, michael@0: { michael@0: name: "source", michael@0: type: "string", michael@0: description: gcli.lookup("calllogChromeSourceTypeDesc"), michael@0: manual: gcli.lookup("calllogChromeSourceTypeManual"), michael@0: } michael@0: ], michael@0: exec: function(args, context) { michael@0: let globalObj; michael@0: let contentWindow = context.environment.window; michael@0: michael@0: if (args.sourceType == "jsm") { michael@0: try { michael@0: globalObj = Cu.import(args.source); michael@0: } michael@0: catch (e) { michael@0: return gcli.lookup("callLogChromeInvalidJSM"); michael@0: } michael@0: } else if (args.sourceType == "content-variable") { michael@0: if (args.source in contentWindow) { michael@0: globalObj = Cu.getGlobalForObject(contentWindow[args.source]); michael@0: } else { michael@0: throw new Error(gcli.lookup("callLogChromeVarNotFoundContent")); michael@0: } michael@0: } else if (args.sourceType == "chrome-variable") { michael@0: let chromeWin = context.environment.chromeDocument.defaultView; michael@0: if (args.source in chromeWin) { michael@0: globalObj = Cu.getGlobalForObject(chromeWin[args.source]); michael@0: } else { michael@0: return gcli.lookup("callLogChromeVarNotFoundChrome"); michael@0: } michael@0: } else { michael@0: let chromeWin = context.environment.chromeDocument.defaultView; michael@0: let sandbox = new Cu.Sandbox(chromeWin, michael@0: { michael@0: sandboxPrototype: chromeWin, michael@0: wantXrays: false, michael@0: sandboxName: "gcli-cmd-calllog-chrome" michael@0: }); michael@0: let returnVal; michael@0: try { michael@0: returnVal = Cu.evalInSandbox(args.source, sandbox, "ECMAv5"); michael@0: sandboxes.push(sandbox); michael@0: } catch(e) { michael@0: // We need to save the message before cleaning up else e contains a dead michael@0: // object. michael@0: let msg = gcli.lookup("callLogChromeEvalException") + ": " + e; michael@0: Cu.nukeSandbox(sandbox); michael@0: return msg; michael@0: } michael@0: michael@0: if (typeof returnVal == "undefined") { michael@0: return gcli.lookup("callLogChromeEvalNeedsObject"); michael@0: } michael@0: michael@0: globalObj = Cu.getGlobalForObject(returnVal); michael@0: } michael@0: michael@0: let dbg = new Debugger(globalObj); michael@0: chromeDebuggers.push(dbg); michael@0: michael@0: dbg.onEnterFrame = function(frame) { michael@0: // BUG 773652 - Make the output from the GCLI calllog command nicer michael@0: contentWindow.console.log(gcli.lookup("callLogChromeMethodCall") + michael@0: ": " + this.callDescription(frame)); michael@0: }.bind(this); michael@0: michael@0: let gBrowser = context.environment.chromeDocument.defaultView.gBrowser; michael@0: let target = TargetFactory.forTab(gBrowser.selectedTab); michael@0: gDevTools.showToolbox(target, "webconsole"); michael@0: michael@0: return gcli.lookup("calllogChromeStartReply"); michael@0: }, michael@0: michael@0: valueToString: function(value) { michael@0: if (typeof value !== "object" || value === null) michael@0: return uneval(value); michael@0: return "[object " + value.class + "]"; michael@0: }, michael@0: michael@0: callDescription: function(frame) { michael@0: let name = frame.callee.name || gcli.lookup("callLogChromeAnonFunction"); michael@0: let args = frame.arguments.map(this.valueToString).join(", "); michael@0: return name + "(" + args + ")"; michael@0: } michael@0: }, michael@0: { michael@0: name: "calllog chromestop", michael@0: description: gcli.lookup("calllogChromeStopDesc"), michael@0: get hidden() gcli.hiddenByChromePref(), michael@0: exec: function(args, context) { michael@0: let numDebuggers = chromeDebuggers.length; michael@0: if (numDebuggers == 0) { michael@0: return gcli.lookup("calllogChromeStopNoLogging"); michael@0: } michael@0: michael@0: for (let dbg of chromeDebuggers) { michael@0: dbg.onEnterFrame = undefined; michael@0: dbg.enabled = false; michael@0: } michael@0: for (let sandbox of sandboxes) { michael@0: Cu.nukeSandbox(sandbox); michael@0: } michael@0: chromeDebuggers = []; michael@0: sandboxes = []; michael@0: michael@0: return gcli.lookupFormat("calllogChromeStopReply", [ numDebuggers ]); michael@0: } michael@0: } michael@0: ];