Rizin
unix-like reverse engineering framework and cli tools
asm_arm_cs.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2013-2018 pancake <pancake@nopcode.org>
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 #include <rz_asm.h>
5 #include <rz_lib.h>
6 #include <ht_uu.h>
7 #include <capstone/capstone.h>
8 #include "../arch/arm/asm-arm.h"
9 #include "../arch/arm/arm_it.h"
10 #include "./asm_arm_hacks.inc"
11 
12 typedef struct arm_cs_context_t {
15  int omode;
16  int obits;
18 
19 bool arm64ass(const char *str, ut64 addr, ut32 *op);
20 
21 static bool check_features(RzAsm *a, cs_insn *insn) {
22  ArmCSContext *ctx = (ArmCSContext *)a->plugin_data;
23  int i;
24  if (!insn || !insn->detail) {
25  return true;
26  }
27  for (i = 0; i < insn->detail->groups_count; i++) {
28  int id = insn->detail->groups[i];
29  switch (id) {
30  case ARM_GRP_ARM:
31  case ARM_GRP_THUMB:
32  case ARM_GRP_THUMB1ONLY:
33  case ARM_GRP_THUMB2:
34  continue;
35  default:
36  if (id < 128) {
37  continue;
38  }
39  }
40  const char *name = cs_group_name(ctx->cd, id);
41  if (!name) {
42  return true;
43  }
44  if (!strstr(a->features, name)) {
45  return false;
46  }
47  }
48  return true;
49 }
50 
51 static const char *cc_name(arm_cc cc) {
52  switch (cc) {
53  case ARM_CC_EQ: // Equal Equal
54  return "eq";
55  case ARM_CC_NE: // Not equal Not equal, or unordered
56  return "ne";
57  case ARM_CC_HS: // Carry set >, ==, or unordered
58  return "hs";
59  case ARM_CC_LO: // Carry clear Less than
60  return "lo";
61  case ARM_CC_MI: // Minus, negative Less than
62  return "mi";
63  case ARM_CC_PL: // Plus, positive or zero >, ==, or unordered
64  return "pl";
65  case ARM_CC_VS: // Overflow Unordered
66  return "vs";
67  case ARM_CC_VC: // No overflow Not unordered
68  return "vc";
69  case ARM_CC_HI: // Unsigned higher Greater than, or unordered
70  return "hi";
71  case ARM_CC_LS: // Unsigned lower or same Less than or equal
72  return "ls";
73  case ARM_CC_GE: // Greater than or equal Greater than or equal
74  return "ge";
75  case ARM_CC_LT: // Less than Less than, or unordered
76  return "lt";
77  case ARM_CC_GT: // Greater than Greater than
78  return "gt";
79  case ARM_CC_LE: // Less than or equal <, ==, or unordered
80  return "le";
81  default:
82  return "";
83  }
84 }
85 
86 static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) {
87  ArmCSContext *ctx = (ArmCSContext *)a->plugin_data;
88 
89  bool disp_hash = a->immdisp;
90  cs_insn *insn = NULL;
91  cs_mode mode = 0;
92  int ret, n = 0;
93 
94  bool thumb = a->bits == 16;
95  mode |= thumb ? CS_MODE_THUMB : CS_MODE_ARM;
96  mode |= (a->big_endian) ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN;
97  if (mode != ctx->omode || a->bits != ctx->obits) {
98  cs_close(&ctx->cd);
99  ctx->cd = 0; // unnecessary
100  ctx->omode = mode;
101  ctx->obits = a->bits;
102  }
103 
104  if (a->cpu) {
105  if (strstr(a->cpu, "cortex")) {
106  mode |= CS_MODE_MCLASS;
107  }
108  if (a->bits != 64) {
109  if (strstr(a->cpu, "v8")) {
110  mode |= CS_MODE_V8;
111  }
112  }
113  }
114  if (a->features && a->bits != 64) {
115  if (strstr(a->features, "v8")) {
116  mode |= CS_MODE_V8;
117  }
118  }
119  if (op) {
120  op->size = 4;
121  rz_strbuf_set(&op->buf_asm, "");
122  }
123  if (!ctx->cd || mode != ctx->omode) {
124  ret = (a->bits == 64) ? cs_open(CS_ARCH_ARM64, mode, &ctx->cd) : cs_open(CS_ARCH_ARM, mode, &ctx->cd);
125  if (ret) {
126  ret = -1;
127  goto beach;
128  }
129  }
131  cs_option(ctx->cd, CS_OPT_DETAIL, (a->features && *a->features) ? CS_OPT_ON : CS_OPT_OFF);
133  if (!buf) {
134  goto beach;
135  }
136  int haa = hackyArmAsm(a, op, buf, len);
137  if (haa > 0) {
138  return haa;
139  }
140 
141  n = cs_disasm(ctx->cd, buf, RZ_MIN(4, len), a->pc, 1, &insn);
142  if (n < 1 || insn->size < 1) {
143  ret = -1;
144  goto beach;
145  }
146  if (op) {
147  op->size = 0;
148  }
149  if (a->features && *a->features) {
150  if (!check_features(a, insn) && op) {
151  op->size = insn->size;
152  rz_strbuf_set(&op->buf_asm, "illegal");
153  }
154  }
155  if (op && !op->size) {
156  op->size = insn->size;
157  if (insn->id == ARM_INS_IT) {
158  rz_arm_it_update_block(&ctx->it, insn);
159  } else {
160  rz_arm_it_update_nonblock(&ctx->it, insn);
161  }
162  if (thumb && rz_arm_it_apply_cond(&ctx->it, insn)) {
163  char *tmpstr = rz_str_newf("%s%s",
164  cs_insn_name(ctx->cd, insn->id),
165  cc_name(insn->detail->arm.cc));
166  rz_str_cpy(insn->mnemonic, tmpstr);
167  free(tmpstr);
168  }
169  char *buf_asm = sdb_fmt("%s%s%s",
170  insn->mnemonic,
171  insn->op_str[0] ? " " : "",
172  insn->op_str);
173  if (!disp_hash) {
174  rz_str_replace_char(buf_asm, '#', 0);
175  }
176  rz_strbuf_set(&op->buf_asm, buf_asm);
177  }
178  cs_free(insn, n);
179 beach:
180  cs_close(&ctx->cd);
181  if (op) {
182  if (!*rz_strbuf_get(&op->buf_asm)) {
183  rz_strbuf_set(&op->buf_asm, "invalid");
184  }
185  return op->size;
186  }
187  return ret;
188 }
189 
190 static int assemble(RzAsm *a, RzAsmOp *op, const char *buf) {
191  const bool is_thumb = (a->bits == 16);
192  int opsize;
193  ut32 opcode;
194  if (a->bits == 64) {
195  if (!arm64ass(buf, a->pc, &opcode)) {
196  return -1;
197  }
198  } else {
199  opcode = armass_assemble(buf, a->pc, is_thumb);
200  if (a->bits != 32 && a->bits != 16) {
201  RZ_LOG_ERROR("assembler: arm: cannot assemble instruction due invalid 'asm.bits' value (accepted only 16 or 32 bits).\n");
202  return -1;
203  }
204  }
205  if (opcode == UT32_MAX) {
206  return -1;
207  }
208  ut8 opbuf[4];
209  if (is_thumb) {
210  const int o = opcode >> 16;
211  opsize = o > 0 ? 4 : 2;
212  if (opsize == 4) {
213  if (a->big_endian) {
214  rz_write_le16(opbuf, opcode >> 16);
215  rz_write_le16(opbuf + 2, opcode & UT16_MAX);
216  } else {
217  rz_write_be32(opbuf, opcode);
218  }
219  } else if (opsize == 2) {
220  if (a->big_endian) {
221  rz_write_le16(opbuf, opcode & UT16_MAX);
222  } else {
223  rz_write_be16(opbuf, opcode & UT16_MAX);
224  }
225  }
226  } else {
227  opsize = 4;
228  if (a->big_endian) {
229  rz_write_le32(opbuf, opcode);
230  } else {
231  rz_write_be32(opbuf, opcode);
232  }
233  }
234  rz_strbuf_setbin(&op->buf, opbuf, opsize);
235  // XXX. thumb endian assembler needs no swap
236  return opsize;
237 }
238 
239 static bool arm_init(void **user) {
241  if (!ctx) {
242  return false;
243  }
245  ctx->cd = 0;
246  ctx->omode = -1;
247  ctx->obits = 32;
248  *user = ctx;
249  return true;
250 }
251 
252 static bool arm_fini(void *user) {
253  rz_return_val_if_fail(user, false);
254  ArmCSContext *ctx = (ArmCSContext *)user;
255  cs_close(&ctx->cd);
257  free(ctx);
258  return true;
259 }
260 
261 static char *mnemonics(RzAsm *a, int id, bool json) {
262  ArmCSContext *ctx = (ArmCSContext *)a->plugin_data;
263  int i;
264  a->cur->disassemble(a, NULL, NULL, -1);
265  if (id != -1) {
266  const char *name = cs_insn_name(ctx->cd, id);
267  if (json) {
268  return name ? rz_str_newf("[\"%s\"]\n", name) : NULL;
269  }
270  return name ? strdup(name) : NULL;
271  }
272  RzStrBuf *buf = rz_strbuf_new("");
273  if (json) {
274  rz_strbuf_append(buf, "[");
275  }
276  for (i = 1;; i++) {
277  const char *op = cs_insn_name(ctx->cd, i);
278  if (!op) {
279  break;
280  }
281  if (json) {
282  rz_strbuf_append(buf, "\"");
283  }
285  if (json) {
286  if (cs_insn_name(ctx->cd, i + 1)) {
287  rz_strbuf_append(buf, "\",");
288  } else {
289  rz_strbuf_append(buf, "\"]\n");
290  }
291  } else {
292  rz_strbuf_append(buf, "\n");
293  }
294  }
295  return rz_strbuf_drain(buf);
296 }
297 
299  .name = "arm",
300  .desc = "Capstone ARM disassembler",
301  .cpus = "v8,cortex,arm1176,cortexA72,cortexA8",
302  .platforms = "bcm2835,omap3430",
303  .features = "v8",
304  .license = "BSD",
305  .arch = "arm",
306  .bits = 16 | 32 | 64,
308  .disassemble = &disassemble,
309  .mnemonics = mnemonics,
310  .assemble = &assemble,
311  .init = &arm_init,
312  .fini = &arm_fini,
313 #if 0
314  // arm32 and arm64
315  "crypto,databarrier,divide,fparmv8,multpro,neon,t2extractpack,"
316  "thumb2dsp,trustzone,v4t,v5t,v5te,v6,v6t2,v7,v8,vfp2,vfp3,vfp4,"
317  "arm,mclass,notmclass,thumb,thumb1only,thumb2,prev8,fpvmlx,"
318  "mulops,crc,dpvfp,v6m"
319 #endif
320 };
321 
322 #ifndef RZ_PLUGIN_INCORE
325  .data = &rz_asm_plugin_arm_cs,
327 };
328 #endif
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
RZ_API void rz_arm_it_context_fini(RzArmITContext *ctx)
Definition: arm_it.c:25
RZ_API void rz_arm_it_context_init(RzArmITContext *ctx)
Definition: arm_it.c:20
RZ_API void rz_arm_it_update_nonblock(RzArmITContext *ctx, cs_insn *insn)
Definition: arm_it.c:70
RZ_API bool rz_arm_it_apply_cond(RzArmITContext *ctx, cs_insn *insn)
Definition: arm_it.c:87
RZ_API void rz_arm_it_update_block(RzArmITContext *ctx, cs_insn *insn)
Definition: arm_it.c:34
ut32 armass_assemble(const char *str, ut64 off, int thumb)
Definition: armass.c:6209
static bool arm_init(void **user)
Definition: asm_arm_cs.c:239
static const char * cc_name(arm_cc cc)
Definition: asm_arm_cs.c:51
static bool check_features(RzAsm *a, cs_insn *insn)
Definition: asm_arm_cs.c:21
bool arm64ass(const char *str, ut64 addr, ut32 *op)
Definition: armass64.c:1348
struct arm_cs_context_t ArmCSContext
RZ_API RzLibStruct rizin_plugin
Definition: asm_arm_cs.c:323
RzAsmPlugin rz_asm_plugin_arm_cs
Definition: asm_arm_cs.c:298
static char * mnemonics(RzAsm *a, int id, bool json)
Definition: asm_arm_cs.c:261
static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len)
Definition: asm_arm_cs.c:86
static bool arm_fini(void *user)
Definition: asm_arm_cs.c:252
static int assemble(RzAsm *a, RzAsmOp *op, const char *buf)
Definition: asm_arm_cs.c:190
@ ARM_INS_IT
Definition: arm.h:857
@ ARM_GRP_THUMB2
Definition: arm.h:921
@ ARM_GRP_ARM
Definition: arm.h:916
@ ARM_GRP_THUMB
Definition: arm.h:919
@ ARM_GRP_THUMB1ONLY
Definition: arm.h:920
arm_cc
ARM condition code.
Definition: arm.h:33
@ ARM_CC_GT
Greater than Greater than.
Definition: arm.h:47
@ ARM_CC_LE
Less than or equal <, ==, or unordered.
Definition: arm.h:48
@ ARM_CC_HI
Unsigned higher Greater than, or unordered.
Definition: arm.h:43
@ ARM_CC_VC
No overflow Not unordered.
Definition: arm.h:42
@ ARM_CC_LS
Unsigned lower or same Less than or equal.
Definition: arm.h:44
@ ARM_CC_GE
Greater than or equal Greater than or equal.
Definition: arm.h:45
@ ARM_CC_VS
Overflow Unordered.
Definition: arm.h:41
@ ARM_CC_PL
Plus, positive or zero >, ==, or unordered.
Definition: arm.h:40
@ ARM_CC_NE
Not equal Not equal, or unordered.
Definition: arm.h:36
@ ARM_CC_LO
Carry clear Less than.
Definition: arm.h:38
@ ARM_CC_EQ
Equal Equal.
Definition: arm.h:35
@ ARM_CC_LT
Less than Less than, or unordered.
Definition: arm.h:46
@ ARM_CC_HS
Carry set >, ==, or unordered.
Definition: arm.h:37
@ ARM_CC_MI
Minus, negative Less than.
Definition: arm.h:39
@ CS_ARCH_ARM64
ARM-64, also called AArch64.
Definition: capstone.h:76
@ CS_ARCH_ARM
ARM architecture (including Thumb, Thumb-2)
Definition: capstone.h:75
cs_mode
Mode type.
Definition: capstone.h:102
@ CS_MODE_MCLASS
ARM's Cortex-M series.
Definition: capstone.h:109
@ CS_MODE_ARM
32-bit ARM
Definition: capstone.h:104
@ CS_MODE_V8
ARMv8 A32 encodings for ARM.
Definition: capstone.h:110
@ CS_MODE_BIG_ENDIAN
big-endian mode
Definition: capstone.h:123
@ CS_MODE_THUMB
ARM's Thumb mode, including Thumb-2.
Definition: capstone.h:108
@ CS_MODE_LITTLE_ENDIAN
little-endian mode (default mode)
Definition: capstone.h:103
@ CS_OPT_DETAIL
Break down instruction structure into details.
Definition: capstone.h:171
@ CS_OPT_SYNTAX
Assembly output syntax.
Definition: capstone.h:170
size_t csh
Definition: capstone.h:71
@ CS_OPT_SYNTAX_NOREGNAME
Prints register name with only number (CS_OPT_SYNTAX)
Definition: capstone.h:187
@ CS_OPT_ON
Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
Definition: capstone.h:183
@ CS_OPT_OFF
Turn OFF an option - default for CS_OPT_DETAIL, CS_OPT_SKIPDATA, CS_OPT_UNSIGNED.
Definition: capstone.h:182
@ CS_OPT_SYNTAX_DEFAULT
Default asm syntax (CS_OPT_SYNTAX).
Definition: capstone.h:184
#define RZ_API
#define NULL
Definition: cris-opc.c:27
CAPSTONE_EXPORT size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
Definition: cs.c:798
CAPSTONE_EXPORT const char *CAPSTONE_API cs_group_name(csh ud, unsigned int group)
Definition: cs.c:1178
CAPSTONE_EXPORT cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle)
Definition: cs.c:453
CAPSTONE_EXPORT const char *CAPSTONE_API cs_insn_name(csh ud, unsigned int insn)
Definition: cs.c:1166
CAPSTONE_EXPORT void CAPSTONE_API cs_free(cs_insn *insn, size_t count)
Definition: cs.c:1017
CAPSTONE_EXPORT cs_err CAPSTONE_API cs_close(csh *handle)
Definition: cs.c:501
CAPSTONE_EXPORT cs_err CAPSTONE_API cs_option(csh ud, cs_opt_type type, size_t value)
Definition: cs.c:646
uint32_t ut32
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
voidpf void * buf
Definition: ioapi.h:138
uint8_t ut8
Definition: lh5801.h:11
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
static bool is_thumb(RzBinFile *bf)
int n
Definition: mipsasm.c:19
@ RZ_ASM_SYNTAX_REGNUM
Definition: rz_asm.h:53
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
static void rz_write_le32(void *dest, ut32 val)
Definition: rz_endian.h:256
static void rz_write_le16(void *dest, ut16 val)
Definition: rz_endian.h:222
static void rz_write_be16(void *dest, ut16 val)
Definition: rz_endian.h:60
static void rz_write_be32(void *dest, ut32 val)
Definition: rz_endian.h:98
@ RZ_LIB_TYPE_ASM
Definition: rz_lib.h:72
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
#define rz_str_cpy(x, y)
Definition: rz_str.h:109
RZ_API int rz_str_replace_char(char *s, int a, int b)
Definition: str.c:169
RZ_API RZ_OWN char * rz_strbuf_drain(RzStrBuf *sb)
Definition: strbuf.c:342
RZ_API const char * rz_strbuf_set(RzStrBuf *sb, const char *s)
Definition: strbuf.c:153
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
RZ_API bool rz_strbuf_append(RzStrBuf *sb, const char *s)
Definition: strbuf.c:222
RZ_API RzStrBuf * rz_strbuf_new(const char *s)
Definition: strbuf.c:8
RZ_API bool rz_strbuf_setbin(RzStrBuf *sb, const ut8 *s, size_t len)
Definition: strbuf.c:85
#define RZ_SYS_ENDIAN_BIG
Definition: rz_types.h:527
#define RZ_SYS_ENDIAN_LITTLE
Definition: rz_types.h:526
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_MIN(x, y)
#define UT32_MAX
Definition: rz_types_base.h:99
#define UT16_MAX
#define RZ_VERSION
Definition: rz_version.h:8
#define a(i)
Definition: sha256.c:41
RzArmITContext it
Definition: z80asm.h:102
const char * name
Definition: rz_asm.h:130
const char * version
Definition: rz_asm.h:133
Definition: dis.c:32
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static int addr
Definition: z80asm.c:58