1/* Capstone Disassembly Engine */
2/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */
3#if defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)
4#pragma warning(disable:4996) // disable MSVC's warning on strcpy()
5#pragma warning(disable:28719) // disable MSVC's warning on strcpy()
6#endif
7#if defined(CAPSTONE_HAS_OSXKERNEL)
8#include <libkern/libkern.h>
9#else
10#include <stddef.h>
11#include <stdio.h>
12#include <stdlib.h>
13#endif
14
15#include <string.h>
16#include <capstone.h>
17
18#include "utils.h"
19#include "MCRegisterInfo.h"
20
21#if defined(_KERNEL_MODE)
22#include "windows\winkernel_mm.h"
23#endif
24
25// Issue #681: Windows kernel does not support formatting float point
26#if defined(_KERNEL_MODE) && !defined(CAPSTONE_DIET)
27#if defined(CAPSTONE_HAS_ARM) || defined(CAPSTONE_HAS_ARM64)
28#define CAPSTONE_STR_INTERNAL(x) #x
29#define CAPSTONE_STR(x) CAPSTONE_STR_INTERNAL(x)
30#define CAPSTONE_MSVC_WRANING_PREFIX __FILE__ "("CAPSTONE_STR(__LINE__)") : warning message : "
31
32#pragma message(CAPSTONE_MSVC_WRANING_PREFIX "Windows driver does not support full features for selected architecture(s). Define CAPSTONE_DIET to compile Capstone with only supported features. See issue #681 for details.")
33
34#undef CAPSTONE_MSVC_WRANING_PREFIX
35#undef CAPSTONE_STR
36#undef CAPSTONE_STR_INTERNAL
37#endif
38#endif // defined(_KERNEL_MODE) && !defined(CAPSTONE_DIET)
39
40#if !defined(CAPSTONE_HAS_OSXKERNEL) && !defined(CAPSTONE_DIET) && !defined(_KERNEL_MODE)
41#define INSN_CACHE_SIZE 32
42#else
43// reduce stack variable size for kernel/firmware
44#define INSN_CACHE_SIZE 8
45#endif
46
47// default SKIPDATA mnemonic
48#ifndef CAPSTONE_DIET
49#define SKIPDATA_MNEM ".byte"
50#else // No printing is available in diet mode
51#define SKIPDATA_MNEM NULL
52#endif
53
54cs_err (*arch_init[MAX_ARCH])(cs_struct *) = { NULL };
55cs_err (*arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t value) = { NULL };
56void (*arch_destroy[MAX_ARCH]) (cs_struct *) = { NULL };
57cs_mode arch_disallowed_mode_mask[MAX_ARCH] = { 0 };
58
59extern void ARM_enable(void);
60extern void AArch64_enable(void);
61extern void Mips_enable(void);
62extern void X86_enable(void);
63extern void PPC_enable(void);
64extern void Sparc_enable(void);
65extern void SystemZ_enable(void);
66extern void XCore_enable(void);
67
68static void archs_enable(void)
69{
70 static bool initialized = false;
71
72 if (initialized)
73 return;
74
75#ifdef CAPSTONE_HAS_ARM
76 ARM_enable();
77#endif
78#ifdef CAPSTONE_HAS_ARM64
79 AArch64_enable();
80#endif
81#ifdef CAPSTONE_HAS_MIPS
82 Mips_enable();
83#endif
84#ifdef CAPSTONE_HAS_POWERPC
85 PPC_enable();
86#endif
87#ifdef CAPSTONE_HAS_SPARC
88 Sparc_enable();
89#endif
90#ifdef CAPSTONE_HAS_SYSZ
91 SystemZ_enable();
92#endif
93#ifdef CAPSTONE_HAS_X86
94 X86_enable();
95#endif
96#ifdef CAPSTONE_HAS_XCORE
97 XCore_enable();
98#endif
99
100
101 initialized = true;
102}
103
104unsigned int all_arch = 0;
105
106#if defined(CAPSTONE_USE_SYS_DYN_MEM)
107#if !defined(CAPSTONE_HAS_OSXKERNEL) && !defined(_KERNEL_MODE)
108cs_malloc_t cs_mem_malloc = malloc;
109cs_calloc_t cs_mem_calloc = calloc;
110cs_realloc_t cs_mem_realloc = realloc;
111cs_free_t cs_mem_free = free;
112cs_vsnprintf_t cs_vsnprintf = vsnprintf;
113#elif defined(_KERNEL_MODE)
114cs_malloc_t cs_mem_malloc = cs_winkernel_malloc;
115cs_calloc_t cs_mem_calloc = cs_winkernel_calloc;
116cs_realloc_t cs_mem_realloc = cs_winkernel_realloc;
117cs_free_t cs_mem_free = cs_winkernel_free;
118cs_vsnprintf_t cs_vsnprintf = cs_winkernel_vsnprintf;
119#else
120extern void* kern_os_malloc(size_t size);
121extern void kern_os_free(void* addr);
122extern void* kern_os_realloc(void* addr, size_t nsize);
123
124static void* cs_kern_os_calloc(size_t num, size_t size)
125{
126 return kern_os_malloc(num * size); // malloc bzeroes the buffer
127}
128
129cs_malloc_t cs_mem_malloc = kern_os_malloc;
130cs_calloc_t cs_mem_calloc = cs_kern_os_calloc;
131cs_realloc_t cs_mem_realloc = kern_os_realloc;
132cs_free_t cs_mem_free = kern_os_free;
133cs_vsnprintf_t cs_vsnprintf = vsnprintf;
134#endif
135#else
136cs_malloc_t cs_mem_malloc = NULL;
137cs_calloc_t cs_mem_calloc = NULL;
138cs_realloc_t cs_mem_realloc = NULL;
139cs_free_t cs_mem_free = NULL;
140cs_vsnprintf_t cs_vsnprintf = NULL;
141#endif
142
143CAPSTONE_EXPORT
144unsigned int CAPSTONE_API cs_version(int *major, int *minor)
145{
146 archs_enable();
147
148 if (major != NULL && minor != NULL) {
149 *major = CS_API_MAJOR;
150 *minor = CS_API_MINOR;
151 }
152
153 return (CS_API_MAJOR << 8) + CS_API_MINOR;
154}
155
156CAPSTONE_EXPORT
157bool CAPSTONE_API cs_support(int query)
158{
159 archs_enable();
160
161 if (query == CS_ARCH_ALL)
162 return all_arch == ((1 << CS_ARCH_ARM) | (1 << CS_ARCH_ARM64) |
163 (1 << CS_ARCH_MIPS) | (1 << CS_ARCH_X86) |
164 (1 << CS_ARCH_PPC) | (1 << CS_ARCH_SPARC) |
165 (1 << CS_ARCH_SYSZ) | (1 << CS_ARCH_XCORE));
166
167 if ((unsigned int)query < CS_ARCH_MAX)
168 return all_arch & (1 << query);
169
170 if (query == CS_SUPPORT_DIET) {
171#ifdef CAPSTONE_DIET
172 return true;
173#else
174 return false;
175#endif
176 }
177
178 if (query == CS_SUPPORT_X86_REDUCE) {
179#if defined(CAPSTONE_HAS_X86) && defined(CAPSTONE_X86_REDUCE)
180 return true;
181#else
182 return false;
183#endif
184 }
185
186 // unsupported query
187 return false;
188}
189
190CAPSTONE_EXPORT
191cs_err CAPSTONE_API cs_errno(csh handle)
192{
193 struct cs_struct *ud;
194 if (!handle)
195 return CS_ERR_CSH;
196
197 ud = (struct cs_struct *)(uintptr_t)handle;
198
199 return ud->errnum;
200}
201
202CAPSTONE_EXPORT
203const char * CAPSTONE_API cs_strerror(cs_err code)
204{
205 switch(code) {
206 default:
207 return "Unknown error code";
208 case CS_ERR_OK:
209 return "OK (CS_ERR_OK)";
210 case CS_ERR_MEM:
211 return "Out of memory (CS_ERR_MEM)";
212 case CS_ERR_ARCH:
213 return "Invalid architecture (CS_ERR_ARCH)";
214 case CS_ERR_HANDLE:
215 return "Invalid handle (CS_ERR_HANDLE)";
216 case CS_ERR_CSH:
217 return "Invalid csh (CS_ERR_CSH)";
218 case CS_ERR_MODE:
219 return "Invalid mode (CS_ERR_MODE)";
220 case CS_ERR_OPTION:
221 return "Invalid option (CS_ERR_OPTION)";
222 case CS_ERR_DETAIL:
223 return "Details are unavailable (CS_ERR_DETAIL)";
224 case CS_ERR_MEMSETUP:
225 return "Dynamic memory management uninitialized (CS_ERR_MEMSETUP)";
226 case CS_ERR_VERSION:
227 return "Different API version between core & binding (CS_ERR_VERSION)";
228 case CS_ERR_DIET:
229 return "Information irrelevant in diet engine (CS_ERR_DIET)";
230 case CS_ERR_SKIPDATA:
231 return "Information irrelevant for 'data' instruction in SKIPDATA mode (CS_ERR_SKIPDATA)";
232 }
233}
234
235CAPSTONE_EXPORT
236cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle)
237{
238 cs_err err;
239 struct cs_struct *ud;
240 if (!cs_mem_malloc || !cs_mem_calloc || !cs_mem_realloc || !cs_mem_free || !cs_vsnprintf)
241 // Error: before cs_open(), dynamic memory management must be initialized
242 // with cs_option(CS_OPT_MEM)
243 return CS_ERR_MEMSETUP;
244
245 archs_enable();
246
247 if (arch < CS_ARCH_MAX && arch_init[arch]) {
248 // verify if requested mode is valid
249 if (mode & arch_disallowed_mode_mask[arch]) {
250 *handle = 0;
251 return CS_ERR_MODE;
252 }
253
254 ud = cs_mem_calloc(1, sizeof(*ud));
255 if (!ud) {
256 // memory insufficient
257 return CS_ERR_MEM;
258 }
259
260 ud->errnum = CS_ERR_OK;
261 ud->arch = arch;
262 ud->mode = mode;
263 // by default, do not break instruction into details
264 ud->detail = CS_OPT_OFF;
265
266 // default skipdata setup
267 ud->skipdata_setup.mnemonic = SKIPDATA_MNEM;
268
269 err = arch_init[ud->arch](ud);
270 if (err) {
271 cs_mem_free(ud);
272 *handle = 0;
273 return err;
274 }
275
276 *handle = (uintptr_t)ud;
277
278 return CS_ERR_OK;
279 } else {
280 *handle = 0;
281 return CS_ERR_ARCH;
282 }
283}
284
285CAPSTONE_EXPORT
286cs_err CAPSTONE_API cs_close(csh *handle)
287{
288 struct cs_struct *ud;
289
290 if (*handle == 0)
291 // invalid handle
292 return CS_ERR_CSH;
293
294 ud = (struct cs_struct *)(*handle);
295
296 if (ud->printer_info)
297 cs_mem_free(ud->printer_info);
298
299 cs_mem_free(ud->insn_cache);
300
301 memset(ud, 0, sizeof(*ud));
302 cs_mem_free(ud);
303
304 // invalidate this handle by ZERO out its value.
305 // this is to make sure it is unusable after cs_close()
306 *handle = 0;
307
308 return CS_ERR_OK;
309}
310
311// fill insn with mnemonic & operands info
312static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
313 PostPrinter_t postprinter, const uint8_t *code)
314{
315#ifndef CAPSTONE_DIET
316 char *sp, *mnem;
317#endif
318 uint16_t copy_size = MIN(sizeof(insn->bytes), insn->size);
319
320 // fill the instruction bytes.
321 // we might skip some redundant bytes in front in the case of X86
322 memcpy(insn->bytes, code + insn->size - copy_size, copy_size);
323 insn->size = copy_size;
324
325 // alias instruction might have ID saved in OpcodePub
326 if (MCInst_getOpcodePub(mci))
327 insn->id = MCInst_getOpcodePub(mci);
328
329 // post printer handles some corner cases (hacky)
330 if (postprinter)
331 postprinter((csh)handle, insn, buffer, mci);
332
333#ifndef CAPSTONE_DIET
334 // fill in mnemonic & operands
335 // find first space or tab
336 mnem = insn->mnemonic;
337 for (sp = buffer; *sp; sp++) {
338 if (*sp == ' '|| *sp == '\t')
339 break;
340 if (*sp == '|') // lock|rep prefix for x86
341 *sp = ' ';
342 // copy to @mnemonic
343 *mnem = *sp;
344 mnem++;
345 }
346
347 *mnem = '\0';
348
349 // copy @op_str
350 if (*sp) {
351 // find the next non-space char
352 sp++;
353 for (; ((*sp == ' ') || (*sp == '\t')); sp++);
354 strncpy(insn->op_str, sp, sizeof(insn->op_str) - 1);
355 insn->op_str[sizeof(insn->op_str) - 1] = '\0';
356 } else
357 insn->op_str[0] = '\0';
358#endif
359}
360
361// how many bytes will we skip when encountering data (CS_OPT_SKIPDATA)?
362// this very much depends on instruction alignment requirement of each arch.
363static uint8_t skipdata_size(cs_struct *handle)
364{
365 switch(handle->arch) {
366 default:
367 // should never reach
368 return (uint8_t)-1;
369 case CS_ARCH_ARM:
370 // skip 2 bytes on Thumb mode.
371 if (handle->mode & CS_MODE_THUMB)
372 return 2;
373 // otherwise, skip 4 bytes
374 return 4;
375 case CS_ARCH_ARM64:
376 case CS_ARCH_MIPS:
377 case CS_ARCH_PPC:
378 case CS_ARCH_SPARC:
379 // skip 4 bytes
380 return 4;
381 case CS_ARCH_SYSZ:
382 // SystemZ instruction's length can be 2, 4 or 6 bytes,
383 // so we just skip 2 bytes
384 return 2;
385 case CS_ARCH_X86:
386 // X86 has no restriction on instruction alignment
387 return 1;
388 case CS_ARCH_XCORE:
389 // XCore instruction's length can be 2 or 4 bytes,
390 // so we just skip 2 bytes
391 return 2;
392 }
393}
394
395CAPSTONE_EXPORT
396cs_err CAPSTONE_API cs_option(csh ud, cs_opt_type type, size_t value)
397{
398 struct cs_struct *handle;
399 archs_enable();
400
401 // cs_option() can be called with NULL handle just for CS_OPT_MEM
402 // This is supposed to be executed before all other APIs (even cs_open())
403 if (type == CS_OPT_MEM) {
404 cs_opt_mem *mem = (cs_opt_mem *)value;
405
406 cs_mem_malloc = mem->malloc;
407 cs_mem_calloc = mem->calloc;
408 cs_mem_realloc = mem->realloc;
409 cs_mem_free = mem->free;
410 cs_vsnprintf = mem->vsnprintf;
411
412 return CS_ERR_OK;
413 }
414
415 handle = (struct cs_struct *)(uintptr_t)ud;
416 if (!handle)
417 return CS_ERR_CSH;
418
419 switch(type) {
420 default:
421 break;
422 case CS_OPT_DETAIL:
423 handle->detail = (cs_opt_value)value;
424 return CS_ERR_OK;
425 case CS_OPT_SKIPDATA:
426 handle->skipdata = (value == CS_OPT_ON);
427 if (handle->skipdata) {
428 if (handle->skipdata_size == 0) {
429 // set the default skipdata size
430 handle->skipdata_size = skipdata_size(handle);
431 }
432 }
433 return CS_ERR_OK;
434 case CS_OPT_SKIPDATA_SETUP:
435 if (value)
436 handle->skipdata_setup = *((cs_opt_skipdata *)value);
437 return CS_ERR_OK;
438 case CS_OPT_MODE:
439 // verify if requested mode is valid
440 if (value & arch_disallowed_mode_mask[handle->arch]) {
441 return CS_ERR_OPTION;
442 }
443 break;
444 }
445
446 return arch_option[handle->arch](handle, type, value);
447}
448
449// generate @op_str for data instruction of SKIPDATA
450#ifndef CAPSTONE_DIET
451static void skipdata_opstr(char *opstr, const uint8_t *buffer, size_t size)
452{
453 char *p = opstr;
454 int len;
455 size_t i;
456 size_t available = sizeof(((cs_insn*)NULL)->op_str);
457
458 if (!size) {
459 opstr[0] = '\0';
460 return;
461 }
462
463 len = cs_snprintf(p, available, "0x%02x", buffer[0]);
464 p+= len;
465 available -= len;
466
467 for(i = 1; i < size; i++) {
468 len = cs_snprintf(p, available, ", 0x%02x", buffer[i]);
469 if (len < 0) {
470 break;
471 }
472 if ((size_t)len > available - 1) {
473 break;
474 }
475 p+= len;
476 available -= len;
477 }
478}
479#endif
480
481// dynamicly allocate memory to contain disasm insn
482// NOTE: caller must free() the allocated memory itself to avoid memory leaking
483CAPSTONE_EXPORT
484size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
485{
486 struct cs_struct *handle;
487 MCInst mci;
488 uint16_t insn_size;
489 size_t c = 0, i;
490 unsigned int f = 0; // index of the next instruction in the cache
491 cs_insn *insn_cache; // cache contains disassembled instructions
492 void *total = NULL;
493 size_t total_size = 0; // total size of output buffer containing all insns
494 bool r;
495 void *tmp;
496 size_t skipdata_bytes;
497 uint64_t offset_org; // save all the original info of the buffer
498 size_t size_org;
499 const uint8_t *buffer_org;
500 unsigned int cache_size = INSN_CACHE_SIZE;
501 size_t next_offset;
502
503 handle = (struct cs_struct *)(uintptr_t)ud;
504 if (!handle) {
505 // FIXME: how to handle this case:
506 // handle->errnum = CS_ERR_HANDLE;
507 return 0;
508 }
509
510 handle->errnum = CS_ERR_OK;
511
512 // reset IT block of ARM structure
513 if (handle->arch == CS_ARCH_ARM)
514 handle->ITBlock.size = 0;
515
516#ifdef CAPSTONE_USE_SYS_DYN_MEM
517 if (count > 0 && count <= INSN_CACHE_SIZE)
518 cache_size = (unsigned int) count;
519#endif
520
521 // save the original offset for SKIPDATA
522 buffer_org = buffer;
523 offset_org = offset;
524 size_org = size;
525
526 total_size = sizeof(cs_insn) * cache_size;
527 total = cs_mem_malloc(total_size);
528 if (total == NULL) {
529 // insufficient memory
530 handle->errnum = CS_ERR_MEM;
531 return 0;
532 }
533
534 insn_cache = total;
535
536 while (size > 0) {
537 MCInst_Init(&mci);
538 mci.csh = handle;
539
540 // relative branches need to know the address & size of current insn
541 mci.address = offset;
542
543 if (handle->detail) {
544 // allocate memory for @detail pointer
545 insn_cache->detail = cs_mem_malloc(sizeof(cs_detail));
546 } else {
547 insn_cache->detail = NULL;
548 }
549
550 // save all the information for non-detailed mode
551 mci.flat_insn = insn_cache;
552 mci.flat_insn->address = offset;
553#ifdef CAPSTONE_DIET
554 // zero out mnemonic & op_str
555 mci.flat_insn->mnemonic[0] = '\0';
556 mci.flat_insn->op_str[0] = '\0';
557#endif
558
559 r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
560 if (r) {
561 SStream ss;
562 SStream_Init(&ss);
563
564 mci.flat_insn->size = insn_size;
565
566 // map internal instruction opcode to public insn ID
567
568 handle->insn_id(handle, insn_cache, mci.Opcode);
569
570 handle->printer(&mci, &ss, handle->printer_info);
571
572 fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer);
573
574 next_offset = insn_size;
575 } else {
576 // encounter a broken instruction
577
578 // free memory of @detail pointer
579 if (handle->detail) {
580 cs_mem_free(insn_cache->detail);
581 }
582
583 // if there is no request to skip data, or remaining data is too small,
584 // then bail out
585 if (!handle->skipdata || handle->skipdata_size > size)
586 break;
587
588 if (handle->skipdata_setup.callback) {
589 skipdata_bytes = handle->skipdata_setup.callback(buffer_org, size_org,
590 (size_t)(offset - offset_org), handle->skipdata_setup.user_data);
591 if (skipdata_bytes > size)
592 // remaining data is not enough
593 break;
594
595 if (!skipdata_bytes)
596 // user requested not to skip data, so bail out
597 break;
598 } else
599 skipdata_bytes = handle->skipdata_size;
600
601 // we have to skip some amount of data, depending on arch & mode
602 insn_cache->id = 0; // invalid ID for this "data" instruction
603 insn_cache->address = offset;
604 insn_cache->size = (uint16_t)skipdata_bytes;
605 memcpy(insn_cache->bytes, buffer, skipdata_bytes);
606#ifdef CAPSTONE_DIET
607 insn_cache->mnemonic[0] = '\0';
608 insn_cache->op_str[0] = '\0';
609#else
610 strncpy(insn_cache->mnemonic, handle->skipdata_setup.mnemonic,
611 sizeof(insn_cache->mnemonic) - 1);
612 skipdata_opstr(insn_cache->op_str, buffer, skipdata_bytes);
613#endif
614 insn_cache->detail = NULL;
615
616 next_offset = skipdata_bytes;
617 }
618
619 // one more instruction entering the cache
620 f++;
621
622 // one more instruction disassembled
623 c++;
624 if (count > 0 && c == count)
625 // already got requested number of instructions
626 break;
627
628 if (f == cache_size) {
629 // full cache, so expand the cache to contain incoming insns
630 cache_size = cache_size * 8 / 5; // * 1.6 ~ golden ratio
631 total_size += (sizeof(cs_insn) * cache_size);
632 tmp = cs_mem_realloc(total, total_size);
633 if (tmp == NULL) { // insufficient memory
634 if (handle->detail) {
635 insn_cache = (cs_insn *)total;
636 for (i = 0; i < c; i++, insn_cache++)
637 cs_mem_free(insn_cache->detail);
638 }
639
640 cs_mem_free(total);
641 *insn = NULL;
642 handle->errnum = CS_ERR_MEM;
643 return 0;
644 }
645
646 total = tmp;
647 // continue to fill in the cache after the last instruction
648 insn_cache = (cs_insn *)((char *)total + sizeof(cs_insn) * c);
649
650 // reset f back to 0, so we fill in the cache from begining
651 f = 0;
652 } else
653 insn_cache++;
654
655 buffer += next_offset;
656 size -= next_offset;
657 offset += next_offset;
658 }
659
660 if (!c) {
661 // we did not disassemble any instruction
662 cs_mem_free(total);
663 total = NULL;
664 } else if (f != cache_size) {
665 // total did not fully use the last cache, so downsize it
666 tmp = cs_mem_realloc(total, total_size - (cache_size - f) * sizeof(*insn_cache));
667 if (tmp == NULL) { // insufficient memory
668 // free all detail pointers
669 if (handle->detail) {
670 insn_cache = (cs_insn *)total;
671 for (i = 0; i < c; i++, insn_cache++)
672 cs_mem_free(insn_cache->detail);
673 }
674
675 cs_mem_free(total);
676 *insn = NULL;
677
678 handle->errnum = CS_ERR_MEM;
679 return 0;
680 }
681
682 total = tmp;
683 }
684
685 *insn = total;
686
687 return c;
688}
689
690CAPSTONE_EXPORT
691CAPSTONE_DEPRECATED
692size_t CAPSTONE_API cs_disasm_ex(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
693{
694 return cs_disasm(ud, buffer, size, offset, count, insn);
695}
696
697CAPSTONE_EXPORT
698void CAPSTONE_API cs_free(cs_insn *insn, size_t count)
699{
700 size_t i;
701
702 // free all detail pointers
703 for (i = 0; i < count; i++)
704 cs_mem_free(insn[i].detail);
705
706 // then free pointer to cs_insn array
707 cs_mem_free(insn);
708}
709
710CAPSTONE_EXPORT
711cs_insn * CAPSTONE_API cs_malloc(csh ud)
712{
713 cs_insn *insn;
714 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
715
716 insn = cs_mem_malloc(sizeof(cs_insn));
717 if (!insn) {
718 // insufficient memory
719 handle->errnum = CS_ERR_MEM;
720 return NULL;
721 } else {
722 if (handle->detail) {
723 // allocate memory for @detail pointer
724 insn->detail = cs_mem_malloc(sizeof(cs_detail));
725 if (insn->detail == NULL) { // insufficient memory
726 cs_mem_free(insn);
727 handle->errnum = CS_ERR_MEM;
728 return NULL;
729 }
730 } else
731 insn->detail = NULL;
732 }
733
734 return insn;
735}
736
737// iterator for instruction "single-stepping"
738CAPSTONE_EXPORT
739bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size,
740 uint64_t *address, cs_insn *insn)
741{
742 struct cs_struct *handle;
743 uint16_t insn_size;
744 MCInst mci;
745 bool r;
746
747 handle = (struct cs_struct *)(uintptr_t)ud;
748 if (!handle) {
749 return false;
750 }
751
752 handle->errnum = CS_ERR_OK;
753
754 MCInst_Init(&mci);
755 mci.csh = handle;
756
757 // relative branches need to know the address & size of current insn
758 mci.address = *address;
759
760 // save all the information for non-detailed mode
761 mci.flat_insn = insn;
762 mci.flat_insn->address = *address;
763#ifdef CAPSTONE_DIET
764 // zero out mnemonic & op_str
765 mci.flat_insn->mnemonic[0] = '\0';
766 mci.flat_insn->op_str[0] = '\0';
767#endif
768
769 r = handle->disasm(ud, *code, *size, &mci, &insn_size, *address, handle->getinsn_info);
770 if (r) {
771 SStream ss;
772 SStream_Init(&ss);
773
774 mci.flat_insn->size = insn_size;
775
776 // map internal instruction opcode to public insn ID
777 handle->insn_id(handle, insn, mci.Opcode);
778
779 handle->printer(&mci, &ss, handle->printer_info);
780
781 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, *code);
782
783 *code += insn_size;
784 *size -= insn_size;
785 *address += insn_size;
786 } else { // encounter a broken instruction
787 size_t skipdata_bytes;
788
789 // if there is no request to skip data, or remaining data is too small,
790 // then bail out
791 if (!handle->skipdata || handle->skipdata_size > *size)
792 return false;
793
794 if (handle->skipdata_setup.callback) {
795 skipdata_bytes = handle->skipdata_setup.callback(*code, *size,
796 0, handle->skipdata_setup.user_data);
797 if (skipdata_bytes > *size)
798 // remaining data is not enough
799 return false;
800
801 if (!skipdata_bytes)
802 // user requested not to skip data, so bail out
803 return false;
804 } else
805 skipdata_bytes = handle->skipdata_size;
806
807 // we have to skip some amount of data, depending on arch & mode
808 insn->id = 0; // invalid ID for this "data" instruction
809 insn->address = *address;
810 insn->size = (uint16_t)skipdata_bytes;
811 memcpy(insn->bytes, *code, skipdata_bytes);
812#ifdef CAPSTONE_DIET
813 insn->mnemonic[0] = '\0';
814 insn->op_str[0] = '\0';
815#else
816 strncpy(insn->mnemonic, handle->skipdata_setup.mnemonic,
817 sizeof(insn->mnemonic) - 1);
818 skipdata_opstr(insn->op_str, *code, skipdata_bytes);
819#endif
820
821 *code += skipdata_bytes;
822 *size -= skipdata_bytes;
823 *address += skipdata_bytes;
824 }
825
826 return true;
827}
828
829// return friendly name of regiser in a string
830CAPSTONE_EXPORT
831const char * CAPSTONE_API cs_reg_name(csh ud, unsigned int reg)
832{
833 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
834
835 if (!handle || handle->reg_name == NULL) {
836 return NULL;
837 }
838
839 return handle->reg_name(ud, reg);
840}
841
842CAPSTONE_EXPORT
843const char * CAPSTONE_API cs_insn_name(csh ud, unsigned int insn)
844{
845 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
846
847 if (!handle || handle->insn_name == NULL) {
848 return NULL;
849 }
850
851 return handle->insn_name(ud, insn);
852}
853
854CAPSTONE_EXPORT
855const char * CAPSTONE_API cs_group_name(csh ud, unsigned int group)
856{
857 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
858
859 if (!handle || handle->group_name == NULL) {
860 return NULL;
861 }
862
863 return handle->group_name(ud, group);
864}
865
866static bool arr_exist(unsigned char *arr, unsigned char max, unsigned int id)
867{
868 int i;
869
870 for (i = 0; i < max; i++) {
871 if (arr[i] == id)
872 return true;
873 }
874
875 return false;
876}
877
878CAPSTONE_EXPORT
879bool CAPSTONE_API cs_insn_group(csh ud, const cs_insn *insn, unsigned int group_id)
880{
881 struct cs_struct *handle;
882 if (!ud)
883 return false;
884
885 handle = (struct cs_struct *)(uintptr_t)ud;
886
887 if (!handle->detail) {
888 handle->errnum = CS_ERR_DETAIL;
889 return false;
890 }
891
892 if(!insn->id) {
893 handle->errnum = CS_ERR_SKIPDATA;
894 return false;
895 }
896
897 if(!insn->detail) {
898 handle->errnum = CS_ERR_DETAIL;
899 return false;
900 }
901
902 return arr_exist(insn->detail->groups, insn->detail->groups_count, group_id);
903}
904
905CAPSTONE_EXPORT
906bool CAPSTONE_API cs_reg_read(csh ud, const cs_insn *insn, unsigned int reg_id)
907{
908 struct cs_struct *handle;
909 if (!ud)
910 return false;
911
912 handle = (struct cs_struct *)(uintptr_t)ud;
913
914 if (!handle->detail) {
915 handle->errnum = CS_ERR_DETAIL;
916 return false;
917 }
918
919 if(!insn->id) {
920 handle->errnum = CS_ERR_SKIPDATA;
921 return false;
922 }
923
924 if(!insn->detail) {
925 handle->errnum = CS_ERR_DETAIL;
926 return false;
927 }
928
929 return arr_exist(insn->detail->regs_read, insn->detail->regs_read_count, reg_id);
930}
931
932CAPSTONE_EXPORT
933bool CAPSTONE_API cs_reg_write(csh ud, const cs_insn *insn, unsigned int reg_id)
934{
935 struct cs_struct *handle;
936 if (!ud)
937 return false;
938
939 handle = (struct cs_struct *)(uintptr_t)ud;
940
941 if (!handle->detail) {
942 handle->errnum = CS_ERR_DETAIL;
943 return false;
944 }
945
946 if(!insn->id) {
947 handle->errnum = CS_ERR_SKIPDATA;
948 return false;
949 }
950
951 if(!insn->detail) {
952 handle->errnum = CS_ERR_DETAIL;
953 return false;
954 }
955
956 return arr_exist(insn->detail->regs_write, insn->detail->regs_write_count, reg_id);
957}
958
959CAPSTONE_EXPORT
960int CAPSTONE_API cs_op_count(csh ud, const cs_insn *insn, unsigned int op_type)
961{
962 struct cs_struct *handle;
963 unsigned int count = 0, i;
964 if (!ud)
965 return -1;
966
967 handle = (struct cs_struct *)(uintptr_t)ud;
968
969 if (!handle->detail) {
970 handle->errnum = CS_ERR_DETAIL;
971 return -1;
972 }
973
974 if(!insn->id) {
975 handle->errnum = CS_ERR_SKIPDATA;
976 return -1;
977 }
978
979 if(!insn->detail) {
980 handle->errnum = CS_ERR_DETAIL;
981 return -1;
982 }
983
984 handle->errnum = CS_ERR_OK;
985
986 switch (handle->arch) {
987 default:
988 handle->errnum = CS_ERR_HANDLE;
989 return -1;
990 case CS_ARCH_ARM:
991 for (i = 0; i < insn->detail->arm.op_count; i++)
992 if (insn->detail->arm.operands[i].type == (arm_op_type)op_type)
993 count++;
994 break;
995 case CS_ARCH_ARM64:
996 for (i = 0; i < insn->detail->arm64.op_count; i++)
997 if (insn->detail->arm64.operands[i].type == (arm64_op_type)op_type)
998 count++;
999 break;
1000 case CS_ARCH_X86:
1001 for (i = 0; i < insn->detail->x86.op_count; i++)
1002 if (insn->detail->x86.operands[i].type == (x86_op_type)op_type)
1003 count++;
1004 break;
1005 case CS_ARCH_MIPS:
1006 for (i = 0; i < insn->detail->mips.op_count; i++)
1007 if (insn->detail->mips.operands[i].type == (mips_op_type)op_type)
1008 count++;
1009 break;
1010 case CS_ARCH_PPC:
1011 for (i = 0; i < insn->detail->ppc.op_count; i++)
1012 if (insn->detail->ppc.operands[i].type == (ppc_op_type)op_type)
1013 count++;
1014 break;
1015 case CS_ARCH_SPARC:
1016 for (i = 0; i < insn->detail->sparc.op_count; i++)
1017 if (insn->detail->sparc.operands[i].type == (sparc_op_type)op_type)
1018 count++;
1019 break;
1020 case CS_ARCH_SYSZ:
1021 for (i = 0; i < insn->detail->sysz.op_count; i++)
1022 if (insn->detail->sysz.operands[i].type == (sysz_op_type)op_type)
1023 count++;
1024 break;
1025 case CS_ARCH_XCORE:
1026 for (i = 0; i < insn->detail->xcore.op_count; i++)
1027 if (insn->detail->xcore.operands[i].type == (xcore_op_type)op_type)
1028 count++;
1029 break;
1030 }
1031
1032 return count;
1033}
1034
1035CAPSTONE_EXPORT
1036int CAPSTONE_API cs_op_index(csh ud, const cs_insn *insn, unsigned int op_type,
1037 unsigned int post)
1038{
1039 struct cs_struct *handle;
1040 unsigned int count = 0, i;
1041 if (!ud)
1042 return -1;
1043
1044 handle = (struct cs_struct *)(uintptr_t)ud;
1045
1046 if (!handle->detail) {
1047 handle->errnum = CS_ERR_DETAIL;
1048 return -1;
1049 }
1050
1051 if(!insn->id) {
1052 handle->errnum = CS_ERR_SKIPDATA;
1053 return -1;
1054 }
1055
1056 if(!insn->detail) {
1057 handle->errnum = CS_ERR_DETAIL;
1058 return -1;
1059 }
1060
1061 handle->errnum = CS_ERR_OK;
1062
1063 switch (handle->arch) {
1064 default:
1065 handle->errnum = CS_ERR_HANDLE;
1066 return -1;
1067 case CS_ARCH_ARM:
1068 for (i = 0; i < insn->detail->arm.op_count; i++) {
1069 if (insn->detail->arm.operands[i].type == (arm_op_type)op_type)
1070 count++;
1071 if (count == post)
1072 return i;
1073 }
1074 break;
1075 case CS_ARCH_ARM64:
1076 for (i = 0; i < insn->detail->arm64.op_count; i++) {
1077 if (insn->detail->arm64.operands[i].type == (arm64_op_type)op_type)
1078 count++;
1079 if (count == post)
1080 return i;
1081 }
1082 break;
1083 case CS_ARCH_X86:
1084 for (i = 0; i < insn->detail->x86.op_count; i++) {
1085 if (insn->detail->x86.operands[i].type == (x86_op_type)op_type)
1086 count++;
1087 if (count == post)
1088 return i;
1089 }
1090 break;
1091 case CS_ARCH_MIPS:
1092 for (i = 0; i < insn->detail->mips.op_count; i++) {
1093 if (insn->detail->mips.operands[i].type == (mips_op_type)op_type)
1094 count++;
1095 if (count == post)
1096 return i;
1097 }
1098 break;
1099 case CS_ARCH_PPC:
1100 for (i = 0; i < insn->detail->ppc.op_count; i++) {
1101 if (insn->detail->ppc.operands[i].type == (ppc_op_type)op_type)
1102 count++;
1103 if (count == post)
1104 return i;
1105 }
1106 break;
1107 case CS_ARCH_SPARC:
1108 for (i = 0; i < insn->detail->sparc.op_count; i++) {
1109 if (insn->detail->sparc.operands[i].type == (sparc_op_type)op_type)
1110 count++;
1111 if (count == post)
1112 return i;
1113 }
1114 break;
1115 case CS_ARCH_SYSZ:
1116 for (i = 0; i < insn->detail->sysz.op_count; i++) {
1117 if (insn->detail->sysz.operands[i].type == (sysz_op_type)op_type)
1118 count++;
1119 if (count == post)
1120 return i;
1121 }
1122 break;
1123 case CS_ARCH_XCORE:
1124 for (i = 0; i < insn->detail->xcore.op_count; i++) {
1125 if (insn->detail->xcore.operands[i].type == (xcore_op_type)op_type)
1126 count++;
1127 if (count == post)
1128 return i;
1129 }
1130 break;
1131 }
1132
1133 return -1;
1134}
1135