]>
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 | ||
999b53ec | 20 | extern "C" { |
e78490c4 | 21 | #include "qemu/osdep.h" |
999b53ec CF |
22 | #include "disas/bfd.h" |
23 | } | |
24 | ||
e78490c4 PM |
25 | #include "vixl/a64/disasm-a64.h" |
26 | ||
999b53ec CF |
27 | using namespace vixl; |
28 | ||
29 | static Decoder *vixl_decoder = NULL; | |
30 | static Disassembler *vixl_disasm = NULL; | |
31 | ||
32 | /* We don't use libvixl's PrintDisassembler because its output | |
33 | * is a little unhelpful (trailing newlines, for example). | |
34 | * Instead we use our own very similar variant so we have | |
35 | * control over the format. | |
36 | */ | |
37 | class QEMUDisassembler : public Disassembler { | |
38 | public: | |
fb200d5f | 39 | QEMUDisassembler() : printf_(NULL), stream_(NULL) { } |
999b53ec CF |
40 | ~QEMUDisassembler() { } |
41 | ||
fb200d5f PC |
42 | void SetStream(FILE *stream) { |
43 | stream_ = stream; | |
44 | } | |
45 | ||
57b73090 | 46 | void SetPrintf(fprintf_function printf_fn) { |
fb200d5f PC |
47 | printf_ = printf_fn; |
48 | } | |
49 | ||
999b53ec | 50 | protected: |
6aea44fc | 51 | virtual void ProcessOutput(const Instruction *instr) { |
fb200d5f | 52 | printf_(stream_, "%08" PRIx32 " %s", |
999b53ec CF |
53 | instr->InstructionBits(), GetOutput()); |
54 | } | |
55 | ||
56 | private: | |
57b73090 | 57 | fprintf_function printf_; |
999b53ec CF |
58 | FILE *stream_; |
59 | }; | |
60 | ||
61 | static int vixl_is_initialized(void) | |
62 | { | |
63 | return vixl_decoder != NULL; | |
64 | } | |
65 | ||
fb200d5f | 66 | static void vixl_init() { |
999b53ec | 67 | vixl_decoder = new Decoder(); |
fb200d5f | 68 | vixl_disasm = new QEMUDisassembler(); |
999b53ec CF |
69 | vixl_decoder->AppendVisitor(vixl_disasm); |
70 | } | |
71 | ||
72 | #define INSN_SIZE 4 | |
73 | ||
74 | /* Disassemble ARM A64 instruction. This is our only entry | |
75 | * point from QEMU's C code. | |
76 | */ | |
77 | int print_insn_arm_a64(uint64_t addr, disassemble_info *info) | |
78 | { | |
79 | uint8_t bytes[INSN_SIZE]; | |
8d298bee PM |
80 | uint32_t instrval; |
81 | const Instruction *instr; | |
999b53ec CF |
82 | int status; |
83 | ||
84 | status = info->read_memory_func(addr, bytes, INSN_SIZE, info); | |
85 | if (status != 0) { | |
86 | info->memory_error_func(status, addr, info); | |
87 | return -1; | |
88 | } | |
89 | ||
90 | if (!vixl_is_initialized()) { | |
fb200d5f | 91 | vixl_init(); |
999b53ec CF |
92 | } |
93 | ||
fb200d5f PC |
94 | ((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func); |
95 | ((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream); | |
96 | ||
8d298bee PM |
97 | instrval = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; |
98 | instr = reinterpret_cast<const Instruction *>(&instrval); | |
99 | vixl_disasm->MapCodeAddress(addr, instr); | |
100 | vixl_decoder->Decode(instr); | |
999b53ec CF |
101 | |
102 | return INSN_SIZE; | |
103 | } |