target/aarch64: a64 disassembler
[fw/openocd] / src / target / a64_disassembler.c
1 /***************************************************************************
2  *   Copyright (C) 2019 by Mete Balci                                      *
3  *   metebalci@gmail.com                                                   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
17  ***************************************************************************/
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include <helper/log.h>
24 #include "target.h"
25 #include "a64_disassembler.h"
26
27 #if HAVE_CAPSTONE
28
29 #include <capstone/capstone.h>
30
31 static void print_opcode(struct command_invocation *cmd, const cs_insn *insn)
32 {
33         uint32_t opcode = 0;
34
35         memcpy(&opcode, insn->bytes, insn->size);
36
37         if (insn->size == 4) {
38
39                 uint16_t opcode_high = opcode >> 16;
40
41                 opcode = opcode & 0xffff;
42
43                 command_print(cmd,
44                                 "0x%08" PRIx64"  %04x %04x\t%s\t%s",
45                                 insn->address,
46                                 opcode,
47                                 opcode_high,
48                                 insn->mnemonic,
49                                 insn->op_str);
50
51         } else {
52
53                 command_print(
54                                 cmd,
55                                 "0x%08" PRIx64"  %04x\t%s\t%s",
56                                 insn->address,
57                                 opcode,
58                                 insn->mnemonic,
59                                 insn->op_str);
60
61         }
62 }
63
64 int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count)
65 {
66         int ret;
67         int csret;
68         csh handle;
69
70         csret = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle);
71
72         if (csret != CS_ERR_OK) {
73
74                 LOG_ERROR("cs_open() failed: %s", cs_strerror(csret));
75                 return ERROR_FAIL;
76
77         }
78
79         csret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
80
81         if (csret != CS_ERR_OK) {
82
83                 LOG_ERROR("cs_option() failed: %s", cs_strerror(csret));
84                 cs_close(&handle);
85                 return ERROR_FAIL;
86
87         }
88
89         cs_insn *insn = cs_malloc(handle);
90
91         if (csret != CS_ERR_OK) {
92
93                 LOG_ERROR("cs_malloc() failed: %s", cs_strerror(csret));
94                 cs_close(&handle);
95                 return ERROR_FAIL;
96
97         }
98
99         while (count > 0) {
100
101                 uint8_t buffer[4];
102
103                 ret = target_read_buffer(target, address, sizeof(buffer), buffer);
104
105                 if (ret != ERROR_OK) {
106                         cs_free(insn, 1);
107                         cs_close(&handle);
108                         return ret;
109                 }
110
111                 size_t size = sizeof(buffer);
112                 const uint8_t *tmp = buffer;
113
114                 ret = cs_disasm_iter(handle, &tmp, &size, &address, insn);
115
116                 if (!ret) {
117
118                         LOG_ERROR("cs_disasm_iter() failed: %s", cs_strerror(cs_errno(handle)));
119                         cs_free(insn, 1);
120                         cs_close(&handle);
121                         return ERROR_FAIL;
122
123                 }
124
125                 print_opcode(cmd, insn);
126                 count--;
127
128         }
129
130         cs_free(insn, 1);
131         cs_close(&handle);
132
133         return ERROR_OK;
134 }
135
136 #else
137
138 int a64_disassemble(struct command_invocation *cmd, struct target *target, target_addr_t address, size_t count)
139 {
140         command_print(cmd, "capstone disassembly framework required");
141
142         return ERROR_FAIL;
143 }
144
145 #endif