| /* |
| * ARM A64 disassembly output wrapper to libvixl |
| * Copyright (c) 2013 Linaro Limited |
| * Written by Claudio Fontana |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| extern "C" { |
| #include "qemu/osdep.h" |
| #include "disas/bfd.h" |
| } |
| |
| #include "vixl/a64/disasm-a64.h" |
| |
| using namespace vixl; |
| |
| static Decoder *vixl_decoder = NULL; |
| static Disassembler *vixl_disasm = NULL; |
| |
| /* We don't use libvixl's PrintDisassembler because its output |
| * is a little unhelpful (trailing newlines, for example). |
| * Instead we use our own very similar variant so we have |
| * control over the format. |
| */ |
| class QEMUDisassembler : public Disassembler { |
| public: |
| QEMUDisassembler() : printf_(NULL), stream_(NULL) { } |
| ~QEMUDisassembler() { } |
| |
| void SetStream(FILE *stream) { |
| stream_ = stream; |
| } |
| |
| void SetPrintf(fprintf_function printf_fn) { |
| printf_ = printf_fn; |
| } |
| |
| protected: |
| virtual void ProcessOutput(const Instruction *instr) { |
| printf_(stream_, "%08" PRIx32 " %s", |
| instr->InstructionBits(), GetOutput()); |
| } |
| |
| private: |
| fprintf_function printf_; |
| FILE *stream_; |
| }; |
| |
| static int vixl_is_initialized(void) |
| { |
| return vixl_decoder != NULL; |
| } |
| |
| static void vixl_init() { |
| vixl_decoder = new Decoder(); |
| vixl_disasm = new QEMUDisassembler(); |
| vixl_decoder->AppendVisitor(vixl_disasm); |
| } |
| |
| #define INSN_SIZE 4 |
| |
| /* Disassemble ARM A64 instruction. This is our only entry |
| * point from QEMU's C code. |
| */ |
| int print_insn_arm_a64(uint64_t addr, disassemble_info *info) |
| { |
| uint8_t bytes[INSN_SIZE]; |
| uint32_t instrval; |
| const Instruction *instr; |
| int status; |
| |
| status = info->read_memory_func(addr, bytes, INSN_SIZE, info); |
| if (status != 0) { |
| info->memory_error_func(status, addr, info); |
| return -1; |
| } |
| |
| if (!vixl_is_initialized()) { |
| vixl_init(); |
| } |
| |
| ((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func); |
| ((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream); |
| |
| instrval = bytes[0] | bytes[1] << 8 | bytes[2] << 16 | bytes[3] << 24; |
| instr = reinterpret_cast<const Instruction *>(&instrval); |
| vixl_disasm->MapCodeAddress(addr, instr); |
| vixl_decoder->Decode(instr); |
| |
| return INSN_SIZE; |
| } |