tor-browser

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

watchpoint-map.js (4428B)


      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 class WatchpointMap {
      8  constructor(threadActor) {
      9    this.threadActor = threadActor;
     10    this._watchpoints = new Map();
     11  }
     12 
     13  _setWatchpoint(objActor, data) {
     14    const { property, label, watchpointType } = data;
     15    const { rawObj } = objActor;
     16 
     17    const desc = objActor.obj.getOwnPropertyDescriptor(property);
     18 
     19    if (
     20      this.has(rawObj, property) ||
     21      desc.set ||
     22      desc.get ||
     23      !desc.configurable
     24    ) {
     25      return null;
     26    }
     27 
     28    function getValue() {
     29      return typeof desc.value === "object" && desc.value
     30        ? desc.value.unsafeDereference()
     31        : desc.value;
     32    }
     33 
     34    function setValue(v) {
     35      desc.value = objActor.obj.makeDebuggeeValue(v);
     36    }
     37 
     38    const maybeHandlePause = type => {
     39      const frame = this.threadActor.dbg.getNewestFrame();
     40 
     41      if (
     42        this.threadActor.shouldSkipAnyBreakpoint ||
     43        !this.threadActor.hasMoved(frame, type) ||
     44        this.threadActor.sourcesManager.isFrameBlackBoxed(frame)
     45      ) {
     46        return;
     47      }
     48 
     49      this.threadActor._pauseAndRespond(frame, {
     50        type,
     51        message: label,
     52      });
     53    };
     54 
     55    if (watchpointType === "get") {
     56      objActor.obj.defineProperty(property, {
     57        configurable: desc.configurable,
     58        enumerable: desc.enumerable,
     59        set: objActor.obj.makeDebuggeeValue(v => {
     60          setValue(v);
     61        }),
     62        get: objActor.obj.makeDebuggeeValue(() => {
     63          maybeHandlePause("getWatchpoint");
     64          return getValue();
     65        }),
     66      });
     67    }
     68 
     69    if (watchpointType === "set") {
     70      objActor.obj.defineProperty(property, {
     71        configurable: desc.configurable,
     72        enumerable: desc.enumerable,
     73        set: objActor.obj.makeDebuggeeValue(v => {
     74          maybeHandlePause("setWatchpoint");
     75          setValue(v);
     76        }),
     77        get: objActor.obj.makeDebuggeeValue(() => {
     78          return getValue();
     79        }),
     80      });
     81    }
     82 
     83    if (watchpointType === "getorset") {
     84      objActor.obj.defineProperty(property, {
     85        configurable: desc.configurable,
     86        enumerable: desc.enumerable,
     87        set: objActor.obj.makeDebuggeeValue(v => {
     88          maybeHandlePause("setWatchpoint");
     89          setValue(v);
     90        }),
     91        get: objActor.obj.makeDebuggeeValue(() => {
     92          maybeHandlePause("getWatchpoint");
     93          return getValue();
     94        }),
     95      });
     96    }
     97 
     98    return desc;
     99  }
    100 
    101  add(objActor, data) {
    102    // Get the object's description before calling setWatchpoint,
    103    // otherwise we'll get the modified property descriptor instead
    104    const desc = this._setWatchpoint(objActor, data);
    105    if (!desc) {
    106      return;
    107    }
    108 
    109    const objWatchpoints = this._watchpoints.get(objActor.rawObj) || new Map();
    110 
    111    objWatchpoints.set(data.property, { ...data, desc });
    112    this._watchpoints.set(objActor.rawObj, objWatchpoints);
    113  }
    114 
    115  has(obj, property) {
    116    const objWatchpoints = this._watchpoints.get(obj);
    117    return objWatchpoints && objWatchpoints.has(property);
    118  }
    119 
    120  get(obj, property) {
    121    const objWatchpoints = this._watchpoints.get(obj);
    122    return objWatchpoints && objWatchpoints.get(property);
    123  }
    124 
    125  remove(objActor, property) {
    126    const { rawObj } = objActor;
    127 
    128    // This should remove watchpoints on all of the object's properties if
    129    // a property isn't passed in as an argument
    130    if (!property) {
    131      for (const objProperty in rawObj) {
    132        this.remove(objActor, objProperty);
    133      }
    134    }
    135 
    136    if (!this.has(rawObj, property)) {
    137      return;
    138    }
    139 
    140    const objWatchpoints = this._watchpoints.get(rawObj);
    141    const { desc } = objWatchpoints.get(property);
    142 
    143    objWatchpoints.delete(property);
    144    this._watchpoints.set(rawObj, objWatchpoints);
    145 
    146    // We should stop keeping track of an object if it no longer
    147    // has a watchpoint
    148    if (objWatchpoints.size == 0) {
    149      this._watchpoints.delete(rawObj);
    150    }
    151 
    152    objActor.obj.defineProperty(property, desc);
    153  }
    154 
    155  removeAll(objActor) {
    156    const objWatchpoints = this._watchpoints.get(objActor.rawObj);
    157    if (!objWatchpoints) {
    158      return;
    159    }
    160 
    161    for (const objProperty in objWatchpoints) {
    162      this.remove(objActor, objProperty);
    163    }
    164  }
    165 }
    166 
    167 exports.WatchpointMap = WatchpointMap;