2014-02-05 21:27:28 +04:00
|
|
|
/*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "a64/disasm-a64.h"
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
#include "disas/bfd.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:
|
2015-06-24 06:57:34 +03:00
|
|
|
QEMUDisassembler() : printf_(NULL), stream_(NULL) { }
|
2014-02-05 21:27:28 +04:00
|
|
|
~QEMUDisassembler() { }
|
|
|
|
|
2015-06-24 06:57:34 +03:00
|
|
|
void SetStream(FILE *stream) {
|
|
|
|
stream_ = stream;
|
|
|
|
}
|
|
|
|
|
2015-07-21 13:18:45 +03:00
|
|
|
void SetPrintf(fprintf_function printf_fn) {
|
2015-06-24 06:57:34 +03:00
|
|
|
printf_ = printf_fn;
|
|
|
|
}
|
|
|
|
|
2014-02-05 21:27:28 +04:00
|
|
|
protected:
|
2014-10-24 15:19:11 +04:00
|
|
|
virtual void ProcessOutput(const Instruction *instr) {
|
2015-06-24 06:57:34 +03:00
|
|
|
printf_(stream_, "%08" PRIx32 " %s",
|
2014-02-05 21:27:28 +04:00
|
|
|
instr->InstructionBits(), GetOutput());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-07-21 13:18:45 +03:00
|
|
|
fprintf_function printf_;
|
2014-02-05 21:27:28 +04:00
|
|
|
FILE *stream_;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int vixl_is_initialized(void)
|
|
|
|
{
|
|
|
|
return vixl_decoder != NULL;
|
|
|
|
}
|
|
|
|
|
2015-06-24 06:57:34 +03:00
|
|
|
static void vixl_init() {
|
2014-02-05 21:27:28 +04:00
|
|
|
vixl_decoder = new Decoder();
|
2015-06-24 06:57:34 +03:00
|
|
|
vixl_disasm = new QEMUDisassembler();
|
2014-02-05 21:27:28 +04:00
|
|
|
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];
|
disas/arm-a64.cc: Tell libvixl correct code addresses
disassembling relative branches in code which doesn't reside at
what the guest CPU would think its execution address is. Use
the new MapCodeAddress() API to tell libvixl where the code is
from the guest CPU's point of view so it can get the target
addresses right.
Previous disassembly:
0x0000000040000000: 580000c0 ldr x0, pc+24 (addr 0x7f6cb7020434)
0x0000000040000004: aa1f03e1 mov x1, xzr
0x0000000040000008: aa1f03e2 mov x2, xzr
0x000000004000000c: aa1f03e3 mov x3, xzr
0x0000000040000010: 58000084 ldr x4, pc+16 (addr 0x7f6cb702042c)
0x0000000040000014: d61f0080 br x4
Fixed disassembly:
0x0000000040000000: 580000c0 ldr x0, pc+24 (addr 0x40000018)
0x0000000040000004: aa1f03e1 mov x1, xzr
0x0000000040000008: aa1f03e2 mov x2, xzr
0x000000004000000c: aa1f03e3 mov x3, xzr
0x0000000040000010: 58000084 ldr x4, pc+16 (addr 0x40000020)
0x0000000040000014: d61f0080 br x4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1422274779-13359-3-git-send-email-peter.maydell@linaro.org
2015-02-05 16:37:25 +03:00
|
|
|
uint32_t instrval;
|
|
|
|
const Instruction *instr;
|
2014-02-05 21:27:28 +04:00
|
|
|
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()) {
|
2015-06-24 06:57:34 +03:00
|
|
|
vixl_init();
|
2014-02-05 21:27:28 +04:00
|
|
|
}
|
|
|
|
|
2015-06-24 06:57:34 +03:00
|
|
|
((QEMUDisassembler *)vixl_disasm)->SetPrintf(info->fprintf_func);
|
|
|
|
((QEMUDisassembler *)vixl_disasm)->SetStream(info->stream);
|
|
|
|
|
disas/arm-a64.cc: Tell libvixl correct code addresses
disassembling relative branches in code which doesn't reside at
what the guest CPU would think its execution address is. Use
the new MapCodeAddress() API to tell libvixl where the code is
from the guest CPU's point of view so it can get the target
addresses right.
Previous disassembly:
0x0000000040000000: 580000c0 ldr x0, pc+24 (addr 0x7f6cb7020434)
0x0000000040000004: aa1f03e1 mov x1, xzr
0x0000000040000008: aa1f03e2 mov x2, xzr
0x000000004000000c: aa1f03e3 mov x3, xzr
0x0000000040000010: 58000084 ldr x4, pc+16 (addr 0x7f6cb702042c)
0x0000000040000014: d61f0080 br x4
Fixed disassembly:
0x0000000040000000: 580000c0 ldr x0, pc+24 (addr 0x40000018)
0x0000000040000004: aa1f03e1 mov x1, xzr
0x0000000040000008: aa1f03e2 mov x2, xzr
0x000000004000000c: aa1f03e3 mov x3, xzr
0x0000000040000010: 58000084 ldr x4, pc+16 (addr 0x40000020)
0x0000000040000014: d61f0080 br x4
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Message-id: 1422274779-13359-3-git-send-email-peter.maydell@linaro.org
2015-02-05 16:37:25 +03:00
|
|
|
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);
|
2014-02-05 21:27:28 +04:00
|
|
|
|
|
|
|
return INSN_SIZE;
|
|
|
|
}
|