]>
Commit | Line | Data |
---|---|---|
999b53ec CF |
1 | /* |
2 | * ARM A64 disassembly output wrapper to libvixl | |
3 | * Copyright (c) 2013 Linaro Limited | |
4 | * Written by Claudio Fontana | |
5 | * | |
6 | * This program is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
e78490c4 | 20 | #include "qemu/osdep.h" |
3979fca4 | 21 | #include "disas/dis-asm.h" |
999b53ec | 22 | |
e78490c4 PM |
23 | #include "vixl/a64/disasm-a64.h" |
24 | ||
999b53ec CF |
25 | using namespace vixl; |
26 | ||
27 | static Decoder *vixl_decoder = NULL; | |
28 | static Disassembler *vixl_disasm = NULL; | |
29 | ||
30 | /* We don't use libvixl's PrintDisassembler because its output | |
31 | * is a little unhelpful (trailing newlines, for example). | |
32 | * Instead we use our own very similar variant so we have | |
33 | * control over the format. | |
34 | */ | |
35 | class QEMUDisassembler : public Disassembler { | |
36 | public: | |
fb200d5f | 37 | QEMUDisassembler() : printf_(NULL), stream_(NULL) { } |
999b53ec CF |
38 | ~QEMUDisassembler() { } |
39 | ||
fb200d5f PC |
40 | void SetStream(FILE *stream) { |
41 | stream_ = stream; | |
42 | } | |
43 | ||
57b73090 | 44 | void SetPrintf(fprintf_function printf_fn) { |
fb200d5f PC |
45 | printf_ = printf_fn; |
46 | } | |
47 | ||
999b53ec | 48 | protected: |
6aea44fc | 49 | virtual void ProcessOutput(const Instruction *instr) { |
fb200d5f | 50 | printf_(stream_, "%08" PRIx32 " %s", |
999b53ec CF |
51 | instr->InstructionBits(), GetOutput()); |
52 | } | |
53 | ||
54 | private: | |
57b73090 | 55 | fprintf_function printf_; |
999b53ec CF |
56 | FILE *stream_; |
57 | }; | |
58 | ||
59 | static int vixl_is_initialized(void) | |
60 | { | |
61 | return vixl_decoder != NULL; | |
62 | } | |
63 | ||
fb200d5f | 64 | static void vixl_init() { |
999b53ec | 65 | vixl_decoder = new Decoder(); |
fb200d5f | 66 | vixl_disasm = new QEMUDisassembler(); |
999b53ec CF |
67 | vixl_decoder->AppendVisitor(vixl_disasm); |
68 | } | |
69 | ||
70 | #define INSN_SIZE 4 | |
71 | ||
72 | /* Disassemble ARM A64 instruction. This is our only entry | |
73 | * point from QEMU's C code. | |
74 | */ | |
75 | int print_insn_arm_a64(uint64_t addr, disassemble_info *info) | |
76 | { | |
77 | uint8_t bytes[INSN_SIZE]; | |
8d298bee PM |
78 | uint32_t instrval; |
79 | const Instruction *instr; | |
999b53ec CF |
80 | int status; |
81 | ||
82 | status = info->read_memory_func(addr, bytes, INSN_SIZE, info); | |
83 | if (status != 0) { | |
84 | info->memory_error_func(status, addr, info); | |
85 | return -1; | |
86 | } | |
87 | ||
88 | if (!vixl_is_initialized()) { | |
fb200d5f | 89 | vixl_init(); |
999b53ec CF |
90 | } |
91 | ||
fb200d5f PC |
92 | ((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func); |
93 | ((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream); | |
94 | ||
8d298bee PM |
95 | instrval = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; |
96 | instr = reinterpret_cast<const Instruction *>(&instrval); | |
97 | vixl_disasm->MapCodeAddress(addr, instr); | |
98 | vixl_decoder->Decode(instr); | |
999b53ec CF |
99 | |
100 | return INSN_SIZE; | |
101 | } |