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#include "qemu/osdep.h" 21#include "disas/dis-asm.h" 22 23#include "vixl/a64/disasm-a64.h" 24 25using namespace vixl; 26 27static Decoder *vixl_decoder = NULL; 28static 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 */ 35class QEMUDisassembler : public Disassembler { 36public: 37 QEMUDisassembler() : printf_(NULL), stream_(NULL) { } 38 ~QEMUDisassembler() { } 39 40 void SetStream(FILE *stream) { 41 stream_ = stream; 42 } 43 44 void SetPrintf(fprintf_function printf_fn) { 45 printf_ = printf_fn; 46 } 47 48protected: 49 virtual void ProcessOutput(const Instruction *instr) { 50 printf_(stream_, "%08" PRIx32 " %s", 51 instr->InstructionBits(), GetOutput()); 52 } 53 54private: 55 fprintf_function printf_; 56 FILE *stream_; 57}; 58 59static int vixl_is_initialized(void) 60{ 61 return vixl_decoder != NULL; 62} 63 64static void vixl_init() { 65 vixl_decoder = new Decoder(); 66 vixl_disasm = new QEMUDisassembler(); 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 */ 75int print_insn_arm_a64(uint64_t addr, disassemble_info *info) 76{ 77 uint8_t bytes[INSN_SIZE]; 78 uint32_t instrval; 79 const Instruction *instr; 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()) { 89 vixl_init(); 90 } 91 92 ((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func); 93 ((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream); 94 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); 99 100 return INSN_SIZE; 101} 102