Add A64 (AArch64) Disassembler using Capstone framework.
Change-Id: Ia92b57001843b11a818af940a468b131e42a03fd
Signed-off-by: Mete Balci <metebalci@gmail.com>
[Antonio Borneo: Rebased on current HEAD]
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5004
Tested-by: jenkins
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
%D%/armv8_dpm.c \
%D%/armv8_opcodes.c \
%D%/aarch64.c \
+ %D%/a64_disassembler.c \
%D%/armv8.c \
%D%/armv8_cache.c
%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 \
--- /dev/null
+/***************************************************************************
+ * 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
--- /dev/null
+/***************************************************************************
+ * 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 */
#include "breakpoints.h"
#include "aarch64.h"
+#include "a64_disassembler.h"
#include "register.h"
#include "target_request.h"
#include "target_type.h"
&armv8->armv8_mmu.armv8_cache);
}
-
COMMAND_HANDLER(aarch64_handle_dbginit_command)
{
struct target *target = get_current_target(CMD_CTX);
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);
.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,