diff options
Diffstat (limited to 'js/src/jit/Disassemble.cpp')
-rw-r--r-- | js/src/jit/Disassemble.cpp | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/js/src/jit/Disassemble.cpp b/js/src/jit/Disassemble.cpp new file mode 100644 index 0000000000..6026df27d6 --- /dev/null +++ b/js/src/jit/Disassemble.cpp @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "jit/Disassemble.h" + +#include <stddef.h> // size_t +#include <stdint.h> // uint8_t, int32_t + +#include "js/Printf.h" // JS_smprintf +#include "js/Utility.h" // JS::UniqueChars + +#if defined(JS_JITSPEW) +# if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) +# include "zydis/ZydisAPI.h" // zydisDisassemble +# elif defined(JS_CODEGEN_ARM64) +# include "jit/arm/disasm/Disasm-arm.h" // js::jit::disasm::* +# include "jit/arm64/vixl/Decoder-vixl.h" // vixl::Decoder +# include "jit/arm64/vixl/Disasm-vixl.h" // vixl::Disassembler +# include "jit/arm64/vixl/Instructions-vixl.h" // vixl::Instruction +# elif defined(JS_CODEGEN_ARM) +# include "jit/arm/disasm/Disasm-arm.h" // js::jit::disasm::* +# endif +#endif + +namespace js { +namespace jit { + +#if defined(JS_JITSPEW) && (defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)) + +bool HasDisassembler() { return true; } + +void Disassemble(uint8_t* code, size_t length, InstrCallback callback) { + zydisDisassemble(code, length, callback); +} + +#elif defined(JS_JITSPEW) && defined(JS_CODEGEN_ARM64) + +class ARM64Disassembler : public vixl::Disassembler { + public: + explicit ARM64Disassembler(InstrCallback callback) : callback_(callback) {} + + protected: + void ProcessOutput(const vixl::Instruction* instr) override { + JS::UniqueChars formatted = JS_smprintf( + "0x%p %08x %s", instr, instr->InstructionBits(), GetOutput()); + callback_(formatted.get()); + } + + private: + InstrCallback callback_; +}; + +bool HasDisassembler() { return true; } + +void Disassemble(uint8_t* code, size_t length, InstrCallback callback) { + ARM64Disassembler dis(callback); + vixl::Decoder decoder; + decoder.AppendVisitor(&dis); + + uint8_t* instr = code; + uint8_t* end = code + length; + + while (instr < end) { + decoder.Decode(reinterpret_cast<vixl::Instruction*>(instr)); + + instr += sizeof(vixl::Instr); + } +} + +#elif defined(JS_JITSPEW) && defined(JS_CODEGEN_ARM) + +bool HasDisassembler() { return true; } + +void Disassemble(uint8_t* code, size_t length, InstrCallback callback) { + disasm::NameConverter converter; + disasm::Disassembler d(converter); + + uint8_t* instr = code; + uint8_t* end = code + length; + + while (instr < end) { + disasm::EmbeddedVector<char, disasm::ReasonableBufferSize> buffer; + buffer[0] = '\0'; + uint8_t* next_instr = instr + d.InstructionDecode(buffer, instr); + + JS::UniqueChars formatted = + JS_smprintf("0x%p %08x %s", instr, *reinterpret_cast<int32_t*>(instr), + buffer.start()); + callback(formatted.get()); + + instr = next_instr; + } +} + +#else + +bool HasDisassembler() { return false; } + +void Disassemble(uint8_t* code, size_t length, InstrCallback callback) { + callback("*** No disassembly available ***\n"); +} + +#endif + +} // namespace jit +} // namespace js |