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