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:
parent
a31e579e87
commit
d7d70c2719
|
@ -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.
|
However, normally it is not necessary to use the command at all.
|
||||||
@end deffn
|
@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]
|
@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
|
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
|
are handled by the run control. With SMP handling enabled, issuing halt or resume to one core will trigger
|
||||||
|
|
|
@ -89,6 +89,7 @@ ARMV8_SRC = \
|
||||||
%D%/armv8_dpm.c \
|
%D%/armv8_dpm.c \
|
||||||
%D%/armv8_opcodes.c \
|
%D%/armv8_opcodes.c \
|
||||||
%D%/aarch64.c \
|
%D%/aarch64.c \
|
||||||
|
%D%/a64_disassembler.c \
|
||||||
%D%/armv8.c \
|
%D%/armv8.c \
|
||||||
%D%/armv8_cache.c
|
%D%/armv8_cache.c
|
||||||
|
|
||||||
|
@ -176,6 +177,7 @@ ARC_SRC = \
|
||||||
%D%/armv7a_cache_l2x.h \
|
%D%/armv7a_cache_l2x.h \
|
||||||
%D%/armv7a_mmu.h \
|
%D%/armv7a_mmu.h \
|
||||||
%D%/arm_disassembler.h \
|
%D%/arm_disassembler.h \
|
||||||
|
%D%/a64_disassembler.h \
|
||||||
%D%/arm_opcodes.h \
|
%D%/arm_opcodes.h \
|
||||||
%D%/arm_simulator.h \
|
%D%/arm_simulator.h \
|
||||||
%D%/arm_semihosting.h \
|
%D%/arm_semihosting.h \
|
||||||
|
|
|
@ -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
|
|
@ -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 */
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "breakpoints.h"
|
#include "breakpoints.h"
|
||||||
#include "aarch64.h"
|
#include "aarch64.h"
|
||||||
|
#include "a64_disassembler.h"
|
||||||
#include "register.h"
|
#include "register.h"
|
||||||
#include "target_request.h"
|
#include "target_request.h"
|
||||||
#include "target_type.h"
|
#include "target_type.h"
|
||||||
|
@ -2566,7 +2567,6 @@ COMMAND_HANDLER(aarch64_handle_cache_info_command)
|
||||||
&armv8->armv8_mmu.armv8_cache);
|
&armv8->armv8_mmu.armv8_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
COMMAND_HANDLER(aarch64_handle_dbginit_command)
|
COMMAND_HANDLER(aarch64_handle_dbginit_command)
|
||||||
{
|
{
|
||||||
struct target *target = get_current_target(CMD_CTX);
|
struct target *target = get_current_target(CMD_CTX);
|
||||||
|
@ -2578,6 +2578,39 @@ COMMAND_HANDLER(aarch64_handle_dbginit_command)
|
||||||
return aarch64_init_debug_access(target);
|
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)
|
COMMAND_HANDLER(aarch64_mask_interrupts_command)
|
||||||
{
|
{
|
||||||
struct target *target = get_current_target(CMD_CTX);
|
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",
|
.help = "Initialize core debug",
|
||||||
.usage = "",
|
.usage = "",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "disassemble",
|
||||||
|
.handler = aarch64_handle_disassemble_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.help = "Disassemble instructions",
|
||||||
|
.usage = "address [count]",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "maskisr",
|
.name = "maskisr",
|
||||||
.handler = aarch64_mask_interrupts_command,
|
.handler = aarch64_mask_interrupts_command,
|
||||||
|
|
Loading…
Reference in New Issue