tor-browser

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

Disassemble.cpp (4485B)


      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 #include "jit/Disassemble.h"
      8 
      9 #include <stddef.h>  // size_t
     10 #include <stdint.h>  // uint8_t, int32_t
     11 
     12 #include "js/Printf.h"   // JS_smprintf
     13 #include "js/Utility.h"  // JS::UniqueChars
     14 
     15 #if defined(JS_JITSPEW)
     16 #  if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
     17 #    include "zydis/ZydisAPI.h"  // zydisDisassemble
     18 #  elif defined(JS_CODEGEN_ARM64)
     19 #    include "jit/arm/disasm/Disasm-arm.h"         // js::jit::disasm::*
     20 #    include "jit/arm64/vixl/Decoder-vixl.h"       // vixl::Decoder
     21 #    include "jit/arm64/vixl/Disasm-vixl.h"        // vixl::Disassembler
     22 #    include "jit/arm64/vixl/Instructions-vixl.h"  // vixl::Instruction
     23 #  elif defined(JS_CODEGEN_ARM)
     24 #    include "jit/arm/disasm/Disasm-arm.h"  // js::jit::disasm::*
     25 #  elif defined(JS_CODEGEN_RISCV64)
     26 #    include "jit/riscv64/disasm/Disasm-riscv64.h"  // js::jit::disasm::*
     27 #  endif
     28 #endif
     29 
     30 namespace js {
     31 namespace jit {
     32 
     33 #if defined(JS_JITSPEW) && (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64))
     34 
     35 bool HasDisassembler() { return true; }
     36 
     37 void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
     38  zydisDisassemble(code, length, callback);
     39 }
     40 
     41 #elif defined(JS_JITSPEW) && defined(JS_CODEGEN_ARM64)
     42 
     43 class ARM64Disassembler : public vixl::Disassembler {
     44 public:
     45  explicit ARM64Disassembler(InstrCallback callback) : callback_(callback) {}
     46 
     47 protected:
     48  void ProcessOutput(const vixl::Instruction* instr) override {
     49    AutoEnterOOMUnsafeRegion oomUnsafe;
     50    JS::UniqueChars formatted = JS_smprintf(
     51        "0x%p  %08x  %s", instr, instr->InstructionBits(), GetOutput());
     52    if (!formatted) {
     53      oomUnsafe.crash("ARM64Disassembler::ProcessOutput");
     54    }
     55    callback_(formatted.get());
     56  }
     57 
     58 private:
     59  InstrCallback callback_;
     60 };
     61 
     62 bool HasDisassembler() { return true; }
     63 
     64 void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
     65  ARM64Disassembler dis(callback);
     66  vixl::Decoder decoder;
     67  decoder.AppendVisitor(&dis);
     68 
     69  uint8_t* instr = code;
     70  uint8_t* end = code + length;
     71 
     72  while (instr < end) {
     73    auto* ins = reinterpret_cast<vixl::Instruction*>(instr);
     74 
     75    decoder.Decode(ins);
     76 
     77    // Check for constant pool.
     78    const auto* skipped = ins->skipPool();
     79    if (ins == skipped) {
     80      // No constant pool, proceed to the next instruction.
     81      instr += sizeof(vixl::Instr);
     82    } else {
     83      // Skip over constant pool entries, because they don't encode valid
     84      // instructions.
     85      callback("*** constant pool ***");
     86      instr = const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(skipped));
     87    }
     88  }
     89 }
     90 
     91 #elif defined(JS_JITSPEW) && defined(JS_CODEGEN_ARM)
     92 
     93 bool HasDisassembler() { return true; }
     94 
     95 void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
     96  disasm::NameConverter converter;
     97  disasm::Disassembler d(converter);
     98 
     99  uint8_t* instr = code;
    100  uint8_t* end = code + length;
    101 
    102  while (instr < end) {
    103    disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer;
    104    buffer[0] = '\0';
    105    uint8_t* next_instr = instr + d.InstructionDecode(buffer, instr);
    106 
    107    JS::UniqueChars formatted =
    108        JS_smprintf("0x%p  %08x  %s", instr, *reinterpret_cast<int32_t*>(instr),
    109                    buffer.start());
    110    callback(formatted.get());
    111 
    112    instr = next_instr;
    113  }
    114 }
    115 
    116 #elif defined(JS_JITSPEW) && defined(JS_CODEGEN_RISCV64)
    117 
    118 bool HasDisassembler() { return true; }
    119 
    120 void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
    121  disasm::NameConverter converter;
    122  disasm::Disassembler d(converter);
    123 
    124  uint8_t* instr = code;
    125  uint8_t* end = code + length;
    126 
    127  while (instr < end) {
    128    EmbeddedVector<char, ReasonableBufferSize> buffer;
    129    buffer[0] = '\0';
    130    uint8_t* next_instr = instr + d.InstructionDecode(buffer, instr);
    131 
    132    JS::UniqueChars formatted =
    133        JS_smprintf("0x%p  %08x  %s", instr, *reinterpret_cast<int32_t*>(instr),
    134                    buffer.start());
    135    callback(formatted.get());
    136 
    137    instr = next_instr;
    138  }
    139 }
    140 
    141 #else
    142 
    143 bool HasDisassembler() { return false; }
    144 
    145 void Disassemble(uint8_t* code, size_t length, InstrCallback callback) {
    146  callback("*** No disassembly available ***\n");
    147 }
    148 
    149 #endif
    150 
    151 }  // namespace jit
    152 }  // namespace js