xref: /kernel/linux/linux-6.6/tools/arch/x86/lib/insn.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * x86 instruction analysis
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) IBM Corporation, 2002, 2004, 2009
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#ifdef __KERNEL__
1062306a36Sopenharmony_ci#include <linux/string.h>
1162306a36Sopenharmony_ci#else
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#endif
1462306a36Sopenharmony_ci#include "../include/asm/inat.h" /* __ignore_sync_check__ */
1562306a36Sopenharmony_ci#include "../include/asm/insn.h" /* __ignore_sync_check__ */
1662306a36Sopenharmony_ci#include "../include/asm-generic/unaligned.h" /* __ignore_sync_check__ */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/errno.h>
1962306a36Sopenharmony_ci#include <linux/kconfig.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "../include/asm/emulate_prefix.h" /* __ignore_sync_check__ */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define leXX_to_cpu(t, r)						\
2462306a36Sopenharmony_ci({									\
2562306a36Sopenharmony_ci	__typeof__(t) v;						\
2662306a36Sopenharmony_ci	switch (sizeof(t)) {						\
2762306a36Sopenharmony_ci	case 4: v = le32_to_cpu(r); break;				\
2862306a36Sopenharmony_ci	case 2: v = le16_to_cpu(r); break;				\
2962306a36Sopenharmony_ci	case 1:	v = r; break;						\
3062306a36Sopenharmony_ci	default:							\
3162306a36Sopenharmony_ci		BUILD_BUG(); break;					\
3262306a36Sopenharmony_ci	}								\
3362306a36Sopenharmony_ci	v;								\
3462306a36Sopenharmony_ci})
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Verify next sizeof(t) bytes can be on the same instruction */
3762306a36Sopenharmony_ci#define validate_next(t, insn, n)	\
3862306a36Sopenharmony_ci	((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define __get_next(t, insn)	\
4162306a36Sopenharmony_ci	({ t r = get_unaligned((t *)(insn)->next_byte); (insn)->next_byte += sizeof(t); leXX_to_cpu(t, r); })
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define __peek_nbyte_next(t, insn, n)	\
4462306a36Sopenharmony_ci	({ t r = get_unaligned((t *)(insn)->next_byte + n); leXX_to_cpu(t, r); })
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define get_next(t, insn)	\
4762306a36Sopenharmony_ci	({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); })
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define peek_nbyte_next(t, insn, n)	\
5062306a36Sopenharmony_ci	({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); })
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define peek_next(t, insn)	peek_nbyte_next(t, insn, 0)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/**
5562306a36Sopenharmony_ci * insn_init() - initialize struct insn
5662306a36Sopenharmony_ci * @insn:	&struct insn to be initialized
5762306a36Sopenharmony_ci * @kaddr:	address (in kernel memory) of instruction (or copy thereof)
5862306a36Sopenharmony_ci * @buf_len:	length of the insn buffer at @kaddr
5962306a36Sopenharmony_ci * @x86_64:	!0 for 64-bit kernel or 64-bit app
6062306a36Sopenharmony_ci */
6162306a36Sopenharmony_civoid insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	/*
6462306a36Sopenharmony_ci	 * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid
6562306a36Sopenharmony_ci	 * even if the input buffer is long enough to hold them.
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	if (buf_len > MAX_INSN_SIZE)
6862306a36Sopenharmony_ci		buf_len = MAX_INSN_SIZE;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	memset(insn, 0, sizeof(*insn));
7162306a36Sopenharmony_ci	insn->kaddr = kaddr;
7262306a36Sopenharmony_ci	insn->end_kaddr = kaddr + buf_len;
7362306a36Sopenharmony_ci	insn->next_byte = kaddr;
7462306a36Sopenharmony_ci	insn->x86_64 = x86_64 ? 1 : 0;
7562306a36Sopenharmony_ci	insn->opnd_bytes = 4;
7662306a36Sopenharmony_ci	if (x86_64)
7762306a36Sopenharmony_ci		insn->addr_bytes = 8;
7862306a36Sopenharmony_ci	else
7962306a36Sopenharmony_ci		insn->addr_bytes = 4;
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic const insn_byte_t xen_prefix[] = { __XEN_EMULATE_PREFIX };
8362306a36Sopenharmony_cistatic const insn_byte_t kvm_prefix[] = { __KVM_EMULATE_PREFIX };
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistatic int __insn_get_emulate_prefix(struct insn *insn,
8662306a36Sopenharmony_ci				     const insn_byte_t *prefix, size_t len)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	size_t i;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
9162306a36Sopenharmony_ci		if (peek_nbyte_next(insn_byte_t, insn, i) != prefix[i])
9262306a36Sopenharmony_ci			goto err_out;
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	insn->emulate_prefix_size = len;
9662306a36Sopenharmony_ci	insn->next_byte += len;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	return 1;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cierr_out:
10162306a36Sopenharmony_ci	return 0;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void insn_get_emulate_prefix(struct insn *insn)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	if (__insn_get_emulate_prefix(insn, xen_prefix, sizeof(xen_prefix)))
10762306a36Sopenharmony_ci		return;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	__insn_get_emulate_prefix(insn, kvm_prefix, sizeof(kvm_prefix));
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/**
11362306a36Sopenharmony_ci * insn_get_prefixes - scan x86 instruction prefix bytes
11462306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
11562306a36Sopenharmony_ci *
11662306a36Sopenharmony_ci * Populates the @insn->prefixes bitmap, and updates @insn->next_byte
11762306a36Sopenharmony_ci * to point to the (first) opcode.  No effect if @insn->prefixes.got
11862306a36Sopenharmony_ci * is already set.
11962306a36Sopenharmony_ci *
12062306a36Sopenharmony_ci * * Returns:
12162306a36Sopenharmony_ci * 0:  on success
12262306a36Sopenharmony_ci * < 0: on error
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_ciint insn_get_prefixes(struct insn *insn)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	struct insn_field *prefixes = &insn->prefixes;
12762306a36Sopenharmony_ci	insn_attr_t attr;
12862306a36Sopenharmony_ci	insn_byte_t b, lb;
12962306a36Sopenharmony_ci	int i, nb;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	if (prefixes->got)
13262306a36Sopenharmony_ci		return 0;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	insn_get_emulate_prefix(insn);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	nb = 0;
13762306a36Sopenharmony_ci	lb = 0;
13862306a36Sopenharmony_ci	b = peek_next(insn_byte_t, insn);
13962306a36Sopenharmony_ci	attr = inat_get_opcode_attribute(b);
14062306a36Sopenharmony_ci	while (inat_is_legacy_prefix(attr)) {
14162306a36Sopenharmony_ci		/* Skip if same prefix */
14262306a36Sopenharmony_ci		for (i = 0; i < nb; i++)
14362306a36Sopenharmony_ci			if (prefixes->bytes[i] == b)
14462306a36Sopenharmony_ci				goto found;
14562306a36Sopenharmony_ci		if (nb == 4)
14662306a36Sopenharmony_ci			/* Invalid instruction */
14762306a36Sopenharmony_ci			break;
14862306a36Sopenharmony_ci		prefixes->bytes[nb++] = b;
14962306a36Sopenharmony_ci		if (inat_is_address_size_prefix(attr)) {
15062306a36Sopenharmony_ci			/* address size switches 2/4 or 4/8 */
15162306a36Sopenharmony_ci			if (insn->x86_64)
15262306a36Sopenharmony_ci				insn->addr_bytes ^= 12;
15362306a36Sopenharmony_ci			else
15462306a36Sopenharmony_ci				insn->addr_bytes ^= 6;
15562306a36Sopenharmony_ci		} else if (inat_is_operand_size_prefix(attr)) {
15662306a36Sopenharmony_ci			/* oprand size switches 2/4 */
15762306a36Sopenharmony_ci			insn->opnd_bytes ^= 6;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_cifound:
16062306a36Sopenharmony_ci		prefixes->nbytes++;
16162306a36Sopenharmony_ci		insn->next_byte++;
16262306a36Sopenharmony_ci		lb = b;
16362306a36Sopenharmony_ci		b = peek_next(insn_byte_t, insn);
16462306a36Sopenharmony_ci		attr = inat_get_opcode_attribute(b);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	/* Set the last prefix */
16762306a36Sopenharmony_ci	if (lb && lb != insn->prefixes.bytes[3]) {
16862306a36Sopenharmony_ci		if (unlikely(insn->prefixes.bytes[3])) {
16962306a36Sopenharmony_ci			/* Swap the last prefix */
17062306a36Sopenharmony_ci			b = insn->prefixes.bytes[3];
17162306a36Sopenharmony_ci			for (i = 0; i < nb; i++)
17262306a36Sopenharmony_ci				if (prefixes->bytes[i] == lb)
17362306a36Sopenharmony_ci					insn_set_byte(prefixes, i, b);
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci		insn_set_byte(&insn->prefixes, 3, lb);
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	/* Decode REX prefix */
17962306a36Sopenharmony_ci	if (insn->x86_64) {
18062306a36Sopenharmony_ci		b = peek_next(insn_byte_t, insn);
18162306a36Sopenharmony_ci		attr = inat_get_opcode_attribute(b);
18262306a36Sopenharmony_ci		if (inat_is_rex_prefix(attr)) {
18362306a36Sopenharmony_ci			insn_field_set(&insn->rex_prefix, b, 1);
18462306a36Sopenharmony_ci			insn->next_byte++;
18562306a36Sopenharmony_ci			if (X86_REX_W(b))
18662306a36Sopenharmony_ci				/* REX.W overrides opnd_size */
18762306a36Sopenharmony_ci				insn->opnd_bytes = 8;
18862306a36Sopenharmony_ci		}
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci	insn->rex_prefix.got = 1;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	/* Decode VEX prefix */
19362306a36Sopenharmony_ci	b = peek_next(insn_byte_t, insn);
19462306a36Sopenharmony_ci	attr = inat_get_opcode_attribute(b);
19562306a36Sopenharmony_ci	if (inat_is_vex_prefix(attr)) {
19662306a36Sopenharmony_ci		insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1);
19762306a36Sopenharmony_ci		if (!insn->x86_64) {
19862306a36Sopenharmony_ci			/*
19962306a36Sopenharmony_ci			 * In 32-bits mode, if the [7:6] bits (mod bits of
20062306a36Sopenharmony_ci			 * ModRM) on the second byte are not 11b, it is
20162306a36Sopenharmony_ci			 * LDS or LES or BOUND.
20262306a36Sopenharmony_ci			 */
20362306a36Sopenharmony_ci			if (X86_MODRM_MOD(b2) != 3)
20462306a36Sopenharmony_ci				goto vex_end;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci		insn_set_byte(&insn->vex_prefix, 0, b);
20762306a36Sopenharmony_ci		insn_set_byte(&insn->vex_prefix, 1, b2);
20862306a36Sopenharmony_ci		if (inat_is_evex_prefix(attr)) {
20962306a36Sopenharmony_ci			b2 = peek_nbyte_next(insn_byte_t, insn, 2);
21062306a36Sopenharmony_ci			insn_set_byte(&insn->vex_prefix, 2, b2);
21162306a36Sopenharmony_ci			b2 = peek_nbyte_next(insn_byte_t, insn, 3);
21262306a36Sopenharmony_ci			insn_set_byte(&insn->vex_prefix, 3, b2);
21362306a36Sopenharmony_ci			insn->vex_prefix.nbytes = 4;
21462306a36Sopenharmony_ci			insn->next_byte += 4;
21562306a36Sopenharmony_ci			if (insn->x86_64 && X86_VEX_W(b2))
21662306a36Sopenharmony_ci				/* VEX.W overrides opnd_size */
21762306a36Sopenharmony_ci				insn->opnd_bytes = 8;
21862306a36Sopenharmony_ci		} else if (inat_is_vex3_prefix(attr)) {
21962306a36Sopenharmony_ci			b2 = peek_nbyte_next(insn_byte_t, insn, 2);
22062306a36Sopenharmony_ci			insn_set_byte(&insn->vex_prefix, 2, b2);
22162306a36Sopenharmony_ci			insn->vex_prefix.nbytes = 3;
22262306a36Sopenharmony_ci			insn->next_byte += 3;
22362306a36Sopenharmony_ci			if (insn->x86_64 && X86_VEX_W(b2))
22462306a36Sopenharmony_ci				/* VEX.W overrides opnd_size */
22562306a36Sopenharmony_ci				insn->opnd_bytes = 8;
22662306a36Sopenharmony_ci		} else {
22762306a36Sopenharmony_ci			/*
22862306a36Sopenharmony_ci			 * For VEX2, fake VEX3-like byte#2.
22962306a36Sopenharmony_ci			 * Makes it easier to decode vex.W, vex.vvvv,
23062306a36Sopenharmony_ci			 * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0.
23162306a36Sopenharmony_ci			 */
23262306a36Sopenharmony_ci			insn_set_byte(&insn->vex_prefix, 2, b2 & 0x7f);
23362306a36Sopenharmony_ci			insn->vex_prefix.nbytes = 2;
23462306a36Sopenharmony_ci			insn->next_byte += 2;
23562306a36Sopenharmony_ci		}
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_civex_end:
23862306a36Sopenharmony_ci	insn->vex_prefix.got = 1;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	prefixes->got = 1;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return 0;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cierr_out:
24562306a36Sopenharmony_ci	return -ENODATA;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci/**
24962306a36Sopenharmony_ci * insn_get_opcode - collect opcode(s)
25062306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
25162306a36Sopenharmony_ci *
25262306a36Sopenharmony_ci * Populates @insn->opcode, updates @insn->next_byte to point past the
25362306a36Sopenharmony_ci * opcode byte(s), and set @insn->attr (except for groups).
25462306a36Sopenharmony_ci * If necessary, first collects any preceding (prefix) bytes.
25562306a36Sopenharmony_ci * Sets @insn->opcode.value = opcode1.  No effect if @insn->opcode.got
25662306a36Sopenharmony_ci * is already 1.
25762306a36Sopenharmony_ci *
25862306a36Sopenharmony_ci * Returns:
25962306a36Sopenharmony_ci * 0:  on success
26062306a36Sopenharmony_ci * < 0: on error
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_ciint insn_get_opcode(struct insn *insn)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	struct insn_field *opcode = &insn->opcode;
26562306a36Sopenharmony_ci	int pfx_id, ret;
26662306a36Sopenharmony_ci	insn_byte_t op;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (opcode->got)
26962306a36Sopenharmony_ci		return 0;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	if (!insn->prefixes.got) {
27262306a36Sopenharmony_ci		ret = insn_get_prefixes(insn);
27362306a36Sopenharmony_ci		if (ret)
27462306a36Sopenharmony_ci			return ret;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/* Get first opcode */
27862306a36Sopenharmony_ci	op = get_next(insn_byte_t, insn);
27962306a36Sopenharmony_ci	insn_set_byte(opcode, 0, op);
28062306a36Sopenharmony_ci	opcode->nbytes = 1;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Check if there is VEX prefix or not */
28362306a36Sopenharmony_ci	if (insn_is_avx(insn)) {
28462306a36Sopenharmony_ci		insn_byte_t m, p;
28562306a36Sopenharmony_ci		m = insn_vex_m_bits(insn);
28662306a36Sopenharmony_ci		p = insn_vex_p_bits(insn);
28762306a36Sopenharmony_ci		insn->attr = inat_get_avx_attribute(op, m, p);
28862306a36Sopenharmony_ci		if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) ||
28962306a36Sopenharmony_ci		    (!inat_accept_vex(insn->attr) &&
29062306a36Sopenharmony_ci		     !inat_is_group(insn->attr))) {
29162306a36Sopenharmony_ci			/* This instruction is bad */
29262306a36Sopenharmony_ci			insn->attr = 0;
29362306a36Sopenharmony_ci			return -EINVAL;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci		/* VEX has only 1 byte for opcode */
29662306a36Sopenharmony_ci		goto end;
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	insn->attr = inat_get_opcode_attribute(op);
30062306a36Sopenharmony_ci	while (inat_is_escape(insn->attr)) {
30162306a36Sopenharmony_ci		/* Get escaped opcode */
30262306a36Sopenharmony_ci		op = get_next(insn_byte_t, insn);
30362306a36Sopenharmony_ci		opcode->bytes[opcode->nbytes++] = op;
30462306a36Sopenharmony_ci		pfx_id = insn_last_prefix_id(insn);
30562306a36Sopenharmony_ci		insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr);
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (inat_must_vex(insn->attr)) {
30962306a36Sopenharmony_ci		/* This instruction is bad */
31062306a36Sopenharmony_ci		insn->attr = 0;
31162306a36Sopenharmony_ci		return -EINVAL;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ciend:
31462306a36Sopenharmony_ci	opcode->got = 1;
31562306a36Sopenharmony_ci	return 0;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cierr_out:
31862306a36Sopenharmony_ci	return -ENODATA;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci/**
32262306a36Sopenharmony_ci * insn_get_modrm - collect ModRM byte, if any
32362306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
32462306a36Sopenharmony_ci *
32562306a36Sopenharmony_ci * Populates @insn->modrm and updates @insn->next_byte to point past the
32662306a36Sopenharmony_ci * ModRM byte, if any.  If necessary, first collects the preceding bytes
32762306a36Sopenharmony_ci * (prefixes and opcode(s)).  No effect if @insn->modrm.got is already 1.
32862306a36Sopenharmony_ci *
32962306a36Sopenharmony_ci * Returns:
33062306a36Sopenharmony_ci * 0:  on success
33162306a36Sopenharmony_ci * < 0: on error
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_ciint insn_get_modrm(struct insn *insn)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct insn_field *modrm = &insn->modrm;
33662306a36Sopenharmony_ci	insn_byte_t pfx_id, mod;
33762306a36Sopenharmony_ci	int ret;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (modrm->got)
34062306a36Sopenharmony_ci		return 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (!insn->opcode.got) {
34362306a36Sopenharmony_ci		ret = insn_get_opcode(insn);
34462306a36Sopenharmony_ci		if (ret)
34562306a36Sopenharmony_ci			return ret;
34662306a36Sopenharmony_ci	}
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	if (inat_has_modrm(insn->attr)) {
34962306a36Sopenharmony_ci		mod = get_next(insn_byte_t, insn);
35062306a36Sopenharmony_ci		insn_field_set(modrm, mod, 1);
35162306a36Sopenharmony_ci		if (inat_is_group(insn->attr)) {
35262306a36Sopenharmony_ci			pfx_id = insn_last_prefix_id(insn);
35362306a36Sopenharmony_ci			insn->attr = inat_get_group_attribute(mod, pfx_id,
35462306a36Sopenharmony_ci							      insn->attr);
35562306a36Sopenharmony_ci			if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) {
35662306a36Sopenharmony_ci				/* Bad insn */
35762306a36Sopenharmony_ci				insn->attr = 0;
35862306a36Sopenharmony_ci				return -EINVAL;
35962306a36Sopenharmony_ci			}
36062306a36Sopenharmony_ci		}
36162306a36Sopenharmony_ci	}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	if (insn->x86_64 && inat_is_force64(insn->attr))
36462306a36Sopenharmony_ci		insn->opnd_bytes = 8;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	modrm->got = 1;
36762306a36Sopenharmony_ci	return 0;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cierr_out:
37062306a36Sopenharmony_ci	return -ENODATA;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci/**
37562306a36Sopenharmony_ci * insn_rip_relative() - Does instruction use RIP-relative addressing mode?
37662306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
37762306a36Sopenharmony_ci *
37862306a36Sopenharmony_ci * If necessary, first collects the instruction up to and including the
37962306a36Sopenharmony_ci * ModRM byte.  No effect if @insn->x86_64 is 0.
38062306a36Sopenharmony_ci */
38162306a36Sopenharmony_ciint insn_rip_relative(struct insn *insn)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct insn_field *modrm = &insn->modrm;
38462306a36Sopenharmony_ci	int ret;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (!insn->x86_64)
38762306a36Sopenharmony_ci		return 0;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (!modrm->got) {
39062306a36Sopenharmony_ci		ret = insn_get_modrm(insn);
39162306a36Sopenharmony_ci		if (ret)
39262306a36Sopenharmony_ci			return 0;
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * For rip-relative instructions, the mod field (top 2 bits)
39662306a36Sopenharmony_ci	 * is zero and the r/m field (bottom 3 bits) is 0x5.
39762306a36Sopenharmony_ci	 */
39862306a36Sopenharmony_ci	return (modrm->nbytes && (modrm->bytes[0] & 0xc7) == 0x5);
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci/**
40262306a36Sopenharmony_ci * insn_get_sib() - Get the SIB byte of instruction
40362306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
40462306a36Sopenharmony_ci *
40562306a36Sopenharmony_ci * If necessary, first collects the instruction up to and including the
40662306a36Sopenharmony_ci * ModRM byte.
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * Returns:
40962306a36Sopenharmony_ci * 0: if decoding succeeded
41062306a36Sopenharmony_ci * < 0: otherwise.
41162306a36Sopenharmony_ci */
41262306a36Sopenharmony_ciint insn_get_sib(struct insn *insn)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	insn_byte_t modrm;
41562306a36Sopenharmony_ci	int ret;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (insn->sib.got)
41862306a36Sopenharmony_ci		return 0;
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	if (!insn->modrm.got) {
42162306a36Sopenharmony_ci		ret = insn_get_modrm(insn);
42262306a36Sopenharmony_ci		if (ret)
42362306a36Sopenharmony_ci			return ret;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (insn->modrm.nbytes) {
42762306a36Sopenharmony_ci		modrm = insn->modrm.bytes[0];
42862306a36Sopenharmony_ci		if (insn->addr_bytes != 2 &&
42962306a36Sopenharmony_ci		    X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) {
43062306a36Sopenharmony_ci			insn_field_set(&insn->sib,
43162306a36Sopenharmony_ci				       get_next(insn_byte_t, insn), 1);
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci	insn->sib.got = 1;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return 0;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cierr_out:
43962306a36Sopenharmony_ci	return -ENODATA;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci/**
44462306a36Sopenharmony_ci * insn_get_displacement() - Get the displacement of instruction
44562306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
44662306a36Sopenharmony_ci *
44762306a36Sopenharmony_ci * If necessary, first collects the instruction up to and including the
44862306a36Sopenharmony_ci * SIB byte.
44962306a36Sopenharmony_ci * Displacement value is sign-expanded.
45062306a36Sopenharmony_ci *
45162306a36Sopenharmony_ci * * Returns:
45262306a36Sopenharmony_ci * 0: if decoding succeeded
45362306a36Sopenharmony_ci * < 0: otherwise.
45462306a36Sopenharmony_ci */
45562306a36Sopenharmony_ciint insn_get_displacement(struct insn *insn)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	insn_byte_t mod, rm, base;
45862306a36Sopenharmony_ci	int ret;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	if (insn->displacement.got)
46162306a36Sopenharmony_ci		return 0;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (!insn->sib.got) {
46462306a36Sopenharmony_ci		ret = insn_get_sib(insn);
46562306a36Sopenharmony_ci		if (ret)
46662306a36Sopenharmony_ci			return ret;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (insn->modrm.nbytes) {
47062306a36Sopenharmony_ci		/*
47162306a36Sopenharmony_ci		 * Interpreting the modrm byte:
47262306a36Sopenharmony_ci		 * mod = 00 - no displacement fields (exceptions below)
47362306a36Sopenharmony_ci		 * mod = 01 - 1-byte displacement field
47462306a36Sopenharmony_ci		 * mod = 10 - displacement field is 4 bytes, or 2 bytes if
47562306a36Sopenharmony_ci		 * 	address size = 2 (0x67 prefix in 32-bit mode)
47662306a36Sopenharmony_ci		 * mod = 11 - no memory operand
47762306a36Sopenharmony_ci		 *
47862306a36Sopenharmony_ci		 * If address size = 2...
47962306a36Sopenharmony_ci		 * mod = 00, r/m = 110 - displacement field is 2 bytes
48062306a36Sopenharmony_ci		 *
48162306a36Sopenharmony_ci		 * If address size != 2...
48262306a36Sopenharmony_ci		 * mod != 11, r/m = 100 - SIB byte exists
48362306a36Sopenharmony_ci		 * mod = 00, SIB base = 101 - displacement field is 4 bytes
48462306a36Sopenharmony_ci		 * mod = 00, r/m = 101 - rip-relative addressing, displacement
48562306a36Sopenharmony_ci		 * 	field is 4 bytes
48662306a36Sopenharmony_ci		 */
48762306a36Sopenharmony_ci		mod = X86_MODRM_MOD(insn->modrm.value);
48862306a36Sopenharmony_ci		rm = X86_MODRM_RM(insn->modrm.value);
48962306a36Sopenharmony_ci		base = X86_SIB_BASE(insn->sib.value);
49062306a36Sopenharmony_ci		if (mod == 3)
49162306a36Sopenharmony_ci			goto out;
49262306a36Sopenharmony_ci		if (mod == 1) {
49362306a36Sopenharmony_ci			insn_field_set(&insn->displacement,
49462306a36Sopenharmony_ci				       get_next(signed char, insn), 1);
49562306a36Sopenharmony_ci		} else if (insn->addr_bytes == 2) {
49662306a36Sopenharmony_ci			if ((mod == 0 && rm == 6) || mod == 2) {
49762306a36Sopenharmony_ci				insn_field_set(&insn->displacement,
49862306a36Sopenharmony_ci					       get_next(short, insn), 2);
49962306a36Sopenharmony_ci			}
50062306a36Sopenharmony_ci		} else {
50162306a36Sopenharmony_ci			if ((mod == 0 && rm == 5) || mod == 2 ||
50262306a36Sopenharmony_ci			    (mod == 0 && base == 5)) {
50362306a36Sopenharmony_ci				insn_field_set(&insn->displacement,
50462306a36Sopenharmony_ci					       get_next(int, insn), 4);
50562306a36Sopenharmony_ci			}
50662306a36Sopenharmony_ci		}
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ciout:
50962306a36Sopenharmony_ci	insn->displacement.got = 1;
51062306a36Sopenharmony_ci	return 0;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cierr_out:
51362306a36Sopenharmony_ci	return -ENODATA;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/* Decode moffset16/32/64. Return 0 if failed */
51762306a36Sopenharmony_cistatic int __get_moffset(struct insn *insn)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	switch (insn->addr_bytes) {
52062306a36Sopenharmony_ci	case 2:
52162306a36Sopenharmony_ci		insn_field_set(&insn->moffset1, get_next(short, insn), 2);
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci	case 4:
52462306a36Sopenharmony_ci		insn_field_set(&insn->moffset1, get_next(int, insn), 4);
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci	case 8:
52762306a36Sopenharmony_ci		insn_field_set(&insn->moffset1, get_next(int, insn), 4);
52862306a36Sopenharmony_ci		insn_field_set(&insn->moffset2, get_next(int, insn), 4);
52962306a36Sopenharmony_ci		break;
53062306a36Sopenharmony_ci	default:	/* opnd_bytes must be modified manually */
53162306a36Sopenharmony_ci		goto err_out;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci	insn->moffset1.got = insn->moffset2.got = 1;
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return 1;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cierr_out:
53862306a36Sopenharmony_ci	return 0;
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/* Decode imm v32(Iz). Return 0 if failed */
54262306a36Sopenharmony_cistatic int __get_immv32(struct insn *insn)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	switch (insn->opnd_bytes) {
54562306a36Sopenharmony_ci	case 2:
54662306a36Sopenharmony_ci		insn_field_set(&insn->immediate, get_next(short, insn), 2);
54762306a36Sopenharmony_ci		break;
54862306a36Sopenharmony_ci	case 4:
54962306a36Sopenharmony_ci	case 8:
55062306a36Sopenharmony_ci		insn_field_set(&insn->immediate, get_next(int, insn), 4);
55162306a36Sopenharmony_ci		break;
55262306a36Sopenharmony_ci	default:	/* opnd_bytes must be modified manually */
55362306a36Sopenharmony_ci		goto err_out;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	return 1;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cierr_out:
55962306a36Sopenharmony_ci	return 0;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci/* Decode imm v64(Iv/Ov), Return 0 if failed */
56362306a36Sopenharmony_cistatic int __get_immv(struct insn *insn)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	switch (insn->opnd_bytes) {
56662306a36Sopenharmony_ci	case 2:
56762306a36Sopenharmony_ci		insn_field_set(&insn->immediate1, get_next(short, insn), 2);
56862306a36Sopenharmony_ci		break;
56962306a36Sopenharmony_ci	case 4:
57062306a36Sopenharmony_ci		insn_field_set(&insn->immediate1, get_next(int, insn), 4);
57162306a36Sopenharmony_ci		insn->immediate1.nbytes = 4;
57262306a36Sopenharmony_ci		break;
57362306a36Sopenharmony_ci	case 8:
57462306a36Sopenharmony_ci		insn_field_set(&insn->immediate1, get_next(int, insn), 4);
57562306a36Sopenharmony_ci		insn_field_set(&insn->immediate2, get_next(int, insn), 4);
57662306a36Sopenharmony_ci		break;
57762306a36Sopenharmony_ci	default:	/* opnd_bytes must be modified manually */
57862306a36Sopenharmony_ci		goto err_out;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci	insn->immediate1.got = insn->immediate2.got = 1;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	return 1;
58362306a36Sopenharmony_cierr_out:
58462306a36Sopenharmony_ci	return 0;
58562306a36Sopenharmony_ci}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci/* Decode ptr16:16/32(Ap) */
58862306a36Sopenharmony_cistatic int __get_immptr(struct insn *insn)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	switch (insn->opnd_bytes) {
59162306a36Sopenharmony_ci	case 2:
59262306a36Sopenharmony_ci		insn_field_set(&insn->immediate1, get_next(short, insn), 2);
59362306a36Sopenharmony_ci		break;
59462306a36Sopenharmony_ci	case 4:
59562306a36Sopenharmony_ci		insn_field_set(&insn->immediate1, get_next(int, insn), 4);
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci	case 8:
59862306a36Sopenharmony_ci		/* ptr16:64 is not exist (no segment) */
59962306a36Sopenharmony_ci		return 0;
60062306a36Sopenharmony_ci	default:	/* opnd_bytes must be modified manually */
60162306a36Sopenharmony_ci		goto err_out;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci	insn_field_set(&insn->immediate2, get_next(unsigned short, insn), 2);
60462306a36Sopenharmony_ci	insn->immediate1.got = insn->immediate2.got = 1;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return 1;
60762306a36Sopenharmony_cierr_out:
60862306a36Sopenharmony_ci	return 0;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci/**
61262306a36Sopenharmony_ci * insn_get_immediate() - Get the immediate in an instruction
61362306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
61462306a36Sopenharmony_ci *
61562306a36Sopenharmony_ci * If necessary, first collects the instruction up to and including the
61662306a36Sopenharmony_ci * displacement bytes.
61762306a36Sopenharmony_ci * Basically, most of immediates are sign-expanded. Unsigned-value can be
61862306a36Sopenharmony_ci * computed by bit masking with ((1 << (nbytes * 8)) - 1)
61962306a36Sopenharmony_ci *
62062306a36Sopenharmony_ci * Returns:
62162306a36Sopenharmony_ci * 0:  on success
62262306a36Sopenharmony_ci * < 0: on error
62362306a36Sopenharmony_ci */
62462306a36Sopenharmony_ciint insn_get_immediate(struct insn *insn)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	int ret;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (insn->immediate.got)
62962306a36Sopenharmony_ci		return 0;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	if (!insn->displacement.got) {
63262306a36Sopenharmony_ci		ret = insn_get_displacement(insn);
63362306a36Sopenharmony_ci		if (ret)
63462306a36Sopenharmony_ci			return ret;
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (inat_has_moffset(insn->attr)) {
63862306a36Sopenharmony_ci		if (!__get_moffset(insn))
63962306a36Sopenharmony_ci			goto err_out;
64062306a36Sopenharmony_ci		goto done;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	if (!inat_has_immediate(insn->attr))
64462306a36Sopenharmony_ci		/* no immediates */
64562306a36Sopenharmony_ci		goto done;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	switch (inat_immediate_size(insn->attr)) {
64862306a36Sopenharmony_ci	case INAT_IMM_BYTE:
64962306a36Sopenharmony_ci		insn_field_set(&insn->immediate, get_next(signed char, insn), 1);
65062306a36Sopenharmony_ci		break;
65162306a36Sopenharmony_ci	case INAT_IMM_WORD:
65262306a36Sopenharmony_ci		insn_field_set(&insn->immediate, get_next(short, insn), 2);
65362306a36Sopenharmony_ci		break;
65462306a36Sopenharmony_ci	case INAT_IMM_DWORD:
65562306a36Sopenharmony_ci		insn_field_set(&insn->immediate, get_next(int, insn), 4);
65662306a36Sopenharmony_ci		break;
65762306a36Sopenharmony_ci	case INAT_IMM_QWORD:
65862306a36Sopenharmony_ci		insn_field_set(&insn->immediate1, get_next(int, insn), 4);
65962306a36Sopenharmony_ci		insn_field_set(&insn->immediate2, get_next(int, insn), 4);
66062306a36Sopenharmony_ci		break;
66162306a36Sopenharmony_ci	case INAT_IMM_PTR:
66262306a36Sopenharmony_ci		if (!__get_immptr(insn))
66362306a36Sopenharmony_ci			goto err_out;
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	case INAT_IMM_VWORD32:
66662306a36Sopenharmony_ci		if (!__get_immv32(insn))
66762306a36Sopenharmony_ci			goto err_out;
66862306a36Sopenharmony_ci		break;
66962306a36Sopenharmony_ci	case INAT_IMM_VWORD:
67062306a36Sopenharmony_ci		if (!__get_immv(insn))
67162306a36Sopenharmony_ci			goto err_out;
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci	default:
67462306a36Sopenharmony_ci		/* Here, insn must have an immediate, but failed */
67562306a36Sopenharmony_ci		goto err_out;
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci	if (inat_has_second_immediate(insn->attr)) {
67862306a36Sopenharmony_ci		insn_field_set(&insn->immediate2, get_next(signed char, insn), 1);
67962306a36Sopenharmony_ci	}
68062306a36Sopenharmony_cidone:
68162306a36Sopenharmony_ci	insn->immediate.got = 1;
68262306a36Sopenharmony_ci	return 0;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_cierr_out:
68562306a36Sopenharmony_ci	return -ENODATA;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci/**
68962306a36Sopenharmony_ci * insn_get_length() - Get the length of instruction
69062306a36Sopenharmony_ci * @insn:	&struct insn containing instruction
69162306a36Sopenharmony_ci *
69262306a36Sopenharmony_ci * If necessary, first collects the instruction up to and including the
69362306a36Sopenharmony_ci * immediates bytes.
69462306a36Sopenharmony_ci *
69562306a36Sopenharmony_ci * Returns:
69662306a36Sopenharmony_ci *  - 0 on success
69762306a36Sopenharmony_ci *  - < 0 on error
69862306a36Sopenharmony_ci*/
69962306a36Sopenharmony_ciint insn_get_length(struct insn *insn)
70062306a36Sopenharmony_ci{
70162306a36Sopenharmony_ci	int ret;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	if (insn->length)
70462306a36Sopenharmony_ci		return 0;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (!insn->immediate.got) {
70762306a36Sopenharmony_ci		ret = insn_get_immediate(insn);
70862306a36Sopenharmony_ci		if (ret)
70962306a36Sopenharmony_ci			return ret;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	insn->length = (unsigned char)((unsigned long)insn->next_byte
71362306a36Sopenharmony_ci				     - (unsigned long)insn->kaddr);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	return 0;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci/* Ensure this instruction is decoded completely */
71962306a36Sopenharmony_cistatic inline int insn_complete(struct insn *insn)
72062306a36Sopenharmony_ci{
72162306a36Sopenharmony_ci	return insn->opcode.got && insn->modrm.got && insn->sib.got &&
72262306a36Sopenharmony_ci		insn->displacement.got && insn->immediate.got;
72362306a36Sopenharmony_ci}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci/**
72662306a36Sopenharmony_ci * insn_decode() - Decode an x86 instruction
72762306a36Sopenharmony_ci * @insn:	&struct insn to be initialized
72862306a36Sopenharmony_ci * @kaddr:	address (in kernel memory) of instruction (or copy thereof)
72962306a36Sopenharmony_ci * @buf_len:	length of the insn buffer at @kaddr
73062306a36Sopenharmony_ci * @m:		insn mode, see enum insn_mode
73162306a36Sopenharmony_ci *
73262306a36Sopenharmony_ci * Returns:
73362306a36Sopenharmony_ci * 0: if decoding succeeded
73462306a36Sopenharmony_ci * < 0: otherwise.
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_ciint insn_decode(struct insn *insn, const void *kaddr, int buf_len, enum insn_mode m)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	int ret;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci#define INSN_MODE_KERN (enum insn_mode)-1 /* __ignore_sync_check__ mode is only valid in the kernel */
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (m == INSN_MODE_KERN)
74362306a36Sopenharmony_ci		insn_init(insn, kaddr, buf_len, IS_ENABLED(CONFIG_X86_64));
74462306a36Sopenharmony_ci	else
74562306a36Sopenharmony_ci		insn_init(insn, kaddr, buf_len, m == INSN_MODE_64);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	ret = insn_get_length(insn);
74862306a36Sopenharmony_ci	if (ret)
74962306a36Sopenharmony_ci		return ret;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	if (insn_complete(insn))
75262306a36Sopenharmony_ci		return 0;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	return -EINVAL;
75562306a36Sopenharmony_ci}
756