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 | |
20 | extern "C" { |
21 | #include "qemu/osdep.h" |
22 | #include "disas/dis-asm.h" |
23 | } |
24 | |
25 | #include "vixl/a64/disasm-a64.h" |
26 | |
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: |
39 | QEMUDisassembler() : printf_(NULL), stream_(NULL) { } |
40 | ~QEMUDisassembler() { } |
41 | |
42 | void SetStream(FILE *stream) { |
43 | stream_ = stream; |
44 | } |
45 | |
46 | void SetPrintf(fprintf_function printf_fn) { |
47 | printf_ = printf_fn; |
48 | } |
49 | |
50 | protected: |
51 | virtual void ProcessOutput(const Instruction *instr) { |
52 | printf_(stream_, "%08" PRIx32 " %s" , |
53 | instr->InstructionBits(), GetOutput()); |
54 | } |
55 | |
56 | private: |
57 | fprintf_function printf_; |
58 | FILE *stream_; |
59 | }; |
60 | |
61 | static int vixl_is_initialized(void) |
62 | { |
63 | return vixl_decoder != NULL; |
64 | } |
65 | |
66 | static void vixl_init() { |
67 | vixl_decoder = new Decoder(); |
68 | vixl_disasm = new QEMUDisassembler(); |
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]; |
80 | uint32_t instrval; |
81 | const Instruction *instr; |
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()) { |
91 | vixl_init(); |
92 | } |
93 | |
94 | ((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func); |
95 | ((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream); |
96 | |
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); |
101 | |
102 | return INSN_SIZE; |
103 | } |
104 | |