1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/third_party/libdisasm/ia32_implicit.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,422 @@ 1.4 +#include <stdlib.h> 1.5 + 1.6 +#include "ia32_implicit.h" 1.7 +#include "ia32_insn.h" 1.8 +#include "ia32_reg.h" 1.9 +#include "x86_operand_list.h" 1.10 + 1.11 +/* Conventions: Register operands which are aliases of another register 1.12 + * operand (e.g. AX in one operand and AL in another) assume that the 1.13 + * operands are different registers and that alias tracking will resolve 1.14 + * data flow. This means that something like 1.15 + * mov ax, al 1.16 + * would have 'write only' access for AX and 'read only' access for AL, 1.17 + * even though both AL and AX are read and written */ 1.18 +typedef struct { 1.19 + uint32_t type; 1.20 + uint32_t operand; 1.21 +} op_implicit_list_t; 1.22 + 1.23 +static op_implicit_list_t list_aaa[] = 1.24 + /* 37 : AAA : rw AL */ 1.25 + /* 3F : AAS : rw AL */ 1.26 + {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* aaa */ 1.27 + 1.28 +static op_implicit_list_t list_aad[] = 1.29 + /* D5 0A, D5 (ib) : AAD : rw AX */ 1.30 + /* D4 0A, D4 (ib) : AAM : rw AX */ 1.31 + {{ OP_R | OP_W, REG_WORD_OFFSET }, {0}}; /* aad */ 1.32 + 1.33 +static op_implicit_list_t list_call[] = 1.34 + /* E8, FF, 9A, FF : CALL : rw ESP, rw EIP */ 1.35 + /* C2, C3, CA, CB : RET : rw ESP, rw EIP */ 1.36 + {{ OP_R | OP_W, REG_EIP_INDEX }, 1.37 + { OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* call, ret */ 1.38 + 1.39 +static op_implicit_list_t list_cbw[] = 1.40 + /* 98 : CBW : r AL, rw AX */ 1.41 + {{ OP_R | OP_W, REG_WORD_OFFSET }, 1.42 + { OP_R, REG_BYTE_OFFSET}, {0}}; /* cbw */ 1.43 + 1.44 +static op_implicit_list_t list_cwde[] = 1.45 + /* 98 : CWDE : r AX, rw EAX */ 1.46 + {{ OP_R | OP_W, REG_DWORD_OFFSET }, 1.47 + { OP_R, REG_WORD_OFFSET }, {0}}; /* cwde */ 1.48 + 1.49 +static op_implicit_list_t list_clts[] = 1.50 + /* 0F 06 : CLTS : rw CR0 */ 1.51 + {{ OP_R | OP_W, REG_CTRL_OFFSET}, {0}}; /* clts */ 1.52 + 1.53 +static op_implicit_list_t list_cmpxchg[] = 1.54 + /* 0F B0 : CMPXCHG : rw AL */ 1.55 + {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* cmpxchg */ 1.56 + 1.57 +static op_implicit_list_t list_cmpxchgb[] = 1.58 + /* 0F B1 : CMPXCHG : rw EAX */ 1.59 + {{ OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* cmpxchg */ 1.60 + 1.61 +static op_implicit_list_t list_cmpxchg8b[] = 1.62 + /* 0F C7 : CMPXCHG8B : rw EDX, rw EAX, r ECX, r EBX */ 1.63 + {{ OP_R | OP_W, REG_DWORD_OFFSET }, 1.64 + { OP_R | OP_W, REG_DWORD_OFFSET + 2 }, 1.65 + { OP_R, REG_DWORD_OFFSET + 1 }, 1.66 + { OP_R, REG_DWORD_OFFSET + 3 }, {0}}; /* cmpxchg8b */ 1.67 + 1.68 +static op_implicit_list_t list_cpuid[] = 1.69 + /* 0F A2 : CPUID : rw EAX, w EBX, w ECX, w EDX */ 1.70 + {{ OP_R | OP_W, REG_DWORD_OFFSET }, 1.71 + { OP_W, REG_DWORD_OFFSET + 1 }, 1.72 + { OP_W, REG_DWORD_OFFSET + 2 }, 1.73 + { OP_W, REG_DWORD_OFFSET + 3 }, {0}}; /* cpuid */ 1.74 + 1.75 +static op_implicit_list_t list_cwd[] = 1.76 + /* 99 : CWD/CWQ : rw EAX, w EDX */ 1.77 + {{ OP_R | OP_W, REG_DWORD_OFFSET }, 1.78 + { OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* cwd */ 1.79 + 1.80 +static op_implicit_list_t list_daa[] = 1.81 + /* 27 : DAA : rw AL */ 1.82 + /* 2F : DAS : rw AL */ 1.83 + {{ OP_R | OP_W, REG_BYTE_OFFSET }, {0}}; /* daa */ 1.84 + 1.85 +static op_implicit_list_t list_idiv[] = 1.86 + /* F6 : DIV, IDIV : r AX, w AL, w AH */ 1.87 + /* FIXED: first op was EAX, not Aw. TODO: verify! */ 1.88 + {{ OP_R, REG_WORD_OFFSET }, 1.89 + { OP_W, REG_BYTE_OFFSET }, 1.90 + { OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* div */ 1.91 + 1.92 +static op_implicit_list_t list_div[] = 1.93 + /* F7 : DIV, IDIV : rw EDX, rw EAX */ 1.94 + {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 }, 1.95 + { OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* div */ 1.96 + 1.97 +static op_implicit_list_t list_enter[] = 1.98 + /* C8 : ENTER : rw ESP w EBP */ 1.99 + {{ OP_R | OP_W, REG_DWORD_OFFSET + 4 }, 1.100 + { OP_R, REG_DWORD_OFFSET + 5 }, {0}}; /* enter */ 1.101 + 1.102 +static op_implicit_list_t list_f2xm1[] = 1.103 + /* D9 F0 : F2XM1 : rw ST(0) */ 1.104 + /* D9 E1 : FABS : rw ST(0) */ 1.105 + /* D9 E0 : FCHS : rw ST(0) */ 1.106 + /* D9 FF : FCOS : rw ST(0)*/ 1.107 + /* D8, DA : FDIV : rw ST(0) */ 1.108 + /* D8, DA : FDIVR : rw ST(0) */ 1.109 + /* D9 F2 : FPTAN : rw ST(0) */ 1.110 + /* D9 FC : FRNDINT : rw ST(0) */ 1.111 + /* D9 FB : FSINCOS : rw ST(0) */ 1.112 + /* D9 FE : FSIN : rw ST(0) */ 1.113 + /* D9 FA : FSQRT : rw ST(0) */ 1.114 + /* D9 F4 : FXTRACT : rw ST(0) */ 1.115 + {{ OP_R | OP_W, REG_FPU_OFFSET }, {0}}; /* f2xm1 */ 1.116 + 1.117 +static op_implicit_list_t list_fcom[] = 1.118 + /* D8, DC, DE D9 : FCOM : r ST(0) */ 1.119 + /* DE, DA : FICOM : r ST(0) */ 1.120 + /* DF, D8 : FIST : r ST(0) */ 1.121 + /* D9 E4 : FTST : r ST(0) */ 1.122 + /* D9 E5 : FXAM : r ST(0) */ 1.123 + {{ OP_R, REG_FPU_OFFSET }, {0}}; /* fcom */ 1.124 + 1.125 +static op_implicit_list_t list_fpatan[] = 1.126 + /* D9 F3 : FPATAN : r ST(0), rw ST(1) */ 1.127 + {{ OP_R, REG_FPU_OFFSET }, {0}}; /* fpatan */ 1.128 + 1.129 +static op_implicit_list_t list_fprem[] = 1.130 + /* D9 F8, D9 F5 : FPREM : rw ST(0) r ST(1) */ 1.131 + /* D9 FD : FSCALE : rw ST(0), r ST(1) */ 1.132 + {{ OP_R | OP_W, REG_FPU_OFFSET }, 1.133 + { OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fprem */ 1.134 + 1.135 +static op_implicit_list_t list_faddp[] = 1.136 + /* DE C1 : FADDP : r ST(0), rw ST(1) */ 1.137 + /* DE E9 : FSUBP : r ST(0), rw ST(1) */ 1.138 + /* D9 F1 : FYL2X : r ST(0), rw ST(1) */ 1.139 + /* D9 F9 : FYL2XP1 : r ST(0), rw ST(1) */ 1.140 + {{ OP_R, REG_FPU_OFFSET }, 1.141 + { OP_R | OP_W, REG_FPU_OFFSET + 1 }, {0}}; /* faddp */ 1.142 + 1.143 +static op_implicit_list_t list_fucompp[] = 1.144 + /* DA E9 : FUCOMPP : r ST(0), r ST(1) */ 1.145 + {{ OP_R, REG_FPU_OFFSET }, 1.146 + { OP_R, REG_FPU_OFFSET + 1 }, {0}}; /* fucompp */ 1.147 + 1.148 +static op_implicit_list_t list_imul[] = 1.149 + /* F6 : IMUL : r AL, w AX */ 1.150 + /* F6 : MUL : r AL, w AX */ 1.151 + {{ OP_R, REG_BYTE_OFFSET }, 1.152 + { OP_W, REG_WORD_OFFSET }, {0}}; /* imul */ 1.153 + 1.154 +static op_implicit_list_t list_mul[] = 1.155 + /* F7 : IMUL : rw EAX, w EDX */ 1.156 + /* F7 : MUL : rw EAX, w EDX */ 1.157 + {{ OP_R | OP_W, REG_DWORD_OFFSET }, 1.158 + { OP_W, REG_DWORD_OFFSET + 2 }, {0}}; /* imul */ 1.159 + 1.160 +static op_implicit_list_t list_lahf[] = 1.161 + /* 9F : LAHF : r EFLAGS, w AH */ 1.162 + {{ OP_R, REG_FLAGS_INDEX }, 1.163 + { OP_W, REG_BYTE_OFFSET + 4 }, {0}}; /* lahf */ 1.164 + 1.165 +static op_implicit_list_t list_ldmxcsr[] = 1.166 + /* 0F AE : LDMXCSR : w MXCSR SSE Control Status Reg */ 1.167 + {{ OP_W, REG_MXCSG_INDEX }, {0}}; /* ldmxcsr */ 1.168 + 1.169 +static op_implicit_list_t list_leave[] = 1.170 + /* C9 : LEAVE : rw ESP, w EBP */ 1.171 + {{ OP_R | OP_W, REG_ESP_INDEX }, 1.172 + { OP_W, REG_DWORD_OFFSET + 5 }, {0}}; /* leave */ 1.173 + 1.174 +static op_implicit_list_t list_lgdt[] = 1.175 + /* 0F 01 : LGDT : w GDTR */ 1.176 + {{ OP_W, REG_GDTR_INDEX }, {0}}; /* lgdt */ 1.177 + 1.178 +static op_implicit_list_t list_lidt[] = 1.179 + /* 0F 01 : LIDT : w IDTR */ 1.180 + {{ OP_W, REG_IDTR_INDEX }, {0}}; /* lidt */ 1.181 + 1.182 +static op_implicit_list_t list_lldt[] = 1.183 + /* 0F 00 : LLDT : w LDTR */ 1.184 + {{ OP_W, REG_LDTR_INDEX }, {0}}; /* lldt */ 1.185 + 1.186 +static op_implicit_list_t list_lmsw[] = 1.187 + /* 0F 01 : LMSW : w CR0 */ 1.188 + {{ OP_W, REG_CTRL_OFFSET }, {0}}; /* lmsw */ 1.189 + 1.190 +static op_implicit_list_t list_loop[] = 1.191 + /* E0, E1, E2 : LOOP : rw ECX */ 1.192 + {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* loop */ 1.193 + 1.194 +static op_implicit_list_t list_ltr[] = 1.195 + /* 0F 00 : LTR : w Task Register */ 1.196 + {{ OP_W, REG_TR_INDEX }, {0}}; /* ltr */ 1.197 + 1.198 +static op_implicit_list_t list_pop[] = 1.199 + /* 8F, 58, 1F, 07, 17, 0F A1, 0F A9 : POP : rw ESP */ 1.200 + /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */ 1.201 + {{ OP_R | OP_W, REG_ESP_INDEX }, {0}}; /* pop, push */ 1.202 + 1.203 +static op_implicit_list_t list_popad[] = 1.204 + /* 61 : POPAD : rw esp, w edi esi ebp ebx edx ecx eax */ 1.205 + {{ OP_R | OP_W, REG_ESP_INDEX }, 1.206 + { OP_W, REG_DWORD_OFFSET + 7 }, 1.207 + { OP_W, REG_DWORD_OFFSET + 6 }, 1.208 + { OP_W, REG_DWORD_OFFSET + 5 }, 1.209 + { OP_W, REG_DWORD_OFFSET + 3 }, 1.210 + { OP_W, REG_DWORD_OFFSET + 2 }, 1.211 + { OP_W, REG_DWORD_OFFSET + 1 }, 1.212 + { OP_W, REG_DWORD_OFFSET }, {0}}; /* popad */ 1.213 + 1.214 +static op_implicit_list_t list_popfd[] = 1.215 + /* 9D : POPFD : rw esp, w eflags */ 1.216 + {{ OP_R | OP_W, REG_ESP_INDEX }, 1.217 + { OP_W, REG_FLAGS_INDEX }, {0}}; /* popfd */ 1.218 + 1.219 +static op_implicit_list_t list_pushad[] = 1.220 + /* FF, 50, 6A, 68, 0E, 16, 1E, 06, 0F A0, 0F A8 : PUSH : rw ESP */ 1.221 + /* 60 : PUSHAD : rw esp, r eax ecx edx ebx esp ebp esi edi */ 1.222 + {{ OP_R | OP_W, REG_ESP_INDEX }, 1.223 + { OP_R, REG_DWORD_OFFSET }, 1.224 + { OP_R, REG_DWORD_OFFSET + 1 }, 1.225 + { OP_R, REG_DWORD_OFFSET + 2 }, 1.226 + { OP_R, REG_DWORD_OFFSET + 3 }, 1.227 + { OP_R, REG_DWORD_OFFSET + 5 }, 1.228 + { OP_R, REG_DWORD_OFFSET + 6 }, 1.229 + { OP_R, REG_DWORD_OFFSET + 7 }, {0}}; /* pushad */ 1.230 + 1.231 +static op_implicit_list_t list_pushfd[] = 1.232 + /* 9C : PUSHFD : rw esp, r eflags */ 1.233 + {{ OP_R | OP_W, REG_ESP_INDEX }, 1.234 + { OP_R, REG_FLAGS_INDEX }, {0}}; /* pushfd */ 1.235 + 1.236 +static op_implicit_list_t list_rdmsr[] = 1.237 + /* 0F 32 : RDMSR : r ECX, w EDX, w EAX */ 1.238 + {{ OP_R, REG_DWORD_OFFSET + 1 }, 1.239 + { OP_W, REG_DWORD_OFFSET + 2 }, 1.240 + { OP_W, REG_DWORD_OFFSET }, {0}}; /* rdmsr */ 1.241 + 1.242 +static op_implicit_list_t list_rdpmc[] = 1.243 + /* 0F 33 : RDPMC : r ECX, w EDX, w EAX */ 1.244 + {{ OP_R, REG_DWORD_OFFSET + 1 }, 1.245 + { OP_W, REG_DWORD_OFFSET + 2 }, 1.246 + { OP_W, REG_DWORD_OFFSET }, {0}}; /* rdpmc */ 1.247 + 1.248 +static op_implicit_list_t list_rdtsc[] = 1.249 + /* 0F 31 : RDTSC : rw EDX, rw EAX */ 1.250 + {{ OP_R | OP_W, REG_DWORD_OFFSET + 2 }, 1.251 + { OP_R | OP_W, REG_DWORD_OFFSET }, {0}}; /* rdtsc */ 1.252 + 1.253 +static op_implicit_list_t list_rep[] = 1.254 + /* F3, F2 ... : REP : rw ECX */ 1.255 + {{ OP_R | OP_W, REG_DWORD_OFFSET + 1 }, {0}};/* rep */ 1.256 + 1.257 +static op_implicit_list_t list_rsm[] = 1.258 + /* 0F AA : RSM : r CR4, r CR0 */ 1.259 + {{ OP_R, REG_CTRL_OFFSET + 4 }, 1.260 + { OP_R, REG_CTRL_OFFSET }, {0}}; /* rsm */ 1.261 + 1.262 +static op_implicit_list_t list_sahf[] = 1.263 + /* 9E : SAHF : r ah, rw eflags (set SF ZF AF PF CF) */ 1.264 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sahf */ 1.265 + 1.266 +static op_implicit_list_t list_sgdt[] = 1.267 + /* 0F : SGDT : r gdtr */ 1.268 + /* TODO: finish this! */ 1.269 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sgdt */ 1.270 + 1.271 +static op_implicit_list_t list_sidt[] = 1.272 + /* 0F : SIDT : r idtr */ 1.273 + /* TODO: finish this! */ 1.274 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sidt */ 1.275 + 1.276 +static op_implicit_list_t list_sldt[] = 1.277 + /* 0F : SLDT : r ldtr */ 1.278 + /* TODO: finish this! */ 1.279 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sldt */ 1.280 + 1.281 +static op_implicit_list_t list_smsw[] = 1.282 + /* 0F : SMSW : r CR0 */ 1.283 + /* TODO: finish this! */ 1.284 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* smsw */ 1.285 + 1.286 +static op_implicit_list_t list_stmxcsr[] = 1.287 + /* 0F AE : STMXCSR : r MXCSR */ 1.288 + /* TODO: finish this! */ 1.289 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* stmxcsr */ 1.290 + 1.291 +static op_implicit_list_t list_str[] = 1.292 + /* 0F 00 : STR : r TR (task register) */ 1.293 + /* TODO: finish this! */ 1.294 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* str */ 1.295 + 1.296 +static op_implicit_list_t list_sysenter[] = 1.297 + /* 0F 34 : SYSENTER : w cs, w eip, w ss, w esp, r CR0, w eflags 1.298 + * r sysenter_cs_msr, sysenter_esp_msr, sysenter_eip_msr */ 1.299 + /* TODO: finish this! */ 1.300 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysenter */ 1.301 + 1.302 +static op_implicit_list_t list_sysexit[] = 1.303 + /* 0F 35 : SYSEXIT : r edx, r ecx, w cs, w eip, w ss, w esp 1.304 + * r sysenter_cs_msr */ 1.305 + /* TODO: finish this! */ 1.306 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* sysexit */ 1.307 + 1.308 +static op_implicit_list_t list_wrmsr[] = 1.309 + /* 0F 30 : WRMST : r edx, r eax, r ecx */ 1.310 + /* TODO: finish this! */ 1.311 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* wrmsr */ 1.312 + 1.313 +static op_implicit_list_t list_xlat[] = 1.314 + /* D7 : XLAT : rw al r ebx (ptr) */ 1.315 + /* TODO: finish this! */ 1.316 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* xlat */ 1.317 +/* TODO: 1.318 + * monitor 0f 01 c8 eax OP_R ecx OP_R edx OP_R 1.319 + * mwait 0f 01 c9 eax OP_R ecx OP_R 1.320 + */ 1.321 +static op_implicit_list_t list_monitor[] = 1.322 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* monitor */ 1.323 +static op_implicit_list_t list_mwait[] = 1.324 + {{ OP_R, REG_DWORD_OFFSET }, {0}}; /* mwait */ 1.325 + 1.326 +op_implicit_list_t *op_implicit_list[] = { 1.327 + /* This is a list of implicit operands which are read/written by 1.328 + * various x86 instructions. Note that modifications to the stack 1.329 + * register are mentioned here, but that additional information on 1.330 + * the effect an instruction has on the stack is contained in the 1.331 + * x86_insn_t 'stack_mod' and 'stack_mod_val' fields. Use of the 1.332 + * eflags register, i.e. setting, clearing, and testing flags, is 1.333 + * not recorded here but rather in the flags_set and flags_tested 1.334 + * fields of the x86_insn_t.*/ 1.335 + NULL, 1.336 + list_aaa, list_aad, list_call, list_cbw, /* 1 - 4 */ 1.337 + list_cwde, list_clts, list_cmpxchg, list_cmpxchgb, /* 5 - 8 */ 1.338 + list_cmpxchg8b, list_cpuid, list_cwd, list_daa, /* 9 - 12 */ 1.339 + list_idiv, list_div, list_enter, list_f2xm1, /* 13 - 16 */ 1.340 + list_fcom, list_fpatan, list_fprem, list_faddp, /* 17 - 20 */ 1.341 + list_fucompp, list_imul, list_mul, list_lahf, /* 21 - 24 */ 1.342 + list_ldmxcsr, list_leave, list_lgdt, list_lidt, /* 25 - 28 */ 1.343 + list_lldt, list_lmsw, list_loop, list_ltr, /* 29 - 32 */ 1.344 + list_pop, list_popad, list_popfd, list_pushad, /* 33 - 36 */ 1.345 + list_pushfd, list_rdmsr, list_rdpmc, list_rdtsc, /* 37 - 40 */ 1.346 + /* NOTE: 'REP' is a hack since it is a prefix: if its position 1.347 + * in the table changes, then change IDX_IMPLICIT_REP in the .h */ 1.348 + list_rep, list_rsm, list_sahf, list_sgdt, /* 41 - 44 */ 1.349 + list_sidt, list_sldt, list_smsw, list_stmxcsr, /* 45 - 48 */ 1.350 + list_str, list_sysenter, list_sysexit, list_wrmsr, /* 49 - 52 */ 1.351 + list_xlat, list_monitor, list_mwait, /* 53 - 55*/ 1.352 + NULL /* end of list */ 1.353 + }; 1.354 + 1.355 +#define LAST_IMPL_IDX 55 1.356 + 1.357 +static void handle_impl_reg( x86_op_t *op, uint32_t val ) { 1.358 + x86_reg_t *reg = &op->data.reg; 1.359 + op->type = op_register; 1.360 + ia32_handle_register( reg, (unsigned int) val ); 1.361 + switch (reg->size) { 1.362 + case 1: 1.363 + op->datatype = op_byte; break; 1.364 + case 2: 1.365 + op->datatype = op_word; break; 1.366 + case 4: 1.367 + op->datatype = op_dword; break; 1.368 + case 8: 1.369 + op->datatype = op_qword; break; 1.370 + case 10: 1.371 + op->datatype = op_extreal; break; 1.372 + case 16: 1.373 + op->datatype = op_dqword; break; 1.374 + } 1.375 + return; 1.376 +} 1.377 + 1.378 +/* 'impl_idx' is the value from the opcode table: between 1 and LAST_IMPL_IDX */ 1.379 +/* returns number of operands added */ 1.380 +unsigned int ia32_insn_implicit_ops( x86_insn_t *insn, unsigned int impl_idx ) { 1.381 + op_implicit_list_t *list; 1.382 + x86_op_t *op; 1.383 + unsigned int num = 0; 1.384 + 1.385 + if (! impl_idx || impl_idx > LAST_IMPL_IDX ) { 1.386 + return 0; 1.387 + } 1.388 + 1.389 + for ( list = op_implicit_list[impl_idx]; list->type; list++, num++ ) { 1.390 + enum x86_op_access access = (enum x86_op_access) OP_PERM(list->type); 1.391 + enum x86_op_flags flags = (enum x86_op_flags) (OP_FLAGS(list->type) >> 12); 1.392 + 1.393 + op = NULL; 1.394 + /* In some cases (MUL), EAX is an implicit operand hardcoded in 1.395 + * the instruction without being explicitly listed in assembly. 1.396 + * For this situation, find the hardcoded operand and add the 1.397 + * implied flag rather than adding a new implicit operand. */ 1.398 + x86_oplist_t * existing; 1.399 + if (ia32_true_register_id(list->operand) == REG_DWORD_OFFSET) { 1.400 + for ( existing = insn->operands; existing; existing = existing->next ) { 1.401 + if (existing->op.type == op_register && 1.402 + existing->op.data.reg.id == list->operand) { 1.403 + op = &existing->op; 1.404 + break; 1.405 + } 1.406 + } 1.407 + } 1.408 + if (!op) { 1.409 + op = x86_operand_new( insn ); 1.410 + /* all implicit operands are registers */ 1.411 + handle_impl_reg( op, list->operand ); 1.412 + /* decrement the 'explicit count' incremented by default in 1.413 + * x86_operand_new */ 1.414 + insn->explicit_count = insn->explicit_count -1; 1.415 + } 1.416 + if (!op) { 1.417 + return num; /* gah! return early */ 1.418 + } 1.419 + op->access |= access; 1.420 + op->flags |= flags; 1.421 + op->flags |= op_implied; 1.422 + } 1.423 + 1.424 + return num; 1.425 +}