Example #1
0
    /**
     * Instruments a getter or setter on the specified target object.
     */
    function overrideAccessor(global, target, name, descriptor, callback) {
      // Invoking .apply on an unxrayed content function doesn't work, because
      // the arguments array is inaccessible to it. Get Xrays back.
      let originalGetter = Cu.unwaiveXrays(target.__lookupGetter__(name));
      let originalSetter = Cu.unwaiveXrays(target.__lookupSetter__(name));

      Object.defineProperty(target, name, {
        get: function(...args) {
          if (!originalGetter) return undefined;
          let result = Cu.waiveXrays(originalGetter.apply(this, args));

          if (self._recording) {
            let type = CallWatcherFront.GETTER_FUNCTION;
            let stack = getStack(name);
            let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
            callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, result);
          }
          return result;
        },
        set: function(...args) {
          if (!originalSetter) return;
          originalSetter.apply(this, args);

          if (self._recording) {
            let type = CallWatcherFront.SETTER_FUNCTION;
            let stack = getStack(name);
            let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
            callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, undefined);
          }
        },
        configurable: descriptor.configurable,
        enumerable: descriptor.enumerable
      });
    }
  onBuildPreview: makeInfallible(function(actor, grip, rawObj) {
    if (!DevToolsUtils.getProperty(actor.obj, "jquery")) {
      return false;
    }

    let length = DevToolsUtils.getProperty(actor.obj, "length");
    if (typeof length != "number") {
      return false;
    }

    let preview = grip.preview = {
      kind: "jQuery",
      length: length,
    };

    if (actor.threadActor._gripDepth > 1) {
      return true;
    }

    Trace.sysout("FireQueryActor.onBuildPreview;", arguments);

    preview.items = [];

    let raw = actor.obj.unsafeDereference();
    for (let i = 0; i < preview.length; ++i) {
      // Array Xrays filter out various possibly-unsafe properties (like
      // functions, and claim that the value is undefined instead. This
      // is generally the right thing for privileged code accessing untrusted
      // objects, but quite confusing for Object previews. So we manually
      // override this protection by waiving Xrays on the array, and re-applying
      // Xrays on any indexed value props that we pull off of it.
      let desc = Object.getOwnPropertyDescriptor(Cu.waiveXrays(raw), i);
      if (desc && !desc.get && !desc.set) {
        let value = Cu.unwaiveXrays(desc.value);
        value = makeDebuggeeValueIfNeeded(actor.obj, value);

        let grip = actor.threadActor.createValueGrip(value);
        preview.items.push(grip);

        let data = hasJQueryData(desc.value);
        if (data) {
          data = Cu.unwaiveXrays(data);
          data = makeDebuggeeValueIfNeeded(actor.obj, data);
          grip.preview.jQueryData = actor.threadActor.createValueGrip(data);

          // xxxHonza: generate preview for the data?
        }
      } else {
        preview.items.push(null);
      }

      if (preview.length == OBJECT_PREVIEW_MAX_ITEMS) {
        break;
      }
    }

    Trace.sysout("FireQueryActor.onPreview; jQuery preview", preview);

    return true;
  }),
Example #3
0
    /**
     * Instruments a function on the specified target object.
     */
    function overrideFunction(global, target, name, descriptor, callback) {
      // Invoking .apply on an unxrayed content function doesn't work, because
      // the arguments array is inaccessible to it. Get Xrays back.
      let originalFunc = Cu.unwaiveXrays(target[name]);

      Cu.exportFunction(function(...args) {
        let result;
        try {
          result = Cu.waiveXrays(originalFunc.apply(this, args));
        } catch (e) {
          throw createContentError(e, unwrappedWindow);
        }

        if (self._recording) {
          let type = CallWatcherFront.METHOD_FUNCTION;
          let stack = getStack(name);
          let timestamp = self.tabActor.window.performance.now() - self._timestampEpoch;
          callback(unwrappedWindow, global, this, type, name, stack, timestamp, args, result);
        }
        return result;
      }, target, { defineAs: name });

      Object.defineProperty(target, name, {
        configurable: descriptor.configurable,
        enumerable: descriptor.enumerable,
        writable: true
      });
    }
Example #4
0
/**
 * Helper function to create a grip from a Map/Set entry
 */
function gripFromEntry({ obj, hooks }, entry) {
  if (!isWorker) {
    entry = Cu.unwaiveXrays(entry);
  }
  return hooks.createValueGrip(
    ObjectUtils.makeDebuggeeValueIfNeeded(obj, entry));
}
Example #5
0
  Array: [function({obj, hooks}, grip) {
    const length = ObjectUtils.getArrayLength(obj);

    grip.preview = {
      kind: "ArrayLike",
      length: length,
    };

    if (hooks.getGripDepth() > 1) {
      return true;
    }

    const raw = obj.unsafeDereference();
    const items = grip.preview.items = [];

    for (let i = 0; i < length; ++i) {
      if (raw) {
        // Array Xrays filter out various possibly-unsafe properties (like
        // functions, and claim that the value is undefined instead. This
        // is generally the right thing for privileged code accessing untrusted
        // objects, but quite confusing for Object previews. So we manually
        // override this protection by waiving Xrays on the array, and re-applying
        // Xrays on any indexed value props that we pull off of it.
        const desc = Object.getOwnPropertyDescriptor(Cu.waiveXrays(raw), i);
        if (desc && !desc.get && !desc.set) {
          let value = Cu.unwaiveXrays(desc.value);
          value = ObjectUtils.makeDebuggeeValueIfNeeded(obj, value);
          items.push(hooks.createValueGrip(value));
        } else {
          items.push(null);
        }
      } else {
        // When recording/replaying we don't have a raw object, but also don't
        // need to deal with Xrays into the debuggee compartment.
        const value = DevToolsUtils.getProperty(obj, i);
        items.push(hooks.createValueGrip(value));
      }

      if (items.length == OBJECT_PREVIEW_MAX_ITEMS) {
        break;
      }
    }

    return true;
  }],
Example #6
0
    context[funcName] = function (...glArgs) {
      if (timing <= 0 && !observer.suppressHandlers) {
        let glBreak = observer[beforeFuncName](glArgs, cache, proxy);
        if (glBreak) {
          return undefined;
        }
      }

      // Invoking .apply on an unxrayed content function doesn't work, because
      // the arguments array is inaccessible to it. Get Xrays back.
      let glResult = Cu.waiveXrays(Cu.unwaiveXrays(originalFunc).apply(this, glArgs));

      if (timing >= 0 && !observer.suppressHandlers) {
        let glBreak = observer[afterFuncName](glArgs, glResult, cache, proxy);
        if (glBreak) {
          return undefined;
        }
      }

      return glResult;
    };
Example #7
0
  form: function() {
    const g = {
      "type": "object",
      "actor": this.actorID,
      "class": this.obj.class,
    };

    const unwrapped = DevToolsUtils.unwrap(this.obj);

    // Unsafe objects must be treated carefully.
    if (!DevToolsUtils.isSafeDebuggerObject(this.obj)) {
      if (DevToolsUtils.isCPOW(this.obj)) {
        // Cross-process object wrappers can't be accessed.
        g.class = "CPOW: " + g.class;
      } else if (unwrapped === undefined) {
        // Objects belonging to an invisible-to-debugger compartment might be proxies,
        // so just in case they shouldn't be accessed.
        g.class = "InvisibleToDebugger: " + g.class;
      } else if (unwrapped.isProxy) {
        // Proxy objects can run traps when accessed, so just create a preview with
        // the target and the handler.
        g.class = "Proxy";
        this.hooks.incrementGripDepth();
        previewers.Proxy[0](this, g, null);
        this.hooks.decrementGripDepth();
      }
      return g;
    }

    // If the debuggee does not subsume the object's compartment, most properties won't
    // be accessible. Cross-orgin Window and Location objects might expose some, though.
    // Change the displayed class, but when creating the preview use the original one.
    if (unwrapped === null) {
      g.class = "Restricted";
    }

    this.hooks.incrementGripDepth();

    g.extensible = this.obj.isExtensible();
    g.frozen = this.obj.isFrozen();
    g.sealed = this.obj.isSealed();

    if (g.class == "Promise") {
      g.promiseState = this._createPromiseState();
    }

    // FF40+: Allow to know how many properties an object has to lazily display them
    // when there is a bunch.
    if (isTypedArray(g)) {
      // Bug 1348761: getOwnPropertyNames is unnecessary slow on TypedArrays
      g.ownPropertyLength = getArrayLength(this.obj);
    } else if (isStorage(g)) {
      g.ownPropertyLength = getStorageLength(this.obj);
    } else if (isReplaying) {
      // When replaying we can get the number of properties directly, to avoid
      // needing to enumerate all of them.
      g.ownPropertyLength = this.obj.getOwnPropertyNamesCount();
    } else {
      try {
        g.ownPropertyLength = this.obj.getOwnPropertyNames().length;
      } catch (err) {
        // The above can throw when the debuggee does not subsume the object's
        // compartment, or for some WrappedNatives like Cu.Sandbox.
      }
    }

    let raw = this.obj.unsafeDereference();

    // If Cu is not defined, we are running on a worker thread, where xrays
    // don't exist. The raw object will be null/unavailable when interacting
    // with a replaying execution.
    if (raw && Cu) {
      raw = Cu.unwaiveXrays(raw);
    }

    if (raw && !DevToolsUtils.isSafeJSObject(raw)) {
      raw = null;
    }

    for (const fn of previewers[this.obj.class] || previewers.Object) {
      try {
        if (fn(this, g, raw)) {
          break;
        }
      } catch (e) {
        const msg = "ObjectActor.prototype.grip previewer function";
        DevToolsUtils.reportException(msg, e);
      }
    }

    this.hooks.decrementGripDepth();
    return g;
  },
Example #8
0
  getListeners(node, {checkOnly} = {}) {
    const handlers = [];
    const listeners = this.getDOMListeners(node);

    for (const listener of listeners) {
      // Ignore listeners without a type, e.g.
      // node.addEventListener("", function() {})
      if (!listener.type) {
        continue;
      }

      // Get the listener object, either a Function or an Object.
      const obj = listener.listenerObject;

      // Ignore listeners without any listener, e.g.
      // node.addEventListener("mouseover", null);
      if (!obj) {
        continue;
      }

      let handler = null;

      // An object without a valid handleEvent is not a valid listener.
      if (typeof obj === "object") {
        const unwrapped = this.unwrap(obj);
        if (typeof unwrapped.handleEvent === "function") {
          handler = Cu.unwaiveXrays(unwrapped.handleEvent);
        }
      } else if (typeof obj === "function") {
        // Ignore DOM events used to trigger jQuery events as they are only
        // useful to the developers of the jQuery library.
        if (JQUERY_LIVE_REGEX.test(obj.toString())) {
          continue;
        }
        // Otherwise, the other valid listener type is function.
        handler = obj;
      }

      // Ignore listeners that have no handler.
      if (!handler) {
        continue;
      }

      // If we shouldn't be showing chrome events due to context and this is a
      // chrome handler we can ignore it.
      if (!this.chromeEnabled && this.isChromeHandler(handler)) {
        continue;
      }

      // If this is checking if a node has any listeners then we have found one
      // so return now.
      if (checkOnly) {
        return true;
      }

      const eventInfo = {
        capturing: listener.capturing,
        type: listener.type,
        handler: handler,
      };

      handlers.push(eventInfo);
    }

    // If this is checking if a node has any listeners then none were found so
    // return false.
    if (checkOnly) {
      return false;
    }

    return handlers;
  }