calllog.js 6.7 KB

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