18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * x86 instruction analysis 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) IBM Corporation, 2002, 2004, 2009 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifdef __KERNEL__ 98c2ecf20Sopenharmony_ci#include <linux/string.h> 108c2ecf20Sopenharmony_ci#else 118c2ecf20Sopenharmony_ci#include <string.h> 128c2ecf20Sopenharmony_ci#endif 138c2ecf20Sopenharmony_ci#include "../include/asm/inat.h" /* __ignore_sync_check__ */ 148c2ecf20Sopenharmony_ci#include "../include/asm/insn.h" /* __ignore_sync_check__ */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/kconfig.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "../include/asm/emulate_prefix.h" /* __ignore_sync_check__ */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Verify next sizeof(t) bytes can be on the same instruction */ 228c2ecf20Sopenharmony_ci#define validate_next(t, insn, n) \ 238c2ecf20Sopenharmony_ci ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define __get_next(t, insn) \ 268c2ecf20Sopenharmony_ci ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define __peek_nbyte_next(t, insn, n) \ 298c2ecf20Sopenharmony_ci ({ t r = *(t*)((insn)->next_byte + n); r; }) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define get_next(t, insn) \ 328c2ecf20Sopenharmony_ci ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define peek_nbyte_next(t, insn, n) \ 358c2ecf20Sopenharmony_ci ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * insn_init() - initialize struct insn 418c2ecf20Sopenharmony_ci * @insn: &struct insn to be initialized 428c2ecf20Sopenharmony_ci * @kaddr: address (in kernel memory) of instruction (or copy thereof) 438c2ecf20Sopenharmony_ci * @x86_64: !0 for 64-bit kernel or 64-bit app 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_civoid insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid 498c2ecf20Sopenharmony_ci * even if the input buffer is long enough to hold them. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci if (buf_len > MAX_INSN_SIZE) 528c2ecf20Sopenharmony_ci buf_len = MAX_INSN_SIZE; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci memset(insn, 0, sizeof(*insn)); 558c2ecf20Sopenharmony_ci insn->kaddr = kaddr; 568c2ecf20Sopenharmony_ci insn->end_kaddr = kaddr + buf_len; 578c2ecf20Sopenharmony_ci insn->next_byte = kaddr; 588c2ecf20Sopenharmony_ci insn->x86_64 = x86_64 ? 1 : 0; 598c2ecf20Sopenharmony_ci insn->opnd_bytes = 4; 608c2ecf20Sopenharmony_ci if (x86_64) 618c2ecf20Sopenharmony_ci insn->addr_bytes = 8; 628c2ecf20Sopenharmony_ci else 638c2ecf20Sopenharmony_ci insn->addr_bytes = 4; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX }; 678c2ecf20Sopenharmony_cistatic const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX }; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int __insn_get_emulate_prefix(struct insn *insn, 708c2ecf20Sopenharmony_ci const insn_byte_t *prefix, size_t len) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci size_t i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 758c2ecf20Sopenharmony_ci if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i]) 768c2ecf20Sopenharmony_ci goto err_out; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci insn->emulate_prefix_size = len; 808c2ecf20Sopenharmony_ci insn->next_byte += len; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return 1; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cierr_out: 858c2ecf20Sopenharmony_ci return 0; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void insn_get_emulate_prefix(struct insn *insn) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix))) 918c2ecf20Sopenharmony_ci return; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci __insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix)); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * insn_get_prefixes - scan x86 instruction prefix bytes 988c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Populates the @insn->prefixes bitmap, and updates @insn->next_byte 1018c2ecf20Sopenharmony_ci * to point to the (first) opcode. No effect if @insn->prefixes.got 1028c2ecf20Sopenharmony_ci * is already set. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * * Returns: 1058c2ecf20Sopenharmony_ci * 0: on success 1068c2ecf20Sopenharmony_ci * < 0: on error 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ciint insn_get_prefixes(struct insn *insn) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct insn_field *prefixes = &insn->prefixes; 1118c2ecf20Sopenharmony_ci insn_attr_t attr; 1128c2ecf20Sopenharmony_ci insn_byte_t b, lb; 1138c2ecf20Sopenharmony_ci int i, nb; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (prefixes->got) 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci insn_get_emulate_prefix(insn); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci nb = 0; 1218c2ecf20Sopenharmony_ci lb = 0; 1228c2ecf20Sopenharmony_ci b = peek_next(insn_byte_t, insn); 1238c2ecf20Sopenharmony_ci attr = inat_get_opcode_attribute(b); 1248c2ecf20Sopenharmony_ci while (inat_is_legacy_prefix(attr)) { 1258c2ecf20Sopenharmony_ci /* Skip if same prefix */ 1268c2ecf20Sopenharmony_ci for (i = 0; i < nb; i++) 1278c2ecf20Sopenharmony_ci if (prefixes->bytes[i] == b) 1288c2ecf20Sopenharmony_ci goto found; 1298c2ecf20Sopenharmony_ci if (nb == 4) 1308c2ecf20Sopenharmony_ci /* Invalid instruction */ 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci prefixes->bytes[nb++] = b; 1338c2ecf20Sopenharmony_ci if (inat_is_address_size_prefix(attr)) { 1348c2ecf20Sopenharmony_ci /* address size switches 2/4 or 4/8 */ 1358c2ecf20Sopenharmony_ci if (insn->x86_64) 1368c2ecf20Sopenharmony_ci insn->addr_bytes ^= 12; 1378c2ecf20Sopenharmony_ci else 1388c2ecf20Sopenharmony_ci insn->addr_bytes ^= 6; 1398c2ecf20Sopenharmony_ci } else if (inat_is_operand_size_prefix(attr)) { 1408c2ecf20Sopenharmony_ci /* oprand size switches 2/4 */ 1418c2ecf20Sopenharmony_ci insn->opnd_bytes ^= 6; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_cifound: 1448c2ecf20Sopenharmony_ci prefixes->nbytes++; 1458c2ecf20Sopenharmony_ci insn->next_byte++; 1468c2ecf20Sopenharmony_ci lb = b; 1478c2ecf20Sopenharmony_ci b = peek_next(insn_byte_t, insn); 1488c2ecf20Sopenharmony_ci attr = inat_get_opcode_attribute(b); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci /* Set the last prefix */ 1518c2ecf20Sopenharmony_ci if (lb && lb != insn->prefixes.bytes[3]) { 1528c2ecf20Sopenharmony_ci if (unlikely(insn->prefixes.bytes[3])) { 1538c2ecf20Sopenharmony_ci /* Swap the last prefix */ 1548c2ecf20Sopenharmony_ci b = insn->prefixes.bytes[3]; 1558c2ecf20Sopenharmony_ci for (i = 0; i < nb; i++) 1568c2ecf20Sopenharmony_ci if (prefixes->bytes[i] == lb) 1578c2ecf20Sopenharmony_ci prefixes->bytes[i] = b; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci insn->prefixes.bytes[3] = lb; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Decode REX prefix */ 1638c2ecf20Sopenharmony_ci if (insn->x86_64) { 1648c2ecf20Sopenharmony_ci b = peek_next(insn_byte_t, insn); 1658c2ecf20Sopenharmony_ci attr = inat_get_opcode_attribute(b); 1668c2ecf20Sopenharmony_ci if (inat_is_rex_prefix(attr)) { 1678c2ecf20Sopenharmony_ci insn->rex_prefix.value = b; 1688c2ecf20Sopenharmony_ci insn->rex_prefix.nbytes = 1; 1698c2ecf20Sopenharmony_ci insn->next_byte++; 1708c2ecf20Sopenharmony_ci if (X86_REX_W(b)) 1718c2ecf20Sopenharmony_ci /* REX.W overrides opnd_size */ 1728c2ecf20Sopenharmony_ci insn->opnd_bytes = 8; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci insn->rex_prefix.got = 1; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* Decode VEX prefix */ 1788c2ecf20Sopenharmony_ci b = peek_next(insn_byte_t, insn); 1798c2ecf20Sopenharmony_ci attr = inat_get_opcode_attribute(b); 1808c2ecf20Sopenharmony_ci if (inat_is_vex_prefix(attr)) { 1818c2ecf20Sopenharmony_ci insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); 1828c2ecf20Sopenharmony_ci if (!insn->x86_64) { 1838c2ecf20Sopenharmony_ci /* 1848c2ecf20Sopenharmony_ci * In 32-bits mode, if the [7:6] bits (mod bits of 1858c2ecf20Sopenharmony_ci * ModRM) on the second byte are not 11b, it is 1868c2ecf20Sopenharmony_ci * LDS or LES or BOUND. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci if (X86_MODRM_MOD(b2) != 3) 1898c2ecf20Sopenharmony_ci goto vex_end; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci insn->vex_prefix.bytes[0] = b; 1928c2ecf20Sopenharmony_ci insn->vex_prefix.bytes[1] = b2; 1938c2ecf20Sopenharmony_ci if (inat_is_evex_prefix(attr)) { 1948c2ecf20Sopenharmony_ci b2 = peek_nbyte_next(insn_byte_t, insn, 2); 1958c2ecf20Sopenharmony_ci insn->vex_prefix.bytes[2] = b2; 1968c2ecf20Sopenharmony_ci b2 = peek_nbyte_next(insn_byte_t, insn, 3); 1978c2ecf20Sopenharmony_ci insn->vex_prefix.bytes[3] = b2; 1988c2ecf20Sopenharmony_ci insn->vex_prefix.nbytes = 4; 1998c2ecf20Sopenharmony_ci insn->next_byte += 4; 2008c2ecf20Sopenharmony_ci if (insn->x86_64 && X86_VEX_W(b2)) 2018c2ecf20Sopenharmony_ci /* VEX.W overrides opnd_size */ 2028c2ecf20Sopenharmony_ci insn->opnd_bytes = 8; 2038c2ecf20Sopenharmony_ci } else if (inat_is_vex3_prefix(attr)) { 2048c2ecf20Sopenharmony_ci b2 = peek_nbyte_next(insn_byte_t, insn, 2); 2058c2ecf20Sopenharmony_ci insn->vex_prefix.bytes[2] = b2; 2068c2ecf20Sopenharmony_ci insn->vex_prefix.nbytes = 3; 2078c2ecf20Sopenharmony_ci insn->next_byte += 3; 2088c2ecf20Sopenharmony_ci if (insn->x86_64 && X86_VEX_W(b2)) 2098c2ecf20Sopenharmony_ci /* VEX.W overrides opnd_size */ 2108c2ecf20Sopenharmony_ci insn->opnd_bytes = 8; 2118c2ecf20Sopenharmony_ci } else { 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * For VEX2, fake VEX3-like byte#2. 2148c2ecf20Sopenharmony_ci * Makes it easier to decode vex.W, vex.vvvv, 2158c2ecf20Sopenharmony_ci * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci insn->vex_prefix.bytes[2] = b2 & 0x7f; 2188c2ecf20Sopenharmony_ci insn->vex_prefix.nbytes = 2; 2198c2ecf20Sopenharmony_ci insn->next_byte += 2; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_civex_end: 2238c2ecf20Sopenharmony_ci insn->vex_prefix.got = 1; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci prefixes->got = 1; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cierr_out: 2308c2ecf20Sopenharmony_ci return -ENODATA; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/** 2348c2ecf20Sopenharmony_ci * insn_get_opcode - collect opcode(s) 2358c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Populates @insn->opcode, updates @insn->next_byte to point past the 2388c2ecf20Sopenharmony_ci * opcode byte(s), and set @insn->attr (except for groups). 2398c2ecf20Sopenharmony_ci * If necessary, first collects any preceding (prefix) bytes. 2408c2ecf20Sopenharmony_ci * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got 2418c2ecf20Sopenharmony_ci * is already 1. 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * Returns: 2448c2ecf20Sopenharmony_ci * 0: on success 2458c2ecf20Sopenharmony_ci * < 0: on error 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ciint insn_get_opcode(struct insn *insn) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct insn_field *opcode = &insn->opcode; 2508c2ecf20Sopenharmony_ci int pfx_id, ret; 2518c2ecf20Sopenharmony_ci insn_byte_t op; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (opcode->got) 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!insn->prefixes.got) { 2578c2ecf20Sopenharmony_ci ret = insn_get_prefixes(insn); 2588c2ecf20Sopenharmony_ci if (ret) 2598c2ecf20Sopenharmony_ci return ret; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Get first opcode */ 2638c2ecf20Sopenharmony_ci op = get_next(insn_byte_t, insn); 2648c2ecf20Sopenharmony_ci opcode->bytes[0] = op; 2658c2ecf20Sopenharmony_ci opcode->nbytes = 1; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Check if there is VEX prefix or not */ 2688c2ecf20Sopenharmony_ci if (insn_is_avx(insn)) { 2698c2ecf20Sopenharmony_ci insn_byte_t m, p; 2708c2ecf20Sopenharmony_ci m = insn_vex_m_bits(insn); 2718c2ecf20Sopenharmony_ci p = insn_vex_p_bits(insn); 2728c2ecf20Sopenharmony_ci insn->attr = inat_get_avx_attribute(op, m, p); 2738c2ecf20Sopenharmony_ci if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || 2748c2ecf20Sopenharmony_ci (!inat_accept_vex(insn->attr) && 2758c2ecf20Sopenharmony_ci !inat_is_group(insn->attr))) { 2768c2ecf20Sopenharmony_ci /* This instruction is bad */ 2778c2ecf20Sopenharmony_ci insn->attr = 0; 2788c2ecf20Sopenharmony_ci return -EINVAL; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci /* VEX has only 1 byte for opcode */ 2818c2ecf20Sopenharmony_ci goto end; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci insn->attr = inat_get_opcode_attribute(op); 2858c2ecf20Sopenharmony_ci while (inat_is_escape(insn->attr)) { 2868c2ecf20Sopenharmony_ci /* Get escaped opcode */ 2878c2ecf20Sopenharmony_ci op = get_next(insn_byte_t, insn); 2888c2ecf20Sopenharmony_ci opcode->bytes[opcode->nbytes++] = op; 2898c2ecf20Sopenharmony_ci pfx_id = insn_last_prefix_id(insn); 2908c2ecf20Sopenharmony_ci insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (inat_must_vex(insn->attr)) { 2948c2ecf20Sopenharmony_ci /* This instruction is bad */ 2958c2ecf20Sopenharmony_ci insn->attr = 0; 2968c2ecf20Sopenharmony_ci return -EINVAL; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ciend: 2998c2ecf20Sopenharmony_ci opcode->got = 1; 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cierr_out: 3038c2ecf20Sopenharmony_ci return -ENODATA; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/** 3078c2ecf20Sopenharmony_ci * insn_get_modrm - collect ModRM byte, if any 3088c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci * Populates @insn->modrm and updates @insn->next_byte to point past the 3118c2ecf20Sopenharmony_ci * ModRM byte, if any. If necessary, first collects the preceding bytes 3128c2ecf20Sopenharmony_ci * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * Returns: 3158c2ecf20Sopenharmony_ci * 0: on success 3168c2ecf20Sopenharmony_ci * < 0: on error 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ciint insn_get_modrm(struct insn *insn) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci struct insn_field *modrm = &insn->modrm; 3218c2ecf20Sopenharmony_ci insn_byte_t pfx_id, mod; 3228c2ecf20Sopenharmony_ci int ret; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci if (modrm->got) 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!insn->opcode.got) { 3288c2ecf20Sopenharmony_ci ret = insn_get_opcode(insn); 3298c2ecf20Sopenharmony_ci if (ret) 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci if (inat_has_modrm(insn->attr)) { 3348c2ecf20Sopenharmony_ci mod = get_next(insn_byte_t, insn); 3358c2ecf20Sopenharmony_ci modrm->value = mod; 3368c2ecf20Sopenharmony_ci modrm->nbytes = 1; 3378c2ecf20Sopenharmony_ci if (inat_is_group(insn->attr)) { 3388c2ecf20Sopenharmony_ci pfx_id = insn_last_prefix_id(insn); 3398c2ecf20Sopenharmony_ci insn->attr = inat_get_group_attribute(mod, pfx_id, 3408c2ecf20Sopenharmony_ci insn->attr); 3418c2ecf20Sopenharmony_ci if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) { 3428c2ecf20Sopenharmony_ci /* Bad insn */ 3438c2ecf20Sopenharmony_ci insn->attr = 0; 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (insn->x86_64 && inat_is_force64(insn->attr)) 3508c2ecf20Sopenharmony_ci insn->opnd_bytes = 8; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci modrm->got = 1; 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cierr_out: 3568c2ecf20Sopenharmony_ci return -ENODATA; 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci/** 3618c2ecf20Sopenharmony_ci * insn_rip_relative() - Does instruction use RIP-relative addressing mode? 3628c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 3638c2ecf20Sopenharmony_ci * 3648c2ecf20Sopenharmony_ci * If necessary, first collects the instruction up to and including the 3658c2ecf20Sopenharmony_ci * ModRM byte. No effect if @insn->x86_64 is 0. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ciint insn_rip_relative(struct insn *insn) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct insn_field *modrm = &insn->modrm; 3708c2ecf20Sopenharmony_ci int ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (!insn->x86_64) 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (!modrm->got) { 3768c2ecf20Sopenharmony_ci ret = insn_get_modrm(insn); 3778c2ecf20Sopenharmony_ci if (ret) 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci /* 3818c2ecf20Sopenharmony_ci * For rip-relative instructions, the mod field (top 2 bits) 3828c2ecf20Sopenharmony_ci * is zero and the r/m field (bottom 3 bits) is 0x5. 3838c2ecf20Sopenharmony_ci */ 3848c2ecf20Sopenharmony_ci return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/** 3888c2ecf20Sopenharmony_ci * insn_get_sib() - Get the SIB byte of instruction 3898c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 3908c2ecf20Sopenharmony_ci * 3918c2ecf20Sopenharmony_ci * If necessary, first collects the instruction up to and including the 3928c2ecf20Sopenharmony_ci * ModRM byte. 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * Returns: 3958c2ecf20Sopenharmony_ci * 0: if decoding succeeded 3968c2ecf20Sopenharmony_ci * < 0: otherwise. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ciint insn_get_sib(struct insn *insn) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci insn_byte_t modrm; 4018c2ecf20Sopenharmony_ci int ret; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (insn->sib.got) 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (!insn->modrm.got) { 4078c2ecf20Sopenharmony_ci ret = insn_get_modrm(insn); 4088c2ecf20Sopenharmony_ci if (ret) 4098c2ecf20Sopenharmony_ci return ret; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (insn->modrm.nbytes) { 4138c2ecf20Sopenharmony_ci modrm = (insn_byte_t)insn->modrm.value; 4148c2ecf20Sopenharmony_ci if (insn->addr_bytes != 2 && 4158c2ecf20Sopenharmony_ci X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { 4168c2ecf20Sopenharmony_ci insn->sib.value = get_next(insn_byte_t, insn); 4178c2ecf20Sopenharmony_ci insn->sib.nbytes = 1; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci insn->sib.got = 1; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cierr_out: 4258c2ecf20Sopenharmony_ci return -ENODATA; 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/** 4308c2ecf20Sopenharmony_ci * insn_get_displacement() - Get the displacement of instruction 4318c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * If necessary, first collects the instruction up to and including the 4348c2ecf20Sopenharmony_ci * SIB byte. 4358c2ecf20Sopenharmony_ci * Displacement value is sign-expanded. 4368c2ecf20Sopenharmony_ci * 4378c2ecf20Sopenharmony_ci * * Returns: 4388c2ecf20Sopenharmony_ci * 0: if decoding succeeded 4398c2ecf20Sopenharmony_ci * < 0: otherwise. 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_ciint insn_get_displacement(struct insn *insn) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci insn_byte_t mod, rm, base; 4448c2ecf20Sopenharmony_ci int ret; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (insn->displacement.got) 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (!insn->sib.got) { 4508c2ecf20Sopenharmony_ci ret = insn_get_sib(insn); 4518c2ecf20Sopenharmony_ci if (ret) 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (insn->modrm.nbytes) { 4568c2ecf20Sopenharmony_ci /* 4578c2ecf20Sopenharmony_ci * Interpreting the modrm byte: 4588c2ecf20Sopenharmony_ci * mod = 00 - no displacement fields (exceptions below) 4598c2ecf20Sopenharmony_ci * mod = 01 - 1-byte displacement field 4608c2ecf20Sopenharmony_ci * mod = 10 - displacement field is 4 bytes, or 2 bytes if 4618c2ecf20Sopenharmony_ci * address size = 2 (0x67 prefix in 32-bit mode) 4628c2ecf20Sopenharmony_ci * mod = 11 - no memory operand 4638c2ecf20Sopenharmony_ci * 4648c2ecf20Sopenharmony_ci * If address size = 2... 4658c2ecf20Sopenharmony_ci * mod = 00, r/m = 110 - displacement field is 2 bytes 4668c2ecf20Sopenharmony_ci * 4678c2ecf20Sopenharmony_ci * If address size != 2... 4688c2ecf20Sopenharmony_ci * mod != 11, r/m = 100 - SIB byte exists 4698c2ecf20Sopenharmony_ci * mod = 00, SIB base = 101 - displacement field is 4 bytes 4708c2ecf20Sopenharmony_ci * mod = 00, r/m = 101 - rip-relative addressing, displacement 4718c2ecf20Sopenharmony_ci * field is 4 bytes 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci mod = X86_MODRM_MOD(insn->modrm.value); 4748c2ecf20Sopenharmony_ci rm = X86_MODRM_RM(insn->modrm.value); 4758c2ecf20Sopenharmony_ci base = X86_SIB_BASE(insn->sib.value); 4768c2ecf20Sopenharmony_ci if (mod == 3) 4778c2ecf20Sopenharmony_ci goto out; 4788c2ecf20Sopenharmony_ci if (mod == 1) { 4798c2ecf20Sopenharmony_ci insn->displacement.value = get_next(signed char, insn); 4808c2ecf20Sopenharmony_ci insn->displacement.nbytes = 1; 4818c2ecf20Sopenharmony_ci } else if (insn->addr_bytes == 2) { 4828c2ecf20Sopenharmony_ci if ((mod == 0 && rm == 6) || mod == 2) { 4838c2ecf20Sopenharmony_ci insn->displacement.value = 4848c2ecf20Sopenharmony_ci get_next(short, insn); 4858c2ecf20Sopenharmony_ci insn->displacement.nbytes = 2; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci } else { 4888c2ecf20Sopenharmony_ci if ((mod == 0 && rm == 5) || mod == 2 || 4898c2ecf20Sopenharmony_ci (mod == 0 && base == 5)) { 4908c2ecf20Sopenharmony_ci insn->displacement.value = get_next(int, insn); 4918c2ecf20Sopenharmony_ci insn->displacement.nbytes = 4; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ciout: 4968c2ecf20Sopenharmony_ci insn->displacement.got = 1; 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cierr_out: 5008c2ecf20Sopenharmony_ci return -ENODATA; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* Decode moffset16/32/64. Return 0 if failed */ 5048c2ecf20Sopenharmony_cistatic int __get_moffset(struct insn *insn) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci switch (insn->addr_bytes) { 5078c2ecf20Sopenharmony_ci case 2: 5088c2ecf20Sopenharmony_ci insn->moffset1.value = get_next(short, insn); 5098c2ecf20Sopenharmony_ci insn->moffset1.nbytes = 2; 5108c2ecf20Sopenharmony_ci break; 5118c2ecf20Sopenharmony_ci case 4: 5128c2ecf20Sopenharmony_ci insn->moffset1.value = get_next(int, insn); 5138c2ecf20Sopenharmony_ci insn->moffset1.nbytes = 4; 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci case 8: 5168c2ecf20Sopenharmony_ci insn->moffset1.value = get_next(int, insn); 5178c2ecf20Sopenharmony_ci insn->moffset1.nbytes = 4; 5188c2ecf20Sopenharmony_ci insn->moffset2.value = get_next(int, insn); 5198c2ecf20Sopenharmony_ci insn->moffset2.nbytes = 4; 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci default: /* opnd_bytes must be modified manually */ 5228c2ecf20Sopenharmony_ci goto err_out; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci insn->moffset1.got = insn->moffset2.got = 1; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return 1; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cierr_out: 5298c2ecf20Sopenharmony_ci return 0; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* Decode imm v32(Iz). Return 0 if failed */ 5338c2ecf20Sopenharmony_cistatic int __get_immv32(struct insn *insn) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci switch (insn->opnd_bytes) { 5368c2ecf20Sopenharmony_ci case 2: 5378c2ecf20Sopenharmony_ci insn->immediate.value = get_next(short, insn); 5388c2ecf20Sopenharmony_ci insn->immediate.nbytes = 2; 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci case 4: 5418c2ecf20Sopenharmony_ci case 8: 5428c2ecf20Sopenharmony_ci insn->immediate.value = get_next(int, insn); 5438c2ecf20Sopenharmony_ci insn->immediate.nbytes = 4; 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci default: /* opnd_bytes must be modified manually */ 5468c2ecf20Sopenharmony_ci goto err_out; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return 1; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cierr_out: 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/* Decode imm v64(Iv/Ov), Return 0 if failed */ 5568c2ecf20Sopenharmony_cistatic int __get_immv(struct insn *insn) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci switch (insn->opnd_bytes) { 5598c2ecf20Sopenharmony_ci case 2: 5608c2ecf20Sopenharmony_ci insn->immediate1.value = get_next(short, insn); 5618c2ecf20Sopenharmony_ci insn->immediate1.nbytes = 2; 5628c2ecf20Sopenharmony_ci break; 5638c2ecf20Sopenharmony_ci case 4: 5648c2ecf20Sopenharmony_ci insn->immediate1.value = get_next(int, insn); 5658c2ecf20Sopenharmony_ci insn->immediate1.nbytes = 4; 5668c2ecf20Sopenharmony_ci break; 5678c2ecf20Sopenharmony_ci case 8: 5688c2ecf20Sopenharmony_ci insn->immediate1.value = get_next(int, insn); 5698c2ecf20Sopenharmony_ci insn->immediate1.nbytes = 4; 5708c2ecf20Sopenharmony_ci insn->immediate2.value = get_next(int, insn); 5718c2ecf20Sopenharmony_ci insn->immediate2.nbytes = 4; 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci default: /* opnd_bytes must be modified manually */ 5748c2ecf20Sopenharmony_ci goto err_out; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci insn->immediate1.got = insn->immediate2.got = 1; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return 1; 5798c2ecf20Sopenharmony_cierr_out: 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/* Decode ptr16:16/32(Ap) */ 5848c2ecf20Sopenharmony_cistatic int __get_immptr(struct insn *insn) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci switch (insn->opnd_bytes) { 5878c2ecf20Sopenharmony_ci case 2: 5888c2ecf20Sopenharmony_ci insn->immediate1.value = get_next(short, insn); 5898c2ecf20Sopenharmony_ci insn->immediate1.nbytes = 2; 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci case 4: 5928c2ecf20Sopenharmony_ci insn->immediate1.value = get_next(int, insn); 5938c2ecf20Sopenharmony_ci insn->immediate1.nbytes = 4; 5948c2ecf20Sopenharmony_ci break; 5958c2ecf20Sopenharmony_ci case 8: 5968c2ecf20Sopenharmony_ci /* ptr16:64 is not exist (no segment) */ 5978c2ecf20Sopenharmony_ci return 0; 5988c2ecf20Sopenharmony_ci default: /* opnd_bytes must be modified manually */ 5998c2ecf20Sopenharmony_ci goto err_out; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci insn->immediate2.value = get_next(unsigned short, insn); 6028c2ecf20Sopenharmony_ci insn->immediate2.nbytes = 2; 6038c2ecf20Sopenharmony_ci insn->immediate1.got = insn->immediate2.got = 1; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return 1; 6068c2ecf20Sopenharmony_cierr_out: 6078c2ecf20Sopenharmony_ci return 0; 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci/** 6118c2ecf20Sopenharmony_ci * insn_get_immediate() - Get the immediate in an instruction 6128c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 6138c2ecf20Sopenharmony_ci * 6148c2ecf20Sopenharmony_ci * If necessary, first collects the instruction up to and including the 6158c2ecf20Sopenharmony_ci * displacement bytes. 6168c2ecf20Sopenharmony_ci * Basically, most of immediates are sign-expanded. Unsigned-value can be 6178c2ecf20Sopenharmony_ci * computed by bit masking with ((1 << (nbytes * 8)) - 1) 6188c2ecf20Sopenharmony_ci * 6198c2ecf20Sopenharmony_ci * Returns: 6208c2ecf20Sopenharmony_ci * 0: on success 6218c2ecf20Sopenharmony_ci * < 0: on error 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ciint insn_get_immediate(struct insn *insn) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci int ret; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (insn->immediate.got) 6288c2ecf20Sopenharmony_ci return 0; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (!insn->displacement.got) { 6318c2ecf20Sopenharmony_ci ret = insn_get_displacement(insn); 6328c2ecf20Sopenharmony_ci if (ret) 6338c2ecf20Sopenharmony_ci return ret; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (inat_has_moffset(insn->attr)) { 6378c2ecf20Sopenharmony_ci if (!__get_moffset(insn)) 6388c2ecf20Sopenharmony_ci goto err_out; 6398c2ecf20Sopenharmony_ci goto done; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!inat_has_immediate(insn->attr)) 6438c2ecf20Sopenharmony_ci /* no immediates */ 6448c2ecf20Sopenharmony_ci goto done; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci switch (inat_immediate_size(insn->attr)) { 6478c2ecf20Sopenharmony_ci case INAT_IMM_BYTE: 6488c2ecf20Sopenharmony_ci insn->immediate.value = get_next(signed char, insn); 6498c2ecf20Sopenharmony_ci insn->immediate.nbytes = 1; 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci case INAT_IMM_WORD: 6528c2ecf20Sopenharmony_ci insn->immediate.value = get_next(short, insn); 6538c2ecf20Sopenharmony_ci insn->immediate.nbytes = 2; 6548c2ecf20Sopenharmony_ci break; 6558c2ecf20Sopenharmony_ci case INAT_IMM_DWORD: 6568c2ecf20Sopenharmony_ci insn->immediate.value = get_next(int, insn); 6578c2ecf20Sopenharmony_ci insn->immediate.nbytes = 4; 6588c2ecf20Sopenharmony_ci break; 6598c2ecf20Sopenharmony_ci case INAT_IMM_QWORD: 6608c2ecf20Sopenharmony_ci insn->immediate1.value = get_next(int, insn); 6618c2ecf20Sopenharmony_ci insn->immediate1.nbytes = 4; 6628c2ecf20Sopenharmony_ci insn->immediate2.value = get_next(int, insn); 6638c2ecf20Sopenharmony_ci insn->immediate2.nbytes = 4; 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci case INAT_IMM_PTR: 6668c2ecf20Sopenharmony_ci if (!__get_immptr(insn)) 6678c2ecf20Sopenharmony_ci goto err_out; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci case INAT_IMM_VWORD32: 6708c2ecf20Sopenharmony_ci if (!__get_immv32(insn)) 6718c2ecf20Sopenharmony_ci goto err_out; 6728c2ecf20Sopenharmony_ci break; 6738c2ecf20Sopenharmony_ci case INAT_IMM_VWORD: 6748c2ecf20Sopenharmony_ci if (!__get_immv(insn)) 6758c2ecf20Sopenharmony_ci goto err_out; 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci default: 6788c2ecf20Sopenharmony_ci /* Here, insn must have an immediate, but failed */ 6798c2ecf20Sopenharmony_ci goto err_out; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci if (inat_has_second_immediate(insn->attr)) { 6828c2ecf20Sopenharmony_ci insn->immediate2.value = get_next(signed char, insn); 6838c2ecf20Sopenharmony_ci insn->immediate2.nbytes = 1; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_cidone: 6868c2ecf20Sopenharmony_ci insn->immediate.got = 1; 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_cierr_out: 6908c2ecf20Sopenharmony_ci return -ENODATA; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci/** 6948c2ecf20Sopenharmony_ci * insn_get_length() - Get the length of instruction 6958c2ecf20Sopenharmony_ci * @insn: &struct insn containing instruction 6968c2ecf20Sopenharmony_ci * 6978c2ecf20Sopenharmony_ci * If necessary, first collects the instruction up to and including the 6988c2ecf20Sopenharmony_ci * immediates bytes. 6998c2ecf20Sopenharmony_ci * 7008c2ecf20Sopenharmony_ci * Returns: 7018c2ecf20Sopenharmony_ci * - 0 on success 7028c2ecf20Sopenharmony_ci * - < 0 on error 7038c2ecf20Sopenharmony_ci*/ 7048c2ecf20Sopenharmony_ciint insn_get_length(struct insn *insn) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci int ret; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci if (insn->length) 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (!insn->immediate.got) { 7128c2ecf20Sopenharmony_ci ret = insn_get_immediate(insn); 7138c2ecf20Sopenharmony_ci if (ret) 7148c2ecf20Sopenharmony_ci return ret; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci insn->length = (unsigned char)((unsigned long)insn->next_byte 7188c2ecf20Sopenharmony_ci - (unsigned long)insn->kaddr); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci/** 7248c2ecf20Sopenharmony_ci * insn_decode() - Decode an x86 instruction 7258c2ecf20Sopenharmony_ci * @insn: &struct insn to be initialized 7268c2ecf20Sopenharmony_ci * @kaddr: address (in kernel memory) of instruction (or copy thereof) 7278c2ecf20Sopenharmony_ci * @buf_len: length of the insn buffer at @kaddr 7288c2ecf20Sopenharmony_ci * @m: insn mode, see enum insn_mode 7298c2ecf20Sopenharmony_ci * 7308c2ecf20Sopenharmony_ci * Returns: 7318c2ecf20Sopenharmony_ci * 0: if decoding succeeded 7328c2ecf20Sopenharmony_ci * < 0: otherwise. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ciint insn_decode(struct insn *insn, const void *kaddr, int buf_len, enum insn_mode m) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci int ret; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci#define INSN_MODE_KERN (enum insn_mode)-1 /* __ignore_sync_check__ mode is only valid in the kernel */ 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (m == INSN_MODE_KERN) 7418c2ecf20Sopenharmony_ci insn_init(insn, kaddr, buf_len, IS_ENABLED(CONFIG_X86_64)); 7428c2ecf20Sopenharmony_ci else 7438c2ecf20Sopenharmony_ci insn_init(insn, kaddr, buf_len, m == INSN_MODE_64); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci ret = insn_get_length(insn); 7468c2ecf20Sopenharmony_ci if (ret) 7478c2ecf20Sopenharmony_ci return ret; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (insn_complete(insn)) 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci return -EINVAL; 7538c2ecf20Sopenharmony_ci} 754