1 /* Capstone Disassembly Engine */
2 /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */
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 <Availability.h>
9 #include <libkern/libkern.h>
10 #else
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #endif
15
16 #include <string.h>
17 #include <capstone/capstone.h>
18
19 #include "utils.h"
20 #include "MCRegisterInfo.h"
21
22 #if defined(_KERNEL_MODE)
23 #include "windows\winkernel_mm.h"
24 #endif
25
26 // Issue #681: Windows kernel does not support formatting float point
27 #if defined(_KERNEL_MODE) && !defined(CAPSTONE_DIET)
28 #if defined(CAPSTONE_HAS_ARM) || defined(CAPSTONE_HAS_ARM64) || defined(CAPSTONE_HAS_M68K)
29 #define CAPSTONE_STR_INTERNAL(x) #x
30 #define CAPSTONE_STR(x) CAPSTONE_STR_INTERNAL(x)
31 #define CAPSTONE_MSVC_WRANING_PREFIX __FILE__ "("CAPSTONE_STR(__LINE__)") : warning message : "
32
33 #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.")
34
35 #undef CAPSTONE_MSVC_WRANING_PREFIX
36 #undef CAPSTONE_STR
37 #undef CAPSTONE_STR_INTERNAL
38 #endif
39 #endif // defined(_KERNEL_MODE) && !defined(CAPSTONE_DIET)
40
41 #if !defined(CAPSTONE_HAS_OSXKERNEL) && !defined(CAPSTONE_DIET) && !defined(_KERNEL_MODE)
42 #define INSN_CACHE_SIZE 32
43 #else
44 // reduce stack variable size for kernel/firmware
45 #define INSN_CACHE_SIZE 8
46 #endif
47
48 // default SKIPDATA mnemonic
49 #ifndef CAPSTONE_DIET
50 #define SKIPDATA_MNEM ".byte"
51 #else // No printing is available in diet mode
52 #define SKIPDATA_MNEM NULL
53 #endif
54
55 #include "arch/AArch64/AArch64Module.h"
56 #include "arch/ARM/ARMModule.h"
57 #include "arch/EVM/EVMModule.h"
58 #include "arch/WASM/WASMModule.h"
59 #include "arch/M680X/M680XModule.h"
60 #include "arch/M68K/M68KModule.h"
61 #include "arch/Mips/MipsModule.h"
62 #include "arch/PowerPC/PPCModule.h"
63 #include "arch/Sparc/SparcModule.h"
64 #include "arch/SystemZ/SystemZModule.h"
65 #include "arch/TMS320C64x/TMS320C64xModule.h"
66 #include "arch/X86/X86Module.h"
67 #include "arch/XCore/XCoreModule.h"
68 #include "arch/RISCV/RISCVModule.h"
69 #include "arch/MOS65XX/MOS65XXModule.h"
70 #include "arch/BPF/BPFModule.h"
71
72 static const struct {
73 // constructor initialization
74 cs_err (*arch_init)(cs_struct *);
75 // support cs_option()
76 cs_err (*arch_option)(cs_struct *, cs_opt_type, size_t value);
77 // bitmask for finding disallowed modes for an arch:
78 // to be called in cs_open()/cs_option()
79 cs_mode arch_disallowed_mode_mask;
80 } arch_configs[MAX_ARCH] = {
81 #ifdef CAPSTONE_HAS_ARM
82 {
83 ARM_global_init,
84 ARM_option,
85 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_V8 | CS_MODE_MCLASS
86 | CS_MODE_THUMB | CS_MODE_BIG_ENDIAN)
87 },
88 #else
89 { NULL, NULL, 0 },
90 #endif
91 #ifdef CAPSTONE_HAS_ARM64
92 {
93 AArch64_global_init,
94 AArch64_option,
95 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_ARM | CS_MODE_BIG_ENDIAN),
96 },
97 #else
98 { NULL, NULL, 0 },
99 #endif
100 #ifdef CAPSTONE_HAS_MIPS
101 {
102 Mips_global_init,
103 Mips_option,
104 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_MICRO
105 | CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN | CS_MODE_MIPS2 | CS_MODE_MIPS3),
106 },
107 #else
108 { NULL, NULL, 0 },
109 #endif
110 #ifdef CAPSTONE_HAS_X86
111 {
112 X86_global_init,
113 X86_option,
114 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_16),
115 },
116 #else
117 { NULL, NULL, 0 },
118 #endif
119 #ifdef CAPSTONE_HAS_POWERPC
120 {
121 PPC_global_init,
122 PPC_option,
123 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_32 | CS_MODE_64 | CS_MODE_BIG_ENDIAN
124 | CS_MODE_QPX),
125 },
126 #else
127 { NULL, NULL, 0 },
128 #endif
129 #ifdef CAPSTONE_HAS_SPARC
130 {
131 Sparc_global_init,
132 Sparc_option,
133 ~(CS_MODE_BIG_ENDIAN | CS_MODE_V9),
134 },
135 #else
136 { NULL, NULL, 0 },
137 #endif
138 #ifdef CAPSTONE_HAS_SYSZ
139 {
140 SystemZ_global_init,
141 SystemZ_option,
142 ~(CS_MODE_BIG_ENDIAN),
143 },
144 #else
145 { NULL, NULL, 0 },
146 #endif
147 #ifdef CAPSTONE_HAS_XCORE
148 {
149 XCore_global_init,
150 XCore_option,
151 ~(CS_MODE_BIG_ENDIAN),
152 },
153 #else
154 { NULL, NULL, 0 },
155 #endif
156 #ifdef CAPSTONE_HAS_M68K
157 {
158 M68K_global_init,
159 M68K_option,
160 ~(CS_MODE_BIG_ENDIAN | CS_MODE_M68K_000 | CS_MODE_M68K_010 | CS_MODE_M68K_020
161 | CS_MODE_M68K_030 | CS_MODE_M68K_040 | CS_MODE_M68K_060),
162 },
163 #else
164 { NULL, NULL, 0 },
165 #endif
166 #ifdef CAPSTONE_HAS_TMS320C64X
167 {
168 TMS320C64x_global_init,
169 TMS320C64x_option,
170 ~(CS_MODE_BIG_ENDIAN),
171 },
172 #else
173 { NULL, NULL, 0 },
174 #endif
175 #ifdef CAPSTONE_HAS_M680X
176 {
177 M680X_global_init,
178 M680X_option,
179 ~(CS_MODE_M680X_6301 | CS_MODE_M680X_6309 | CS_MODE_M680X_6800
180 | CS_MODE_M680X_6801 | CS_MODE_M680X_6805 | CS_MODE_M680X_6808
181 | CS_MODE_M680X_6809 | CS_MODE_M680X_6811 | CS_MODE_M680X_CPU12
182 | CS_MODE_M680X_HCS08),
183 },
184 #else
185 { NULL, NULL, 0 },
186 #endif
187 #ifdef CAPSTONE_HAS_EVM
188 {
189 EVM_global_init,
190 EVM_option,
191 0,
192 },
193 #else
194 { NULL, NULL, 0 },
195 #endif
196 #ifdef CAPSTONE_HAS_MOS65XX
197 {
198 MOS65XX_global_init,
199 MOS65XX_option,
200 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_MOS65XX_6502 | CS_MODE_MOS65XX_65C02
201 | CS_MODE_MOS65XX_W65C02 | CS_MODE_MOS65XX_65816_LONG_MX),
202 },
203 #else
204 { NULL, NULL, 0 },
205 #endif
206 #ifdef CAPSTONE_HAS_WASM
207 {
208 WASM_global_init,
209 WASM_option,
210 0,
211 },
212 #else
213 { NULL, NULL, 0 },
214 #endif
215 #ifdef CAPSTONE_HAS_BPF
216 {
217 BPF_global_init,
218 BPF_option,
219 ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC | CS_MODE_BPF_EXTENDED
220 | CS_MODE_BIG_ENDIAN),
221 },
222 #else
223 { NULL, NULL, 0 },
224 #endif
225 #ifdef CAPSTONE_HAS_RISCV
226 {
227 RISCV_global_init,
228 RISCV_option,
229 ~(CS_MODE_RISCV32 | CS_MODE_RISCV64 | CS_MODE_RISCVC),
230 },
231 #else
232 { NULL, NULL, 0 },
233 #endif
234 };
235
236 // bitmask of enabled architectures
237 static const uint32_t all_arch = 0
238 #ifdef CAPSTONE_HAS_ARM
239 | (1 << CS_ARCH_ARM)
240 #endif
241 #ifdef CAPSTONE_HAS_ARM64
242 | (1 << CS_ARCH_ARM64)
243 #endif
244 #ifdef CAPSTONE_HAS_MIPS
245 | (1 << CS_ARCH_MIPS)
246 #endif
247 #ifdef CAPSTONE_HAS_X86
248 | (1 << CS_ARCH_X86)
249 #endif
250 #ifdef CAPSTONE_HAS_POWERPC
251 | (1 << CS_ARCH_PPC)
252 #endif
253 #ifdef CAPSTONE_HAS_SPARC
254 | (1 << CS_ARCH_SPARC)
255 #endif
256 #ifdef CAPSTONE_HAS_SYSZ
257 | (1 << CS_ARCH_SYSZ)
258 #endif
259 #ifdef CAPSTONE_HAS_XCORE
260 | (1 << CS_ARCH_XCORE)
261 #endif
262 #ifdef CAPSTONE_HAS_M68K
263 | (1 << CS_ARCH_M68K)
264 #endif
265 #ifdef CAPSTONE_HAS_TMS320C64X
266 | (1 << CS_ARCH_TMS320C64X)
267 #endif
268 #ifdef CAPSTONE_HAS_M680X
269 | (1 << CS_ARCH_M680X)
270 #endif
271 #ifdef CAPSTONE_HAS_EVM
272 | (1 << CS_ARCH_EVM)
273 #endif
274 #ifdef CAPSTONE_HAS_MOS65XX
275 | (1 << CS_ARCH_MOS65XX)
276 #endif
277 #ifdef CAPSTONE_HAS_WASM
278 | (1 << CS_ARCH_WASM)
279 #endif
280 #ifdef CAPSTONE_HAS_BPF
281 | (1 << CS_ARCH_BPF)
282 #endif
283 #ifdef CAPSTONE_HAS_RISCV
284 | (1 << CS_ARCH_RISCV)
285 #endif
286 ;
287
288
289 #if defined(CAPSTONE_USE_SYS_DYN_MEM)
290 #if !defined(CAPSTONE_HAS_OSXKERNEL) && !defined(_KERNEL_MODE)
291 // default
292 cs_malloc_t cs_mem_malloc = malloc;
293 cs_calloc_t cs_mem_calloc = calloc;
294 cs_realloc_t cs_mem_realloc = realloc;
295 cs_free_t cs_mem_free = free;
296 #if defined(_WIN32_WCE)
297 cs_vsnprintf_t cs_vsnprintf = _vsnprintf;
298 #else
299 cs_vsnprintf_t cs_vsnprintf = vsnprintf;
300 #endif // defined(_WIN32_WCE)
301
302 #elif defined(_KERNEL_MODE)
303 // Windows driver
304 cs_malloc_t cs_mem_malloc = cs_winkernel_malloc;
305 cs_calloc_t cs_mem_calloc = cs_winkernel_calloc;
306 cs_realloc_t cs_mem_realloc = cs_winkernel_realloc;
307 cs_free_t cs_mem_free = cs_winkernel_free;
308 cs_vsnprintf_t cs_vsnprintf = cs_winkernel_vsnprintf;
309 #else
310 // OSX kernel
311 extern void* kern_os_malloc(size_t size);
312 extern void kern_os_free(void* addr);
313 extern void* kern_os_realloc(void* addr, size_t nsize);
314
cs_kern_os_calloc(size_t num,size_t size)315 static void* cs_kern_os_calloc(size_t num, size_t size)
316 {
317 return kern_os_malloc(num * size); // malloc bzeroes the buffer
318 }
319
320 cs_malloc_t cs_mem_malloc = kern_os_malloc;
321 cs_calloc_t cs_mem_calloc = cs_kern_os_calloc;
322 cs_realloc_t cs_mem_realloc = kern_os_realloc;
323 cs_free_t cs_mem_free = kern_os_free;
324 cs_vsnprintf_t cs_vsnprintf = vsnprintf;
325 #endif // !defined(CAPSTONE_HAS_OSXKERNEL) && !defined(_KERNEL_MODE)
326 #else
327 // User-defined
328 cs_malloc_t cs_mem_malloc = NULL;
329 cs_calloc_t cs_mem_calloc = NULL;
330 cs_realloc_t cs_mem_realloc = NULL;
331 cs_free_t cs_mem_free = NULL;
332 cs_vsnprintf_t cs_vsnprintf = NULL;
333
334 #endif // defined(CAPSTONE_USE_SYS_DYN_MEM)
335
336 CAPSTONE_EXPORT
cs_version(int * major,int * minor)337 unsigned int CAPSTONE_API cs_version(int *major, int *minor)
338 {
339 if (major != NULL && minor != NULL) {
340 *major = CS_API_MAJOR;
341 *minor = CS_API_MINOR;
342 }
343
344 return (CS_API_MAJOR << 8) + CS_API_MINOR;
345 }
346
347 CAPSTONE_EXPORT
cs_support(int query)348 bool CAPSTONE_API cs_support(int query)
349 {
350 if (query == CS_ARCH_ALL)
351 return all_arch == ((1 << CS_ARCH_ARM) | (1 << CS_ARCH_ARM64) |
352 (1 << CS_ARCH_MIPS) | (1 << CS_ARCH_X86) |
353 (1 << CS_ARCH_PPC) | (1 << CS_ARCH_SPARC) |
354 (1 << CS_ARCH_SYSZ) | (1 << CS_ARCH_XCORE) |
355 (1 << CS_ARCH_M68K) | (1 << CS_ARCH_TMS320C64X) |
356 (1 << CS_ARCH_M680X) | (1 << CS_ARCH_EVM) |
357 (1 << CS_ARCH_RISCV) | (1 << CS_ARCH_MOS65XX) |
358 (1 << CS_ARCH_WASM) | (1 << CS_ARCH_BPF));
359
360 if ((unsigned int)query < CS_ARCH_MAX)
361 return all_arch & (1 << query);
362
363 if (query == CS_SUPPORT_DIET) {
364 #ifdef CAPSTONE_DIET
365 return true;
366 #else
367 return false;
368 #endif
369 }
370
371 if (query == CS_SUPPORT_X86_REDUCE) {
372 #if defined(CAPSTONE_HAS_X86) && defined(CAPSTONE_X86_REDUCE)
373 return true;
374 #else
375 return false;
376 #endif
377 }
378
379 // unsupported query
380 return false;
381 }
382
383 CAPSTONE_EXPORT
cs_errno(csh handle)384 cs_err CAPSTONE_API cs_errno(csh handle)
385 {
386 struct cs_struct *ud;
387 if (!handle)
388 return CS_ERR_CSH;
389
390 ud = (struct cs_struct *)(uintptr_t)handle;
391
392 return ud->errnum;
393 }
394
395 CAPSTONE_EXPORT
cs_strerror(cs_err code)396 const char * CAPSTONE_API cs_strerror(cs_err code)
397 {
398 switch(code) {
399 default:
400 return "Unknown error code";
401 case CS_ERR_OK:
402 return "OK (CS_ERR_OK)";
403 case CS_ERR_MEM:
404 return "Out of memory (CS_ERR_MEM)";
405 case CS_ERR_ARCH:
406 return "Invalid/unsupported architecture(CS_ERR_ARCH)";
407 case CS_ERR_HANDLE:
408 return "Invalid handle (CS_ERR_HANDLE)";
409 case CS_ERR_CSH:
410 return "Invalid csh (CS_ERR_CSH)";
411 case CS_ERR_MODE:
412 return "Invalid mode (CS_ERR_MODE)";
413 case CS_ERR_OPTION:
414 return "Invalid option (CS_ERR_OPTION)";
415 case CS_ERR_DETAIL:
416 return "Details are unavailable (CS_ERR_DETAIL)";
417 case CS_ERR_MEMSETUP:
418 return "Dynamic memory management uninitialized (CS_ERR_MEMSETUP)";
419 case CS_ERR_VERSION:
420 return "Different API version between core & binding (CS_ERR_VERSION)";
421 case CS_ERR_DIET:
422 return "Information irrelevant in diet engine (CS_ERR_DIET)";
423 case CS_ERR_SKIPDATA:
424 return "Information irrelevant for 'data' instruction in SKIPDATA mode (CS_ERR_SKIPDATA)";
425 case CS_ERR_X86_ATT:
426 return "AT&T syntax is unavailable (CS_ERR_X86_ATT)";
427 case CS_ERR_X86_INTEL:
428 return "INTEL syntax is unavailable (CS_ERR_X86_INTEL)";
429 case CS_ERR_X86_MASM:
430 return "MASM syntax is unavailable (CS_ERR_X86_MASM)";
431 }
432 }
433
434 CAPSTONE_EXPORT
cs_open(cs_arch arch,cs_mode mode,csh * handle)435 cs_err CAPSTONE_API cs_open(cs_arch arch, cs_mode mode, csh *handle)
436 {
437 cs_err err;
438 struct cs_struct *ud;
439 if (!cs_mem_malloc || !cs_mem_calloc || !cs_mem_realloc || !cs_mem_free || !cs_vsnprintf)
440 // Error: before cs_open(), dynamic memory management must be initialized
441 // with cs_option(CS_OPT_MEM)
442 return CS_ERR_MEMSETUP;
443
444 if (arch < CS_ARCH_MAX && arch_configs[arch].arch_init) {
445 // verify if requested mode is valid
446 if (mode & arch_configs[arch].arch_disallowed_mode_mask) {
447 *handle = 0;
448 return CS_ERR_MODE;
449 }
450
451 ud = cs_mem_calloc(1, sizeof(*ud));
452 if (!ud) {
453 // memory insufficient
454 return CS_ERR_MEM;
455 }
456
457 ud->errnum = CS_ERR_OK;
458 ud->arch = arch;
459 ud->mode = mode;
460 // by default, do not break instruction into details
461 ud->detail = CS_OPT_OFF;
462
463 // default skipdata setup
464 ud->skipdata_setup.mnemonic = SKIPDATA_MNEM;
465
466 err = arch_configs[ud->arch].arch_init(ud);
467 if (err) {
468 cs_mem_free(ud);
469 *handle = 0;
470 return err;
471 }
472
473 *handle = (uintptr_t)ud;
474
475 return CS_ERR_OK;
476 } else {
477 *handle = 0;
478 return CS_ERR_ARCH;
479 }
480 }
481
482 CAPSTONE_EXPORT
cs_close(csh * handle)483 cs_err CAPSTONE_API cs_close(csh *handle)
484 {
485 struct cs_struct *ud;
486 struct insn_mnem *next, *tmp;
487
488 if (*handle == 0)
489 // invalid handle
490 return CS_ERR_CSH;
491
492 ud = (struct cs_struct *)(*handle);
493
494 if (ud->printer_info)
495 cs_mem_free(ud->printer_info);
496
497 // free the linked list of customized mnemonic
498 tmp = ud->mnem_list;
499 while(tmp) {
500 next = tmp->next;
501 cs_mem_free(tmp);
502 tmp = next;
503 }
504
505 cs_mem_free(ud->insn_cache);
506
507 memset(ud, 0, sizeof(*ud));
508 cs_mem_free(ud);
509
510 // invalidate this handle by ZERO out its value.
511 // this is to make sure it is unusable after cs_close()
512 *handle = 0;
513
514 return CS_ERR_OK;
515 }
516
517 // replace str1 in target with str2; target starts with str1
518 // output is put into result (which is array of char with size CS_MNEMONIC_SIZE)
519 // return 0 on success, -1 on failure
str_replace(char * result,char * target,const char * str1,char * str2)520 static int str_replace(char *result, char *target, const char *str1, char *str2)
521 {
522 // only perform replacement if the output fits into result
523 if (strlen(target) - strlen(str1) + strlen(str2) < CS_MNEMONIC_SIZE - 1) {
524 // copy str2 to begining of result
525 strcpy(result, str2);
526 // skip str1 - already replaced by str2
527 strcat(result, target + strlen(str1));
528
529 return 0;
530 } else
531 return -1;
532 }
533
534 // fill insn with mnemonic & operands info
fill_insn(struct cs_struct * handle,cs_insn * insn,char * buffer,MCInst * mci,PostPrinter_t postprinter,const uint8_t * code)535 static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
536 PostPrinter_t postprinter, const uint8_t *code)
537 {
538 #ifndef CAPSTONE_DIET
539 char *sp, *mnem;
540 #endif
541 uint16_t copy_size = MIN(sizeof(insn->bytes), insn->size);
542
543 // fill the instruction bytes.
544 // we might skip some redundant bytes in front in the case of X86
545 memcpy(insn->bytes, code + insn->size - copy_size, copy_size);
546 insn->size = copy_size;
547
548 // alias instruction might have ID saved in OpcodePub
549 if (MCInst_getOpcodePub(mci))
550 insn->id = MCInst_getOpcodePub(mci);
551
552 // post printer handles some corner cases (hacky)
553 if (postprinter)
554 postprinter((csh)handle, insn, buffer, mci);
555
556 #ifndef CAPSTONE_DIET
557 // fill in mnemonic & operands
558 // find first space or tab
559 mnem = insn->mnemonic;
560 for (sp = buffer; *sp; sp++) {
561 if (*sp == ' '|| *sp == '\t')
562 break;
563 if (*sp == '|') // lock|rep prefix for x86
564 *sp = ' ';
565 // copy to @mnemonic
566 *mnem = *sp;
567 mnem++;
568 }
569
570 *mnem = '\0';
571
572 // we might have customized mnemonic
573 if (handle->mnem_list) {
574 struct insn_mnem *tmp = handle->mnem_list;
575 while(tmp) {
576 if (tmp->insn.id == insn->id) {
577 char str[CS_MNEMONIC_SIZE];
578
579 if (!str_replace(str, insn->mnemonic, cs_insn_name((csh)handle, insn->id), tmp->insn.mnemonic)) {
580 // copy result to mnemonic
581 (void)strncpy(insn->mnemonic, str, sizeof(insn->mnemonic) - 1);
582 insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
583 }
584
585 break;
586 }
587 tmp = tmp->next;
588 }
589 }
590
591 // copy @op_str
592 if (*sp) {
593 // find the next non-space char
594 sp++;
595 for (; ((*sp == ' ') || (*sp == '\t')); sp++);
596 strncpy(insn->op_str, sp, sizeof(insn->op_str) - 1);
597 insn->op_str[sizeof(insn->op_str) - 1] = '\0';
598 } else
599 insn->op_str[0] = '\0';
600 #endif
601 }
602
603 // how many bytes will we skip when encountering data (CS_OPT_SKIPDATA)?
604 // this very much depends on instruction alignment requirement of each arch.
skipdata_size(cs_struct * handle)605 static uint8_t skipdata_size(cs_struct *handle)
606 {
607 switch(handle->arch) {
608 default:
609 // should never reach
610 return (uint8_t)-1;
611 case CS_ARCH_ARM:
612 // skip 2 bytes on Thumb mode.
613 if (handle->mode & CS_MODE_THUMB)
614 return 2;
615 // otherwise, skip 4 bytes
616 return 4;
617 case CS_ARCH_ARM64:
618 case CS_ARCH_MIPS:
619 case CS_ARCH_PPC:
620 case CS_ARCH_SPARC:
621 // skip 4 bytes
622 return 4;
623 case CS_ARCH_SYSZ:
624 // SystemZ instruction's length can be 2, 4 or 6 bytes,
625 // so we just skip 2 bytes
626 return 2;
627 case CS_ARCH_X86:
628 // X86 has no restriction on instruction alignment
629 return 1;
630 case CS_ARCH_XCORE:
631 // XCore instruction's length can be 2 or 4 bytes,
632 // so we just skip 2 bytes
633 return 2;
634 case CS_ARCH_M68K:
635 // M68K has 2 bytes instruction alignment but contain multibyte instruction so we skip 2 bytes
636 return 2;
637 case CS_ARCH_TMS320C64X:
638 // TMS320C64x alignment is 4.
639 return 4;
640 case CS_ARCH_M680X:
641 // M680X alignment is 1.
642 return 1;
643 case CS_ARCH_EVM:
644 // EVM alignment is 1.
645 return 1;
646 case CS_ARCH_WASM:
647 //WASM alignment is 1
648 return 1;
649 case CS_ARCH_MOS65XX:
650 // MOS65XX alignment is 1.
651 return 1;
652 case CS_ARCH_BPF:
653 // both classic and extended BPF have alignment 8.
654 return 8;
655 case CS_ARCH_RISCV:
656 // special compress mode
657 if (handle->mode & CS_MODE_RISCVC)
658 return 1;
659 return 4;
660 }
661 }
662
663 CAPSTONE_EXPORT
cs_option(csh ud,cs_opt_type type,size_t value)664 cs_err CAPSTONE_API cs_option(csh ud, cs_opt_type type, size_t value)
665 {
666 struct cs_struct *handle;
667 cs_opt_mnem *opt;
668
669 // cs_option() can be called with NULL handle just for CS_OPT_MEM
670 // This is supposed to be executed before all other APIs (even cs_open())
671 if (type == CS_OPT_MEM) {
672 cs_opt_mem *mem = (cs_opt_mem *)value;
673
674 cs_mem_malloc = mem->malloc;
675 cs_mem_calloc = mem->calloc;
676 cs_mem_realloc = mem->realloc;
677 cs_mem_free = mem->free;
678 cs_vsnprintf = mem->vsnprintf;
679
680 return CS_ERR_OK;
681 }
682
683 handle = (struct cs_struct *)(uintptr_t)ud;
684 if (!handle)
685 return CS_ERR_CSH;
686
687 switch(type) {
688 default:
689 break;
690
691 case CS_OPT_UNSIGNED:
692 handle->imm_unsigned = (cs_opt_value)value;
693 return CS_ERR_OK;
694
695 case CS_OPT_DETAIL:
696 handle->detail = (cs_opt_value)value;
697 return CS_ERR_OK;
698
699 case CS_OPT_SKIPDATA:
700 handle->skipdata = (value == CS_OPT_ON);
701 if (handle->skipdata) {
702 if (handle->skipdata_size == 0) {
703 // set the default skipdata size
704 handle->skipdata_size = skipdata_size(handle);
705 }
706 }
707 return CS_ERR_OK;
708
709 case CS_OPT_SKIPDATA_SETUP:
710 if (value)
711 handle->skipdata_setup = *((cs_opt_skipdata *)value);
712 return CS_ERR_OK;
713
714 case CS_OPT_MNEMONIC:
715 opt = (cs_opt_mnem *)value;
716 if (opt->id) {
717 if (opt->mnemonic) {
718 struct insn_mnem *tmp;
719
720 // add new instruction, or replace existing instruction
721 // 1. find if we already had this insn in the linked list
722 tmp = handle->mnem_list;
723 while(tmp) {
724 if (tmp->insn.id == opt->id) {
725 // found this instruction, so replace its mnemonic
726 (void)strncpy(tmp->insn.mnemonic, opt->mnemonic, sizeof(tmp->insn.mnemonic) - 1);
727 tmp->insn.mnemonic[sizeof(tmp->insn.mnemonic) - 1] = '\0';
728 break;
729 }
730 tmp = tmp->next;
731 }
732
733 // 2. add this instruction if we have not had it yet
734 if (!tmp) {
735 tmp = cs_mem_malloc(sizeof(*tmp));
736 tmp->insn.id = opt->id;
737 (void)strncpy(tmp->insn.mnemonic, opt->mnemonic, sizeof(tmp->insn.mnemonic) - 1);
738 tmp->insn.mnemonic[sizeof(tmp->insn.mnemonic) - 1] = '\0';
739 // this new instruction is heading the list
740 tmp->next = handle->mnem_list;
741 handle->mnem_list = tmp;
742 }
743 return CS_ERR_OK;
744 } else {
745 struct insn_mnem *prev, *tmp;
746
747 // we want to delete an existing instruction
748 // iterate the list to find the instruction to remove it
749 tmp = handle->mnem_list;
750 prev = tmp;
751 while(tmp) {
752 if (tmp->insn.id == opt->id) {
753 // delete this instruction
754 if (tmp == prev) {
755 // head of the list
756 handle->mnem_list = tmp->next;
757 } else {
758 prev->next = tmp->next;
759 }
760 cs_mem_free(tmp);
761 break;
762 }
763 prev = tmp;
764 tmp = tmp->next;
765 }
766 }
767 }
768 return CS_ERR_OK;
769
770 case CS_OPT_MODE:
771 // verify if requested mode is valid
772 if (value & arch_configs[handle->arch].arch_disallowed_mode_mask) {
773 return CS_ERR_OPTION;
774 }
775 break;
776 }
777
778 return arch_configs[handle->arch].arch_option(handle, type, value);
779 }
780
781 // generate @op_str for data instruction of SKIPDATA
782 #ifndef CAPSTONE_DIET
skipdata_opstr(char * opstr,const uint8_t * buffer,size_t size)783 static void skipdata_opstr(char *opstr, const uint8_t *buffer, size_t size)
784 {
785 char *p = opstr;
786 int len;
787 size_t i;
788 size_t available = sizeof(((cs_insn*)NULL)->op_str);
789
790 if (!size) {
791 opstr[0] = '\0';
792 return;
793 }
794
795 len = cs_snprintf(p, available, "0x%02x", buffer[0]);
796 p+= len;
797 available -= len;
798
799 for(i = 1; i < size; i++) {
800 len = cs_snprintf(p, available, ", 0x%02x", buffer[i]);
801 if (len < 0) {
802 break;
803 }
804 if ((size_t)len > available - 1) {
805 break;
806 }
807 p+= len;
808 available -= len;
809 }
810 }
811 #endif
812
813 // dynamicly allocate memory to contain disasm insn
814 // NOTE: caller must free() the allocated memory itself to avoid memory leaking
815 CAPSTONE_EXPORT
cs_disasm(csh ud,const uint8_t * buffer,size_t size,uint64_t offset,size_t count,cs_insn ** insn)816 size_t CAPSTONE_API cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
817 {
818 struct cs_struct *handle;
819 MCInst mci;
820 uint16_t insn_size;
821 size_t c = 0, i;
822 unsigned int f = 0; // index of the next instruction in the cache
823 cs_insn *insn_cache; // cache contains disassembled instructions
824 void *total = NULL;
825 size_t total_size = 0; // total size of output buffer containing all insns
826 bool r;
827 void *tmp;
828 size_t skipdata_bytes;
829 uint64_t offset_org; // save all the original info of the buffer
830 size_t size_org;
831 const uint8_t *buffer_org;
832 unsigned int cache_size = INSN_CACHE_SIZE;
833 size_t next_offset;
834
835 handle = (struct cs_struct *)(uintptr_t)ud;
836 if (!handle) {
837 // FIXME: how to handle this case:
838 // handle->errnum = CS_ERR_HANDLE;
839 return 0;
840 }
841
842 handle->errnum = CS_ERR_OK;
843
844 // reset IT block of ARM structure
845 if (handle->arch == CS_ARCH_ARM)
846 handle->ITBlock.size = 0;
847
848 #ifdef CAPSTONE_USE_SYS_DYN_MEM
849 if (count > 0 && count <= INSN_CACHE_SIZE)
850 cache_size = (unsigned int) count;
851 #endif
852
853 // save the original offset for SKIPDATA
854 buffer_org = buffer;
855 offset_org = offset;
856 size_org = size;
857
858 total_size = sizeof(cs_insn) * cache_size;
859 total = cs_mem_malloc(total_size);
860 if (total == NULL) {
861 // insufficient memory
862 handle->errnum = CS_ERR_MEM;
863 return 0;
864 }
865
866 insn_cache = total;
867
868 while (size > 0) {
869 MCInst_Init(&mci);
870 mci.csh = handle;
871
872 // relative branches need to know the address & size of current insn
873 mci.address = offset;
874
875 if (handle->detail) {
876 // allocate memory for @detail pointer
877 insn_cache->detail = cs_mem_malloc(sizeof(cs_detail));
878 } else {
879 insn_cache->detail = NULL;
880 }
881
882 // save all the information for non-detailed mode
883 mci.flat_insn = insn_cache;
884 mci.flat_insn->address = offset;
885 #ifdef CAPSTONE_DIET
886 // zero out mnemonic & op_str
887 mci.flat_insn->mnemonic[0] = '\0';
888 mci.flat_insn->op_str[0] = '\0';
889 #endif
890
891 r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
892 if (r) {
893 SStream ss;
894 SStream_Init(&ss);
895
896 mci.flat_insn->size = insn_size;
897
898 // map internal instruction opcode to public insn ID
899
900 handle->insn_id(handle, insn_cache, mci.Opcode);
901
902 handle->printer(&mci, &ss, handle->printer_info);
903 fill_insn(handle, insn_cache, ss.buffer, &mci, handle->post_printer, buffer);
904
905 // adjust for pseudo opcode (X86)
906 if (handle->arch == CS_ARCH_X86)
907 insn_cache->id += mci.popcode_adjust;
908
909 next_offset = insn_size;
910 } else {
911 // encounter a broken instruction
912
913 // free memory of @detail pointer
914 if (handle->detail) {
915 cs_mem_free(insn_cache->detail);
916 }
917
918 // if there is no request to skip data, or remaining data is too small,
919 // then bail out
920 if (!handle->skipdata || handle->skipdata_size > size)
921 break;
922
923 if (handle->skipdata_setup.callback) {
924 skipdata_bytes = handle->skipdata_setup.callback(buffer_org, size_org,
925 (size_t)(offset - offset_org), handle->skipdata_setup.user_data);
926 if (skipdata_bytes > size)
927 // remaining data is not enough
928 break;
929
930 if (!skipdata_bytes)
931 // user requested not to skip data, so bail out
932 break;
933 } else
934 skipdata_bytes = handle->skipdata_size;
935
936 // we have to skip some amount of data, depending on arch & mode
937 insn_cache->id = 0; // invalid ID for this "data" instruction
938 insn_cache->address = offset;
939 insn_cache->size = (uint16_t)skipdata_bytes;
940 memcpy(insn_cache->bytes, buffer, skipdata_bytes);
941 #ifdef CAPSTONE_DIET
942 insn_cache->mnemonic[0] = '\0';
943 insn_cache->op_str[0] = '\0';
944 #else
945 strncpy(insn_cache->mnemonic, handle->skipdata_setup.mnemonic,
946 sizeof(insn_cache->mnemonic) - 1);
947 skipdata_opstr(insn_cache->op_str, buffer, skipdata_bytes);
948 #endif
949 insn_cache->detail = NULL;
950
951 next_offset = skipdata_bytes;
952 }
953
954 // one more instruction entering the cache
955 f++;
956
957 // one more instruction disassembled
958 c++;
959 if (count > 0 && c == count)
960 // already got requested number of instructions
961 break;
962
963 if (f == cache_size) {
964 // full cache, so expand the cache to contain incoming insns
965 cache_size = cache_size * 8 / 5; // * 1.6 ~ golden ratio
966 total_size += (sizeof(cs_insn) * cache_size);
967 tmp = cs_mem_realloc(total, total_size);
968 if (tmp == NULL) { // insufficient memory
969 if (handle->detail) {
970 insn_cache = (cs_insn *)total;
971 for (i = 0; i < c; i++, insn_cache++)
972 cs_mem_free(insn_cache->detail);
973 }
974
975 cs_mem_free(total);
976 *insn = NULL;
977 handle->errnum = CS_ERR_MEM;
978 return 0;
979 }
980
981 total = tmp;
982 // continue to fill in the cache after the last instruction
983 insn_cache = (cs_insn *)((char *)total + sizeof(cs_insn) * c);
984
985 // reset f back to 0, so we fill in the cache from begining
986 f = 0;
987 } else
988 insn_cache++;
989
990 buffer += next_offset;
991 size -= next_offset;
992 offset += next_offset;
993 }
994
995 if (!c) {
996 // we did not disassemble any instruction
997 cs_mem_free(total);
998 total = NULL;
999 } else if (f != cache_size) {
1000 // total did not fully use the last cache, so downsize it
1001 tmp = cs_mem_realloc(total, total_size - (cache_size - f) * sizeof(*insn_cache));
1002 if (tmp == NULL) { // insufficient memory
1003 // free all detail pointers
1004 if (handle->detail) {
1005 insn_cache = (cs_insn *)total;
1006 for (i = 0; i < c; i++, insn_cache++)
1007 cs_mem_free(insn_cache->detail);
1008 }
1009
1010 cs_mem_free(total);
1011 *insn = NULL;
1012
1013 handle->errnum = CS_ERR_MEM;
1014 return 0;
1015 }
1016
1017 total = tmp;
1018 }
1019
1020 *insn = total;
1021
1022 return c;
1023 }
1024
1025 CAPSTONE_EXPORT
cs_free(cs_insn * insn,size_t count)1026 void CAPSTONE_API cs_free(cs_insn *insn, size_t count)
1027 {
1028 size_t i;
1029
1030 // free all detail pointers
1031 for (i = 0; i < count; i++)
1032 cs_mem_free(insn[i].detail);
1033
1034 // then free pointer to cs_insn array
1035 cs_mem_free(insn);
1036 }
1037
1038 CAPSTONE_EXPORT
cs_malloc(csh ud)1039 cs_insn * CAPSTONE_API cs_malloc(csh ud)
1040 {
1041 cs_insn *insn;
1042 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
1043
1044 insn = cs_mem_malloc(sizeof(cs_insn));
1045 if (!insn) {
1046 // insufficient memory
1047 handle->errnum = CS_ERR_MEM;
1048 return NULL;
1049 } else {
1050 if (handle->detail) {
1051 // allocate memory for @detail pointer
1052 insn->detail = cs_mem_malloc(sizeof(cs_detail));
1053 if (insn->detail == NULL) { // insufficient memory
1054 cs_mem_free(insn);
1055 handle->errnum = CS_ERR_MEM;
1056 return NULL;
1057 }
1058 } else
1059 insn->detail = NULL;
1060 }
1061
1062 return insn;
1063 }
1064
1065 // iterator for instruction "single-stepping"
1066 CAPSTONE_EXPORT
cs_disasm_iter(csh ud,const uint8_t ** code,size_t * size,uint64_t * address,cs_insn * insn)1067 bool CAPSTONE_API cs_disasm_iter(csh ud, const uint8_t **code, size_t *size,
1068 uint64_t *address, cs_insn *insn)
1069 {
1070 struct cs_struct *handle;
1071 uint16_t insn_size;
1072 MCInst mci;
1073 bool r;
1074
1075 handle = (struct cs_struct *)(uintptr_t)ud;
1076 if (!handle) {
1077 return false;
1078 }
1079
1080 handle->errnum = CS_ERR_OK;
1081
1082 MCInst_Init(&mci);
1083 mci.csh = handle;
1084
1085 // relative branches need to know the address & size of current insn
1086 mci.address = *address;
1087
1088 // save all the information for non-detailed mode
1089 mci.flat_insn = insn;
1090 mci.flat_insn->address = *address;
1091 #ifdef CAPSTONE_DIET
1092 // zero out mnemonic & op_str
1093 mci.flat_insn->mnemonic[0] = '\0';
1094 mci.flat_insn->op_str[0] = '\0';
1095 #endif
1096
1097 r = handle->disasm(ud, *code, *size, &mci, &insn_size, *address, handle->getinsn_info);
1098 if (r) {
1099 SStream ss;
1100 SStream_Init(&ss);
1101
1102 mci.flat_insn->size = insn_size;
1103
1104 // map internal instruction opcode to public insn ID
1105 handle->insn_id(handle, insn, mci.Opcode);
1106
1107 handle->printer(&mci, &ss, handle->printer_info);
1108
1109 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, *code);
1110
1111 // adjust for pseudo opcode (X86)
1112 if (handle->arch == CS_ARCH_X86)
1113 insn->id += mci.popcode_adjust;
1114
1115 *code += insn_size;
1116 *size -= insn_size;
1117 *address += insn_size;
1118 } else { // encounter a broken instruction
1119 size_t skipdata_bytes;
1120
1121 // if there is no request to skip data, or remaining data is too small,
1122 // then bail out
1123 if (!handle->skipdata || handle->skipdata_size > *size)
1124 return false;
1125
1126 if (handle->skipdata_setup.callback) {
1127 skipdata_bytes = handle->skipdata_setup.callback(*code, *size,
1128 0, handle->skipdata_setup.user_data);
1129 if (skipdata_bytes > *size)
1130 // remaining data is not enough
1131 return false;
1132
1133 if (!skipdata_bytes)
1134 // user requested not to skip data, so bail out
1135 return false;
1136 } else
1137 skipdata_bytes = handle->skipdata_size;
1138
1139 // we have to skip some amount of data, depending on arch & mode
1140 insn->id = 0; // invalid ID for this "data" instruction
1141 insn->address = *address;
1142 insn->size = (uint16_t)skipdata_bytes;
1143 #ifdef CAPSTONE_DIET
1144 insn->mnemonic[0] = '\0';
1145 insn->op_str[0] = '\0';
1146 #else
1147 memcpy(insn->bytes, *code, skipdata_bytes);
1148 strncpy(insn->mnemonic, handle->skipdata_setup.mnemonic,
1149 sizeof(insn->mnemonic) - 1);
1150 skipdata_opstr(insn->op_str, *code, skipdata_bytes);
1151 #endif
1152
1153 *code += skipdata_bytes;
1154 *size -= skipdata_bytes;
1155 *address += skipdata_bytes;
1156 }
1157
1158 return true;
1159 }
1160
1161 // return friendly name of regiser in a string
1162 CAPSTONE_EXPORT
cs_reg_name(csh ud,unsigned int reg)1163 const char * CAPSTONE_API cs_reg_name(csh ud, unsigned int reg)
1164 {
1165 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
1166
1167 if (!handle || handle->reg_name == NULL) {
1168 return NULL;
1169 }
1170
1171 return handle->reg_name(ud, reg);
1172 }
1173
1174 CAPSTONE_EXPORT
cs_insn_name(csh ud,unsigned int insn)1175 const char * CAPSTONE_API cs_insn_name(csh ud, unsigned int insn)
1176 {
1177 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
1178
1179 if (!handle || handle->insn_name == NULL) {
1180 return NULL;
1181 }
1182
1183 return handle->insn_name(ud, insn);
1184 }
1185
1186 CAPSTONE_EXPORT
cs_group_name(csh ud,unsigned int group)1187 const char * CAPSTONE_API cs_group_name(csh ud, unsigned int group)
1188 {
1189 struct cs_struct *handle = (struct cs_struct *)(uintptr_t)ud;
1190
1191 if (!handle || handle->group_name == NULL) {
1192 return NULL;
1193 }
1194
1195 return handle->group_name(ud, group);
1196 }
1197
1198 CAPSTONE_EXPORT
cs_insn_group(csh ud,const cs_insn * insn,unsigned int group_id)1199 bool CAPSTONE_API cs_insn_group(csh ud, const cs_insn *insn, unsigned int group_id)
1200 {
1201 struct cs_struct *handle;
1202 if (!ud)
1203 return false;
1204
1205 handle = (struct cs_struct *)(uintptr_t)ud;
1206
1207 if (!handle->detail) {
1208 handle->errnum = CS_ERR_DETAIL;
1209 return false;
1210 }
1211
1212 if (!insn->id) {
1213 handle->errnum = CS_ERR_SKIPDATA;
1214 return false;
1215 }
1216
1217 if (!insn->detail) {
1218 handle->errnum = CS_ERR_DETAIL;
1219 return false;
1220 }
1221
1222 return arr_exist8(insn->detail->groups, insn->detail->groups_count, group_id);
1223 }
1224
1225 CAPSTONE_EXPORT
cs_reg_read(csh ud,const cs_insn * insn,unsigned int reg_id)1226 bool CAPSTONE_API cs_reg_read(csh ud, const cs_insn *insn, unsigned int reg_id)
1227 {
1228 struct cs_struct *handle;
1229 if (!ud)
1230 return false;
1231
1232 handle = (struct cs_struct *)(uintptr_t)ud;
1233
1234 if (!handle->detail) {
1235 handle->errnum = CS_ERR_DETAIL;
1236 return false;
1237 }
1238
1239 if (!insn->id) {
1240 handle->errnum = CS_ERR_SKIPDATA;
1241 return false;
1242 }
1243
1244 if (!insn->detail) {
1245 handle->errnum = CS_ERR_DETAIL;
1246 return false;
1247 }
1248
1249 return arr_exist(insn->detail->regs_read, insn->detail->regs_read_count, reg_id);
1250 }
1251
1252 CAPSTONE_EXPORT
cs_reg_write(csh ud,const cs_insn * insn,unsigned int reg_id)1253 bool CAPSTONE_API cs_reg_write(csh ud, const cs_insn *insn, unsigned int reg_id)
1254 {
1255 struct cs_struct *handle;
1256 if (!ud)
1257 return false;
1258
1259 handle = (struct cs_struct *)(uintptr_t)ud;
1260
1261 if (!handle->detail) {
1262 handle->errnum = CS_ERR_DETAIL;
1263 return false;
1264 }
1265
1266 if (!insn->id) {
1267 handle->errnum = CS_ERR_SKIPDATA;
1268 return false;
1269 }
1270
1271 if (!insn->detail) {
1272 handle->errnum = CS_ERR_DETAIL;
1273 return false;
1274 }
1275
1276 return arr_exist(insn->detail->regs_write, insn->detail->regs_write_count, reg_id);
1277 }
1278
1279 CAPSTONE_EXPORT
cs_op_count(csh ud,const cs_insn * insn,unsigned int op_type)1280 int CAPSTONE_API cs_op_count(csh ud, const cs_insn *insn, unsigned int op_type)
1281 {
1282 struct cs_struct *handle;
1283 unsigned int count = 0, i;
1284 if (!ud)
1285 return -1;
1286
1287 handle = (struct cs_struct *)(uintptr_t)ud;
1288
1289 if (!handle->detail) {
1290 handle->errnum = CS_ERR_DETAIL;
1291 return -1;
1292 }
1293
1294 if (!insn->id) {
1295 handle->errnum = CS_ERR_SKIPDATA;
1296 return -1;
1297 }
1298
1299 if (!insn->detail) {
1300 handle->errnum = CS_ERR_DETAIL;
1301 return -1;
1302 }
1303
1304 handle->errnum = CS_ERR_OK;
1305
1306 switch (handle->arch) {
1307 default:
1308 handle->errnum = CS_ERR_HANDLE;
1309 return -1;
1310 case CS_ARCH_ARM:
1311 for (i = 0; i < insn->detail->arm.op_count; i++)
1312 if (insn->detail->arm.operands[i].type == (arm_op_type)op_type)
1313 count++;
1314 break;
1315 case CS_ARCH_ARM64:
1316 for (i = 0; i < insn->detail->arm64.op_count; i++)
1317 if (insn->detail->arm64.operands[i].type == (arm64_op_type)op_type)
1318 count++;
1319 break;
1320 case CS_ARCH_X86:
1321 for (i = 0; i < insn->detail->x86.op_count; i++)
1322 if (insn->detail->x86.operands[i].type == (x86_op_type)op_type)
1323 count++;
1324 break;
1325 case CS_ARCH_MIPS:
1326 for (i = 0; i < insn->detail->mips.op_count; i++)
1327 if (insn->detail->mips.operands[i].type == (mips_op_type)op_type)
1328 count++;
1329 break;
1330 case CS_ARCH_PPC:
1331 for (i = 0; i < insn->detail->ppc.op_count; i++)
1332 if (insn->detail->ppc.operands[i].type == (ppc_op_type)op_type)
1333 count++;
1334 break;
1335 case CS_ARCH_SPARC:
1336 for (i = 0; i < insn->detail->sparc.op_count; i++)
1337 if (insn->detail->sparc.operands[i].type == (sparc_op_type)op_type)
1338 count++;
1339 break;
1340 case CS_ARCH_SYSZ:
1341 for (i = 0; i < insn->detail->sysz.op_count; i++)
1342 if (insn->detail->sysz.operands[i].type == (sysz_op_type)op_type)
1343 count++;
1344 break;
1345 case CS_ARCH_XCORE:
1346 for (i = 0; i < insn->detail->xcore.op_count; i++)
1347 if (insn->detail->xcore.operands[i].type == (xcore_op_type)op_type)
1348 count++;
1349 break;
1350 case CS_ARCH_M68K:
1351 for (i = 0; i < insn->detail->m68k.op_count; i++)
1352 if (insn->detail->m68k.operands[i].type == (m68k_op_type)op_type)
1353 count++;
1354 break;
1355 case CS_ARCH_TMS320C64X:
1356 for (i = 0; i < insn->detail->tms320c64x.op_count; i++)
1357 if (insn->detail->tms320c64x.operands[i].type == (tms320c64x_op_type)op_type)
1358 count++;
1359 break;
1360 case CS_ARCH_M680X:
1361 for (i = 0; i < insn->detail->m680x.op_count; i++)
1362 if (insn->detail->m680x.operands[i].type == (m680x_op_type)op_type)
1363 count++;
1364 break;
1365 case CS_ARCH_EVM:
1366 break;
1367 case CS_ARCH_MOS65XX:
1368 for (i = 0; i < insn->detail->mos65xx.op_count; i++)
1369 if (insn->detail->mos65xx.operands[i].type == (mos65xx_op_type)op_type)
1370 count++;
1371 break;
1372 case CS_ARCH_WASM:
1373 for (i = 0; i < insn->detail->wasm.op_count; i++)
1374 if (insn->detail->wasm.operands[i].type == (wasm_op_type)op_type)
1375 count++;
1376 break;
1377 case CS_ARCH_BPF:
1378 for (i = 0; i < insn->detail->bpf.op_count; i++)
1379 if (insn->detail->bpf.operands[i].type == (bpf_op_type)op_type)
1380 count++;
1381 break;
1382 case CS_ARCH_RISCV:
1383 for (i = 0; i < insn->detail->riscv.op_count; i++)
1384 if (insn->detail->riscv.operands[i].type == (riscv_op_type)op_type)
1385 count++;
1386 break;
1387 }
1388
1389 return count;
1390 }
1391
1392 CAPSTONE_EXPORT
cs_op_index(csh ud,const cs_insn * insn,unsigned int op_type,unsigned int post)1393 int CAPSTONE_API cs_op_index(csh ud, const cs_insn *insn, unsigned int op_type,
1394 unsigned int post)
1395 {
1396 struct cs_struct *handle;
1397 unsigned int count = 0, i;
1398 if (!ud)
1399 return -1;
1400
1401 handle = (struct cs_struct *)(uintptr_t)ud;
1402
1403 if (!handle->detail) {
1404 handle->errnum = CS_ERR_DETAIL;
1405 return -1;
1406 }
1407
1408 if (!insn->id) {
1409 handle->errnum = CS_ERR_SKIPDATA;
1410 return -1;
1411 }
1412
1413 if (!insn->detail) {
1414 handle->errnum = CS_ERR_DETAIL;
1415 return -1;
1416 }
1417
1418 handle->errnum = CS_ERR_OK;
1419
1420 switch (handle->arch) {
1421 default:
1422 handle->errnum = CS_ERR_HANDLE;
1423 return -1;
1424 case CS_ARCH_ARM:
1425 for (i = 0; i < insn->detail->arm.op_count; i++) {
1426 if (insn->detail->arm.operands[i].type == (arm_op_type)op_type)
1427 count++;
1428 if (count == post)
1429 return i;
1430 }
1431 break;
1432 case CS_ARCH_ARM64:
1433 for (i = 0; i < insn->detail->arm64.op_count; i++) {
1434 if (insn->detail->arm64.operands[i].type == (arm64_op_type)op_type)
1435 count++;
1436 if (count == post)
1437 return i;
1438 }
1439 break;
1440 case CS_ARCH_X86:
1441 for (i = 0; i < insn->detail->x86.op_count; i++) {
1442 if (insn->detail->x86.operands[i].type == (x86_op_type)op_type)
1443 count++;
1444 if (count == post)
1445 return i;
1446 }
1447 break;
1448 case CS_ARCH_MIPS:
1449 for (i = 0; i < insn->detail->mips.op_count; i++) {
1450 if (insn->detail->mips.operands[i].type == (mips_op_type)op_type)
1451 count++;
1452 if (count == post)
1453 return i;
1454 }
1455 break;
1456 case CS_ARCH_PPC:
1457 for (i = 0; i < insn->detail->ppc.op_count; i++) {
1458 if (insn->detail->ppc.operands[i].type == (ppc_op_type)op_type)
1459 count++;
1460 if (count == post)
1461 return i;
1462 }
1463 break;
1464 case CS_ARCH_SPARC:
1465 for (i = 0; i < insn->detail->sparc.op_count; i++) {
1466 if (insn->detail->sparc.operands[i].type == (sparc_op_type)op_type)
1467 count++;
1468 if (count == post)
1469 return i;
1470 }
1471 break;
1472 case CS_ARCH_SYSZ:
1473 for (i = 0; i < insn->detail->sysz.op_count; i++) {
1474 if (insn->detail->sysz.operands[i].type == (sysz_op_type)op_type)
1475 count++;
1476 if (count == post)
1477 return i;
1478 }
1479 break;
1480 case CS_ARCH_XCORE:
1481 for (i = 0; i < insn->detail->xcore.op_count; i++) {
1482 if (insn->detail->xcore.operands[i].type == (xcore_op_type)op_type)
1483 count++;
1484 if (count == post)
1485 return i;
1486 }
1487 break;
1488 case CS_ARCH_M68K:
1489 for (i = 0; i < insn->detail->m68k.op_count; i++) {
1490 if (insn->detail->m68k.operands[i].type == (m68k_op_type)op_type)
1491 count++;
1492 if (count == post)
1493 return i;
1494 }
1495 break;
1496 case CS_ARCH_TMS320C64X:
1497 for (i = 0; i < insn->detail->tms320c64x.op_count; i++) {
1498 if (insn->detail->tms320c64x.operands[i].type == (tms320c64x_op_type)op_type)
1499 count++;
1500 if (count == post)
1501 return i;
1502 }
1503 break;
1504 case CS_ARCH_M680X:
1505 for (i = 0; i < insn->detail->m680x.op_count; i++) {
1506 if (insn->detail->m680x.operands[i].type == (m680x_op_type)op_type)
1507 count++;
1508 if (count == post)
1509 return i;
1510 }
1511 break;
1512 case CS_ARCH_EVM:
1513 #if 0
1514 for (i = 0; i < insn->detail->evm.op_count; i++) {
1515 if (insn->detail->evm.operands[i].type == (evm_op_type)op_type)
1516 count++;
1517 if (count == post)
1518 return i;
1519 }
1520 #endif
1521 break;
1522 case CS_ARCH_MOS65XX:
1523 for (i = 0; i < insn->detail->mos65xx.op_count; i++) {
1524 if (insn->detail->mos65xx.operands[i].type == (mos65xx_op_type)op_type)
1525 count++;
1526 if (count == post)
1527 return i;
1528 }
1529 break;
1530 case CS_ARCH_WASM:
1531 for (i = 0; i < insn->detail->wasm.op_count; i++) {
1532 if (insn->detail->wasm.operands[i].type == (wasm_op_type)op_type)
1533 count++;
1534 if (count == post)
1535 return i;
1536 }
1537 break;
1538 case CS_ARCH_BPF:
1539 for (i = 0; i < insn->detail->bpf.op_count; i++) {
1540 if (insn->detail->bpf.operands[i].type == (bpf_op_type)op_type)
1541 count++;
1542 if (count == post)
1543 return i;
1544 }
1545 break;
1546 case CS_ARCH_RISCV:
1547 for (i = 0; i < insn->detail->riscv.op_count; i++) {
1548 if (insn->detail->riscv.operands[i].type == (riscv_op_type)op_type)
1549 count++;
1550 if (count == post)
1551 return i;
1552 }
1553 break;
1554 }
1555
1556 return -1;
1557 }
1558
1559 CAPSTONE_EXPORT
cs_regs_access(csh ud,const cs_insn * insn,cs_regs regs_read,uint8_t * regs_read_count,cs_regs regs_write,uint8_t * regs_write_count)1560 cs_err CAPSTONE_API cs_regs_access(csh ud, const cs_insn *insn,
1561 cs_regs regs_read, uint8_t *regs_read_count,
1562 cs_regs regs_write, uint8_t *regs_write_count)
1563 {
1564 struct cs_struct *handle;
1565
1566 if (!ud)
1567 return -1;
1568
1569 handle = (struct cs_struct *)(uintptr_t)ud;
1570
1571 #ifdef CAPSTONE_DIET
1572 // This API does not work in DIET mode
1573 handle->errnum = CS_ERR_DIET;
1574 return CS_ERR_DIET;
1575 #else
1576 if (!handle->detail) {
1577 handle->errnum = CS_ERR_DETAIL;
1578 return CS_ERR_DETAIL;
1579 }
1580
1581 if (!insn->id) {
1582 handle->errnum = CS_ERR_SKIPDATA;
1583 return CS_ERR_SKIPDATA;
1584 }
1585
1586 if (!insn->detail) {
1587 handle->errnum = CS_ERR_DETAIL;
1588 return CS_ERR_DETAIL;
1589 }
1590
1591 if (handle->reg_access) {
1592 handle->reg_access(insn, regs_read, regs_read_count, regs_write, regs_write_count);
1593 } else {
1594 // this arch is unsupported yet
1595 handle->errnum = CS_ERR_ARCH;
1596 return CS_ERR_ARCH;
1597 }
1598
1599 return CS_ERR_OK;
1600 #endif
1601 }
1602