tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

logEvent.js (6307B)


      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 DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js");
      8 loader.lazyRequireGetter(
      9  this,
     10  "ObjectUtils",
     11  "resource://devtools/server/actors/object/utils.js"
     12 );
     13 const {
     14  formatDisplayName,
     15 } = require("resource://devtools/server/actors/frame.js");
     16 const {
     17  TYPES,
     18  getResourceWatcher,
     19 } = require("resource://devtools/server/actors/resources/index.js");
     20 loader.lazyRequireGetter(
     21  this,
     22  ["isValidSavedFrame"],
     23  "devtools/server/actors/frame",
     24  true
     25 );
     26 
     27 // Get a string message to display when a frame evaluation throws.
     28 function getThrownMessage(completion) {
     29  try {
     30    if (completion.throw.getOwnPropertyDescriptor) {
     31      return completion.throw.getOwnPropertyDescriptor("message").value;
     32    } else if (completion.toString) {
     33      return completion.toString();
     34    }
     35  } catch (ex) {
     36    // ignore
     37  }
     38  return "Unknown exception";
     39 }
     40 module.exports.getThrownMessage = getThrownMessage;
     41 
     42 function evalAndLogEvent({
     43  threadActor,
     44  frame,
     45  level,
     46  expression,
     47  bindings,
     48  showStacktrace,
     49 }) {
     50  const frameLocation = threadActor.sourcesManager.getFrameLocation(frame);
     51  const { sourceActor, line } = frameLocation;
     52  const displayName = formatDisplayName(frame);
     53  const stacktrace = showStacktrace ? [] : undefined;
     54 
     55  if (showStacktrace) {
     56    let currentFrame = frame;
     57    while (currentFrame) {
     58      if (currentFrame.script) {
     59        stacktrace.push({
     60          filename: currentFrame.script.url,
     61          functionName: currentFrame.script.displayName,
     62          lineNumber: currentFrame.script.startLine,
     63          columnNumber: currentFrame.script.startColumn,
     64          sourceId: currentFrame.script.source.id,
     65        });
     66      } else {
     67        stacktrace.push({
     68          filename: "unknown",
     69          functionName: currentFrame.displayName || "anonymous",
     70          lineNumber: 0,
     71          columnNumber: 0,
     72          sourceId: "",
     73        });
     74      }
     75      const olderSavedFrame =
     76        currentFrame.olderSavedFrame &&
     77        isValidSavedFrame(threadActor, currentFrame.olderSavedFrame)
     78          ? currentFrame.olderSavedFrame
     79          : null;
     80      currentFrame = currentFrame.older || olderSavedFrame;
     81    }
     82  }
     83 
     84  // TODO remove this branch when (#1749668) lands (#1609540)
     85  if (isWorker) {
     86    threadActor.targetActor._consoleActor.evaluateJS({
     87      text: showStacktrace
     88        ? `console.trace(...${expression})`
     89        : `console.log(...${expression})`,
     90      bindings: { displayName, ...bindings },
     91      url: sourceActor.url,
     92      lineNumber: line,
     93      disableBreaks: true,
     94    });
     95 
     96    return undefined;
     97  }
     98 
     99  let completion;
    100  // Ensure disabling all types of breakpoints for all sources while evaluating the log points
    101  threadActor.insideClientEvaluation = { disableBreaks: true };
    102  try {
    103    completion = frame.evalWithBindings(
    104      expression,
    105      {
    106        displayName,
    107        ...bindings,
    108      },
    109      { hideFromDebugger: true }
    110    );
    111  } finally {
    112    threadActor.insideClientEvaluation = null;
    113  }
    114 
    115  let value;
    116  if (!completion) {
    117    // The evaluation was killed (possibly by the slow script dialog).
    118    value = ["Evaluation failed"];
    119  } else if ("return" in completion) {
    120    value = [];
    121    const length = ObjectUtils.getArrayLength(completion.return);
    122    for (let i = 0; i < length; i++) {
    123      value.push(DevToolsUtils.getProperty(completion.return, i));
    124    }
    125  } else {
    126    value = [getThrownMessage(completion)];
    127    level = `${level}Error`;
    128  }
    129 
    130  ChromeUtils.addProfilerMarker("Debugger log point", undefined, value);
    131 
    132  emitConsoleMessage(threadActor, frameLocation, value, level, stacktrace);
    133 
    134  return undefined;
    135 }
    136 
    137 function logEvent({ threadActor, frame }) {
    138  const frameLocation = threadActor.sourcesManager.getFrameLocation(frame);
    139  const { sourceActor, line } = frameLocation;
    140 
    141  // TODO remove this branch when (#1749668) lands (#1609540)
    142  if (isWorker) {
    143    const bindings = {};
    144    for (let i = 0; i < frame.arguments.length; i++) {
    145      bindings[`x${i}`] = frame.arguments[i];
    146    }
    147    threadActor.targetActor._consoleActor.evaluateJS({
    148      text: `console.log(${Object.keys(bindings).join(",")})`,
    149      bindings,
    150      url: sourceActor.url,
    151      lineNumber: line,
    152      disableBreaks: true,
    153    });
    154 
    155    return undefined;
    156  }
    157 
    158  emitConsoleMessage(threadActor, frameLocation, frame.arguments, "logPoint");
    159 
    160  return undefined;
    161 }
    162 
    163 function emitConsoleMessage(
    164  threadActor,
    165  frameLocation,
    166  args,
    167  level,
    168  stacktrace
    169 ) {
    170  const targetActor = threadActor.targetActor;
    171  const { sourceActor, line, column } = frameLocation;
    172 
    173  const message = {
    174    filename: sourceActor.url,
    175 
    176    // The line is 1-based
    177    lineNumber: line,
    178    // `frameLocation` comes from the SourcesManager which uses 0-base column
    179    // whereas CONSOLE_MESSAGE resources emits 1-based columns.
    180    columnNumber: column + 1,
    181    arguments: args,
    182    level,
    183    timeStamp: ChromeUtils.dateNow(),
    184    chromeContext:
    185      targetActor.actorID &&
    186      /conn\d+\.parentProcessTarget\d+/.test(targetActor.actorID),
    187    // The 'prepareConsoleMessageForRemote' method in webconsoleActor expects internal source ID,
    188    // thus we can't set sourceId directly to sourceActorID.
    189    sourceId: sourceActor.internalSourceId,
    190    stacktrace,
    191  };
    192 
    193  // Note that only WindowGlobalTarget actor support resource watcher
    194  // This is still missing for worker and content processes
    195  const consoleMessageWatcher = getResourceWatcher(
    196    targetActor,
    197    TYPES.CONSOLE_MESSAGE
    198  );
    199  if (consoleMessageWatcher) {
    200    consoleMessageWatcher.emitMessages([message], false);
    201  } else {
    202    // Bug 1642296: Once we enable ConsoleMessage resource on the server, we should remove onConsoleAPICall
    203    // from the WebConsoleActor, and only support the ConsoleMessageWatcher codepath.
    204    message.arguments = message.arguments.map(arg =>
    205      arg && typeof arg.unsafeDereference === "function"
    206        ? arg.unsafeDereference()
    207        : arg
    208    );
    209    targetActor._consoleActor.onConsoleAPICall(message);
    210  }
    211 }
    212 
    213 module.exports.evalAndLogEvent = evalAndLogEvent;
    214 module.exports.logEvent = logEvent;