Rizin
unix-like reverse engineering framework and cli tools
test_arm_regression.c
Go to the documentation of this file.
1 /* Capstone Disassembler Engine */
2 /* By David Hogarty, 2014 */
3 
4 // the following must precede stdio (woo, thanks msft)
5 #if defined(_MSC_VER) && _MSC_VER < 1900
6 #define _CRT_SECURE_NO_WARNINGS
7 #define snprintf _snprintf
8 #endif
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include <capstone/platform.h>
14 #include <capstone/capstone.h>
15 
16 static csh handle;
17 
18 struct platform {
21  unsigned char *code;
22  size_t size;
23  char *comment;
24  int syntax;
25 };
26 
27 static char *hex_string(unsigned char *str, size_t len)
28 {
29  // returns a malloced string that has the hex version of the string in it
30  // null if failed to malloc
31  char *hex_out;
32  size_t i;
33 
34  hex_out = (char *) malloc(len*2 + 1); // two ascii characters per input character, plus trailing null
35  if (!hex_out) { goto Exit; }
36 
37  for (i = 0; i < len; ++i) {
38  snprintf(hex_out + (i*2), 2, "%02x", str[i]);
39  }
40 
41  hex_out[len*2] = 0; // trailing null
42 
43 Exit:
44  return hex_out;
45 }
46 
47 static void snprint_insn_detail(char * buf, size_t * cur, size_t * left, cs_insn *ins)
48 {
49  size_t used = 0;
50 
51 #define _this_printf(...) \
52  { \
53  size_t used = 0; \
54  used = snprintf(buf + *cur, *left, __VA_ARGS__); \
55  *left -= used; \
56  *cur += used; \
57  }
58 
59  cs_arm *arm;
60  int i;
61 
62  // detail can be NULL on "data" instruction if SKIPDATA option is turned ON
63  if (ins->detail == NULL)
64  return;
65 
66  arm = &(ins->detail->arm);
67 
68  if (arm->op_count)
69  _this_printf("\top_count: %u\n", arm->op_count);
70 
71  for (i = 0; i < arm->op_count; i++) {
72  cs_arm_op *op = &(arm->operands[i]);
73  switch((int)op->type) {
74  default:
75  break;
76  case ARM_OP_REG:
77  _this_printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg));
78  break;
79  case ARM_OP_IMM:
80  _this_printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm);
81  break;
82  case ARM_OP_FP:
83  _this_printf("\t\toperands[%u].type: FP = %f\n", i, op->fp);
84  break;
85  case ARM_OP_MEM:
86  _this_printf("\t\toperands[%u].type: MEM\n", i);
87  if (op->mem.base != X86_REG_INVALID)
88  _this_printf("\t\t\toperands[%u].mem.base: REG = %s\n",
89  i, cs_reg_name(handle, op->mem.base));
90  if (op->mem.index != X86_REG_INVALID)
91  _this_printf("\t\t\toperands[%u].mem.index: REG = %s\n",
92  i, cs_reg_name(handle, op->mem.index));
93  if (op->mem.scale != 1)
94  _this_printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale);
95  if (op->mem.disp != 0)
96  _this_printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp);
97 
98  break;
99  case ARM_OP_PIMM:
100  _this_printf("\t\toperands[%u].type: P-IMM = %u\n", i, op->imm);
101  break;
102  case ARM_OP_CIMM:
103  _this_printf("\t\toperands[%u].type: C-IMM = %u\n", i, op->imm);
104  break;
105  }
106 
107  if (op->shift.type != ARM_SFT_INVALID && op->shift.value) {
108  if (op->shift.type < ARM_SFT_ASR_REG) {
109  // shift with constant value
110  _this_printf("\t\t\tShift: %u = %u\n", op->shift.type, op->shift.value);
111  } else {
112  // shift with register
113  _this_printf("\t\t\tShift: %u = %s\n", op->shift.type,
114  cs_reg_name(handle, op->shift.value));
115  }
116  }
117  }
118 
119  if (arm->cc != ARM_CC_AL && arm->cc != ARM_CC_INVALID) {
120  _this_printf("\tCode condition: %u\n", arm->cc);
121  }
122 
123  if (arm->update_flags) {
124  _this_printf("\tUpdate-flags: True\n");
125  }
126 
127  if (arm->writeback) {
128  _this_printf("\tWrite-back: True\n");
129  }
130 
131 #undef _this_printf
132 }
133 
134 static void print_insn_detail(cs_insn *ins)
135 {
136  char a_buf[2048];
137  size_t cur=0, left=2048;
138  snprint_insn_detail(a_buf, &cur, &left, ins);
139  printf("%s\n", a_buf);
140 }
141 
142 struct invalid_code {
143  unsigned char *code;
144  size_t size;
145  char *comment;
146 };
147 
148 #define MAX_INVALID_CODES 16
149 
156 };
157 
158 static void test_invalids()
159 {
160  struct invalid_instructions invalids[] = {{
161  CS_ARCH_ARM,
163  "Thumb",
164  1,
165  {{
166  (unsigned char *)"\xbd\xe8\x1e\xff",
167  4,
168  "invalid thumb2 pop because sp used and because both pc and lr are "
169  "present at the same time"
170  }},
171  }};
172 
173  struct invalid_instructions * invalid = NULL;
174 
175  uint64_t address = 0x1000;
176  cs_insn *insn;
177  int i;
178  int j;
179  size_t count;
180 
181  printf("\nShould be invalid\n"
182  "-----------------\n");
183 
184  for (i = 0; i < sizeof(invalids)/sizeof(invalids[0]); i++) {
185  cs_err err;
186 
187  invalid = invalids + i;
188  err = cs_open(invalid->arch, invalid->mode, &handle);
189 
190  if (err) {
191  printf("Failed on cs_open() with error returned: %u\n", err);
192  continue;
193  }
194 
197 
198  for (j = 0; j < invalid->num_invalid_codes; ++j) {
199  struct invalid_code *invalid_code = NULL;
200  char *hex_str = NULL;
201 
202  invalid_code = invalid->invalid_codes + j;
203 
205 
206  printf("%s %s: %s\n", invalid->platform_comment, hex_str, invalid_code->comment);
207 
208  free(hex_str);
209 
211  invalid_code->code, invalid_code->size, address, 0, &insn
212  );
213 
214  if (count) {
215  size_t k;
216  printf(" ERROR:\n");
217 
218  for (k = 0; k < count; k++) {
219  printf(" 0x%"PRIx64":\t%s\t%s\n",
220  insn[k].address, insn[k].mnemonic, insn[k].op_str);
221  print_insn_detail(&insn[k]);
222  }
223  cs_free(insn, count);
224 
225  } else {
226  printf(" SUCCESS: invalid\n");
227  }
228  }
229 
230  cs_close(&handle);
231  }
232 }
233 
234 struct valid_code {
235  unsigned char *code;
236  size_t size;
239  char *comment;
240 };
241 
242 #define MAX_VALID_CODES 16
249 };
250 
251 static void test_valids()
252 {
253  struct valid_instructions valids[] = {{
254  CS_ARCH_ARM,
256  "Thumb",
257  3,
258  {{ (unsigned char *)"\x00\xf0\x26\xe8", 4, 0x352,
259  "0x352:\tblx\t#0x3a0\n"
260  "\top_count: 1\n"
261  "\t\toperands[0].type: IMM = 0x3a0\n",
262 
263  "thumb2 blx with misaligned immediate"
264  }, { (unsigned char *)"\x05\xdd", 2, 0x1f0,
265  "0x1f0:\tble\t#0x1fe\n"
266  "\top_count: 1\n"
267  "\t\toperands[0].type: IMM = 0x1fe\n"
268  "\tCode condition: 14\n",
269 
270  "thumb b cc with thumb-aligned target"
271  }, { (unsigned char *)"\xbd\xe8\xf0\x8f", 4, 0,
272  "0x0:\tpop.w\t{r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
273  "\top_count: 9\n"
274  "\t\toperands[0].type: REG = r4\n"
275  "\t\toperands[1].type: REG = r5\n"
276  "\t\toperands[2].type: REG = r6\n"
277  "\t\toperands[3].type: REG = r7\n"
278  "\t\toperands[4].type: REG = r8\n"
279  "\t\toperands[5].type: REG = r9\n"
280  "\t\toperands[6].type: REG = r10\n"
281  "\t\toperands[7].type: REG = r11\n"
282  "\t\toperands[8].type: REG = pc\n",
283 
284  "thumb2 pop that should be valid"
285  },
286  }
287  }};
288 
289  struct valid_instructions * valid = NULL;
290 
291  uint64_t address = 0x1000;
292  cs_insn *insn;
293  int i;
294  int j;
295  size_t count;
296 
297 
298  for (i = 0; i < sizeof(valids)/sizeof(valids[0]); i++) {
299  cs_err err;
300 
301  valid = valids + i;
302  err = cs_open(valid->arch, valid->mode, &handle);
303 
304  if (err) {
305  printf("Failed on cs_open() with error returned: %u\n", err);
306  continue;
307  }
308 
311 
312 #define _this_printf(...) \
313  { \
314  size_t used = 0; \
315  used = snprintf(tmp_buf + cur, left, __VA_ARGS__); \
316  left -= used; \
317  cur += used; \
318  }
319  printf("\nShould be valid\n"
320  "---------------\n");
321 
322  for (j = 0; j < valid->num_valid_codes; ++j) {
323  char tmp_buf[2048];
324  size_t left = 2048;
325  size_t cur = 0;
326  size_t used = 0;
327  int success = 0;
328  char * hex_str = NULL;
329 
330  struct valid_code * valid_code = NULL;
331  valid_code = valid->valid_codes + j;
332 
334 
335  printf("%s %s @ 0x%04x: %s\n %s",
336  valid->platform_comment, hex_str, valid_code->start_addr,
338 
341  valid_code->start_addr, 0, &insn
342  );
343 
344  if (count) {
345  size_t k;
346  size_t max_len = 0;
347  size_t tmp_len = 0;
348 
349  for (k = 0; k < count; k++) {
350  _this_printf(
351  "0x%"PRIx64":\t%s\t%s\n",
352  insn[k].address, insn[k].mnemonic,
353  insn[k].op_str
354  );
355 
356  snprint_insn_detail(tmp_buf, &cur, &left, &insn[k]);
357  }
358 
359  max_len = strlen(tmp_buf);
360  tmp_len = strlen(valid_code->expected_out);
361  if (tmp_len > max_len) {
362  max_len = tmp_len;
363  }
364 
365  if (memcmp(tmp_buf, valid_code->expected_out, max_len)) {
366  printf(
367  " ERROR: '''\n%s''' does not match"
368  " expected '''\n%s'''\n",
369  tmp_buf, valid_code->expected_out
370  );
371  } else {
372  printf(" SUCCESS: valid\n");
373  }
374 
375  cs_free(insn, count);
376 
377  } else {
378  printf("ERROR: invalid\n");
379  }
380  }
381 
382  cs_close(&handle);
383  }
384 
385 #undef _this_prinf
386 }
387 
388 int main()
389 {
390  test_invalids();
391  test_valids();
392  return 0;
393 }
394 
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static bool err
Definition: armass.c:435
@ ARM_SFT_INVALID
Definition: arm.h:19
@ ARM_SFT_ASR_REG
shift with register
Definition: arm.h:25
@ ARM_OP_IMM
= CS_OP_IMM (Immediate operand).
Definition: arm.h:164
@ ARM_OP_REG
= CS_OP_REG (Register operand).
Definition: arm.h:163
@ ARM_OP_CIMM
C-Immediate (coprocessor registers)
Definition: arm.h:167
@ ARM_OP_PIMM
P-Immediate (coprocessor registers)
Definition: arm.h:168
@ ARM_OP_MEM
= CS_OP_MEM (Memory operand).
Definition: arm.h:165
@ ARM_OP_FP
= CS_OP_FP (Floating-Point operand).
Definition: arm.h:166
@ ARM_CC_AL
Always (unconditional) Always (unconditional)
Definition: arm.h:49
@ ARM_CC_INVALID
Definition: arm.h:34
cs_arch
Architecture type.
Definition: capstone.h:74
@ CS_ARCH_ARM
ARM architecture (including Thumb, Thumb-2)
Definition: capstone.h:75
cs_mode
Mode type.
Definition: capstone.h:102
@ CS_MODE_THUMB
ARM's Thumb mode, including Thumb-2.
Definition: capstone.h:108
@ 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
@ X86_REG_INVALID
Definition: x86.h:20
#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 cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle)
Definition: cs.c:453
CAPSTONE_EXPORT void CAPSTONE_API cs_free(cs_insn *insn, size_t count)
Definition: cs.c:1017
CAPSTONE_EXPORT const char *CAPSTONE_API cs_reg_name(csh ud, unsigned int reg)
Definition: cs.c:1154
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
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
const char * k
Definition: dsignal.c:11
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
static char hex_str[]
Definition: utils.c:9
void * malloc(size_t size)
Definition: malloc.c:123
unsigned int uint32_t
Definition: sftypes.h:29
unsigned long uint64_t
Definition: sftypes.h:28
Instruction operand.
Definition: arm.h:391
Instruction structure.
Definition: arm.h:424
unsigned char * code
struct invalid_code invalid_codes[MAX_INVALID_CODES]
unsigned char * code
unsigned char * code
struct valid_code valid_codes[MAX_VALID_CODES]
bool valid
Definition: core.c:77
#define PRIx64
Definition: sysdefs.h:94
static csh handle
#define MAX_VALID_CODES
static void test_invalids()
static void test_valids()
static void print_insn_detail(cs_insn *ins)
#define _this_printf(...)
#define MAX_INVALID_CODES
static char * hex_string(unsigned char *str, size_t len)
int main()
static void snprint_insn_detail(char *buf, size_t *cur, size_t *left, cs_insn *ins)
Definition: dis.c:32
mnemonic
Definition: z80asm.h:48