|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 const { Cc, Ci, Cu } = require("chrome"); |
|
8 const TargetFactory = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.TargetFactory; |
|
9 const gcli = require("gcli/index"); |
|
10 |
|
11 loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm"); |
|
12 |
|
13 loader.lazyGetter(this, "Debugger", () => { |
|
14 let global = Cu.getGlobalForObject({}); |
|
15 let JsDebugger = Cu.import("resource://gre/modules/jsdebugger.jsm", {}); |
|
16 JsDebugger.addDebuggerToGlobal(global); |
|
17 return global.Debugger; |
|
18 }); |
|
19 |
|
20 let debuggers = []; |
|
21 let chromeDebuggers = []; |
|
22 let sandboxes = []; |
|
23 |
|
24 exports.items = [ |
|
25 { |
|
26 name: "calllog", |
|
27 description: gcli.lookup("calllogDesc") |
|
28 }, |
|
29 { |
|
30 name: "calllog start", |
|
31 description: gcli.lookup("calllogStartDesc"), |
|
32 |
|
33 exec: function(args, context) { |
|
34 let contentWindow = context.environment.window; |
|
35 |
|
36 let dbg = new Debugger(contentWindow); |
|
37 dbg.onEnterFrame = function(frame) { |
|
38 // BUG 773652 - Make the output from the GCLI calllog command nicer |
|
39 contentWindow.console.log("Method call: " + this.callDescription(frame)); |
|
40 }.bind(this); |
|
41 |
|
42 debuggers.push(dbg); |
|
43 |
|
44 let gBrowser = context.environment.chromeDocument.defaultView.gBrowser; |
|
45 let target = TargetFactory.forTab(gBrowser.selectedTab); |
|
46 gDevTools.showToolbox(target, "webconsole"); |
|
47 |
|
48 return gcli.lookup("calllogStartReply"); |
|
49 }, |
|
50 |
|
51 callDescription: function(frame) { |
|
52 let name = "<anonymous>"; |
|
53 if (frame.callee.name) { |
|
54 name = frame.callee.name; |
|
55 } |
|
56 else { |
|
57 let desc = frame.callee.getOwnPropertyDescriptor("displayName"); |
|
58 if (desc && desc.value && typeof desc.value == "string") { |
|
59 name = desc.value; |
|
60 } |
|
61 } |
|
62 |
|
63 let args = frame.arguments.map(this.valueToString).join(", "); |
|
64 return name + "(" + args + ")"; |
|
65 }, |
|
66 |
|
67 valueToString: function(value) { |
|
68 if (typeof value !== "object" || value === null) { |
|
69 return uneval(value); |
|
70 } |
|
71 return "[object " + value.class + "]"; |
|
72 } |
|
73 }, |
|
74 { |
|
75 name: "calllog stop", |
|
76 description: gcli.lookup("calllogStopDesc"), |
|
77 |
|
78 exec: function(args, context) { |
|
79 let numDebuggers = debuggers.length; |
|
80 if (numDebuggers == 0) { |
|
81 return gcli.lookup("calllogStopNoLogging"); |
|
82 } |
|
83 |
|
84 for (let dbg of debuggers) { |
|
85 dbg.onEnterFrame = undefined; |
|
86 } |
|
87 debuggers = []; |
|
88 |
|
89 return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]); |
|
90 } |
|
91 }, |
|
92 { |
|
93 name: "calllog chromestart", |
|
94 description: gcli.lookup("calllogChromeStartDesc"), |
|
95 get hidden() gcli.hiddenByChromePref(), |
|
96 params: [ |
|
97 { |
|
98 name: "sourceType", |
|
99 type: { |
|
100 name: "selection", |
|
101 data: ["content-variable", "chrome-variable", "jsm", "javascript"] |
|
102 } |
|
103 }, |
|
104 { |
|
105 name: "source", |
|
106 type: "string", |
|
107 description: gcli.lookup("calllogChromeSourceTypeDesc"), |
|
108 manual: gcli.lookup("calllogChromeSourceTypeManual"), |
|
109 } |
|
110 ], |
|
111 exec: function(args, context) { |
|
112 let globalObj; |
|
113 let contentWindow = context.environment.window; |
|
114 |
|
115 if (args.sourceType == "jsm") { |
|
116 try { |
|
117 globalObj = Cu.import(args.source); |
|
118 } |
|
119 catch (e) { |
|
120 return gcli.lookup("callLogChromeInvalidJSM"); |
|
121 } |
|
122 } else if (args.sourceType == "content-variable") { |
|
123 if (args.source in contentWindow) { |
|
124 globalObj = Cu.getGlobalForObject(contentWindow[args.source]); |
|
125 } else { |
|
126 throw new Error(gcli.lookup("callLogChromeVarNotFoundContent")); |
|
127 } |
|
128 } else if (args.sourceType == "chrome-variable") { |
|
129 let chromeWin = context.environment.chromeDocument.defaultView; |
|
130 if (args.source in chromeWin) { |
|
131 globalObj = Cu.getGlobalForObject(chromeWin[args.source]); |
|
132 } else { |
|
133 return gcli.lookup("callLogChromeVarNotFoundChrome"); |
|
134 } |
|
135 } else { |
|
136 let chromeWin = context.environment.chromeDocument.defaultView; |
|
137 let sandbox = new Cu.Sandbox(chromeWin, |
|
138 { |
|
139 sandboxPrototype: chromeWin, |
|
140 wantXrays: false, |
|
141 sandboxName: "gcli-cmd-calllog-chrome" |
|
142 }); |
|
143 let returnVal; |
|
144 try { |
|
145 returnVal = Cu.evalInSandbox(args.source, sandbox, "ECMAv5"); |
|
146 sandboxes.push(sandbox); |
|
147 } catch(e) { |
|
148 // We need to save the message before cleaning up else e contains a dead |
|
149 // object. |
|
150 let msg = gcli.lookup("callLogChromeEvalException") + ": " + e; |
|
151 Cu.nukeSandbox(sandbox); |
|
152 return msg; |
|
153 } |
|
154 |
|
155 if (typeof returnVal == "undefined") { |
|
156 return gcli.lookup("callLogChromeEvalNeedsObject"); |
|
157 } |
|
158 |
|
159 globalObj = Cu.getGlobalForObject(returnVal); |
|
160 } |
|
161 |
|
162 let dbg = new Debugger(globalObj); |
|
163 chromeDebuggers.push(dbg); |
|
164 |
|
165 dbg.onEnterFrame = function(frame) { |
|
166 // BUG 773652 - Make the output from the GCLI calllog command nicer |
|
167 contentWindow.console.log(gcli.lookup("callLogChromeMethodCall") + |
|
168 ": " + this.callDescription(frame)); |
|
169 }.bind(this); |
|
170 |
|
171 let gBrowser = context.environment.chromeDocument.defaultView.gBrowser; |
|
172 let target = TargetFactory.forTab(gBrowser.selectedTab); |
|
173 gDevTools.showToolbox(target, "webconsole"); |
|
174 |
|
175 return gcli.lookup("calllogChromeStartReply"); |
|
176 }, |
|
177 |
|
178 valueToString: function(value) { |
|
179 if (typeof value !== "object" || value === null) |
|
180 return uneval(value); |
|
181 return "[object " + value.class + "]"; |
|
182 }, |
|
183 |
|
184 callDescription: function(frame) { |
|
185 let name = frame.callee.name || gcli.lookup("callLogChromeAnonFunction"); |
|
186 let args = frame.arguments.map(this.valueToString).join(", "); |
|
187 return name + "(" + args + ")"; |
|
188 } |
|
189 }, |
|
190 { |
|
191 name: "calllog chromestop", |
|
192 description: gcli.lookup("calllogChromeStopDesc"), |
|
193 get hidden() gcli.hiddenByChromePref(), |
|
194 exec: function(args, context) { |
|
195 let numDebuggers = chromeDebuggers.length; |
|
196 if (numDebuggers == 0) { |
|
197 return gcli.lookup("calllogChromeStopNoLogging"); |
|
198 } |
|
199 |
|
200 for (let dbg of chromeDebuggers) { |
|
201 dbg.onEnterFrame = undefined; |
|
202 dbg.enabled = false; |
|
203 } |
|
204 for (let sandbox of sandboxes) { |
|
205 Cu.nukeSandbox(sandbox); |
|
206 } |
|
207 chromeDebuggers = []; |
|
208 sandboxes = []; |
|
209 |
|
210 return gcli.lookupFormat("calllogChromeStopReply", [ numDebuggers ]); |
|
211 } |
|
212 } |
|
213 ]; |