blob: 250fa22e3d6948761e4c9fbf687f94b4640299e6 [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:
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
169// fill insn with mnemonic & operands info
170static void fill_insn(cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
171 PostPrinter_t printer)
172{
173 memcpy(insn, &mci->pub_insn, sizeof(*insn));
174
175 // map internal instruction opcode to public insn ID
Nguyen Anh Quynhad61c492013-11-30 16:23:31 +0800176 if (handle->insn_id)
177 handle->insn_id(insn, MCInst_getOpcode(mci));
178
179 // alias instruction might have ID saved in OpcodePub
Nguyen Anh Quynh6b7abe32013-11-30 00:54:24 +0800180 if (MCInst_getOpcodePub(mci))
Nguyen Anh Quynhad61c492013-11-30 16:23:31 +0800181 insn->id = MCInst_getOpcodePub(mci);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800182
183 if (printer)
184 printer(insn->id, insn, buffer);
185
186 // fill in mnemonic & operands
187 char *tab = strchr(buffer, '\t');
188 if (tab) {
189 *tab = '\0';
190 strncpy(insn->op_str, tab + 1, sizeof(insn->op_str) - 1);
191 insn->op_str[sizeof(insn->op_str) - 1] = '\0';
192 } else
193 insn->op_str[0] = '\0';
194
195 strncpy(insn->mnemonic, buffer, sizeof(insn->mnemonic) - 1);
196 insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
197}
198
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800199cs_err cs_option(csh ud, unsigned int option)
200{
201 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
202 if (!handle)
203 return CS_ERR_CSH;
204
205 if (option & CS_OPT_X86_INTEL)
206 handle->printer = X86_Intel_printInst;
207
208 if (option & CS_OPT_X86_ATT)
209 handle->printer = X86_ATT_printInst;
210
211 return CS_ERR_OK;
212}
213
pancakec04f8732013-12-03 02:51:46 +0100214size_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 +0800215{
216 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
217 MCInst mci;
218 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800219 size_t c = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800220
221 if (!handle) {
222 // FIXME: handle this case?
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800223 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800224 return 0;
225 }
226
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800227 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800228
229 while (size > 0) {
230 MCInst_Init(&mci);
231
232 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
233 if (r) {
234 SStream ss;
235 SStream_Init(&ss);
236
237 mci.pub_insn.size = insn_size;
238 mci.pub_insn.address = offset;
239 mci.mode = handle->mode;
240 handle->printer(&mci, &ss, handle->printer_info);
241
242 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer);
243
244 c++;
245 insn++;
246 buffer += insn_size;
247 size -= insn_size;
248 offset += insn_size;
249
250 if (count > 0) {
251 if (c == count)
252 return c;
253 }
254 } else // face a broken instruction?
255 return c;
256 }
257
258 return c;
259}
260
261// dynamicly allocate memory to contain disasm insn
262// NOTE: caller must free() the allocated memory itself to avoid memory leaking
pancakec04f8732013-12-03 02:51:46 +0100263size_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 +0800264{
265 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
266 MCInst mci;
267 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800268 size_t c = 0, f = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800269 cs_insn insn_cache[64];
270 void *total = NULL;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800271 size_t total_size = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800272
273 if (!handle) {
274 // FIXME: how to handle this case:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800275 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800276 return 0;
277 }
278
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800279 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800280
281 while (size > 0) {
282 MCInst_Init(&mci);
283
284 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
285 if (r) {
286 SStream ss;
287 SStream_Init(&ss);
288
289 mci.pub_insn.size = insn_size;
290 mci.pub_insn.address = offset;
291 mci.mode = handle->mode;
292 handle->printer(&mci, &ss, handle->printer_info);
293
294 fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer);
295 f++;
296
297 if (f == ARR_SIZE(insn_cache)) {
298 // resize total to contain newly disasm insns
299 total_size += sizeof(insn_cache);
300 void *tmp = realloc(total, total_size);
301 if (tmp == NULL) { // insufficient memory
302 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800303 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800304 return 0;
305 }
306
307 total = tmp;
308 memcpy(total + total_size - sizeof(insn_cache), insn_cache, sizeof(insn_cache));
309 // reset f back to 0
310 f = 0;
311 }
312
313 c++;
314 buffer += insn_size;
315 size -= insn_size;
316 offset += insn_size;
317
318 if (count > 0 && c == count)
319 break;
320 } else // encounter a broken instruction
321 break;
322 }
323
324 if (f) {
325 // resize total to contain newly disasm insns
326 void *tmp = realloc(total, total_size + f * sizeof(insn_cache[0]));
327 if (tmp == NULL) { // insufficient memory
328 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800329 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800330 return 0;
331 }
332
333 total = tmp;
334 memcpy(total + total_size, insn_cache, f * sizeof(insn_cache[0]));
335 }
336
337 *insn = total;
338
339 return c;
340}
341
342void cs_free(void *m)
343{
344 free(m);
345}
346
347// return friendly name of regiser in a string
348char *cs_reg_name(csh ud, unsigned int reg)
349{
350 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
351
352 if (!handle || handle->reg_name == NULL) {
353 return NULL;
354 }
355
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800356 return handle->reg_name(reg);
357}
358
359char *cs_insn_name(csh ud, unsigned int insn)
360{
361 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
362
363 if (!handle || handle->insn_name == NULL) {
364 return NULL;
365 }
366
367 return handle->insn_name(insn);
368}
369
370static bool arr_exist(unsigned int *arr, int max, unsigned int id)
371{
372 int i;
373
374 for (i = 0; i < max; i++) {
375 if (arr[i] == id)
376 return true;
377 }
378
379 return false;
380}
381
382bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
383{
384 if (!handle)
385 return false;
386
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800387 return arr_exist(insn->groups, insn->groups_count, group_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800388}
389
390bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
391{
392 if (!handle)
393 return false;
394
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800395 return arr_exist(insn->regs_read, insn->regs_read_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800396}
397
398bool cs_reg_write(csh handle, cs_insn *insn, unsigned int reg_id)
399{
400 if (!handle)
401 return false;
402
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800403 return arr_exist(insn->regs_write, insn->regs_write_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800404}
405
406int cs_op_count(csh ud, cs_insn *insn, unsigned int op_type)
407{
408 if (!ud)
409 return -1;
410
411 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
412 unsigned int count = 0, i;
413
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800414 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800415
416 switch (handle->arch) {
417 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800418 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800419 return -1;
420 case CS_ARCH_ARM:
421 for (i = 0; i < insn->arm.op_count; i++)
422 if (insn->arm.operands[i].type == op_type)
423 count++;
424 break;
425 case CS_ARCH_ARM64:
426 for (i = 0; i < insn->arm64.op_count; i++)
427 if (insn->arm64.operands[i].type == op_type)
428 count++;
429 break;
430 case CS_ARCH_X86:
431 for (i = 0; i < insn->x86.op_count; i++)
432 if (insn->x86.operands[i].type == op_type)
433 count++;
434 break;
435 case CS_ARCH_MIPS:
436 for (i = 0; i < insn->mips.op_count; i++)
437 if (insn->mips.operands[i].type == op_type)
438 count++;
439 break;
440 }
441
442 return count;
443}
444
445int cs_op_index(csh ud, cs_insn *insn, unsigned int op_type,
446 unsigned int post)
447{
448 if (!ud)
449 return -1;
450
451 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
452 unsigned int count = 0, i;
453
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800454 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800455
456 switch (handle->arch) {
457 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800458 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800459 return -1;
460 case CS_ARCH_ARM:
461 for (i = 0; i < insn->arm.op_count; i++) {
462 if (insn->arm.operands[i].type == op_type)
463 count++;
464 if (count == post)
465 return i;
466 }
467 break;
468 case CS_ARCH_ARM64:
469 for (i = 0; i < insn->arm64.op_count; i++) {
470 if (insn->arm64.operands[i].type == op_type)
471 count++;
472 if (count == post)
473 return i;
474 }
475 break;
476 case CS_ARCH_X86:
477 for (i = 0; i < insn->x86.op_count; i++) {
478 if (insn->x86.operands[i].type == op_type)
479 count++;
480 if (count == post)
481 return i;
482 }
483 break;
484 case CS_ARCH_MIPS:
485 for (i = 0; i < insn->mips.op_count; i++) {
486 if (insn->mips.operands[i].type == op_type)
487 count++;
488 if (count == post)
489 return i;
490 }
491 break;
492 }
493
494 return -1;
495}