tor-browser

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

Disassembler-shared.h (6166B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef jit_shared_Disassembler_shared_h
      8 #define jit_shared_Disassembler_shared_h
      9 
     10 #include "mozilla/Atomics.h"
     11 #include "mozilla/Attributes.h"
     12 
     13 #include <stdarg.h>
     14 #include <stddef.h>
     15 #include <stdint.h>
     16 
     17 #include "jstypes.h"  // JS_PUBLIC_API
     18 
     19 #if defined(JS_DISASM_ARM) || defined(JS_DISASM_ARM64)
     20 #  define JS_DISASM_SUPPORTED
     21 #endif
     22 
     23 namespace js {
     24 
     25 class JS_PUBLIC_API Sprinter;
     26 
     27 namespace jit {
     28 
     29 class Label;
     30 
     31 // A wrapper around spew/disassembly functionality.  The disassembler is built
     32 // on a per-instruction disassembler (as in our ARM, ARM64 back-ends) and
     33 // formats labels with meaningful names and literals with meaningful values, if
     34 // the assembler creates documentation (with provided helpers) at appropriate
     35 // points.
     36 
     37 class DisassemblerSpew {
     38 #ifdef JS_DISASM_SUPPORTED
     39  struct Node {
     40    const Label* key;  // Never dereferenced, only used for its value
     41    uint32_t value;    // The printable label value
     42    bool bound;        // If the label has been seen by spewBind()
     43    Node* next;
     44  };
     45 
     46  Node* lookup(const Label* key);
     47  Node* add(const Label* key, uint32_t value);
     48  bool remove(const Label* key);
     49 
     50  uint32_t probe(const Label* l);
     51  uint32_t define(const Label* l);
     52  uint32_t internalResolve(const Label* l);
     53 #endif
     54 
     55  void spewVA(const char* fmt, va_list args) MOZ_FORMAT_PRINTF(2, 0);
     56 
     57 public:
     58  DisassemblerSpew();
     59  ~DisassemblerSpew();
     60 
     61 #ifdef JS_DISASM_SUPPORTED
     62  // Set indentation strings.  The spewer retains a reference to s.
     63  void setLabelIndent(const char* s);
     64  void setTargetIndent(const char* s);
     65 #endif
     66 
     67  // Set the spew printer, which will always be used if it is set, regardless
     68  // of whether the system spew channel is enabled or not.  The spewer retains
     69  // a reference to sp.
     70  void setPrinter(Sprinter* sp);
     71 
     72  // Return true if disassembly spew is disabled and no additional printer is
     73  // set.
     74  bool isDisabled();
     75 
     76  // Format and print text on the spew channel; output is suppressed if spew
     77  // is disabled.  The output is not indented, and is terminated by a newline.
     78  void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
     79 
     80  // Documentation for a label reference.
     81  struct LabelDoc {
     82 #ifdef JS_DISASM_SUPPORTED
     83    LabelDoc() : doc(0), bound(false), valid(false) {}
     84    LabelDoc(uint32_t doc, bool bound) : doc(doc), bound(bound), valid(true) {}
     85    const uint32_t doc;
     86    const bool bound;
     87    const bool valid;
     88 #else
     89    LabelDoc() = default;
     90    LabelDoc(uint32_t, bool) {}
     91 #endif
     92  };
     93 
     94  // Documentation for a literal load.
     95  struct LiteralDoc {
     96 #ifdef JS_DISASM_SUPPORTED
     97    enum class Type { Patchable, I32, U32, I64, U64, F32, F64 };
     98    const Type type;
     99    union {
    100      int32_t i32;
    101      uint32_t u32;
    102      int64_t i64;
    103      uint64_t u64;
    104      float f32;
    105      double f64;
    106    } value;
    107    LiteralDoc() : type(Type::Patchable) {}
    108    explicit LiteralDoc(int32_t v) : type(Type::I32) { value.i32 = v; }
    109    explicit LiteralDoc(uint32_t v) : type(Type::U32) { value.u32 = v; }
    110    explicit LiteralDoc(int64_t v) : type(Type::I64) { value.i64 = v; }
    111    explicit LiteralDoc(uint64_t v) : type(Type::U64) { value.u64 = v; }
    112    explicit LiteralDoc(float v) : type(Type::F32) { value.f32 = v; }
    113    explicit LiteralDoc(double v) : type(Type::F64) { value.f64 = v; }
    114 #else
    115    LiteralDoc() = default;
    116    explicit LiteralDoc(int32_t) {}
    117    explicit LiteralDoc(uint32_t) {}
    118    explicit LiteralDoc(int64_t) {}
    119    explicit LiteralDoc(uint64_t) {}
    120    explicit LiteralDoc(float) {}
    121    explicit LiteralDoc(double) {}
    122 #endif
    123  };
    124 
    125  // Reference a label, resolving it to a printable representation.
    126  //
    127  // NOTE: The printable representation depends on the state of the label, so
    128  // if we call resolve() when emitting & disassembling a branch instruction
    129  // then it should be called before the label becomes Used, if emitting the
    130  // branch can change the label's state.
    131  //
    132  // If the disassembler is not defined this returns a structure that is
    133  // marked not valid.
    134  LabelDoc refLabel(const Label* l);
    135 
    136 #ifdef JS_DISASM_SUPPORTED
    137  // Spew the label information previously gathered by refLabel(), at a point
    138  // where the label is referenced.  The output is indented by targetIndent_
    139  // and terminated by a newline.
    140  void spewRef(const LabelDoc& target);
    141 
    142  // Spew the label at the point where the label is bound.  The output is
    143  // indented by labelIndent_ and terminated by a newline.
    144  void spewBind(const Label* label);
    145 
    146  // Spew a retarget directive at the point where the retarget is recorded.
    147  // The output is indented by labelIndent_ and terminated by a newline.
    148  void spewRetarget(const Label* label, const Label* target);
    149 
    150  // Format a literal value into the buffer.  The buffer is always
    151  // NUL-terminated even if this chops the formatted value.
    152  void formatLiteral(const LiteralDoc& doc, char* buffer, size_t bufsize);
    153 
    154  // Print any unbound labels, one per line, with normal label indent and with
    155  // a comment indicating the label is not defined.  Labels can be referenced
    156  // but unbound in some legitimate cases, normally for traps.  Printing them
    157  // reduces confusion.
    158  void spewOrphans();
    159 #endif
    160 
    161 private:
    162  Sprinter* printer_;
    163 #ifdef JS_DISASM_SUPPORTED
    164  const char* labelIndent_;
    165  const char* targetIndent_;
    166  uint32_t spewNext_;
    167  Node* nodes_;
    168  uint32_t tag_;
    169 
    170  // This global is used to disambiguate concurrently live assemblers, see
    171  // comments in Disassembler-shared.cpp for why this is desirable.
    172  //
    173  // The variable is atomic to avoid any kind of complaint from thread
    174  // sanitizers etc.  However, trying to look at disassembly without using
    175  // --no-threads is basically insane, so you can ignore the multi-threading
    176  // implications here.
    177  static mozilla::Atomic<uint32_t> counter_;
    178 #endif
    179 };
    180 
    181 }  // namespace jit
    182 }  // namespace js
    183 
    184 #endif  // jit_shared_Disassembler_shared_h