blob: 1203421f65b38722752dfdf692ba4133603b6a64 [file] [log] [blame]
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +08001/* Capstone Disassembler Engine */
2/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <capstone.h>
8
9#include "cs_priv.h"
10
11#include "MCRegisterInfo.h"
12
13#include "arch/X86/X86Disassembler.h"
14#include "arch/X86/X86InstPrinter.h"
15#include "arch/X86/mapping.h"
16
17#include "arch/ARM/ARMDisassembler.h"
18#include "arch/ARM/ARMInstPrinter.h"
19#include "arch/ARM/mapping.h"
20
21#include "arch/Mips/MipsDisassembler.h"
22#include "arch/Mips/MipsInstPrinter.h"
23#include "arch/Mips/mapping.h"
24
25#include "arch/AArch64/AArch64Disassembler.h"
26#include "arch/AArch64/AArch64InstPrinter.h"
27#include "arch/AArch64/mapping.h"
28
29#include "utils.h"
30
Nguyen Anh Quynh36df4bb2013-12-10 13:31:20 +080031
32void cs_version(int *major, int *minor)
33{
34 *major = CS_API_MAJOR;
35 *minor = CS_API_MINOR;
36}
37
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080038cs_err cs_errno(csh handle)
39{
40 if (!handle)
41 return CS_ERR_CSH;
42
43 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
44
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +080045 return ud->errnum;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080046}
47
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080048cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle)
49{
50 cs_struct *ud;
51
52 ud = calloc(1, sizeof(*ud));
53 if (!ud) {
54 // memory insufficient
55 return CS_ERR_MEM;
56 }
57
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +080058 ud->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080059 ud->arch = arch;
60 ud->mode = mode;
61 ud->big_endian = mode & CS_MODE_BIG_ENDIAN;
62 ud->reg_name = NULL;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +080063 ud->detail = CS_OPT_ON; // by default break instruction into details
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080064
65 switch (ud->arch) {
66 case CS_ARCH_X86:
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +080067 // by default, we use Intel syntax
68 ud->printer = X86_Intel_printInst;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080069 ud->printer_info = NULL;
70 ud->disasm = X86_getInstruction;
71 ud->reg_name = X86_reg_name;
72 ud->insn_id = X86_get_insn_id;
73 ud->insn_name = X86_insn_name;
Nguyen Anh Quynha01d1542013-12-12 15:54:30 +080074 ud->post_printer = X86_post_printer;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080075 break;
76 case CS_ARCH_ARM: {
77 MCRegisterInfo *mri = malloc(sizeof(*mri));
78
79 ARM_init(mri);
80
81 ud->printer = ARM_printInst;
82 ud->printer_info = mri;
83 ud->reg_name = ARM_reg_name;
84 ud->insn_id = ARM_get_insn_id;
85 ud->insn_name = ARM_insn_name;
86 ud->post_printer = ARM_post_printer;
87
88 if (ud->mode & CS_MODE_THUMB)
89 ud->disasm = Thumb_getInstruction;
90 else
91 ud->disasm = ARM_getInstruction;
92 break;
93 }
94 case CS_ARCH_MIPS: {
95 MCRegisterInfo *mri = malloc(sizeof(*mri));
96
97 Mips_init(mri);
98 ud->printer = Mips_printInst;
99 ud->printer_info = mri;
100 ud->getinsn_info = mri;
101 ud->reg_name = Mips_reg_name;
102 ud->insn_id = Mips_get_insn_id;
103 ud->insn_name = Mips_insn_name;
104
105 if (ud->mode & CS_MODE_32)
106 ud->disasm = Mips_getInstruction;
107 else
108 ud->disasm = Mips64_getInstruction;
109
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800110 break;
111 }
112 case CS_ARCH_ARM64: {
113 MCRegisterInfo *mri = malloc(sizeof(*mri));
114
115 AArch64_init(mri);
116 ud->printer = AArch64_printInst;
117 ud->printer_info = mri;
118 ud->getinsn_info = mri;
119 ud->disasm = AArch64_getInstruction;
120 ud->reg_name = AArch64_reg_name;
121 ud->insn_id = AArch64_get_insn_id;
122 ud->insn_name = AArch64_insn_name;
123 ud->post_printer = AArch64_post_printer;
124 break;
125 }
126 default: // unsupported architecture
127 free(ud);
128 return CS_ERR_ARCH;
129 }
130
131 *handle = (uintptr_t)ud;
132
133 return CS_ERR_OK;
134}
135
136cs_err cs_close(csh handle)
137{
138 if (!handle)
139 return CS_ERR_CSH;
140
141 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
142
143 switch (ud->arch) {
144 case CS_ARCH_X86:
145 break;
146 case CS_ARCH_ARM:
147 case CS_ARCH_MIPS:
148 case CS_ARCH_ARM64:
149 free(ud->printer_info);
150 break;
151 default: // unsupported architecture
152 return CS_ERR_HANDLE;
153 }
154
155 memset(ud, 0, sizeof(*ud));
156 free(ud);
157
158 return CS_ERR_OK;
159}
160
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800161#define MIN(x, y) ((x) < (y) ? (x) : (y))
162
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800163// fill insn with mnemonic & operands info
164static void fill_insn(cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
pancakef0e4eed2013-12-11 22:14:42 +0100165 PostPrinter_t printer, const uint8_t *code)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800166{
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800167 if (handle->detail) {
168 memcpy(insn, &mci->pub_insn, sizeof(*insn));
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800169
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800170 // fill the instruction bytes
171 memcpy(insn->bytes, code, MIN(sizeof(insn->bytes), insn->size));
Nguyen Anh Quynhad61c492013-11-30 16:23:31 +0800172
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800173 } else {
174 insn->address = mci->address;
175 insn->size = mci->insn_size;
176 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800177
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800178 // map internal instruction opcode to public insn ID
179 if (handle->insn_id)
180 handle->insn_id(insn, MCInst_getOpcode(mci), handle->detail);
181
182 // alias instruction might have ID saved in OpcodePub
183 if (MCInst_getOpcodePub(mci))
184 insn->id = MCInst_getOpcodePub(mci);
185
186 // post printer handles some corner cases (hacky)
187 if (printer)
188 printer((csh)handle, insn, buffer);
189
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800190 // fill in mnemonic & operands
Nguyen Anh Quynhdefb9bc2013-12-12 14:00:12 +0800191 // find first space or tab
192 char *sp = buffer;
193 for (sp = buffer; *sp; sp++)
194 if (*sp == ' '||*sp == '\t')
195 break;
196 if (*sp) {
197 *sp = '\0';
Nguyen Anh Quynh86dc3932013-12-12 14:43:39 +0800198 // find the next non-space char
199 sp++;
200 for (; ((*sp == ' ') || (*sp == '\t')); sp++);
201 strncpy(insn->op_str, sp, sizeof(insn->op_str) - 1);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800202 insn->op_str[sizeof(insn->op_str) - 1] = '\0';
203 } else
204 insn->op_str[0] = '\0';
205
206 strncpy(insn->mnemonic, buffer, sizeof(insn->mnemonic) - 1);
207 insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
208}
209
Nguyen Anh Quynhda8adad2013-12-04 09:44:07 +0800210cs_err cs_option(csh ud, cs_opt_type type, size_t value)
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800211{
212 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
213 if (!handle)
214 return CS_ERR_CSH;
215
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800216 switch(type) {
217 default:
218 break;
219 case CS_OPT_DETAIL:
220 handle->detail = value;
221 return CS_ERR_OK;
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800222 case CS_OPT_SYNTAX:
223 switch (handle->arch) {
224 default:
225 // only selected archs care about CS_OPT_SYNTAX
226 handle->errnum = CS_ERR_OPTION;
227 return CS_ERR_OPTION;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800228
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800229 case CS_ARCH_X86:
230 switch(value) {
231 default:
232 // wrong syntax value
233 handle->errnum = CS_ERR_OPTION;
234 return CS_ERR_OPTION;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800235
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800236 case CS_OPT_SYNTAX_INTEL:
237 handle->printer = X86_Intel_printInst;
238 break;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800239
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800240 case CS_OPT_SYNTAX_ATT:
241 handle->printer = X86_ATT_printInst;
242 break;
243 }
244 break;
245 }
246 break;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800247
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800248 case CS_OPT_MODE: // change engine's mode at run-time
249 handle->mode = value;
250 switch (handle->arch) {
251 default:
252 // only selected archs care about CS_OPT_SYNTAX
253 break;
254 case CS_ARCH_ARM:
255 if (value & CS_MODE_THUMB)
256 handle->disasm = Thumb_getInstruction;
257 else
258 handle->disasm = ARM_getInstruction;
259
260 handle->mode = value;
261 break;
262 case CS_ARCH_MIPS:
263 if (value & CS_MODE_32)
264 handle->disasm = Mips_getInstruction;
265 else
266 handle->disasm = Mips64_getInstruction;
267
268 handle->mode = value;
269 break;
Nguyen Anh Quynhfe8030b2013-12-06 10:09:43 +0800270 }
Nguyen Anh Quynh4a60a562013-12-03 21:56:54 +0800271 break;
272 }
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800273
274 return CS_ERR_OK;
275}
276
pancakef0e4eed2013-12-11 22:14:42 +0100277size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn *insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800278{
279 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
280 MCInst mci;
281 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800282 size_t c = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800283
284 if (!handle) {
285 // FIXME: handle this case?
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800286 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800287 return 0;
288 }
289
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800290 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800291 memset(insn, 0, count * sizeof(*insn));
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800292
293 while (size > 0) {
294 MCInst_Init(&mci);
Nguyen Anh Quynh1f449282013-12-15 14:04:59 +0800295 mci.detail = handle->detail;
296 mci.mode = handle->mode;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800297
298 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
299 if (r) {
300 SStream ss;
301 SStream_Init(&ss);
302
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800303 // relative branches need to know the address & size of current insn
304 mci.insn_size = insn_size;
305 mci.address = offset;
306
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800307 if (handle->detail) {
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800308 // save all the information for non-detailed mode
309 mci.pub_insn.address = offset;
310 mci.pub_insn.size = insn_size;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800311 }
312
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800313 handle->printer(&mci, &ss, handle->printer_info);
314
Joxean114df0e2013-12-04 07:11:32 +0100315 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800316
317 c++;
318 insn++;
319 buffer += insn_size;
320 size -= insn_size;
321 offset += insn_size;
322
Nguyen Anh Quynh9a0dbab2013-12-15 22:25:58 +0800323 if (c == count)
324 return c;
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800325 } else
Nguyen Anh Quynh9a0dbab2013-12-15 22:25:58 +0800326 // face a broken instruction? then we stop here
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800327 return c;
328 }
329
330 return c;
331}
332
333// dynamicly allocate memory to contain disasm insn
334// NOTE: caller must free() the allocated memory itself to avoid memory leaking
pancakef0e4eed2013-12-11 22:14:42 +0100335size_t cs_disasm_dyn(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800336{
337 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
338 MCInst mci;
339 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800340 size_t c = 0, f = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800341 cs_insn insn_cache[64];
342 void *total = NULL;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800343 size_t total_size = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800344
345 if (!handle) {
346 // FIXME: how to handle this case:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800347 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800348 return 0;
349 }
350
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800351 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800352
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800353 memset(insn_cache, 0, sizeof(insn_cache));
354
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800355 while (size > 0) {
356 MCInst_Init(&mci);
Nguyen Anh Quynh1f449282013-12-15 14:04:59 +0800357 mci.detail = handle->detail;
358 mci.mode = handle->mode;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800359
360 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
361 if (r) {
362 SStream ss;
363 SStream_Init(&ss);
364
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800365 // relative branches need to know the address & size of current insn
366 mci.insn_size = insn_size;
367 mci.address = offset;
368
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800369 if (handle->detail) {
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800370 // save all the information for non-detailed mode
371 mci.pub_insn.address = offset;
372 mci.pub_insn.size = insn_size;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800373 }
374
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800375 handle->printer(&mci, &ss, handle->printer_info);
376
Joxean114df0e2013-12-04 07:11:32 +0100377 fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800378
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800379 f++;
380
381 if (f == ARR_SIZE(insn_cache)) {
382 // resize total to contain newly disasm insns
383 total_size += sizeof(insn_cache);
384 void *tmp = realloc(total, total_size);
385 if (tmp == NULL) { // insufficient memory
386 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800387 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800388 return 0;
389 }
390
391 total = tmp;
392 memcpy(total + total_size - sizeof(insn_cache), insn_cache, sizeof(insn_cache));
393 // reset f back to 0
394 f = 0;
395 }
396
397 c++;
398 buffer += insn_size;
399 size -= insn_size;
400 offset += insn_size;
401
402 if (count > 0 && c == count)
403 break;
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800404 } else {
405 // encounter a broken instruction
406 // XXX: TODO: JOXEAN continue here
407 break;
408 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800409 }
410
411 if (f) {
412 // resize total to contain newly disasm insns
413 void *tmp = realloc(total, total_size + f * sizeof(insn_cache[0]));
414 if (tmp == NULL) { // insufficient memory
415 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800416 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800417 return 0;
418 }
419
420 total = tmp;
421 memcpy(total + total_size, insn_cache, f * sizeof(insn_cache[0]));
422 }
423
424 *insn = total;
425
426 return c;
427}
428
429void cs_free(void *m)
430{
431 free(m);
432}
433
434// return friendly name of regiser in a string
pancakef0e4eed2013-12-11 22:14:42 +0100435const char *cs_reg_name(csh ud, unsigned int reg)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800436{
437 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
438
439 if (!handle || handle->reg_name == NULL) {
440 return NULL;
441 }
442
Nguyen Anh Quynha253c7a2013-12-09 10:26:18 +0800443 return handle->reg_name(ud, reg);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800444}
445
pancakef0e4eed2013-12-11 22:14:42 +0100446const char *cs_insn_name(csh ud, unsigned int insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800447{
448 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
449
450 if (!handle || handle->insn_name == NULL) {
451 return NULL;
452 }
453
Nguyen Anh Quynha253c7a2013-12-09 10:26:18 +0800454 return handle->insn_name(ud, insn);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800455}
456
Nguyen Anh Quynh70083562013-12-20 22:02:20 +0800457static bool arr_exist(unsigned char *arr, unsigned char max, unsigned int id)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800458{
459 int i;
460
461 for (i = 0; i < max; i++) {
462 if (arr[i] == id)
463 return true;
464 }
465
466 return false;
467}
468
469bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
470{
471 if (!handle)
472 return false;
473
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800474 return arr_exist(insn->groups, insn->groups_count, group_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800475}
476
477bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
478{
479 if (!handle)
480 return false;
481
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800482 return arr_exist(insn->regs_read, insn->regs_read_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800483}
484
485bool cs_reg_write(csh handle, cs_insn *insn, unsigned int reg_id)
486{
487 if (!handle)
488 return false;
489
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800490 return arr_exist(insn->regs_write, insn->regs_write_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800491}
492
493int cs_op_count(csh ud, cs_insn *insn, unsigned int op_type)
494{
495 if (!ud)
496 return -1;
497
498 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
499 unsigned int count = 0, i;
500
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800501 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800502
503 switch (handle->arch) {
504 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800505 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800506 return -1;
507 case CS_ARCH_ARM:
508 for (i = 0; i < insn->arm.op_count; i++)
509 if (insn->arm.operands[i].type == op_type)
510 count++;
511 break;
512 case CS_ARCH_ARM64:
513 for (i = 0; i < insn->arm64.op_count; i++)
514 if (insn->arm64.operands[i].type == op_type)
515 count++;
516 break;
517 case CS_ARCH_X86:
518 for (i = 0; i < insn->x86.op_count; i++)
519 if (insn->x86.operands[i].type == op_type)
520 count++;
521 break;
522 case CS_ARCH_MIPS:
523 for (i = 0; i < insn->mips.op_count; i++)
524 if (insn->mips.operands[i].type == op_type)
525 count++;
526 break;
527 }
528
529 return count;
530}
531
532int cs_op_index(csh ud, cs_insn *insn, unsigned int op_type,
533 unsigned int post)
534{
535 if (!ud)
536 return -1;
537
538 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
539 unsigned int count = 0, i;
540
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800541 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800542
543 switch (handle->arch) {
544 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800545 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800546 return -1;
547 case CS_ARCH_ARM:
548 for (i = 0; i < insn->arm.op_count; i++) {
549 if (insn->arm.operands[i].type == op_type)
550 count++;
551 if (count == post)
552 return i;
553 }
554 break;
555 case CS_ARCH_ARM64:
556 for (i = 0; i < insn->arm64.op_count; i++) {
557 if (insn->arm64.operands[i].type == op_type)
558 count++;
559 if (count == post)
560 return i;
561 }
562 break;
563 case CS_ARCH_X86:
564 for (i = 0; i < insn->x86.op_count; i++) {
565 if (insn->x86.operands[i].type == op_type)
566 count++;
567 if (count == post)
568 return i;
569 }
570 break;
571 case CS_ARCH_MIPS:
572 for (i = 0; i < insn->mips.op_count; i++) {
573 if (insn->mips.operands[i].type == op_type)
574 count++;
575 if (count == post)
576 return i;
577 }
578 break;
579 }
580
581 return -1;
582}