blob: 60ecd21259e31f4e5adcd3cd9ca35cded8b5aa06 [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
37#define API_MINOR 5
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:
73 if (ud->mode & CS_MODE_SYNTAX_ATT)
74 ud->printer = X86_ATT_printInst;
75 else
76 ud->printer = X86_Intel_printInst;
77 ud->printer_info = NULL;
78 ud->disasm = X86_getInstruction;
79 ud->reg_name = X86_reg_name;
80 ud->insn_id = X86_get_insn_id;
81 ud->insn_name = X86_insn_name;
82 break;
83 case CS_ARCH_ARM: {
84 MCRegisterInfo *mri = malloc(sizeof(*mri));
85
86 ARM_init(mri);
87
88 ud->printer = ARM_printInst;
89 ud->printer_info = mri;
90 ud->reg_name = ARM_reg_name;
91 ud->insn_id = ARM_get_insn_id;
92 ud->insn_name = ARM_insn_name;
93 ud->post_printer = ARM_post_printer;
94
95 if (ud->mode & CS_MODE_THUMB)
96 ud->disasm = Thumb_getInstruction;
97 else
98 ud->disasm = ARM_getInstruction;
99 break;
100 }
101 case CS_ARCH_MIPS: {
102 MCRegisterInfo *mri = malloc(sizeof(*mri));
103
104 Mips_init(mri);
105 ud->printer = Mips_printInst;
106 ud->printer_info = mri;
107 ud->getinsn_info = mri;
108 ud->reg_name = Mips_reg_name;
109 ud->insn_id = Mips_get_insn_id;
110 ud->insn_name = Mips_insn_name;
111
112 if (ud->mode & CS_MODE_32)
113 ud->disasm = Mips_getInstruction;
114 else
115 ud->disasm = Mips64_getInstruction;
116
117 if (ud->mode & CS_MODE_MICRO)
118 ud->micro_mips = true;
119
120 break;
121 }
122 case CS_ARCH_ARM64: {
123 MCRegisterInfo *mri = malloc(sizeof(*mri));
124
125 AArch64_init(mri);
126 ud->printer = AArch64_printInst;
127 ud->printer_info = mri;
128 ud->getinsn_info = mri;
129 ud->disasm = AArch64_getInstruction;
130 ud->reg_name = AArch64_reg_name;
131 ud->insn_id = AArch64_get_insn_id;
132 ud->insn_name = AArch64_insn_name;
133 ud->post_printer = AArch64_post_printer;
134 break;
135 }
136 default: // unsupported architecture
137 free(ud);
138 return CS_ERR_ARCH;
139 }
140
141 *handle = (uintptr_t)ud;
142
143 return CS_ERR_OK;
144}
145
146cs_err cs_close(csh handle)
147{
148 if (!handle)
149 return CS_ERR_CSH;
150
151 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
152
153 switch (ud->arch) {
154 case CS_ARCH_X86:
155 break;
156 case CS_ARCH_ARM:
157 case CS_ARCH_MIPS:
158 case CS_ARCH_ARM64:
159 free(ud->printer_info);
160 break;
161 default: // unsupported architecture
162 return CS_ERR_HANDLE;
163 }
164
165 memset(ud, 0, sizeof(*ud));
166 free(ud);
167
168 return CS_ERR_OK;
169}
170
171// 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';
Joxean114df0e2013-12-04 07:11:32 +0100199
200 // fill the instruction bytes
201 memcpy(insn->hex_code, code, MIN(sizeof(insn->hex_code), insn->size));
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800202}
203
pancakec04f8732013-12-03 02:51:46 +0100204size_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 +0800205{
206 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
207 MCInst mci;
208 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800209 size_t c = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800210
211 if (!handle) {
212 // FIXME: handle this case?
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800213 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800214 return 0;
215 }
216
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800217 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800218
219 while (size > 0) {
220 MCInst_Init(&mci);
221
222 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
223 if (r) {
224 SStream ss;
225 SStream_Init(&ss);
226
227 mci.pub_insn.size = insn_size;
228 mci.pub_insn.address = offset;
229 mci.mode = handle->mode;
230 handle->printer(&mci, &ss, handle->printer_info);
231
Joxean114df0e2013-12-04 07:11:32 +0100232 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800233
234 c++;
235 insn++;
236 buffer += insn_size;
237 size -= insn_size;
238 offset += insn_size;
239
240 if (count > 0) {
241 if (c == count)
242 return c;
243 }
Joxean114df0e2013-12-04 07:11:32 +0100244 } else { // face a broken instruction?
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800245 return c;
Joxean114df0e2013-12-04 07:11:32 +0100246 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800247 }
248
249 return c;
250}
251
252// dynamicly allocate memory to contain disasm insn
253// NOTE: caller must free() the allocated memory itself to avoid memory leaking
pancakec04f8732013-12-03 02:51:46 +0100254size_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 +0800255{
256 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
257 MCInst mci;
258 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800259 size_t c = 0, f = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800260 cs_insn insn_cache[64];
261 void *total = NULL;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800262 size_t total_size = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800263
264 if (!handle) {
265 // FIXME: how to handle this case:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800266 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800267 return 0;
268 }
269
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800270 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800271
272 while (size > 0) {
273 MCInst_Init(&mci);
274
275 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
276 if (r) {
277 SStream ss;
278 SStream_Init(&ss);
279
280 mci.pub_insn.size = insn_size;
281 mci.pub_insn.address = offset;
282 mci.mode = handle->mode;
283 handle->printer(&mci, &ss, handle->printer_info);
284
Joxean114df0e2013-12-04 07:11:32 +0100285 fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800286 f++;
287
288 if (f == ARR_SIZE(insn_cache)) {
289 // resize total to contain newly disasm insns
290 total_size += sizeof(insn_cache);
291 void *tmp = realloc(total, total_size);
292 if (tmp == NULL) { // insufficient memory
293 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800294 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800295 return 0;
296 }
297
298 total = tmp;
299 memcpy(total + total_size - sizeof(insn_cache), insn_cache, sizeof(insn_cache));
300 // reset f back to 0
301 f = 0;
302 }
303
304 c++;
305 buffer += insn_size;
306 size -= insn_size;
307 offset += insn_size;
308
309 if (count > 0 && c == count)
310 break;
Joxean114df0e2013-12-04 07:11:32 +0100311 } else { // encounter a broken instruction
312 // XXX: TODO: JOXEAN continue here
313 break;
314 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800315 }
316
317 if (f) {
318 // resize total to contain newly disasm insns
319 void *tmp = realloc(total, total_size + f * sizeof(insn_cache[0]));
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, insn_cache, f * sizeof(insn_cache[0]));
328 }
329
330 *insn = total;
331
332 return c;
333}
334
335void cs_free(void *m)
336{
337 free(m);
338}
339
340// return friendly name of regiser in a string
341char *cs_reg_name(csh ud, unsigned int reg)
342{
343 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
344
345 if (!handle || handle->reg_name == NULL) {
346 return NULL;
347 }
348
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800349 return handle->reg_name(reg);
350}
351
352char *cs_insn_name(csh ud, unsigned int insn)
353{
354 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
355
356 if (!handle || handle->insn_name == NULL) {
357 return NULL;
358 }
359
360 return handle->insn_name(insn);
361}
362
363static bool arr_exist(unsigned int *arr, int max, unsigned int id)
364{
365 int i;
366
367 for (i = 0; i < max; i++) {
368 if (arr[i] == id)
369 return true;
370 }
371
372 return false;
373}
374
375bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
376{
377 if (!handle)
378 return false;
379
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800380 return arr_exist(insn->groups, insn->groups_count, group_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800381}
382
383bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
384{
385 if (!handle)
386 return false;
387
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800388 return arr_exist(insn->regs_read, insn->regs_read_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800389}
390
391bool cs_reg_write(csh handle, cs_insn *insn, unsigned int reg_id)
392{
393 if (!handle)
394 return false;
395
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800396 return arr_exist(insn->regs_write, insn->regs_write_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800397}
398
399int cs_op_count(csh ud, cs_insn *insn, unsigned int op_type)
400{
401 if (!ud)
402 return -1;
403
404 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
405 unsigned int count = 0, i;
406
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800407 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800408
409 switch (handle->arch) {
410 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800411 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800412 return -1;
413 case CS_ARCH_ARM:
414 for (i = 0; i < insn->arm.op_count; i++)
415 if (insn->arm.operands[i].type == op_type)
416 count++;
417 break;
418 case CS_ARCH_ARM64:
419 for (i = 0; i < insn->arm64.op_count; i++)
420 if (insn->arm64.operands[i].type == op_type)
421 count++;
422 break;
423 case CS_ARCH_X86:
424 for (i = 0; i < insn->x86.op_count; i++)
425 if (insn->x86.operands[i].type == op_type)
426 count++;
427 break;
428 case CS_ARCH_MIPS:
429 for (i = 0; i < insn->mips.op_count; i++)
430 if (insn->mips.operands[i].type == op_type)
431 count++;
432 break;
433 }
434
435 return count;
436}
437
438int cs_op_index(csh ud, cs_insn *insn, unsigned int op_type,
439 unsigned int post)
440{
441 if (!ud)
442 return -1;
443
444 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
445 unsigned int count = 0, i;
446
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800447 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800448
449 switch (handle->arch) {
450 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800451 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800452 return -1;
453 case CS_ARCH_ARM:
454 for (i = 0; i < insn->arm.op_count; i++) {
455 if (insn->arm.operands[i].type == op_type)
456 count++;
457 if (count == post)
458 return i;
459 }
460 break;
461 case CS_ARCH_ARM64:
462 for (i = 0; i < insn->arm64.op_count; i++) {
463 if (insn->arm64.operands[i].type == op_type)
464 count++;
465 if (count == post)
466 return i;
467 }
468 break;
469 case CS_ARCH_X86:
470 for (i = 0; i < insn->x86.op_count; i++) {
471 if (insn->x86.operands[i].type == op_type)
472 count++;
473 if (count == post)
474 return i;
475 }
476 break;
477 case CS_ARCH_MIPS:
478 for (i = 0; i < insn->mips.op_count; i++) {
479 if (insn->mips.operands[i].type == op_type)
480 count++;
481 if (count == post)
482 return i;
483 }
484 break;
485 }
486
487 return -1;
488}