blob: c62cab89845c02114c4b5707e86dea33229f97bb [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 Quynh4b95d9f2013-12-04 13:48:52 +080037#define API_MINOR 6
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:
212 break;
213 case CS_ARCH_X86:
Nguyen Anh Quynhb8ce68e2013-12-03 23:45:08 +0800214 if (type & CS_OPT_SYNTAX) {
215 switch(value) {
216 default:
217 break;
Nguyen Anh Quynhc618db42013-12-04 00:05:04 +0800218 case CS_OPT_SYNTAX_INTEL:
Nguyen Anh Quynhb8ce68e2013-12-03 23:45:08 +0800219 handle->printer = X86_Intel_printInst;
220 break;
Nguyen Anh Quynhc618db42013-12-04 00:05:04 +0800221 case CS_OPT_SYNTAX_ATT:
Nguyen Anh Quynhb8ce68e2013-12-03 23:45:08 +0800222 handle->printer = X86_ATT_printInst;
223 break;
224 }
225 }
Nguyen Anh Quynh4a60a562013-12-03 21:56:54 +0800226 break;
227 }
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800228
229 return CS_ERR_OK;
230}
231
pancakec04f8732013-12-03 02:51:46 +0100232size_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 +0800233{
234 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
235 MCInst mci;
236 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800237 size_t c = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800238
239 if (!handle) {
240 // FIXME: handle this case?
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800241 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800242 return 0;
243 }
244
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800245 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800246
247 while (size > 0) {
248 MCInst_Init(&mci);
249
250 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
251 if (r) {
252 SStream ss;
253 SStream_Init(&ss);
254
255 mci.pub_insn.size = insn_size;
256 mci.pub_insn.address = offset;
257 mci.mode = handle->mode;
258 handle->printer(&mci, &ss, handle->printer_info);
259
Joxean114df0e2013-12-04 07:11:32 +0100260 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800261
262 c++;
263 insn++;
264 buffer += insn_size;
265 size -= insn_size;
266 offset += insn_size;
267
268 if (count > 0) {
269 if (c == count)
270 return c;
271 }
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800272 } else
273 // face a broken instruction?
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800274 return c;
275 }
276
277 return c;
278}
279
280// dynamicly allocate memory to contain disasm insn
281// NOTE: caller must free() the allocated memory itself to avoid memory leaking
pancakec04f8732013-12-03 02:51:46 +0100282size_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 +0800283{
284 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
285 MCInst mci;
286 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800287 size_t c = 0, f = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800288 cs_insn insn_cache[64];
289 void *total = NULL;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800290 size_t total_size = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800291
292 if (!handle) {
293 // FIXME: how to handle this case:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800294 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800295 return 0;
296 }
297
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800298 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800299
300 while (size > 0) {
301 MCInst_Init(&mci);
302
303 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
304 if (r) {
305 SStream ss;
306 SStream_Init(&ss);
307
308 mci.pub_insn.size = insn_size;
309 mci.pub_insn.address = offset;
310 mci.mode = handle->mode;
311 handle->printer(&mci, &ss, handle->printer_info);
312
Joxean114df0e2013-12-04 07:11:32 +0100313 fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800314 f++;
315
316 if (f == ARR_SIZE(insn_cache)) {
317 // resize total to contain newly disasm insns
318 total_size += sizeof(insn_cache);
319 void *tmp = realloc(total, total_size);
320 if (tmp == NULL) { // insufficient memory
321 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800322 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800323 return 0;
324 }
325
326 total = tmp;
327 memcpy(total + total_size - sizeof(insn_cache), insn_cache, sizeof(insn_cache));
328 // reset f back to 0
329 f = 0;
330 }
331
332 c++;
333 buffer += insn_size;
334 size -= insn_size;
335 offset += insn_size;
336
337 if (count > 0 && c == count)
338 break;
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800339 } else {
340 // encounter a broken instruction
341 // XXX: TODO: JOXEAN continue here
342 break;
343 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800344 }
345
346 if (f) {
347 // resize total to contain newly disasm insns
348 void *tmp = realloc(total, total_size + f * sizeof(insn_cache[0]));
349 if (tmp == NULL) { // insufficient memory
350 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800351 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800352 return 0;
353 }
354
355 total = tmp;
356 memcpy(total + total_size, insn_cache, f * sizeof(insn_cache[0]));
357 }
358
359 *insn = total;
360
361 return c;
362}
363
364void cs_free(void *m)
365{
366 free(m);
367}
368
369// return friendly name of regiser in a string
370char *cs_reg_name(csh ud, unsigned int reg)
371{
372 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
373
374 if (!handle || handle->reg_name == NULL) {
375 return NULL;
376 }
377
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800378 return handle->reg_name(reg);
379}
380
381char *cs_insn_name(csh ud, unsigned int insn)
382{
383 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
384
385 if (!handle || handle->insn_name == NULL) {
386 return NULL;
387 }
388
389 return handle->insn_name(insn);
390}
391
392static bool arr_exist(unsigned int *arr, int max, unsigned int id)
393{
394 int i;
395
396 for (i = 0; i < max; i++) {
397 if (arr[i] == id)
398 return true;
399 }
400
401 return false;
402}
403
404bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
405{
406 if (!handle)
407 return false;
408
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800409 return arr_exist(insn->groups, insn->groups_count, group_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800410}
411
412bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
413{
414 if (!handle)
415 return false;
416
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800417 return arr_exist(insn->regs_read, insn->regs_read_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800418}
419
420bool cs_reg_write(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_write, insn->regs_write_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800426}
427
428int cs_op_count(csh ud, cs_insn *insn, unsigned int op_type)
429{
430 if (!ud)
431 return -1;
432
433 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
434 unsigned int count = 0, i;
435
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800436 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800437
438 switch (handle->arch) {
439 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800440 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800441 return -1;
442 case CS_ARCH_ARM:
443 for (i = 0; i < insn->arm.op_count; i++)
444 if (insn->arm.operands[i].type == op_type)
445 count++;
446 break;
447 case CS_ARCH_ARM64:
448 for (i = 0; i < insn->arm64.op_count; i++)
449 if (insn->arm64.operands[i].type == op_type)
450 count++;
451 break;
452 case CS_ARCH_X86:
453 for (i = 0; i < insn->x86.op_count; i++)
454 if (insn->x86.operands[i].type == op_type)
455 count++;
456 break;
457 case CS_ARCH_MIPS:
458 for (i = 0; i < insn->mips.op_count; i++)
459 if (insn->mips.operands[i].type == op_type)
460 count++;
461 break;
462 }
463
464 return count;
465}
466
467int cs_op_index(csh ud, cs_insn *insn, unsigned int op_type,
468 unsigned int post)
469{
470 if (!ud)
471 return -1;
472
473 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
474 unsigned int count = 0, i;
475
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800476 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800477
478 switch (handle->arch) {
479 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800480 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800481 return -1;
482 case CS_ARCH_ARM:
483 for (i = 0; i < insn->arm.op_count; i++) {
484 if (insn->arm.operands[i].type == op_type)
485 count++;
486 if (count == post)
487 return i;
488 }
489 break;
490 case CS_ARCH_ARM64:
491 for (i = 0; i < insn->arm64.op_count; i++) {
492 if (insn->arm64.operands[i].type == op_type)
493 count++;
494 if (count == post)
495 return i;
496 }
497 break;
498 case CS_ARCH_X86:
499 for (i = 0; i < insn->x86.op_count; i++) {
500 if (insn->x86.operands[i].type == op_type)
501 count++;
502 if (count == post)
503 return i;
504 }
505 break;
506 case CS_ARCH_MIPS:
507 for (i = 0; i < insn->mips.op_count; i++) {
508 if (insn->mips.operands[i].type == op_type)
509 count++;
510 if (count == post)
511 return i;
512 }
513 break;
514 }
515
516 return -1;
517}