From d7d70c2719e6fe94dc9ca15aeb81cf142d597cdc Mon Sep 17 00:00:00 2001 From: Mete Balci Date: Sat, 30 Mar 2019 12:27:57 +0100 Subject: [PATCH] target/aarch64: a64 disassembler Add A64 (AArch64) Disassembler using Capstone framework. Change-Id: Ia92b57001843b11a818af940a468b131e42a03fd Signed-off-by: Mete Balci [Antonio Borneo: Rebased on current HEAD] Signed-off-by: Antonio Borneo Reviewed-on: http://openocd.zylin.com/5004 Tested-by: jenkins --- doc/openocd.texi | 6 ++ src/target/Makefile.am | 2 + src/target/a64_disassembler.c | 145 ++++++++++++++++++++++++++++++++++ src/target/a64_disassembler.h | 30 +++++++ src/target/aarch64.c | 42 +++++++++- 5 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 src/target/a64_disassembler.c create mode 100644 src/target/a64_disassembler.h diff --git a/doc/openocd.texi b/doc/openocd.texi index 8c99228c3..317f188d2 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9349,6 +9349,12 @@ target code relies on. In a configuration file, the command would typically be c However, normally it is not necessary to use the command at all. @end deffn +@deffn Command {aarch64 disassemble} address [count] +@cindex disassemble +Disassembles @var{count} instructions starting at @var{address}. +If @var{count} is not specified, a single instruction is disassembled. +@end deffn + @deffn Command {aarch64 smp} [on|off] Display, enable or disable SMP handling mode. The state of SMP handling influences the way targets in an SMP group are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 724f38c24..19ba7714e 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -89,6 +89,7 @@ ARMV8_SRC = \ %D%/armv8_dpm.c \ %D%/armv8_opcodes.c \ %D%/aarch64.c \ + %D%/a64_disassembler.c \ %D%/armv8.c \ %D%/armv8_cache.c @@ -176,6 +177,7 @@ ARC_SRC = \ %D%/armv7a_cache_l2x.h \ %D%/armv7a_mmu.h \ %D%/arm_disassembler.h \ + %D%/a64_disassembler.h \ %D%/arm_opcodes.h \ %D%/arm_simulator.h \ %D%/arm_semihosting.h \ diff --git a/src/target/a64_disassembler.c b/src/target/a64_disassembler.c new file mode 100644 index 000000000..bd78129dd --- /dev/null +++ b/src/target/a64_disassembler.c @@ -0,0 +1,145 @@ +/*************************************************************************** + * Copyright (C) 2019 by Mete Balci * + * metebalci@gmail.com * + * * + * 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 . * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "target.h" +#include "a64_disassembler.h" + +#if HAVE_CAPSTONE + +#include + +static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) +{ + uint32_t opcode = 0; + + memcpy(&opcode, insn->bytes, insn->size); + + if (insn->size == 4) { + + uint16_t opcode_high = opcode >> 16; + + opcode = opcode & 0xffff; + + command_print(cmd, + "0x%08" PRIx64" %04x %04x\t%s\t%s", + insn->address, + opcode, + opcode_high, + insn->mnemonic, + insn->op_str); + + } else { + + command_print( + cmd, + "0x%08" PRIx64" %04x\t%s\t%s", + insn->address, + opcode, + insn->mnemonic, + insn->op_str); + + } +} + +int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count) +{ + int ret; + int csret; + csh handle; + + csret = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle); + + if (csret != CS_ERR_OK) { + + LOG_ERROR("cs_open() failed: %s", cs_strerror(csret)); + return ERROR_FAIL; + + } + + csret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); + + if (csret != CS_ERR_OK) { + + LOG_ERROR("cs_option() failed: %s", cs_strerror(csret)); + cs_close(&handle); + return ERROR_FAIL; + + } + + cs_insn *insn = cs_malloc(handle); + + if (csret != CS_ERR_OK) { + + LOG_ERROR("cs_malloc() failed: %s", cs_strerror(csret)); + cs_close(&handle); + return ERROR_FAIL; + + } + + while (count > 0) { + + uint8_t buffer[4]; + + ret = target_read_buffer(target, address, sizeof(buffer), buffer); + + if (ret != ERROR_OK) { + cs_free(insn, 1); + cs_close(&handle); + return ret; + } + + size_t size = sizeof(buffer); + const uint8_t *tmp = buffer; + + ret = cs_disasm_iter(handle, &tmp, &size, &address, insn); + + if (!ret) { + + LOG_ERROR("cs_disasm_iter() failed: %s", cs_strerror(cs_errno(handle))); + cs_free(insn, 1); + cs_close(&handle); + return ERROR_FAIL; + + } + + print_opcode(cmd, insn); + count--; + + } + + cs_free(insn, 1); + cs_close(&handle); + + return ERROR_OK; +} + +#else + +int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count) +{ + command_print(cmd, "capstone disassembly framework required"); + + return ERROR_FAIL; +} + +#endif diff --git a/src/target/a64_disassembler.h b/src/target/a64_disassembler.h new file mode 100644 index 000000000..5c58bbfe5 --- /dev/null +++ b/src/target/a64_disassembler.h @@ -0,0 +1,30 @@ +/*************************************************************************** + * Copyright (C) 2019 by Mete Balci * + * metebalci@gmail.com * + * * + * 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 . * + ***************************************************************************/ + +#ifndef OPENOCD_TARGET_AARCH64_DISASSEMBLER_H +#define OPENOCD_TARGET_AARCH64_DISASSEMBLER_H + +#include "target.h" + +int a64_disassemble( + struct command_invocation *cmd, + struct target *target, + target_addr_t address, + size_t count); + +#endif /* OPENOCD_TARGET_AARCH64_DISASSEMBLER_H */ diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 4febc8c96..dee16d116 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -23,6 +23,7 @@ #include "breakpoints.h" #include "aarch64.h" +#include "a64_disassembler.h" #include "register.h" #include "target_request.h" #include "target_type.h" @@ -2566,7 +2567,6 @@ COMMAND_HANDLER(aarch64_handle_cache_info_command) &armv8->armv8_mmu.armv8_cache); } - COMMAND_HANDLER(aarch64_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); @@ -2578,6 +2578,39 @@ COMMAND_HANDLER(aarch64_handle_dbginit_command) return aarch64_init_debug_access(target); } +COMMAND_HANDLER(aarch64_handle_disassemble_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (target == NULL) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (aarch64->common_magic != AARCH64_COMMON_MAGIC) { + command_print(CMD, "current target isn't an AArch64"); + return ERROR_FAIL; + } + + int count = 1; + target_addr_t address; + + switch (CMD_ARGC) { + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); + /* FALL THROUGH */ + case 1: + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return a64_disassemble(CMD, target, address, count); +} + COMMAND_HANDLER(aarch64_mask_interrupts_command) { struct target *target = get_current_target(CMD_CTX); @@ -2758,6 +2791,13 @@ static const struct command_registration aarch64_exec_command_handlers[] = { .help = "Initialize core debug", .usage = "", }, + { + .name = "disassemble", + .handler = aarch64_handle_disassemble_command, + .mode = COMMAND_EXEC, + .help = "Disassemble instructions", + .usage = "address [count]", + }, { .name = "maskisr", .handler = aarch64_mask_interrupts_command,