diff options
-rw-r--r-- | doc/openocd.texi | 6 | ||||
-rw-r--r-- | src/target/Makefile.am | 2 | ||||
-rw-r--r-- | src/target/a64_disassembler.c | 145 | ||||
-rw-r--r-- | src/target/a64_disassembler.h | 30 | ||||
-rw-r--r-- | src/target/aarch64.c | 42 |
5 files changed, 224 insertions, 1 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi index 8c99228..317f188 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 724f38c..19ba771 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 0000000..bd78129 --- /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 <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <helper/log.h> +#include "target.h" +#include "a64_disassembler.h" + +#if HAVE_CAPSTONE + +#include <capstone/capstone.h> + +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 0000000..5c58bbf --- /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 <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#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 4febc8c..dee16d1 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); @@ -2759,6 +2792,13 @@ static const struct command_registration aarch64_exec_command_handlers[] = { .usage = "", }, { + .name = "disassemble", + .handler = aarch64_handle_disassemble_command, + .mode = COMMAND_EXEC, + .help = "Disassemble instructions", + .usage = "address [count]", + }, + { .name = "maskisr", .handler = aarch64_mask_interrupts_command, .mode = COMMAND_ANY, |