target/aarch64: a64 disassembler

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
This commit is contained in:
Mete Balci 2019-03-30 12:27:57 +01:00 committed by Antonio Borneo
parent a31e579e87
commit d7d70c2719
5 changed files with 224 additions and 1 deletions

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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 */

View File

@ -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,