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