blob: 75ef9b9c54be3cd13ba58f8d501b9136306c5d0c [file] [log] [blame]
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +08001/* Capstone Disassembler Engine */
2/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <capstone.h>
8
9#include "cs_priv.h"
10
11#include "MCRegisterInfo.h"
12
13#include "arch/X86/X86Disassembler.h"
14#include "arch/X86/X86InstPrinter.h"
15#include "arch/X86/mapping.h"
16
17#include "arch/ARM/ARMDisassembler.h"
18#include "arch/ARM/ARMInstPrinter.h"
19#include "arch/ARM/mapping.h"
20
21#include "arch/Mips/MipsDisassembler.h"
22#include "arch/Mips/MipsInstPrinter.h"
23#include "arch/Mips/mapping.h"
24
25#include "arch/AArch64/AArch64Disassembler.h"
26#include "arch/AArch64/AArch64InstPrinter.h"
27#include "arch/AArch64/mapping.h"
28
29#include "utils.h"
30
Nguyen Anh Quynh5dbe12a2013-12-03 12:27:46 +080031// Package version
32#define PKG_MAJOR 1
33#define PKG_MINOR 0
34
35// API version
36#define API_MAJOR 1
Nguyen Anh Quynh26a43712013-12-04 23:08:32 +080037#define API_MINOR 7
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080038
39cs_err cs_errno(csh handle)
40{
41 if (!handle)
42 return CS_ERR_CSH;
43
44 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
45
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +080046 return ud->errnum;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080047}
48
49void cs_version(int *major, int *minor)
50{
Nguyen Anh Quynh5dbe12a2013-12-03 12:27:46 +080051 *major = API_MAJOR;
52 *minor = API_MINOR;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080053}
54
55cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle)
56{
57 cs_struct *ud;
58
59 ud = calloc(1, sizeof(*ud));
60 if (!ud) {
61 // memory insufficient
62 return CS_ERR_MEM;
63 }
64
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +080065 ud->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080066 ud->arch = arch;
67 ud->mode = mode;
68 ud->big_endian = mode & CS_MODE_BIG_ENDIAN;
69 ud->reg_name = NULL;
70
71 switch (ud->arch) {
72 case CS_ARCH_X86:
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +080073 // by default, we use Intel syntax
74 ud->printer = X86_Intel_printInst;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080075 ud->printer_info = NULL;
76 ud->disasm = X86_getInstruction;
77 ud->reg_name = X86_reg_name;
78 ud->insn_id = X86_get_insn_id;
79 ud->insn_name = X86_insn_name;
80 break;
81 case CS_ARCH_ARM: {
82 MCRegisterInfo *mri = malloc(sizeof(*mri));
83
84 ARM_init(mri);
85
86 ud->printer = ARM_printInst;
87 ud->printer_info = mri;
88 ud->reg_name = ARM_reg_name;
89 ud->insn_id = ARM_get_insn_id;
90 ud->insn_name = ARM_insn_name;
91 ud->post_printer = ARM_post_printer;
92
93 if (ud->mode & CS_MODE_THUMB)
94 ud->disasm = Thumb_getInstruction;
95 else
96 ud->disasm = ARM_getInstruction;
97 break;
98 }
99 case CS_ARCH_MIPS: {
100 MCRegisterInfo *mri = malloc(sizeof(*mri));
101
102 Mips_init(mri);
103 ud->printer = Mips_printInst;
104 ud->printer_info = mri;
105 ud->getinsn_info = mri;
106 ud->reg_name = Mips_reg_name;
107 ud->insn_id = Mips_get_insn_id;
108 ud->insn_name = Mips_insn_name;
109
110 if (ud->mode & CS_MODE_32)
111 ud->disasm = Mips_getInstruction;
112 else
113 ud->disasm = Mips64_getInstruction;
114
115 if (ud->mode & CS_MODE_MICRO)
116 ud->micro_mips = true;
117
118 break;
119 }
120 case CS_ARCH_ARM64: {
121 MCRegisterInfo *mri = malloc(sizeof(*mri));
122
123 AArch64_init(mri);
124 ud->printer = AArch64_printInst;
125 ud->printer_info = mri;
126 ud->getinsn_info = mri;
127 ud->disasm = AArch64_getInstruction;
128 ud->reg_name = AArch64_reg_name;
129 ud->insn_id = AArch64_get_insn_id;
130 ud->insn_name = AArch64_insn_name;
131 ud->post_printer = AArch64_post_printer;
132 break;
133 }
134 default: // unsupported architecture
135 free(ud);
136 return CS_ERR_ARCH;
137 }
138
139 *handle = (uintptr_t)ud;
140
141 return CS_ERR_OK;
142}
143
144cs_err cs_close(csh handle)
145{
146 if (!handle)
147 return CS_ERR_CSH;
148
149 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
150
151 switch (ud->arch) {
152 case CS_ARCH_X86:
153 break;
154 case CS_ARCH_ARM:
155 case CS_ARCH_MIPS:
156 case CS_ARCH_ARM64:
157 free(ud->printer_info);
158 break;
159 default: // unsupported architecture
160 return CS_ERR_HANDLE;
161 }
162
163 memset(ud, 0, sizeof(*ud));
164 free(ud);
165
166 return CS_ERR_OK;
167}
168
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800169#define MIN(x, y) ((x) < (y) ? (x) : (y))
170
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800171// fill insn with mnemonic & operands info
172static void fill_insn(cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
Joxean114df0e2013-12-04 07:11:32 +0100173 PostPrinter_t printer, unsigned char *code)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800174{
175 memcpy(insn, &mci->pub_insn, sizeof(*insn));
176
177 // map internal instruction opcode to public insn ID
Nguyen Anh Quynhad61c492013-11-30 16:23:31 +0800178 if (handle->insn_id)
179 handle->insn_id(insn, MCInst_getOpcode(mci));
180
181 // alias instruction might have ID saved in OpcodePub
Nguyen Anh Quynh6b7abe32013-11-30 00:54:24 +0800182 if (MCInst_getOpcodePub(mci))
Nguyen Anh Quynhad61c492013-11-30 16:23:31 +0800183 insn->id = MCInst_getOpcodePub(mci);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800184
185 if (printer)
186 printer(insn->id, insn, buffer);
187
188 // fill in mnemonic & operands
189 char *tab = strchr(buffer, '\t');
190 if (tab) {
191 *tab = '\0';
192 strncpy(insn->op_str, tab + 1, sizeof(insn->op_str) - 1);
193 insn->op_str[sizeof(insn->op_str) - 1] = '\0';
194 } else
195 insn->op_str[0] = '\0';
196
197 strncpy(insn->mnemonic, buffer, sizeof(insn->mnemonic) - 1);
198 insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800199
200 // fill the instruction bytes
201 memcpy(insn->bytes, code, MIN(sizeof(insn->bytes), insn->size));
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800202}
203
Nguyen Anh Quynhda8adad2013-12-04 09:44:07 +0800204cs_err cs_option(csh ud, cs_opt_type type, size_t value)
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800205{
206 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
207 if (!handle)
208 return CS_ERR_CSH;
209
Nguyen Anh Quynh4a60a562013-12-03 21:56:54 +0800210 switch (handle->arch) {
211 default:
Nguyen Anh Quynhfe8030b2013-12-06 10:09:43 +0800212 handle->errnum = CS_ERR_OPTION;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800213 return CS_ERR_OPTION;
214
Nguyen Anh Quynh4a60a562013-12-03 21:56:54 +0800215 case CS_ARCH_X86:
Nguyen Anh Quynhb8ce68e2013-12-03 23:45:08 +0800216 if (type & CS_OPT_SYNTAX) {
217 switch(value) {
218 default:
Nguyen Anh Quynhfe8030b2013-12-06 10:09:43 +0800219 handle->errnum = CS_ERR_OPTION;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800220 return CS_ERR_OPTION;
221
Nguyen Anh Quynhc618db42013-12-04 00:05:04 +0800222 case CS_OPT_SYNTAX_INTEL:
Nguyen Anh Quynhb8ce68e2013-12-03 23:45:08 +0800223 handle->printer = X86_Intel_printInst;
224 break;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800225
Nguyen Anh Quynhc618db42013-12-04 00:05:04 +0800226 case CS_OPT_SYNTAX_ATT:
Nguyen Anh Quynhb8ce68e2013-12-03 23:45:08 +0800227 handle->printer = X86_ATT_printInst;
228 break;
229 }
Nguyen Anh Quynhfe8030b2013-12-06 10:09:43 +0800230 } else {
231 handle->errnum = CS_ERR_OPTION;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800232 return CS_ERR_OPTION;
Nguyen Anh Quynhfe8030b2013-12-06 10:09:43 +0800233 }
Nguyen Anh Quynh4a60a562013-12-03 21:56:54 +0800234 break;
235 }
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800236
237 return CS_ERR_OK;
238}
239
pancakec04f8732013-12-03 02:51:46 +0100240size_t cs_disasm(csh ud, unsigned char *buffer, size_t size, uint64_t offset, size_t count, cs_insn *insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800241{
242 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
243 MCInst mci;
244 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800245 size_t c = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800246
247 if (!handle) {
248 // FIXME: handle this case?
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800249 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800250 return 0;
251 }
252
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800253 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800254
255 while (size > 0) {
256 MCInst_Init(&mci);
257
258 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
259 if (r) {
260 SStream ss;
261 SStream_Init(&ss);
262
263 mci.pub_insn.size = insn_size;
264 mci.pub_insn.address = offset;
265 mci.mode = handle->mode;
266 handle->printer(&mci, &ss, handle->printer_info);
267
Joxean114df0e2013-12-04 07:11:32 +0100268 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800269
270 c++;
271 insn++;
272 buffer += insn_size;
273 size -= insn_size;
274 offset += insn_size;
275
276 if (count > 0) {
277 if (c == count)
278 return c;
279 }
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800280 } else
281 // face a broken instruction?
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800282 return c;
283 }
284
285 return c;
286}
287
288// dynamicly allocate memory to contain disasm insn
289// NOTE: caller must free() the allocated memory itself to avoid memory leaking
pancakec04f8732013-12-03 02:51:46 +0100290size_t cs_disasm_dyn(csh ud, unsigned char *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800291{
292 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
293 MCInst mci;
294 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800295 size_t c = 0, f = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800296 cs_insn insn_cache[64];
297 void *total = NULL;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800298 size_t total_size = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800299
300 if (!handle) {
301 // FIXME: how to handle this case:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800302 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800303 return 0;
304 }
305
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800306 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800307
308 while (size > 0) {
309 MCInst_Init(&mci);
310
311 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
312 if (r) {
313 SStream ss;
314 SStream_Init(&ss);
315
316 mci.pub_insn.size = insn_size;
317 mci.pub_insn.address = offset;
318 mci.mode = handle->mode;
319 handle->printer(&mci, &ss, handle->printer_info);
320
Joxean114df0e2013-12-04 07:11:32 +0100321 fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800322 f++;
323
324 if (f == ARR_SIZE(insn_cache)) {
325 // resize total to contain newly disasm insns
326 total_size += sizeof(insn_cache);
327 void *tmp = realloc(total, total_size);
328 if (tmp == NULL) { // insufficient memory
329 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800330 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800331 return 0;
332 }
333
334 total = tmp;
335 memcpy(total + total_size - sizeof(insn_cache), insn_cache, sizeof(insn_cache));
336 // reset f back to 0
337 f = 0;
338 }
339
340 c++;
341 buffer += insn_size;
342 size -= insn_size;
343 offset += insn_size;
344
345 if (count > 0 && c == count)
346 break;
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800347 } else {
348 // encounter a broken instruction
349 // XXX: TODO: JOXEAN continue here
350 break;
351 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800352 }
353
354 if (f) {
355 // resize total to contain newly disasm insns
356 void *tmp = realloc(total, total_size + f * sizeof(insn_cache[0]));
357 if (tmp == NULL) { // insufficient memory
358 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800359 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800360 return 0;
361 }
362
363 total = tmp;
364 memcpy(total + total_size, insn_cache, f * sizeof(insn_cache[0]));
365 }
366
367 *insn = total;
368
369 return c;
370}
371
372void cs_free(void *m)
373{
374 free(m);
375}
376
377// return friendly name of regiser in a string
378char *cs_reg_name(csh ud, unsigned int reg)
379{
380 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
381
382 if (!handle || handle->reg_name == NULL) {
383 return NULL;
384 }
385
Nguyen Anh Quynha253c7a2013-12-09 10:26:18 +0800386 return handle->reg_name(ud, reg);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800387}
388
389char *cs_insn_name(csh ud, unsigned int insn)
390{
391 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
392
393 if (!handle || handle->insn_name == NULL) {
394 return NULL;
395 }
396
Nguyen Anh Quynha253c7a2013-12-09 10:26:18 +0800397 return handle->insn_name(ud, insn);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800398}
399
400static bool arr_exist(unsigned int *arr, int max, unsigned int id)
401{
402 int i;
403
404 for (i = 0; i < max; i++) {
405 if (arr[i] == id)
406 return true;
407 }
408
409 return false;
410}
411
412bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
413{
414 if (!handle)
415 return false;
416
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800417 return arr_exist(insn->groups, insn->groups_count, group_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800418}
419
420bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
421{
422 if (!handle)
423 return false;
424
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800425 return arr_exist(insn->regs_read, insn->regs_read_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800426}
427
428bool cs_reg_write(csh handle, cs_insn *insn, unsigned int reg_id)
429{
430 if (!handle)
431 return false;
432
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800433 return arr_exist(insn->regs_write, insn->regs_write_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800434}
435
436int cs_op_count(csh ud, cs_insn *insn, unsigned int op_type)
437{
438 if (!ud)
439 return -1;
440
441 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
442 unsigned int count = 0, i;
443
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800444 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800445
446 switch (handle->arch) {
447 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800448 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800449 return -1;
450 case CS_ARCH_ARM:
451 for (i = 0; i < insn->arm.op_count; i++)
452 if (insn->arm.operands[i].type == op_type)
453 count++;
454 break;
455 case CS_ARCH_ARM64:
456 for (i = 0; i < insn->arm64.op_count; i++)
457 if (insn->arm64.operands[i].type == op_type)
458 count++;
459 break;
460 case CS_ARCH_X86:
461 for (i = 0; i < insn->x86.op_count; i++)
462 if (insn->x86.operands[i].type == op_type)
463 count++;
464 break;
465 case CS_ARCH_MIPS:
466 for (i = 0; i < insn->mips.op_count; i++)
467 if (insn->mips.operands[i].type == op_type)
468 count++;
469 break;
470 }
471
472 return count;
473}
474
475int cs_op_index(csh ud, cs_insn *insn, unsigned int op_type,
476 unsigned int post)
477{
478 if (!ud)
479 return -1;
480
481 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
482 unsigned int count = 0, i;
483
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800484 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800485
486 switch (handle->arch) {
487 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800488 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800489 return -1;
490 case CS_ARCH_ARM:
491 for (i = 0; i < insn->arm.op_count; i++) {
492 if (insn->arm.operands[i].type == op_type)
493 count++;
494 if (count == post)
495 return i;
496 }
497 break;
498 case CS_ARCH_ARM64:
499 for (i = 0; i < insn->arm64.op_count; i++) {
500 if (insn->arm64.operands[i].type == op_type)
501 count++;
502 if (count == post)
503 return i;
504 }
505 break;
506 case CS_ARCH_X86:
507 for (i = 0; i < insn->x86.op_count; i++) {
508 if (insn->x86.operands[i].type == op_type)
509 count++;
510 if (count == post)
511 return i;
512 }
513 break;
514 case CS_ARCH_MIPS:
515 for (i = 0; i < insn->mips.op_count; i++) {
516 if (insn->mips.operands[i].type == op_type)
517 count++;
518 if (count == post)
519 return i;
520 }
521 break;
522 }
523
524 return -1;
525}