1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/* -*- 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 {
AutoEnterOOMUnsafeRegion oomUnsafe;
JS::UniqueChars formatted = JS_smprintf(
"0x%p %08x %s", instr, instr->InstructionBits(), GetOutput());
if (!formatted) {
oomUnsafe.crash("ARM64Disassembler::ProcessOutput");
}
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
|