tor-browser

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

Simulator-arm.h (19231B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 // Copyright 2012 the V8 project authors. All rights reserved.
      3 // Redistribution and use in source and binary forms, with or without
      4 // modification, are permitted provided that the following conditions are
      5 // met:
      6 //
      7 //     * Redistributions of source code must retain the above copyright
      8 //       notice, this list of conditions and the following disclaimer.
      9 //     * Redistributions in binary form must reproduce the above
     10 //       copyright notice, this list of conditions and the following
     11 //       disclaimer in the documentation and/or other materials provided
     12 //       with the distribution.
     13 //     * Neither the name of Google Inc. nor the names of its
     14 //       contributors may be used to endorse or promote products derived
     15 //       from this software without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 #ifndef jit_arm_Simulator_arm_h
     30 #define jit_arm_Simulator_arm_h
     31 
     32 #ifdef JS_SIMULATOR_ARM
     33 
     34 #  include "mozilla/Atomics.h"
     35 
     36 #  include "jit/arm/Architecture-arm.h"
     37 #  include "jit/arm/disasm/Disasm-arm.h"
     38 #  include "jit/IonTypes.h"
     39 #  include "js/AllocPolicy.h"
     40 #  include "js/ProfilingFrameIterator.h"
     41 #  include "threading/Thread.h"
     42 #  include "vm/MutexIDs.h"
     43 #  include "wasm/WasmSignalHandlers.h"
     44 
     45 namespace js {
     46 namespace jit {
     47 
     48 class JitActivation;
     49 class Simulator;
     50 class Redirection;
     51 class CachePage;
     52 class AutoLockSimulator;
     53 
     54 // When the SingleStepCallback is called, the simulator is about to execute
     55 // sim->get_pc() and the current machine state represents the completed
     56 // execution of the previous pc.
     57 using SingleStepCallback = void (*)(void* arg, Simulator* sim, void* pc);
     58 
     59 // VFP rounding modes. See ARM DDI 0406B Page A2-29.
     60 enum VFPRoundingMode {
     61  SimRN = 0 << 22,  // Round to Nearest.
     62  SimRP = 1 << 22,  // Round towards Plus Infinity.
     63  SimRM = 2 << 22,  // Round towards Minus Infinity.
     64  SimRZ = 3 << 22,  // Round towards zero.
     65 
     66  // Aliases.
     67  kRoundToNearest = SimRN,
     68  kRoundToPlusInf = SimRP,
     69  kRoundToMinusInf = SimRM,
     70  kRoundToZero = SimRZ
     71 };
     72 
     73 const uint32_t kVFPRoundingModeMask = 3 << 22;
     74 
     75 using Instr = int32_t;
     76 class SimInstruction;
     77 
     78 // Per thread simulator state.
     79 class Simulator {
     80 public:
     81  friend class ArmDebugger;
     82  enum Register {
     83    no_reg = -1,
     84    r0 = 0,
     85    r1,
     86    r2,
     87    r3,
     88    r4,
     89    r5,
     90    r6,
     91    r7,
     92    r8,
     93    r9,
     94    r10,
     95    r11,
     96    r12,
     97    r13,
     98    r14,
     99    r15,
    100    num_registers,
    101    fp = 11,
    102    ip = 12,
    103    sp = 13,
    104    lr = 14,
    105    pc = 15,
    106    s0 = 0,
    107    s1,
    108    s2,
    109    s3,
    110    s4,
    111    s5,
    112    s6,
    113    s7,
    114    s8,
    115    s9,
    116    s10,
    117    s11,
    118    s12,
    119    s13,
    120    s14,
    121    s15,
    122    s16,
    123    s17,
    124    s18,
    125    s19,
    126    s20,
    127    s21,
    128    s22,
    129    s23,
    130    s24,
    131    s25,
    132    s26,
    133    s27,
    134    s28,
    135    s29,
    136    s30,
    137    s31,
    138    num_s_registers = 32,
    139    d0 = 0,
    140    d1,
    141    d2,
    142    d3,
    143    d4,
    144    d5,
    145    d6,
    146    d7,
    147    d8,
    148    d9,
    149    d10,
    150    d11,
    151    d12,
    152    d13,
    153    d14,
    154    d15,
    155    d16,
    156    d17,
    157    d18,
    158    d19,
    159    d20,
    160    d21,
    161    d22,
    162    d23,
    163    d24,
    164    d25,
    165    d26,
    166    d27,
    167    d28,
    168    d29,
    169    d30,
    170    d31,
    171    num_d_registers = 32,
    172    q0 = 0,
    173    q1,
    174    q2,
    175    q3,
    176    q4,
    177    q5,
    178    q6,
    179    q7,
    180    q8,
    181    q9,
    182    q10,
    183    q11,
    184    q12,
    185    q13,
    186    q14,
    187    q15,
    188    num_q_registers = 16
    189  };
    190 
    191  // Returns nullptr on OOM.
    192  static Simulator* Create();
    193 
    194  static void Destroy(Simulator* simulator);
    195 
    196  // Constructor/destructor are for internal use only; use the static methods
    197  // above.
    198  Simulator();
    199  ~Simulator();
    200 
    201  // The currently executing Simulator instance. Potentially there can be one
    202  // for each native thread.
    203  static Simulator* Current();
    204 
    205  static uintptr_t StackLimit() { return Simulator::Current()->stackLimit(); }
    206 
    207  // Disassemble some instructions starting at instr and print them
    208  // on stdout.  Useful for working within GDB after a MOZ_CRASH(),
    209  // among other things.
    210  //
    211  // Typical use within a crashed instruction decoding method is simply:
    212  //
    213  //   call Simulator::disassemble(instr, 1)
    214  //
    215  // or use one of the more convenient inline methods below.
    216  static void disassemble(SimInstruction* instr, size_t n);
    217 
    218  // Disassemble one instruction.
    219  // "call disasm(instr)"
    220  void disasm(SimInstruction* instr);
    221 
    222  // Disassemble n instructions starting at instr.
    223  // "call disasm(instr, 3)"
    224  void disasm(SimInstruction* instr, size_t n);
    225 
    226  // Skip backwards m instructions before starting, then disassemble n
    227  // instructions.
    228  // "call disasm(instr, 3, 7)"
    229  void disasm(SimInstruction* instr, size_t m, size_t n);
    230 
    231  uintptr_t* addressOfStackLimit();
    232 
    233  // Accessors for register state. Reading the pc value adheres to the ARM
    234  // architecture specification and is off by a 8 from the currently executing
    235  // instruction.
    236  void set_register(int reg, int32_t value);
    237  int32_t get_register(int reg) const;
    238  double get_double_from_register_pair(int reg);
    239  void set_register_pair_from_double(int reg, double* value);
    240  void set_dw_register(int dreg, const int* dbl);
    241 
    242  // Support for VFP.
    243  void get_d_register(int dreg, uint64_t* value);
    244  void set_d_register(int dreg, const uint64_t* value);
    245  void get_d_register(int dreg, uint32_t* value);
    246  void set_d_register(int dreg, const uint32_t* value);
    247  void get_q_register(int qreg, uint64_t* value);
    248  void set_q_register(int qreg, const uint64_t* value);
    249  void get_q_register(int qreg, uint32_t* value);
    250  void set_q_register(int qreg, const uint32_t* value);
    251  void set_s_register(int reg, unsigned int value);
    252  unsigned int get_s_register(int reg) const;
    253 
    254  void set_d_register_from_double(int dreg, const double& dbl) {
    255    setVFPRegister<double, 2>(dreg, dbl);
    256  }
    257  void get_double_from_d_register(int dreg, double* out) {
    258    getFromVFPRegister<double, 2>(dreg, out);
    259  }
    260  void set_s_register_from_float(int sreg, const float flt) {
    261    setVFPRegister<float, 1>(sreg, flt);
    262  }
    263  void get_float_from_s_register(int sreg, float* out) {
    264    getFromVFPRegister<float, 1>(sreg, out);
    265  }
    266  void set_s_register_from_sinteger(int sreg, const int sint) {
    267    setVFPRegister<int, 1>(sreg, sint);
    268  }
    269  int get_sinteger_from_s_register(int sreg) {
    270    int ret;
    271    getFromVFPRegister<int, 1>(sreg, &ret);
    272    return ret;
    273  }
    274 
    275  // Special case of set_register and get_register to access the raw PC value.
    276  void set_pc(int32_t value);
    277  int32_t get_pc() const;
    278 
    279  template <typename T>
    280  T get_pc_as() const {
    281    return reinterpret_cast<T>(get_pc());
    282  }
    283 
    284  void enable_single_stepping(SingleStepCallback cb, void* arg);
    285  void disable_single_stepping();
    286 
    287  uintptr_t stackLimit() const;
    288  bool overRecursed(uintptr_t newsp = 0) const;
    289  bool overRecursedWithExtra(uint32_t extra) const;
    290 
    291  // Executes ARM instructions until the PC reaches end_sim_pc.
    292  template <bool EnableStopSimAt>
    293  void execute();
    294 
    295  // Sets up the simulator state and grabs the result on return.
    296  int32_t call(uint8_t* entry, int argument_count, ...);
    297 
    298  // Debugger input.
    299  void setLastDebuggerInput(char* input);
    300  char* lastDebuggerInput() { return lastDebuggerInput_; }
    301 
    302  // Returns true if pc register contains one of the 'special_values' defined
    303  // below (bad_lr, end_sim_pc).
    304  bool has_bad_pc() const;
    305 
    306 private:
    307  enum special_values {
    308    // Known bad pc value to ensure that the simulator does not execute
    309    // without being properly setup.
    310    bad_lr = -1,
    311    // A pc value used to signal the simulator to stop execution. Generally
    312    // the lr is set to this value on transition from native C code to
    313    // simulated execution, so that the simulator can "return" to the native
    314    // C code.
    315    end_sim_pc = -2
    316  };
    317 
    318  // ForbidUnaligned means "always fault on unaligned access".
    319  //
    320  // AllowUnaligned means "allow the unaligned access if other conditions are
    321  // met".  The "other conditions" vary with the instruction: For all
    322  // instructions the base condition is !ARMFlags::HasAlignmentFault(), ie, the
    323  // chip is configured to allow unaligned accesses.  For instructions like VLD1
    324  // there is an additional constraint that the alignment attribute in the
    325  // instruction must be set to "default alignment".
    326 
    327  enum UnalignedPolicy { ForbidUnaligned, AllowUnaligned };
    328 
    329  bool init();
    330 
    331  // Checks if the current instruction should be executed based on its
    332  // condition bits.
    333  inline bool conditionallyExecute(SimInstruction* instr);
    334 
    335  // Helper functions to set the conditional flags in the architecture state.
    336  void setNZFlags(int32_t val);
    337  void setCFlag(bool val);
    338  void setVFlag(bool val);
    339  bool carryFrom(int32_t left, int32_t right, int32_t carry = 0);
    340  bool borrowFrom(int32_t left, int32_t right);
    341  bool overflowFrom(int32_t alu_out, int32_t left, int32_t right,
    342                    bool addition);
    343 
    344  inline int getCarry() { return c_flag_ ? 1 : 0; };
    345 
    346  // Support for VFP.
    347  void compute_FPSCR_Flags(double val1, double val2);
    348  void copy_FPSCR_to_APSR();
    349  inline void canonicalizeNaN(double* value);
    350  inline void canonicalizeNaN(float* value);
    351 
    352  // Helper functions to decode common "addressing" modes
    353  int32_t getShiftRm(SimInstruction* instr, bool* carry_out);
    354  int32_t getImm(SimInstruction* instr, bool* carry_out);
    355  int32_t processPU(SimInstruction* instr, int num_regs, int operand_size,
    356                    intptr_t* start_address, intptr_t* end_address);
    357  void handleRList(SimInstruction* instr, bool load);
    358  void handleVList(SimInstruction* inst);
    359  void softwareInterrupt(SimInstruction* instr);
    360 
    361  // Stop helper functions.
    362  inline bool isStopInstruction(SimInstruction* instr);
    363  inline bool isWatchedStop(uint32_t bkpt_code);
    364  inline bool isEnabledStop(uint32_t bkpt_code);
    365  inline void enableStop(uint32_t bkpt_code);
    366  inline void disableStop(uint32_t bkpt_code);
    367  inline void increaseStopCounter(uint32_t bkpt_code);
    368  void printStopInfo(uint32_t code);
    369 
    370  // Handle a wasm interrupt triggered by an async signal handler.
    371  JS::ProfilingFrameIterator::RegisterState registerState();
    372 
    373  // Handle any wasm faults, returning true if the fault was handled.
    374  // This method is rather hot so inline the normal (no-wasm) case.
    375  bool MOZ_ALWAYS_INLINE handleWasmSegFault(int32_t addr, unsigned numBytes) {
    376    if (MOZ_LIKELY(!wasm::CodeExists)) {
    377      return false;
    378    }
    379 
    380    uint8_t* newPC;
    381    if (!wasm::MemoryAccessTraps(registerState(), (uint8_t*)addr, numBytes,
    382                                 &newPC)) {
    383      return false;
    384    }
    385 
    386    set_pc(int32_t(newPC));
    387    return true;
    388  }
    389 
    390  // Read and write memory.
    391  inline uint8_t readBU(int32_t addr);
    392  inline int8_t readB(int32_t addr);
    393  inline void writeB(int32_t addr, uint8_t value);
    394  inline void writeB(int32_t addr, int8_t value);
    395 
    396  inline uint8_t readExBU(int32_t addr);
    397  inline int32_t writeExB(int32_t addr, uint8_t value);
    398 
    399  inline uint16_t readHU(int32_t addr, SimInstruction* instr);
    400  inline int16_t readH(int32_t addr, SimInstruction* instr);
    401  // Note: Overloaded on the sign of the value.
    402  inline void writeH(int32_t addr, uint16_t value, SimInstruction* instr);
    403  inline void writeH(int32_t addr, int16_t value, SimInstruction* instr);
    404 
    405  inline uint16_t readExHU(int32_t addr, SimInstruction* instr);
    406  inline int32_t writeExH(int32_t addr, uint16_t value, SimInstruction* instr);
    407 
    408  inline int readW(int32_t addr, SimInstruction* instr,
    409                   UnalignedPolicy f = ForbidUnaligned);
    410  inline void writeW(int32_t addr, int value, SimInstruction* instr,
    411                     UnalignedPolicy f = ForbidUnaligned);
    412 
    413  inline uint64_t readQ(int32_t addr, SimInstruction* instr,
    414                        UnalignedPolicy f = ForbidUnaligned);
    415  inline void writeQ(int32_t addr, uint64_t value, SimInstruction* instr,
    416                     UnalignedPolicy f = ForbidUnaligned);
    417 
    418  inline int readExW(int32_t addr, SimInstruction* instr);
    419  inline int writeExW(int32_t addr, int value, SimInstruction* instr);
    420 
    421  int32_t* readDW(int32_t addr);
    422  void writeDW(int32_t addr, int32_t value1, int32_t value2);
    423 
    424  int32_t readExDW(int32_t addr, int32_t* hibits);
    425  int32_t writeExDW(int32_t addr, int32_t value1, int32_t value2);
    426 
    427  // Executing is handled based on the instruction type.
    428  // Both type 0 and type 1 rolled into one.
    429  void decodeType01(SimInstruction* instr);
    430  void decodeType2(SimInstruction* instr);
    431  void decodeType3(SimInstruction* instr);
    432  void decodeType4(SimInstruction* instr);
    433  void decodeType5(SimInstruction* instr);
    434  void decodeType6(SimInstruction* instr);
    435  void decodeType7(SimInstruction* instr);
    436 
    437  // Support for VFP.
    438  void decodeTypeVFP(SimInstruction* instr);
    439  void decodeType6CoprocessorIns(SimInstruction* instr);
    440  void decodeSpecialCondition(SimInstruction* instr);
    441 
    442  void decodeVMOVBetweenCoreAndSinglePrecisionRegisters(SimInstruction* instr);
    443  void decodeVCMP(SimInstruction* instr);
    444  void decodeVCVTBetweenDoubleAndSingle(SimInstruction* instr);
    445  void decodeVCVTBetweenFloatingPointAndInteger(SimInstruction* instr);
    446  void decodeVCVTBetweenFloatingPointAndIntegerFrac(SimInstruction* instr);
    447  void decodeVCVTBetweenFloatingPointAndHalf(SimInstruction* instr);
    448 
    449  // Support for some system functions.
    450  void decodeType7CoprocessorIns(SimInstruction* instr);
    451 
    452  // Executes one instruction.
    453  void instructionDecode(SimInstruction* instr);
    454 
    455 public:
    456  static int64_t StopSimAt;
    457 
    458  // For testing the MoveResolver code, a MoveResolver is set up, and
    459  // the VFP registers are loaded with pre-determined values,
    460  // then the sequence of code is simulated.  In order to test this with the
    461  // simulator, the callee-saved registers can't be trashed. This flag
    462  // disables that feature.
    463  bool skipCalleeSavedRegsCheck;
    464 
    465  // Runtime call support.
    466  static void* RedirectNativeFunction(void* nativeFunction,
    467                                      ABIFunctionType type);
    468 
    469 private:
    470  // Handle arguments and return value for runtime FP functions.
    471  void getFpArgs(double* x, double* y, int32_t* z);
    472  void getFpFromStack(int32_t* stack, double* x1);
    473  void setCallResultDouble(double result);
    474  void setCallResultFloat(float result);
    475  void setCallResult(int64_t res);
    476  void scratchVolatileRegisters(void* target = nullptr);
    477 
    478  template <class ReturnType, int register_size>
    479  void getFromVFPRegister(int reg_index, ReturnType* out);
    480 
    481  template <class InputType, int register_size>
    482  void setVFPRegister(int reg_index, const InputType& value);
    483 
    484  void callInternal(uint8_t* entry);
    485 
    486  // Architecture state.
    487  // Saturating instructions require a Q flag to indicate saturation.
    488  // There is currently no way to read the CPSR directly, and thus read the Q
    489  // flag, so this is left unimplemented.
    490  int32_t registers_[16];
    491  bool n_flag_;
    492  bool z_flag_;
    493  bool c_flag_;
    494  bool v_flag_;
    495 
    496  // VFP architecture state.
    497  uint32_t vfp_registers_[num_d_registers * 2];
    498  bool n_flag_FPSCR_;
    499  bool z_flag_FPSCR_;
    500  bool c_flag_FPSCR_;
    501  bool v_flag_FPSCR_;
    502 
    503  // VFP rounding mode. See ARM DDI 0406B Page A2-29.
    504  VFPRoundingMode FPSCR_rounding_mode_;
    505  bool FPSCR_default_NaN_mode_;
    506 
    507  // VFP FP exception flags architecture state.
    508  bool inv_op_vfp_flag_;
    509  bool div_zero_vfp_flag_;
    510  bool overflow_vfp_flag_;
    511  bool underflow_vfp_flag_;
    512  bool inexact_vfp_flag_;
    513 
    514  // Simulator support.
    515  char* stack_;
    516  uintptr_t stackLimit_;
    517  bool pc_modified_;
    518  int64_t icount_;
    519 
    520  // Debugger input.
    521  char* lastDebuggerInput_;
    522 
    523  // Registered breakpoints.
    524  SimInstruction* break_pc_;
    525  Instr break_instr_;
    526 
    527  // Single-stepping support
    528  bool single_stepping_;
    529  SingleStepCallback single_step_callback_;
    530  void* single_step_callback_arg_;
    531 
    532  // A stop is watched if its code is less than kNumOfWatchedStops.
    533  // Only watched stops support enabling/disabling and the counter feature.
    534  static const uint32_t kNumOfWatchedStops = 256;
    535 
    536  // Breakpoint is disabled if bit 31 is set.
    537  static const uint32_t kStopDisabledBit = 1 << 31;
    538 
    539  // A stop is enabled, meaning the simulator will stop when meeting the
    540  // instruction, if bit 31 of watched_stops_[code].count is unset.
    541  // The value watched_stops_[code].count & ~(1 << 31) indicates how many times
    542  // the breakpoint was hit or gone through.
    543  struct StopCountAndDesc {
    544    uint32_t count;
    545    char* desc;
    546  };
    547  StopCountAndDesc watched_stops_[kNumOfWatchedStops];
    548 
    549 public:
    550  int64_t icount() { return icount_; }
    551 
    552 private:
    553  // Exclusive access monitor
    554  void exclusiveMonitorSet(uint64_t value);
    555  uint64_t exclusiveMonitorGetAndClear(bool* held);
    556  void exclusiveMonitorClear();
    557 
    558  bool exclusiveMonitorHeld_;
    559  uint64_t exclusiveMonitor_;
    560 };
    561 
    562 // Process wide simulator state.
    563 class SimulatorProcess {
    564  friend class Redirection;
    565  friend class AutoLockSimulatorCache;
    566 
    567 private:
    568  // ICache checking.
    569  struct ICacheHasher {
    570    using Key = void*;
    571    using Lookup = void*;
    572    static HashNumber hash(const Lookup& l);
    573    static bool match(const Key& k, const Lookup& l);
    574  };
    575 
    576 public:
    577  using ICacheMap = HashMap<void*, CachePage*, ICacheHasher, SystemAllocPolicy>;
    578 
    579  static mozilla::Atomic<size_t, mozilla::ReleaseAcquire>
    580      ICacheCheckingDisableCount;
    581  static void FlushICache(void* start, size_t size);
    582 
    583  static void checkICacheLocked(SimInstruction* instr);
    584 
    585  static bool initialize() {
    586    singleton_ = js_new<SimulatorProcess>();
    587    return singleton_;
    588  }
    589  static void destroy() {
    590    js_delete(singleton_);
    591    singleton_ = nullptr;
    592  }
    593 
    594  SimulatorProcess();
    595  ~SimulatorProcess();
    596 
    597 private:
    598  static SimulatorProcess* singleton_;
    599 
    600  // This lock creates a critical section around 'redirection_' and
    601  // 'icache_', which are referenced both by the execution engine
    602  // and by the off-thread compiler (see Redirection::Get in the cpp file).
    603  Mutex cacheLock_ MOZ_UNANNOTATED;
    604 
    605  Redirection* redirection_;
    606  ICacheMap icache_;
    607 
    608 public:
    609  static ICacheMap& icache() {
    610    // Technically we need the lock to access the innards of the
    611    // icache, not to take its address, but the latter condition
    612    // serves as a useful complement to the former.
    613    singleton_->cacheLock_.assertOwnedByCurrentThread();
    614    return singleton_->icache_;
    615  }
    616 
    617  static Redirection* redirection() {
    618    singleton_->cacheLock_.assertOwnedByCurrentThread();
    619    return singleton_->redirection_;
    620  }
    621 
    622  static void setRedirection(js::jit::Redirection* redirection) {
    623    singleton_->cacheLock_.assertOwnedByCurrentThread();
    624    singleton_->redirection_ = redirection;
    625  }
    626 };
    627 
    628 }  // namespace jit
    629 }  // namespace js
    630 
    631 #endif /* JS_SIMULATOR_ARM */
    632 
    633 #endif /* jit_arm_Simulator_arm_h */