174fe6c29SRuslan Bukin /*
285f87cf4SRuslan Bukin  * Copyright (c) 2013-2019, Intel Corporation
374fe6c29SRuslan Bukin  *
474fe6c29SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
574fe6c29SRuslan Bukin  * modification, are permitted provided that the following conditions are met:
674fe6c29SRuslan Bukin  *
774fe6c29SRuslan Bukin  *  * Redistributions of source code must retain the above copyright notice,
874fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer.
974fe6c29SRuslan Bukin  *  * Redistributions in binary form must reproduce the above copyright notice,
1074fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer in the documentation
1174fe6c29SRuslan Bukin  *    and/or other materials provided with the distribution.
1274fe6c29SRuslan Bukin  *  * Neither the name of Intel Corporation nor the names of its contributors
1374fe6c29SRuslan Bukin  *    may be used to endorse or promote products derived from this software
1474fe6c29SRuslan Bukin  *    without specific prior written permission.
1574fe6c29SRuslan Bukin  *
1674fe6c29SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1774fe6c29SRuslan Bukin  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1874fe6c29SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1974fe6c29SRuslan Bukin  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2074fe6c29SRuslan Bukin  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2174fe6c29SRuslan Bukin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2274fe6c29SRuslan Bukin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2374fe6c29SRuslan Bukin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2474fe6c29SRuslan Bukin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2574fe6c29SRuslan Bukin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2674fe6c29SRuslan Bukin  * POSSIBILITY OF SUCH DAMAGE.
2774fe6c29SRuslan Bukin  */
2874fe6c29SRuslan Bukin 
2974fe6c29SRuslan Bukin #include "pt_ild.h"
3074fe6c29SRuslan Bukin #include "pti-imm-defs.h"
3174fe6c29SRuslan Bukin #include "pti-imm.h"
3274fe6c29SRuslan Bukin #include "pti-modrm-defs.h"
3374fe6c29SRuslan Bukin #include "pti-modrm.h"
3474fe6c29SRuslan Bukin #include "pti-disp-defs.h"
3574fe6c29SRuslan Bukin #include "pti-disp.h"
3685f87cf4SRuslan Bukin #include "pti-disp_default.h"
3785f87cf4SRuslan Bukin #include "pti-sib.h"
3874fe6c29SRuslan Bukin 
3974fe6c29SRuslan Bukin #include <string.h>
4074fe6c29SRuslan Bukin 
4174fe6c29SRuslan Bukin 
4285f87cf4SRuslan Bukin static const uint8_t eamode_table[2][4] = {
4385f87cf4SRuslan Bukin 	/* Default: */ {
4485f87cf4SRuslan Bukin 		/* ptem_unknown = */	ptem_unknown,
4585f87cf4SRuslan Bukin 		/* ptem_16bit = */	ptem_16bit,
4685f87cf4SRuslan Bukin 		/* ptem_32bit = */	ptem_32bit,
4785f87cf4SRuslan Bukin 		/* ptem_64bit = */	ptem_64bit
4885f87cf4SRuslan Bukin 	},
4974fe6c29SRuslan Bukin 
5085f87cf4SRuslan Bukin 	/* With Address-size prefix (0x67): */ {
5185f87cf4SRuslan Bukin 		/* ptem_unknown = */	ptem_unknown,
5285f87cf4SRuslan Bukin 		/* ptem_16bit = */	ptem_32bit,
5385f87cf4SRuslan Bukin 		/* ptem_32bit = */	ptem_16bit,
5485f87cf4SRuslan Bukin 		/* ptem_64bit = */	ptem_32bit
5574fe6c29SRuslan Bukin 	}
5685f87cf4SRuslan Bukin };
5774fe6c29SRuslan Bukin 
5874fe6c29SRuslan Bukin /* SOME ACCESSORS */
5974fe6c29SRuslan Bukin 
get_byte(const struct pt_ild * ild,uint8_t i)6074fe6c29SRuslan Bukin static inline uint8_t get_byte(const struct pt_ild *ild, uint8_t i)
6174fe6c29SRuslan Bukin {
6274fe6c29SRuslan Bukin 	return ild->itext[i];
6374fe6c29SRuslan Bukin }
6474fe6c29SRuslan Bukin 
get_byte_ptr(const struct pt_ild * ild,uint8_t i)6574fe6c29SRuslan Bukin static inline uint8_t const *get_byte_ptr(const struct pt_ild *ild, uint8_t i)
6674fe6c29SRuslan Bukin {
6774fe6c29SRuslan Bukin 	return ild->itext + i;
6874fe6c29SRuslan Bukin }
6974fe6c29SRuslan Bukin 
mode_64b(const struct pt_ild * ild)7074fe6c29SRuslan Bukin static inline int mode_64b(const struct pt_ild *ild)
7174fe6c29SRuslan Bukin {
7274fe6c29SRuslan Bukin 	return ild->mode == ptem_64bit;
7374fe6c29SRuslan Bukin }
7474fe6c29SRuslan Bukin 
mode_32b(const struct pt_ild * ild)7574fe6c29SRuslan Bukin static inline int mode_32b(const struct pt_ild *ild)
7674fe6c29SRuslan Bukin {
7774fe6c29SRuslan Bukin 	return ild->mode == ptem_32bit;
7874fe6c29SRuslan Bukin }
7974fe6c29SRuslan Bukin 
bits_match(uint8_t x,uint8_t mask,uint8_t target)8074fe6c29SRuslan Bukin static inline int bits_match(uint8_t x, uint8_t mask, uint8_t target)
8174fe6c29SRuslan Bukin {
8274fe6c29SRuslan Bukin 	return (x & mask) == target;
8374fe6c29SRuslan Bukin }
8474fe6c29SRuslan Bukin 
8574fe6c29SRuslan Bukin static inline enum pt_exec_mode
pti_get_nominal_eosz_non64(const struct pt_ild * ild)8674fe6c29SRuslan Bukin pti_get_nominal_eosz_non64(const struct pt_ild *ild)
8774fe6c29SRuslan Bukin {
8874fe6c29SRuslan Bukin 	if (mode_32b(ild)) {
8974fe6c29SRuslan Bukin 		if (ild->u.s.osz)
9074fe6c29SRuslan Bukin 			return ptem_16bit;
9174fe6c29SRuslan Bukin 		return ptem_32bit;
9274fe6c29SRuslan Bukin 	}
9374fe6c29SRuslan Bukin 	if (ild->u.s.osz)
9474fe6c29SRuslan Bukin 		return ptem_32bit;
9574fe6c29SRuslan Bukin 	return ptem_16bit;
9674fe6c29SRuslan Bukin }
9774fe6c29SRuslan Bukin 
9874fe6c29SRuslan Bukin static inline enum pt_exec_mode
pti_get_nominal_eosz(const struct pt_ild * ild)9974fe6c29SRuslan Bukin pti_get_nominal_eosz(const struct pt_ild *ild)
10074fe6c29SRuslan Bukin {
10174fe6c29SRuslan Bukin 	if (mode_64b(ild)) {
10274fe6c29SRuslan Bukin 		if (ild->u.s.rex_w)
10374fe6c29SRuslan Bukin 			return ptem_64bit;
10474fe6c29SRuslan Bukin 		if (ild->u.s.osz)
10574fe6c29SRuslan Bukin 			return ptem_16bit;
10674fe6c29SRuslan Bukin 		return ptem_32bit;
10774fe6c29SRuslan Bukin 	}
10874fe6c29SRuslan Bukin 	return pti_get_nominal_eosz_non64(ild);
10974fe6c29SRuslan Bukin }
11074fe6c29SRuslan Bukin 
11174fe6c29SRuslan Bukin static inline enum pt_exec_mode
pti_get_nominal_eosz_df64(const struct pt_ild * ild)11274fe6c29SRuslan Bukin pti_get_nominal_eosz_df64(const struct pt_ild *ild)
11374fe6c29SRuslan Bukin {
11474fe6c29SRuslan Bukin 	if (mode_64b(ild)) {
11574fe6c29SRuslan Bukin 		if (ild->u.s.rex_w)
11674fe6c29SRuslan Bukin 			return ptem_64bit;
11774fe6c29SRuslan Bukin 		if (ild->u.s.osz)
11874fe6c29SRuslan Bukin 			return ptem_16bit;
11974fe6c29SRuslan Bukin 		/* only this next line of code is different relative
12074fe6c29SRuslan Bukin 		   to pti_get_nominal_eosz(), above */
12174fe6c29SRuslan Bukin 		return ptem_64bit;
12274fe6c29SRuslan Bukin 	}
12374fe6c29SRuslan Bukin 	return pti_get_nominal_eosz_non64(ild);
12474fe6c29SRuslan Bukin }
12574fe6c29SRuslan Bukin 
12674fe6c29SRuslan Bukin static inline enum pt_exec_mode
pti_get_nominal_easz_non64(const struct pt_ild * ild)12774fe6c29SRuslan Bukin pti_get_nominal_easz_non64(const struct pt_ild *ild)
12874fe6c29SRuslan Bukin {
12974fe6c29SRuslan Bukin 	if (mode_32b(ild)) {
13074fe6c29SRuslan Bukin 		if (ild->u.s.asz)
13174fe6c29SRuslan Bukin 			return ptem_16bit;
13274fe6c29SRuslan Bukin 		return ptem_32bit;
13374fe6c29SRuslan Bukin 	}
13474fe6c29SRuslan Bukin 	if (ild->u.s.asz)
13574fe6c29SRuslan Bukin 		return ptem_32bit;
13674fe6c29SRuslan Bukin 	return ptem_16bit;
13774fe6c29SRuslan Bukin }
13874fe6c29SRuslan Bukin 
13974fe6c29SRuslan Bukin static inline enum pt_exec_mode
pti_get_nominal_easz(const struct pt_ild * ild)14074fe6c29SRuslan Bukin pti_get_nominal_easz(const struct pt_ild *ild)
14174fe6c29SRuslan Bukin {
14274fe6c29SRuslan Bukin 	if (mode_64b(ild)) {
14374fe6c29SRuslan Bukin 		if (ild->u.s.asz)
14474fe6c29SRuslan Bukin 			return ptem_32bit;
14574fe6c29SRuslan Bukin 		return ptem_64bit;
14674fe6c29SRuslan Bukin 	}
14774fe6c29SRuslan Bukin 	return pti_get_nominal_easz_non64(ild);
14874fe6c29SRuslan Bukin }
14974fe6c29SRuslan Bukin 
resolve_z(uint8_t * pbytes,enum pt_exec_mode eosz)15074fe6c29SRuslan Bukin static inline int resolve_z(uint8_t *pbytes, enum pt_exec_mode eosz)
15174fe6c29SRuslan Bukin {
15274fe6c29SRuslan Bukin 	static const uint8_t bytes[] = { 2, 4, 4 };
15374fe6c29SRuslan Bukin 	unsigned int idx;
15474fe6c29SRuslan Bukin 
15574fe6c29SRuslan Bukin 	if (!pbytes)
15674fe6c29SRuslan Bukin 		return -pte_internal;
15774fe6c29SRuslan Bukin 
15874fe6c29SRuslan Bukin 	idx = (unsigned int) eosz - 1;
15974fe6c29SRuslan Bukin 	if (sizeof(bytes) <= idx)
16074fe6c29SRuslan Bukin 		return -pte_bad_insn;
16174fe6c29SRuslan Bukin 
16274fe6c29SRuslan Bukin 	*pbytes = bytes[idx];
16374fe6c29SRuslan Bukin 	return 0;
16474fe6c29SRuslan Bukin }
16574fe6c29SRuslan Bukin 
resolve_v(uint8_t * pbytes,enum pt_exec_mode eosz)16674fe6c29SRuslan Bukin static inline int resolve_v(uint8_t *pbytes, enum pt_exec_mode eosz)
16774fe6c29SRuslan Bukin {
16874fe6c29SRuslan Bukin 	static const uint8_t bytes[] = { 2, 4, 8 };
16974fe6c29SRuslan Bukin 	unsigned int idx;
17074fe6c29SRuslan Bukin 
17174fe6c29SRuslan Bukin 	if (!pbytes)
17274fe6c29SRuslan Bukin 		return -pte_internal;
17374fe6c29SRuslan Bukin 
17474fe6c29SRuslan Bukin 	idx = (unsigned int) eosz - 1;
17574fe6c29SRuslan Bukin 	if (sizeof(bytes) <= idx)
17674fe6c29SRuslan Bukin 		return -pte_bad_insn;
17774fe6c29SRuslan Bukin 
17874fe6c29SRuslan Bukin 	*pbytes = bytes[idx];
17974fe6c29SRuslan Bukin 	return 0;
18074fe6c29SRuslan Bukin }
18174fe6c29SRuslan Bukin 
18274fe6c29SRuslan Bukin /*  DECODERS */
18374fe6c29SRuslan Bukin 
set_imm_bytes(struct pt_ild * ild)18474fe6c29SRuslan Bukin static int set_imm_bytes(struct pt_ild *ild)
18574fe6c29SRuslan Bukin {
18674fe6c29SRuslan Bukin 	/*: set ild->imm1_bytes and  ild->imm2_bytes for maps 0/1 */
18774fe6c29SRuslan Bukin 	static uint8_t const *const map_map[] = {
18874fe6c29SRuslan Bukin 		/* map 0 */ imm_bytes_map_0x0,
18974fe6c29SRuslan Bukin 		/* map 1 */ imm_bytes_map_0x0F
19074fe6c29SRuslan Bukin 	};
19174fe6c29SRuslan Bukin 	uint8_t map, imm_code;
19274fe6c29SRuslan Bukin 
19374fe6c29SRuslan Bukin 	if (!ild)
19474fe6c29SRuslan Bukin 		return -pte_internal;
19574fe6c29SRuslan Bukin 
19674fe6c29SRuslan Bukin 	map = ild->map;
19774fe6c29SRuslan Bukin 
19874fe6c29SRuslan Bukin 	if ((sizeof(map_map) / sizeof(*map_map)) <= map)
19974fe6c29SRuslan Bukin 		return 0;
20074fe6c29SRuslan Bukin 
20174fe6c29SRuslan Bukin 	imm_code = map_map[map][ild->nominal_opcode];
20274fe6c29SRuslan Bukin 	switch (imm_code) {
20374fe6c29SRuslan Bukin 	case PTI_IMM_NONE:
20474fe6c29SRuslan Bukin 	case PTI_0_IMM_WIDTH_CONST_l2:
20574fe6c29SRuslan Bukin 	default:
20674fe6c29SRuslan Bukin 		return 0;
20774fe6c29SRuslan Bukin 
20874fe6c29SRuslan Bukin 	case PTI_UIMM8_IMM_WIDTH_CONST_l2:
20974fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
21074fe6c29SRuslan Bukin 		return 0;
21174fe6c29SRuslan Bukin 
21274fe6c29SRuslan Bukin 	case PTI_SIMM8_IMM_WIDTH_CONST_l2:
21374fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
21474fe6c29SRuslan Bukin 		return 0;
21574fe6c29SRuslan Bukin 
21674fe6c29SRuslan Bukin 	case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2:
21774fe6c29SRuslan Bukin 		/* SIMMz(eosz) */
21874fe6c29SRuslan Bukin 		return resolve_z(&ild->imm1_bytes, pti_get_nominal_eosz(ild));
21974fe6c29SRuslan Bukin 
22074fe6c29SRuslan Bukin 	case PTI_UIMMv_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2:
22174fe6c29SRuslan Bukin 		/* UIMMv(eosz) */
22274fe6c29SRuslan Bukin 		return resolve_v(&ild->imm1_bytes, pti_get_nominal_eosz(ild));
22374fe6c29SRuslan Bukin 
22474fe6c29SRuslan Bukin 	case PTI_UIMM16_IMM_WIDTH_CONST_l2:
22574fe6c29SRuslan Bukin 		ild->imm1_bytes = 2;
22674fe6c29SRuslan Bukin 		return 0;
22774fe6c29SRuslan Bukin 
22874fe6c29SRuslan Bukin 	case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_DF64_EOSZ_l2:
22974fe6c29SRuslan Bukin 		/* push defaults to eosz64 in 64b mode, then uses SIMMz */
23074fe6c29SRuslan Bukin 		return resolve_z(&ild->imm1_bytes,
23174fe6c29SRuslan Bukin 				 pti_get_nominal_eosz_df64(ild));
23274fe6c29SRuslan Bukin 
23374fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf7_l1:
23474fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2) {
23574fe6c29SRuslan Bukin 			return resolve_z(&ild->imm1_bytes,
23674fe6c29SRuslan Bukin 					 pti_get_nominal_eosz(ild));
23774fe6c29SRuslan Bukin 		}
23874fe6c29SRuslan Bukin 		return 0;
23974fe6c29SRuslan Bukin 
24074fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xc7_l1:
24174fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 0) {
24274fe6c29SRuslan Bukin 			return resolve_z(&ild->imm1_bytes,
24374fe6c29SRuslan Bukin 					 pti_get_nominal_eosz(ild));
24474fe6c29SRuslan Bukin 		}
24574fe6c29SRuslan Bukin 		return 0;
24674fe6c29SRuslan Bukin 
24774fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf6_l1:
24874fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2)
24974fe6c29SRuslan Bukin 			ild->imm1_bytes = 1;
25074fe6c29SRuslan Bukin 
25174fe6c29SRuslan Bukin 		return 0;
25274fe6c29SRuslan Bukin 
25374fe6c29SRuslan Bukin 	case PTI_IMM_hasimm_map0x0_op0xc8_l1:
25474fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0) {
25574fe6c29SRuslan Bukin 			/*enter -> imm1=2, imm2=1 */
25674fe6c29SRuslan Bukin 			ild->imm1_bytes = 2;
25774fe6c29SRuslan Bukin 			ild->imm2_bytes = 1;
25874fe6c29SRuslan Bukin 		}
25974fe6c29SRuslan Bukin 		return 0;
26074fe6c29SRuslan Bukin 
26174fe6c29SRuslan Bukin 	case PTI_IMM_hasimm_map0x0F_op0x78_l1:
26274fe6c29SRuslan Bukin 		/* AMD SSE4a (insertq/extrq use  osz/f2) vs vmread
26374fe6c29SRuslan Bukin 		 * (no prefixes)
26474fe6c29SRuslan Bukin 		 */
26574fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_1) {
26674fe6c29SRuslan Bukin 			if (ild->u.s.osz || ild->u.s.last_f2f3 == 2) {
26774fe6c29SRuslan Bukin 				ild->imm1_bytes = 1;
26874fe6c29SRuslan Bukin 				ild->imm2_bytes = 1;
26974fe6c29SRuslan Bukin 			}
27074fe6c29SRuslan Bukin 		}
27174fe6c29SRuslan Bukin 		return 0;
27274fe6c29SRuslan Bukin 	}
27374fe6c29SRuslan Bukin }
27474fe6c29SRuslan Bukin 
imm_dec(struct pt_ild * ild,uint8_t length)27574fe6c29SRuslan Bukin static int imm_dec(struct pt_ild *ild, uint8_t length)
27674fe6c29SRuslan Bukin {
27774fe6c29SRuslan Bukin 	int errcode;
27874fe6c29SRuslan Bukin 
27974fe6c29SRuslan Bukin 	if (!ild)
28074fe6c29SRuslan Bukin 		return -pte_internal;
28174fe6c29SRuslan Bukin 
28274fe6c29SRuslan Bukin 	if (ild->map == PTI_MAP_AMD3DNOW) {
28374fe6c29SRuslan Bukin 		if (ild->max_bytes <= length)
28474fe6c29SRuslan Bukin 			return -pte_bad_insn;
28574fe6c29SRuslan Bukin 
28674fe6c29SRuslan Bukin 		ild->nominal_opcode = get_byte(ild, length);
28774fe6c29SRuslan Bukin 		return length + 1;
28874fe6c29SRuslan Bukin 	}
28974fe6c29SRuslan Bukin 
29074fe6c29SRuslan Bukin 	errcode = set_imm_bytes(ild);
29174fe6c29SRuslan Bukin 	if (errcode < 0)
29274fe6c29SRuslan Bukin 		return errcode;
29374fe6c29SRuslan Bukin 
29474fe6c29SRuslan Bukin 	length += ild->imm1_bytes;
29574fe6c29SRuslan Bukin 	length += ild->imm2_bytes;
29674fe6c29SRuslan Bukin 	if (ild->max_bytes < length)
29774fe6c29SRuslan Bukin 		return -pte_bad_insn;
29874fe6c29SRuslan Bukin 
29974fe6c29SRuslan Bukin 	return length;
30074fe6c29SRuslan Bukin }
30174fe6c29SRuslan Bukin 
compute_disp_dec(struct pt_ild * ild)30274fe6c29SRuslan Bukin static int compute_disp_dec(struct pt_ild *ild)
30374fe6c29SRuslan Bukin {
30474fe6c29SRuslan Bukin 	/* set ild->disp_bytes for maps 0 and 1. */
30574fe6c29SRuslan Bukin 	static uint8_t const *const map_map[] = {
30674fe6c29SRuslan Bukin 		/* map 0 */ disp_bytes_map_0x0,
30774fe6c29SRuslan Bukin 		/* map 1 */ disp_bytes_map_0x0F
30874fe6c29SRuslan Bukin 	};
30974fe6c29SRuslan Bukin 	uint8_t map, disp_kind;
31074fe6c29SRuslan Bukin 
31174fe6c29SRuslan Bukin 	if (!ild)
31274fe6c29SRuslan Bukin 		return -pte_internal;
31374fe6c29SRuslan Bukin 
31474fe6c29SRuslan Bukin 	if (0 < ild->disp_bytes)
31574fe6c29SRuslan Bukin 		return 0;
31674fe6c29SRuslan Bukin 
31774fe6c29SRuslan Bukin 	map = ild->map;
31874fe6c29SRuslan Bukin 
31974fe6c29SRuslan Bukin 	if ((sizeof(map_map) / sizeof(*map_map)) <= map)
32074fe6c29SRuslan Bukin 		return 0;
32174fe6c29SRuslan Bukin 
32274fe6c29SRuslan Bukin 	disp_kind = map_map[map][ild->nominal_opcode];
32374fe6c29SRuslan Bukin 	switch (disp_kind) {
32474fe6c29SRuslan Bukin 	case PTI_DISP_NONE:
32574fe6c29SRuslan Bukin 		ild->disp_bytes = 0;
32674fe6c29SRuslan Bukin 		return 0;
32774fe6c29SRuslan Bukin 
32874fe6c29SRuslan Bukin 	case PTI_PRESERVE_DEFAULT:
32974fe6c29SRuslan Bukin 		/* nothing to do */
33074fe6c29SRuslan Bukin 		return 0;
33174fe6c29SRuslan Bukin 
33274fe6c29SRuslan Bukin 	case PTI_BRDISP8:
33374fe6c29SRuslan Bukin 		ild->disp_bytes = 1;
33474fe6c29SRuslan Bukin 		return 0;
33574fe6c29SRuslan Bukin 
33674fe6c29SRuslan Bukin 	case PTI_DISP_BUCKET_0_l1:
33774fe6c29SRuslan Bukin 		/* BRDISPz(eosz) for 16/32 modes, and BRDISP32 for 64b mode */
33874fe6c29SRuslan Bukin 		if (mode_64b(ild)) {
33974fe6c29SRuslan Bukin 			ild->disp_bytes = 4;
34074fe6c29SRuslan Bukin 			return 0;
34174fe6c29SRuslan Bukin 		}
34274fe6c29SRuslan Bukin 
34374fe6c29SRuslan Bukin 		return resolve_z(&ild->disp_bytes,
34474fe6c29SRuslan Bukin 				 pti_get_nominal_eosz(ild));
34574fe6c29SRuslan Bukin 
34674fe6c29SRuslan Bukin 	case PTI_MEMDISPv_DISP_WIDTH_ASZ_NONTERM_EASZ_l2:
34774fe6c29SRuslan Bukin 		/* MEMDISPv(easz) */
34874fe6c29SRuslan Bukin 		return resolve_v(&ild->disp_bytes, pti_get_nominal_easz(ild));
34974fe6c29SRuslan Bukin 
35074fe6c29SRuslan Bukin 	case PTI_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2:
35174fe6c29SRuslan Bukin 		/* BRDISPz(eosz) for 16/32/64 modes */
35274fe6c29SRuslan Bukin 		return resolve_z(&ild->disp_bytes, pti_get_nominal_eosz(ild));
35374fe6c29SRuslan Bukin 
35474fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_DISP_map0x0_op0xc7_l1:
35574fe6c29SRuslan Bukin 		/* reg=0 -> preserve, reg=7 -> BRDISPz(eosz) */
35674fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 7) {
35774fe6c29SRuslan Bukin 			return resolve_z(&ild->disp_bytes,
35874fe6c29SRuslan Bukin 					 pti_get_nominal_eosz(ild));
35974fe6c29SRuslan Bukin 		}
36074fe6c29SRuslan Bukin 		return 0;
36174fe6c29SRuslan Bukin 
36274fe6c29SRuslan Bukin 	default:
36374fe6c29SRuslan Bukin 		return -pte_bad_insn;
36474fe6c29SRuslan Bukin 	}
36574fe6c29SRuslan Bukin }
36674fe6c29SRuslan Bukin 
disp_dec(struct pt_ild * ild,uint8_t length)36774fe6c29SRuslan Bukin static int disp_dec(struct pt_ild *ild, uint8_t length)
36874fe6c29SRuslan Bukin {
36974fe6c29SRuslan Bukin 	uint8_t disp_bytes;
37074fe6c29SRuslan Bukin 	int errcode;
37174fe6c29SRuslan Bukin 
37274fe6c29SRuslan Bukin 	if (!ild)
37374fe6c29SRuslan Bukin 		return -pte_internal;
37474fe6c29SRuslan Bukin 
37574fe6c29SRuslan Bukin 	errcode = compute_disp_dec(ild);
37674fe6c29SRuslan Bukin 	if (errcode < 0)
37774fe6c29SRuslan Bukin 		return errcode;
37874fe6c29SRuslan Bukin 
37974fe6c29SRuslan Bukin 	disp_bytes = ild->disp_bytes;
38074fe6c29SRuslan Bukin 	if (disp_bytes == 0)
38174fe6c29SRuslan Bukin 		return imm_dec(ild, length);
38274fe6c29SRuslan Bukin 
38374fe6c29SRuslan Bukin 	if (length + disp_bytes > ild->max_bytes)
38474fe6c29SRuslan Bukin 		return -pte_bad_insn;
38574fe6c29SRuslan Bukin 
38674fe6c29SRuslan Bukin 	/*Record only position; must be able to re-read itext bytes for actual
38774fe6c29SRuslan Bukin 	   value. (SMC/CMC issue). */
38874fe6c29SRuslan Bukin 	ild->disp_pos = length;
38974fe6c29SRuslan Bukin 
39074fe6c29SRuslan Bukin 	return imm_dec(ild, length + disp_bytes);
39174fe6c29SRuslan Bukin }
39274fe6c29SRuslan Bukin 
sib_dec(struct pt_ild * ild,uint8_t length)39374fe6c29SRuslan Bukin static int sib_dec(struct pt_ild *ild, uint8_t length)
39474fe6c29SRuslan Bukin {
39574fe6c29SRuslan Bukin 	uint8_t sib;
39674fe6c29SRuslan Bukin 
39774fe6c29SRuslan Bukin 	if (!ild)
39874fe6c29SRuslan Bukin 		return -pte_internal;
39974fe6c29SRuslan Bukin 
40074fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
40174fe6c29SRuslan Bukin 		return -pte_bad_insn;
40274fe6c29SRuslan Bukin 
40374fe6c29SRuslan Bukin 	sib = get_byte(ild, length);
40474fe6c29SRuslan Bukin 	if ((sib & 0x07) == 0x05 && pti_get_modrm_mod(ild) == 0)
40574fe6c29SRuslan Bukin 		ild->disp_bytes = 4;
40674fe6c29SRuslan Bukin 
40774fe6c29SRuslan Bukin 	return disp_dec(ild, length + 1);
40874fe6c29SRuslan Bukin }
40974fe6c29SRuslan Bukin 
modrm_dec(struct pt_ild * ild,uint8_t length)41074fe6c29SRuslan Bukin static int modrm_dec(struct pt_ild *ild, uint8_t length)
41174fe6c29SRuslan Bukin {
41274fe6c29SRuslan Bukin 	static uint8_t const *const has_modrm_2d[2] = {
41374fe6c29SRuslan Bukin 		has_modrm_map_0x0,
41474fe6c29SRuslan Bukin 		has_modrm_map_0x0F
41574fe6c29SRuslan Bukin 	};
41674fe6c29SRuslan Bukin 	int has_modrm = PTI_MODRM_FALSE;
41774fe6c29SRuslan Bukin 	pti_map_enum_t map;
41874fe6c29SRuslan Bukin 
41974fe6c29SRuslan Bukin 	if (!ild)
42074fe6c29SRuslan Bukin 		return -pte_internal;
42174fe6c29SRuslan Bukin 
42274fe6c29SRuslan Bukin 	map = pti_get_map(ild);
42374fe6c29SRuslan Bukin 	if (map >= PTI_MAP_2)
42474fe6c29SRuslan Bukin 		has_modrm = PTI_MODRM_TRUE;
42574fe6c29SRuslan Bukin 	else
42674fe6c29SRuslan Bukin 		has_modrm = has_modrm_2d[map][ild->nominal_opcode];
42774fe6c29SRuslan Bukin 
42874fe6c29SRuslan Bukin 	if (has_modrm == PTI_MODRM_FALSE || has_modrm == PTI_MODRM_UNDEF)
42974fe6c29SRuslan Bukin 		return disp_dec(ild, length);
43074fe6c29SRuslan Bukin 
43174fe6c29SRuslan Bukin 	/* really >= here because we have not eaten the byte yet */
43274fe6c29SRuslan Bukin 	if (length >= ild->max_bytes)
43374fe6c29SRuslan Bukin 		return -pte_bad_insn;
43474fe6c29SRuslan Bukin 
43574fe6c29SRuslan Bukin 	ild->modrm_byte = get_byte(ild, length);
43674fe6c29SRuslan Bukin 
43774fe6c29SRuslan Bukin 	if (has_modrm != PTI_MODRM_IGNORE_MOD) {
43874fe6c29SRuslan Bukin 		/* set disp_bytes and sib using simple tables */
43974fe6c29SRuslan Bukin 
44074fe6c29SRuslan Bukin 		uint8_t eamode = eamode_table[ild->u.s.asz][ild->mode];
44174fe6c29SRuslan Bukin 		uint8_t mod = (uint8_t) pti_get_modrm_mod(ild);
44274fe6c29SRuslan Bukin 		uint8_t rm = (uint8_t) pti_get_modrm_rm(ild);
44385f87cf4SRuslan Bukin 		uint8_t sib;
44474fe6c29SRuslan Bukin 
44585f87cf4SRuslan Bukin 		ild->disp_bytes = disp_default[eamode][mod][rm];
44674fe6c29SRuslan Bukin 
44785f87cf4SRuslan Bukin 		sib = has_sib[eamode][mod][rm];
44885f87cf4SRuslan Bukin 		if (sib)
44974fe6c29SRuslan Bukin 			return sib_dec(ild, length + 1);
45074fe6c29SRuslan Bukin 	}
45174fe6c29SRuslan Bukin 
45274fe6c29SRuslan Bukin 	return disp_dec(ild, length + 1);
45374fe6c29SRuslan Bukin }
45474fe6c29SRuslan Bukin 
get_next_as_opcode(struct pt_ild * ild,uint8_t length)45574fe6c29SRuslan Bukin static inline int get_next_as_opcode(struct pt_ild *ild, uint8_t length)
45674fe6c29SRuslan Bukin {
45774fe6c29SRuslan Bukin 	if (!ild)
45874fe6c29SRuslan Bukin 		return -pte_internal;
45974fe6c29SRuslan Bukin 
46074fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
46174fe6c29SRuslan Bukin 		return -pte_bad_insn;
46274fe6c29SRuslan Bukin 
46374fe6c29SRuslan Bukin 	ild->nominal_opcode = get_byte(ild, length);
46474fe6c29SRuslan Bukin 
46574fe6c29SRuslan Bukin 	return modrm_dec(ild, length + 1);
46674fe6c29SRuslan Bukin }
46774fe6c29SRuslan Bukin 
opcode_dec(struct pt_ild * ild,uint8_t length)46874fe6c29SRuslan Bukin static int opcode_dec(struct pt_ild *ild, uint8_t length)
46974fe6c29SRuslan Bukin {
47074fe6c29SRuslan Bukin 	uint8_t b, m;
47174fe6c29SRuslan Bukin 
47274fe6c29SRuslan Bukin 	if (!ild)
47374fe6c29SRuslan Bukin 		return -pte_internal;
47474fe6c29SRuslan Bukin 
47574fe6c29SRuslan Bukin 	/*no need to check max_bytes - it was checked in previous scanners */
47674fe6c29SRuslan Bukin 	b = get_byte(ild, length);
47774fe6c29SRuslan Bukin 	if (b != 0x0F) {	/* 1B opcodes, map 0 */
47874fe6c29SRuslan Bukin 		ild->map = PTI_MAP_0;
47974fe6c29SRuslan Bukin 		ild->nominal_opcode = b;
48074fe6c29SRuslan Bukin 
48174fe6c29SRuslan Bukin 		return modrm_dec(ild, length + 1);
48274fe6c29SRuslan Bukin 	}
48374fe6c29SRuslan Bukin 
48474fe6c29SRuslan Bukin 	length++;		/* eat the 0x0F */
48574fe6c29SRuslan Bukin 
48674fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
48774fe6c29SRuslan Bukin 		return -pte_bad_insn;
48874fe6c29SRuslan Bukin 
48974fe6c29SRuslan Bukin 	/* 0x0F opcodes MAPS 1,2,3 */
49074fe6c29SRuslan Bukin 	m = get_byte(ild, length);
49174fe6c29SRuslan Bukin 	if (m == 0x38) {
49274fe6c29SRuslan Bukin 		ild->map = PTI_MAP_2;
49374fe6c29SRuslan Bukin 
49474fe6c29SRuslan Bukin 		return get_next_as_opcode(ild, length + 1);
49574fe6c29SRuslan Bukin 	} else if (m == 0x3A) {
49674fe6c29SRuslan Bukin 		ild->map = PTI_MAP_3;
49774fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
49874fe6c29SRuslan Bukin 
49974fe6c29SRuslan Bukin 		return get_next_as_opcode(ild, length + 1);
50074fe6c29SRuslan Bukin 	} else if (bits_match(m, 0xf8, 0x38)) {
50174fe6c29SRuslan Bukin 		ild->map = PTI_MAP_INVALID;
50274fe6c29SRuslan Bukin 
50374fe6c29SRuslan Bukin 		return get_next_as_opcode(ild, length + 1);
50474fe6c29SRuslan Bukin 	} else if (m == 0x0F) {	/* 3dNow */
50574fe6c29SRuslan Bukin 		ild->map = PTI_MAP_AMD3DNOW;
50674fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
50774fe6c29SRuslan Bukin 		/* real opcode is in immediate later on, but we need an
50874fe6c29SRuslan Bukin 		 * opcode now. */
50974fe6c29SRuslan Bukin 		ild->nominal_opcode = 0x0F;
51074fe6c29SRuslan Bukin 
51174fe6c29SRuslan Bukin 		return modrm_dec(ild, length + 1);
51274fe6c29SRuslan Bukin 	} else {	/* map 1 (simple two byte opcodes) */
51374fe6c29SRuslan Bukin 		ild->nominal_opcode = m;
51474fe6c29SRuslan Bukin 		ild->map = PTI_MAP_1;
51574fe6c29SRuslan Bukin 
51674fe6c29SRuslan Bukin 		return modrm_dec(ild, length + 1);
51774fe6c29SRuslan Bukin 	}
51874fe6c29SRuslan Bukin }
51974fe6c29SRuslan Bukin 
52074fe6c29SRuslan Bukin typedef int (*prefix_decoder)(struct pt_ild *ild, uint8_t length, uint8_t rex);
52185f87cf4SRuslan Bukin 
52285f87cf4SRuslan Bukin static int prefix_osz(struct pt_ild *ild, uint8_t length, uint8_t rex);
52385f87cf4SRuslan Bukin static int prefix_asz(struct pt_ild *ild, uint8_t length, uint8_t rex);
52485f87cf4SRuslan Bukin static int prefix_lock(struct pt_ild *ild, uint8_t length, uint8_t rex);
52585f87cf4SRuslan Bukin static int prefix_f2(struct pt_ild *ild, uint8_t length, uint8_t rex);
52685f87cf4SRuslan Bukin static int prefix_f3(struct pt_ild *ild, uint8_t length, uint8_t rex);
52785f87cf4SRuslan Bukin static int prefix_rex(struct pt_ild *ild, uint8_t length, uint8_t rex);
52885f87cf4SRuslan Bukin static int prefix_vex_c4(struct pt_ild *ild, uint8_t length, uint8_t rex);
52985f87cf4SRuslan Bukin static int prefix_vex_c5(struct pt_ild *ild, uint8_t length, uint8_t rex);
53085f87cf4SRuslan Bukin static int prefix_evex(struct pt_ild *ild, uint8_t length, uint8_t rex);
53185f87cf4SRuslan Bukin static int prefix_ignore(struct pt_ild *ild, uint8_t length, uint8_t rex);
53285f87cf4SRuslan Bukin static int prefix_done(struct pt_ild *ild, uint8_t length, uint8_t rex);
53385f87cf4SRuslan Bukin 
53485f87cf4SRuslan Bukin static const prefix_decoder prefix_table[256] = {
53585f87cf4SRuslan Bukin 	/* 00 = */ prefix_done,
53685f87cf4SRuslan Bukin 	/* 01 = */ prefix_done,
53785f87cf4SRuslan Bukin 	/* 02 = */ prefix_done,
53885f87cf4SRuslan Bukin 	/* 03 = */ prefix_done,
53985f87cf4SRuslan Bukin 	/* 04 = */ prefix_done,
54085f87cf4SRuslan Bukin 	/* 05 = */ prefix_done,
54185f87cf4SRuslan Bukin 	/* 06 = */ prefix_done,
54285f87cf4SRuslan Bukin 	/* 07 = */ prefix_done,
54385f87cf4SRuslan Bukin 	/* 08 = */ prefix_done,
54485f87cf4SRuslan Bukin 	/* 09 = */ prefix_done,
54585f87cf4SRuslan Bukin 	/* 0a = */ prefix_done,
54685f87cf4SRuslan Bukin 	/* 0b = */ prefix_done,
54785f87cf4SRuslan Bukin 	/* 0c = */ prefix_done,
54885f87cf4SRuslan Bukin 	/* 0d = */ prefix_done,
54985f87cf4SRuslan Bukin 	/* 0e = */ prefix_done,
55085f87cf4SRuslan Bukin 	/* 0f = */ prefix_done,
55185f87cf4SRuslan Bukin 
55285f87cf4SRuslan Bukin 	/* 10 = */ prefix_done,
55385f87cf4SRuslan Bukin 	/* 11 = */ prefix_done,
55485f87cf4SRuslan Bukin 	/* 12 = */ prefix_done,
55585f87cf4SRuslan Bukin 	/* 13 = */ prefix_done,
55685f87cf4SRuslan Bukin 	/* 14 = */ prefix_done,
55785f87cf4SRuslan Bukin 	/* 15 = */ prefix_done,
55885f87cf4SRuslan Bukin 	/* 16 = */ prefix_done,
55985f87cf4SRuslan Bukin 	/* 17 = */ prefix_done,
56085f87cf4SRuslan Bukin 	/* 18 = */ prefix_done,
56185f87cf4SRuslan Bukin 	/* 19 = */ prefix_done,
56285f87cf4SRuslan Bukin 	/* 1a = */ prefix_done,
56385f87cf4SRuslan Bukin 	/* 1b = */ prefix_done,
56485f87cf4SRuslan Bukin 	/* 1c = */ prefix_done,
56585f87cf4SRuslan Bukin 	/* 1d = */ prefix_done,
56685f87cf4SRuslan Bukin 	/* 1e = */ prefix_done,
56785f87cf4SRuslan Bukin 	/* 1f = */ prefix_done,
56885f87cf4SRuslan Bukin 
56985f87cf4SRuslan Bukin 	/* 20 = */ prefix_done,
57085f87cf4SRuslan Bukin 	/* 21 = */ prefix_done,
57185f87cf4SRuslan Bukin 	/* 22 = */ prefix_done,
57285f87cf4SRuslan Bukin 	/* 23 = */ prefix_done,
57385f87cf4SRuslan Bukin 	/* 24 = */ prefix_done,
57485f87cf4SRuslan Bukin 	/* 25 = */ prefix_done,
57585f87cf4SRuslan Bukin 	/* 26 = */ prefix_ignore,
57685f87cf4SRuslan Bukin 	/* 27 = */ prefix_done,
57785f87cf4SRuslan Bukin 	/* 28 = */ prefix_done,
57885f87cf4SRuslan Bukin 	/* 29 = */ prefix_done,
57985f87cf4SRuslan Bukin 	/* 2a = */ prefix_done,
58085f87cf4SRuslan Bukin 	/* 2b = */ prefix_done,
58185f87cf4SRuslan Bukin 	/* 2c = */ prefix_done,
58285f87cf4SRuslan Bukin 	/* 2d = */ prefix_done,
58385f87cf4SRuslan Bukin 	/* 2e = */ prefix_ignore,
58485f87cf4SRuslan Bukin 	/* 2f = */ prefix_done,
58585f87cf4SRuslan Bukin 
58685f87cf4SRuslan Bukin 	/* 30 = */ prefix_done,
58785f87cf4SRuslan Bukin 	/* 31 = */ prefix_done,
58885f87cf4SRuslan Bukin 	/* 32 = */ prefix_done,
58985f87cf4SRuslan Bukin 	/* 33 = */ prefix_done,
59085f87cf4SRuslan Bukin 	/* 34 = */ prefix_done,
59185f87cf4SRuslan Bukin 	/* 35 = */ prefix_done,
59285f87cf4SRuslan Bukin 	/* 36 = */ prefix_ignore,
59385f87cf4SRuslan Bukin 	/* 37 = */ prefix_done,
59485f87cf4SRuslan Bukin 	/* 38 = */ prefix_done,
59585f87cf4SRuslan Bukin 	/* 39 = */ prefix_done,
59685f87cf4SRuslan Bukin 	/* 3a = */ prefix_done,
59785f87cf4SRuslan Bukin 	/* 3b = */ prefix_done,
59885f87cf4SRuslan Bukin 	/* 3c = */ prefix_done,
59985f87cf4SRuslan Bukin 	/* 3d = */ prefix_done,
60085f87cf4SRuslan Bukin 	/* 3e = */ prefix_ignore,
60185f87cf4SRuslan Bukin 	/* 3f = */ prefix_done,
60285f87cf4SRuslan Bukin 
60385f87cf4SRuslan Bukin 	/* 40 = */ prefix_rex,
60485f87cf4SRuslan Bukin 	/* 41 = */ prefix_rex,
60585f87cf4SRuslan Bukin 	/* 42 = */ prefix_rex,
60685f87cf4SRuslan Bukin 	/* 43 = */ prefix_rex,
60785f87cf4SRuslan Bukin 	/* 44 = */ prefix_rex,
60885f87cf4SRuslan Bukin 	/* 45 = */ prefix_rex,
60985f87cf4SRuslan Bukin 	/* 46 = */ prefix_rex,
61085f87cf4SRuslan Bukin 	/* 47 = */ prefix_rex,
61185f87cf4SRuslan Bukin 	/* 48 = */ prefix_rex,
61285f87cf4SRuslan Bukin 	/* 49 = */ prefix_rex,
61385f87cf4SRuslan Bukin 	/* 4a = */ prefix_rex,
61485f87cf4SRuslan Bukin 	/* 4b = */ prefix_rex,
61585f87cf4SRuslan Bukin 	/* 4c = */ prefix_rex,
61685f87cf4SRuslan Bukin 	/* 4d = */ prefix_rex,
61785f87cf4SRuslan Bukin 	/* 4e = */ prefix_rex,
61885f87cf4SRuslan Bukin 	/* 4f = */ prefix_rex,
61985f87cf4SRuslan Bukin 
62085f87cf4SRuslan Bukin 	/* 50 = */ prefix_done,
62185f87cf4SRuslan Bukin 	/* 51 = */ prefix_done,
62285f87cf4SRuslan Bukin 	/* 52 = */ prefix_done,
62385f87cf4SRuslan Bukin 	/* 53 = */ prefix_done,
62485f87cf4SRuslan Bukin 	/* 54 = */ prefix_done,
62585f87cf4SRuslan Bukin 	/* 55 = */ prefix_done,
62685f87cf4SRuslan Bukin 	/* 56 = */ prefix_done,
62785f87cf4SRuslan Bukin 	/* 57 = */ prefix_done,
62885f87cf4SRuslan Bukin 	/* 58 = */ prefix_done,
62985f87cf4SRuslan Bukin 	/* 59 = */ prefix_done,
63085f87cf4SRuslan Bukin 	/* 5a = */ prefix_done,
63185f87cf4SRuslan Bukin 	/* 5b = */ prefix_done,
63285f87cf4SRuslan Bukin 	/* 5c = */ prefix_done,
63385f87cf4SRuslan Bukin 	/* 5d = */ prefix_done,
63485f87cf4SRuslan Bukin 	/* 5e = */ prefix_done,
63585f87cf4SRuslan Bukin 	/* 5f = */ prefix_done,
63685f87cf4SRuslan Bukin 
63785f87cf4SRuslan Bukin 	/* 60 = */ prefix_done,
63885f87cf4SRuslan Bukin 	/* 61 = */ prefix_done,
63985f87cf4SRuslan Bukin 	/* 62 = */ prefix_evex,
64085f87cf4SRuslan Bukin 	/* 63 = */ prefix_done,
64185f87cf4SRuslan Bukin 	/* 64 = */ prefix_ignore,
64285f87cf4SRuslan Bukin 	/* 65 = */ prefix_ignore,
64385f87cf4SRuslan Bukin 	/* 66 = */ prefix_osz,
64485f87cf4SRuslan Bukin 	/* 67 = */ prefix_asz,
64585f87cf4SRuslan Bukin 	/* 68 = */ prefix_done,
64685f87cf4SRuslan Bukin 	/* 69 = */ prefix_done,
64785f87cf4SRuslan Bukin 	/* 6a = */ prefix_done,
64885f87cf4SRuslan Bukin 	/* 6b = */ prefix_done,
64985f87cf4SRuslan Bukin 	/* 6c = */ prefix_done,
65085f87cf4SRuslan Bukin 	/* 6d = */ prefix_done,
65185f87cf4SRuslan Bukin 	/* 6e = */ prefix_done,
65285f87cf4SRuslan Bukin 	/* 6f = */ prefix_done,
65385f87cf4SRuslan Bukin 
65485f87cf4SRuslan Bukin 	/* 70 = */ prefix_done,
65585f87cf4SRuslan Bukin 	/* 71 = */ prefix_done,
65685f87cf4SRuslan Bukin 	/* 72 = */ prefix_done,
65785f87cf4SRuslan Bukin 	/* 73 = */ prefix_done,
65885f87cf4SRuslan Bukin 	/* 74 = */ prefix_done,
65985f87cf4SRuslan Bukin 	/* 75 = */ prefix_done,
66085f87cf4SRuslan Bukin 	/* 76 = */ prefix_done,
66185f87cf4SRuslan Bukin 	/* 77 = */ prefix_done,
66285f87cf4SRuslan Bukin 	/* 78 = */ prefix_done,
66385f87cf4SRuslan Bukin 	/* 79 = */ prefix_done,
66485f87cf4SRuslan Bukin 	/* 7a = */ prefix_done,
66585f87cf4SRuslan Bukin 	/* 7b = */ prefix_done,
66685f87cf4SRuslan Bukin 	/* 7c = */ prefix_done,
66785f87cf4SRuslan Bukin 	/* 7d = */ prefix_done,
66885f87cf4SRuslan Bukin 	/* 7e = */ prefix_done,
66985f87cf4SRuslan Bukin 	/* 7f = */ prefix_done,
67085f87cf4SRuslan Bukin 
67185f87cf4SRuslan Bukin 	/* 80 = */ prefix_done,
67285f87cf4SRuslan Bukin 	/* 81 = */ prefix_done,
67385f87cf4SRuslan Bukin 	/* 82 = */ prefix_done,
67485f87cf4SRuslan Bukin 	/* 83 = */ prefix_done,
67585f87cf4SRuslan Bukin 	/* 84 = */ prefix_done,
67685f87cf4SRuslan Bukin 	/* 85 = */ prefix_done,
67785f87cf4SRuslan Bukin 	/* 86 = */ prefix_done,
67885f87cf4SRuslan Bukin 	/* 87 = */ prefix_done,
67985f87cf4SRuslan Bukin 	/* 88 = */ prefix_done,
68085f87cf4SRuslan Bukin 	/* 89 = */ prefix_done,
68185f87cf4SRuslan Bukin 	/* 8a = */ prefix_done,
68285f87cf4SRuslan Bukin 	/* 8b = */ prefix_done,
68385f87cf4SRuslan Bukin 	/* 8c = */ prefix_done,
68485f87cf4SRuslan Bukin 	/* 8d = */ prefix_done,
68585f87cf4SRuslan Bukin 	/* 8e = */ prefix_done,
68685f87cf4SRuslan Bukin 	/* 8f = */ prefix_done,
68785f87cf4SRuslan Bukin 
68885f87cf4SRuslan Bukin 	/* 90 = */ prefix_done,
68985f87cf4SRuslan Bukin 	/* 91 = */ prefix_done,
69085f87cf4SRuslan Bukin 	/* 92 = */ prefix_done,
69185f87cf4SRuslan Bukin 	/* 93 = */ prefix_done,
69285f87cf4SRuslan Bukin 	/* 94 = */ prefix_done,
69385f87cf4SRuslan Bukin 	/* 95 = */ prefix_done,
69485f87cf4SRuslan Bukin 	/* 96 = */ prefix_done,
69585f87cf4SRuslan Bukin 	/* 97 = */ prefix_done,
69685f87cf4SRuslan Bukin 	/* 98 = */ prefix_done,
69785f87cf4SRuslan Bukin 	/* 99 = */ prefix_done,
69885f87cf4SRuslan Bukin 	/* 9a = */ prefix_done,
69985f87cf4SRuslan Bukin 	/* 9b = */ prefix_done,
70085f87cf4SRuslan Bukin 	/* 9c = */ prefix_done,
70185f87cf4SRuslan Bukin 	/* 9d = */ prefix_done,
70285f87cf4SRuslan Bukin 	/* 9e = */ prefix_done,
70385f87cf4SRuslan Bukin 	/* 9f = */ prefix_done,
70485f87cf4SRuslan Bukin 
70585f87cf4SRuslan Bukin 	/* a0 = */ prefix_done,
70685f87cf4SRuslan Bukin 	/* a1 = */ prefix_done,
70785f87cf4SRuslan Bukin 	/* a2 = */ prefix_done,
70885f87cf4SRuslan Bukin 	/* a3 = */ prefix_done,
70985f87cf4SRuslan Bukin 	/* a4 = */ prefix_done,
71085f87cf4SRuslan Bukin 	/* a5 = */ prefix_done,
71185f87cf4SRuslan Bukin 	/* a6 = */ prefix_done,
71285f87cf4SRuslan Bukin 	/* a7 = */ prefix_done,
71385f87cf4SRuslan Bukin 	/* a8 = */ prefix_done,
71485f87cf4SRuslan Bukin 	/* a9 = */ prefix_done,
71585f87cf4SRuslan Bukin 	/* aa = */ prefix_done,
71685f87cf4SRuslan Bukin 	/* ab = */ prefix_done,
71785f87cf4SRuslan Bukin 	/* ac = */ prefix_done,
71885f87cf4SRuslan Bukin 	/* ad = */ prefix_done,
71985f87cf4SRuslan Bukin 	/* ae = */ prefix_done,
72085f87cf4SRuslan Bukin 	/* af = */ prefix_done,
72185f87cf4SRuslan Bukin 
72285f87cf4SRuslan Bukin 	/* b0 = */ prefix_done,
72385f87cf4SRuslan Bukin 	/* b1 = */ prefix_done,
72485f87cf4SRuslan Bukin 	/* b2 = */ prefix_done,
72585f87cf4SRuslan Bukin 	/* b3 = */ prefix_done,
72685f87cf4SRuslan Bukin 	/* b4 = */ prefix_done,
72785f87cf4SRuslan Bukin 	/* b5 = */ prefix_done,
72885f87cf4SRuslan Bukin 	/* b6 = */ prefix_done,
72985f87cf4SRuslan Bukin 	/* b7 = */ prefix_done,
73085f87cf4SRuslan Bukin 	/* b8 = */ prefix_done,
73185f87cf4SRuslan Bukin 	/* b9 = */ prefix_done,
73285f87cf4SRuslan Bukin 	/* ba = */ prefix_done,
73385f87cf4SRuslan Bukin 	/* bb = */ prefix_done,
73485f87cf4SRuslan Bukin 	/* bc = */ prefix_done,
73585f87cf4SRuslan Bukin 	/* bd = */ prefix_done,
73685f87cf4SRuslan Bukin 	/* be = */ prefix_done,
73785f87cf4SRuslan Bukin 	/* bf = */ prefix_done,
73885f87cf4SRuslan Bukin 
73985f87cf4SRuslan Bukin 	/* c0 = */ prefix_done,
74085f87cf4SRuslan Bukin 	/* c1 = */ prefix_done,
74185f87cf4SRuslan Bukin 	/* c2 = */ prefix_done,
74285f87cf4SRuslan Bukin 	/* c3 = */ prefix_done,
74385f87cf4SRuslan Bukin 	/* c4 = */ prefix_vex_c4,
74485f87cf4SRuslan Bukin 	/* c5 = */ prefix_vex_c5,
74585f87cf4SRuslan Bukin 	/* c6 = */ prefix_done,
74685f87cf4SRuslan Bukin 	/* c7 = */ prefix_done,
74785f87cf4SRuslan Bukin 	/* c8 = */ prefix_done,
74885f87cf4SRuslan Bukin 	/* c9 = */ prefix_done,
74985f87cf4SRuslan Bukin 	/* ca = */ prefix_done,
75085f87cf4SRuslan Bukin 	/* cb = */ prefix_done,
75185f87cf4SRuslan Bukin 	/* cc = */ prefix_done,
75285f87cf4SRuslan Bukin 	/* cd = */ prefix_done,
75385f87cf4SRuslan Bukin 	/* ce = */ prefix_done,
75485f87cf4SRuslan Bukin 	/* cf = */ prefix_done,
75585f87cf4SRuslan Bukin 
75685f87cf4SRuslan Bukin 	/* d0 = */ prefix_done,
75785f87cf4SRuslan Bukin 	/* d1 = */ prefix_done,
75885f87cf4SRuslan Bukin 	/* d2 = */ prefix_done,
75985f87cf4SRuslan Bukin 	/* d3 = */ prefix_done,
76085f87cf4SRuslan Bukin 	/* d4 = */ prefix_done,
76185f87cf4SRuslan Bukin 	/* d5 = */ prefix_done,
76285f87cf4SRuslan Bukin 	/* d6 = */ prefix_done,
76385f87cf4SRuslan Bukin 	/* d7 = */ prefix_done,
76485f87cf4SRuslan Bukin 	/* d8 = */ prefix_done,
76585f87cf4SRuslan Bukin 	/* d9 = */ prefix_done,
76685f87cf4SRuslan Bukin 	/* da = */ prefix_done,
76785f87cf4SRuslan Bukin 	/* db = */ prefix_done,
76885f87cf4SRuslan Bukin 	/* dc = */ prefix_done,
76985f87cf4SRuslan Bukin 	/* dd = */ prefix_done,
77085f87cf4SRuslan Bukin 	/* de = */ prefix_done,
77185f87cf4SRuslan Bukin 	/* df = */ prefix_done,
77285f87cf4SRuslan Bukin 
77385f87cf4SRuslan Bukin 	/* e0 = */ prefix_done,
77485f87cf4SRuslan Bukin 	/* e1 = */ prefix_done,
77585f87cf4SRuslan Bukin 	/* e2 = */ prefix_done,
77685f87cf4SRuslan Bukin 	/* e3 = */ prefix_done,
77785f87cf4SRuslan Bukin 	/* e4 = */ prefix_done,
77885f87cf4SRuslan Bukin 	/* e5 = */ prefix_done,
77985f87cf4SRuslan Bukin 	/* e6 = */ prefix_done,
78085f87cf4SRuslan Bukin 	/* e7 = */ prefix_done,
78185f87cf4SRuslan Bukin 	/* e8 = */ prefix_done,
78285f87cf4SRuslan Bukin 	/* e9 = */ prefix_done,
78385f87cf4SRuslan Bukin 	/* ea = */ prefix_done,
78485f87cf4SRuslan Bukin 	/* eb = */ prefix_done,
78585f87cf4SRuslan Bukin 	/* ec = */ prefix_done,
78685f87cf4SRuslan Bukin 	/* ed = */ prefix_done,
78785f87cf4SRuslan Bukin 	/* ee = */ prefix_done,
78885f87cf4SRuslan Bukin 	/* ef = */ prefix_done,
78985f87cf4SRuslan Bukin 
79085f87cf4SRuslan Bukin 	/* f0 = */ prefix_lock,
79185f87cf4SRuslan Bukin 	/* f1 = */ prefix_done,
79285f87cf4SRuslan Bukin 	/* f2 = */ prefix_f2,
79385f87cf4SRuslan Bukin 	/* f3 = */ prefix_f3,
79485f87cf4SRuslan Bukin 	/* f4 = */ prefix_done,
79585f87cf4SRuslan Bukin 	/* f5 = */ prefix_done,
79685f87cf4SRuslan Bukin 	/* f6 = */ prefix_done,
79785f87cf4SRuslan Bukin 	/* f7 = */ prefix_done,
79885f87cf4SRuslan Bukin 	/* f8 = */ prefix_done,
79985f87cf4SRuslan Bukin 	/* f9 = */ prefix_done,
80085f87cf4SRuslan Bukin 	/* fa = */ prefix_done,
80185f87cf4SRuslan Bukin 	/* fb = */ prefix_done,
80285f87cf4SRuslan Bukin 	/* fc = */ prefix_done,
80385f87cf4SRuslan Bukin 	/* fd = */ prefix_done,
80485f87cf4SRuslan Bukin 	/* fe = */ prefix_done,
80585f87cf4SRuslan Bukin 	/* ff = */ prefix_done
80685f87cf4SRuslan Bukin };
80774fe6c29SRuslan Bukin 
prefix_decode(struct pt_ild * ild,uint8_t length,uint8_t rex)80874fe6c29SRuslan Bukin static inline int prefix_decode(struct pt_ild *ild, uint8_t length, uint8_t rex)
80974fe6c29SRuslan Bukin {
81074fe6c29SRuslan Bukin 	uint8_t byte;
81174fe6c29SRuslan Bukin 
81274fe6c29SRuslan Bukin 	if (!ild)
81374fe6c29SRuslan Bukin 		return -pte_internal;
81474fe6c29SRuslan Bukin 
81574fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
81674fe6c29SRuslan Bukin 		return -pte_bad_insn;
81774fe6c29SRuslan Bukin 
81874fe6c29SRuslan Bukin 	byte = get_byte(ild, length);
81974fe6c29SRuslan Bukin 
82074fe6c29SRuslan Bukin 	return prefix_table[byte](ild, length, rex);
82174fe6c29SRuslan Bukin }
82274fe6c29SRuslan Bukin 
prefix_next(struct pt_ild * ild,uint8_t length,uint8_t rex)82374fe6c29SRuslan Bukin static inline int prefix_next(struct pt_ild *ild, uint8_t length, uint8_t rex)
82474fe6c29SRuslan Bukin {
82574fe6c29SRuslan Bukin 	return prefix_decode(ild, length + 1, rex);
82674fe6c29SRuslan Bukin }
82774fe6c29SRuslan Bukin 
prefix_osz(struct pt_ild * ild,uint8_t length,uint8_t rex)82874fe6c29SRuslan Bukin static int prefix_osz(struct pt_ild *ild, uint8_t length, uint8_t rex)
82974fe6c29SRuslan Bukin {
83074fe6c29SRuslan Bukin 	(void) rex;
83174fe6c29SRuslan Bukin 
83274fe6c29SRuslan Bukin 	if (!ild)
83374fe6c29SRuslan Bukin 		return -pte_internal;
83474fe6c29SRuslan Bukin 
83574fe6c29SRuslan Bukin 	ild->u.s.osz = 1;
83674fe6c29SRuslan Bukin 
83774fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
83874fe6c29SRuslan Bukin }
83974fe6c29SRuslan Bukin 
prefix_asz(struct pt_ild * ild,uint8_t length,uint8_t rex)84074fe6c29SRuslan Bukin static int prefix_asz(struct pt_ild *ild, uint8_t length, uint8_t rex)
84174fe6c29SRuslan Bukin {
84274fe6c29SRuslan Bukin 	(void) rex;
84374fe6c29SRuslan Bukin 
84474fe6c29SRuslan Bukin 	if (!ild)
84574fe6c29SRuslan Bukin 		return -pte_internal;
84674fe6c29SRuslan Bukin 
84774fe6c29SRuslan Bukin 	ild->u.s.asz = 1;
84874fe6c29SRuslan Bukin 
84974fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
85074fe6c29SRuslan Bukin }
85174fe6c29SRuslan Bukin 
prefix_lock(struct pt_ild * ild,uint8_t length,uint8_t rex)85274fe6c29SRuslan Bukin static int prefix_lock(struct pt_ild *ild, uint8_t length, uint8_t rex)
85374fe6c29SRuslan Bukin {
85474fe6c29SRuslan Bukin 	(void) rex;
85574fe6c29SRuslan Bukin 
85674fe6c29SRuslan Bukin 	if (!ild)
85774fe6c29SRuslan Bukin 		return -pte_internal;
85874fe6c29SRuslan Bukin 
85974fe6c29SRuslan Bukin 	ild->u.s.lock = 1;
86074fe6c29SRuslan Bukin 
86174fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
86274fe6c29SRuslan Bukin }
86374fe6c29SRuslan Bukin 
prefix_f2(struct pt_ild * ild,uint8_t length,uint8_t rex)86474fe6c29SRuslan Bukin static int prefix_f2(struct pt_ild *ild, uint8_t length, uint8_t rex)
86574fe6c29SRuslan Bukin {
86674fe6c29SRuslan Bukin 	(void) rex;
86774fe6c29SRuslan Bukin 
86874fe6c29SRuslan Bukin 	if (!ild)
86974fe6c29SRuslan Bukin 		return -pte_internal;
87074fe6c29SRuslan Bukin 
87174fe6c29SRuslan Bukin 	ild->u.s.f2 = 1;
87274fe6c29SRuslan Bukin 	ild->u.s.last_f2f3 = 2;
87374fe6c29SRuslan Bukin 
87474fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
87574fe6c29SRuslan Bukin }
87674fe6c29SRuslan Bukin 
prefix_f3(struct pt_ild * ild,uint8_t length,uint8_t rex)87774fe6c29SRuslan Bukin static int prefix_f3(struct pt_ild *ild, uint8_t length, uint8_t rex)
87874fe6c29SRuslan Bukin {
87974fe6c29SRuslan Bukin 	(void) rex;
88074fe6c29SRuslan Bukin 
88174fe6c29SRuslan Bukin 	if (!ild)
88274fe6c29SRuslan Bukin 		return -pte_internal;
88374fe6c29SRuslan Bukin 
88474fe6c29SRuslan Bukin 	ild->u.s.f3 = 1;
88574fe6c29SRuslan Bukin 	ild->u.s.last_f2f3 = 3;
88674fe6c29SRuslan Bukin 
88774fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
88874fe6c29SRuslan Bukin }
88974fe6c29SRuslan Bukin 
prefix_ignore(struct pt_ild * ild,uint8_t length,uint8_t rex)89074fe6c29SRuslan Bukin static int prefix_ignore(struct pt_ild *ild, uint8_t length, uint8_t rex)
89174fe6c29SRuslan Bukin {
89274fe6c29SRuslan Bukin 	(void) rex;
89374fe6c29SRuslan Bukin 
89474fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
89574fe6c29SRuslan Bukin }
89674fe6c29SRuslan Bukin 
prefix_done(struct pt_ild * ild,uint8_t length,uint8_t rex)89774fe6c29SRuslan Bukin static int prefix_done(struct pt_ild *ild, uint8_t length, uint8_t rex)
89874fe6c29SRuslan Bukin {
89974fe6c29SRuslan Bukin 	if (!ild)
90074fe6c29SRuslan Bukin 		return -pte_internal;
90174fe6c29SRuslan Bukin 
90274fe6c29SRuslan Bukin 	if (rex & 0x04)
90374fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
90474fe6c29SRuslan Bukin 	if (rex & 0x08)
90574fe6c29SRuslan Bukin 		ild->u.s.rex_w = 1;
90674fe6c29SRuslan Bukin 
90774fe6c29SRuslan Bukin 	return opcode_dec(ild, length);
90874fe6c29SRuslan Bukin }
90974fe6c29SRuslan Bukin 
prefix_rex(struct pt_ild * ild,uint8_t length,uint8_t rex)91074fe6c29SRuslan Bukin static int prefix_rex(struct pt_ild *ild, uint8_t length, uint8_t rex)
91174fe6c29SRuslan Bukin {
91274fe6c29SRuslan Bukin 	(void) rex;
91374fe6c29SRuslan Bukin 
91474fe6c29SRuslan Bukin 	if (!ild)
91574fe6c29SRuslan Bukin 		return -pte_internal;
91674fe6c29SRuslan Bukin 
91774fe6c29SRuslan Bukin 	if (mode_64b(ild))
91874fe6c29SRuslan Bukin 		return prefix_next(ild, length, get_byte(ild, length));
91974fe6c29SRuslan Bukin 	else
92074fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
92174fe6c29SRuslan Bukin }
92274fe6c29SRuslan Bukin 
prefix_vex_done(struct pt_ild * ild,uint8_t length)92374fe6c29SRuslan Bukin static inline int prefix_vex_done(struct pt_ild *ild, uint8_t length)
92474fe6c29SRuslan Bukin {
92574fe6c29SRuslan Bukin 	if (!ild)
92674fe6c29SRuslan Bukin 		return -pte_internal;
92774fe6c29SRuslan Bukin 
92874fe6c29SRuslan Bukin 	ild->nominal_opcode = get_byte(ild, length);
92974fe6c29SRuslan Bukin 
93074fe6c29SRuslan Bukin 	return modrm_dec(ild, length + 1);
93174fe6c29SRuslan Bukin }
93274fe6c29SRuslan Bukin 
prefix_vex_c5(struct pt_ild * ild,uint8_t length,uint8_t rex)93374fe6c29SRuslan Bukin static int prefix_vex_c5(struct pt_ild *ild, uint8_t length, uint8_t rex)
93474fe6c29SRuslan Bukin {
93574fe6c29SRuslan Bukin 	uint8_t max_bytes;
93674fe6c29SRuslan Bukin 	uint8_t p1;
93774fe6c29SRuslan Bukin 
93874fe6c29SRuslan Bukin 	(void) rex;
93974fe6c29SRuslan Bukin 
94074fe6c29SRuslan Bukin 	if (!ild)
94174fe6c29SRuslan Bukin 		return -pte_internal;
94274fe6c29SRuslan Bukin 
94374fe6c29SRuslan Bukin 	max_bytes = ild->max_bytes;
94474fe6c29SRuslan Bukin 
94574fe6c29SRuslan Bukin 	/* Read the next byte to validate that this is indeed VEX. */
94674fe6c29SRuslan Bukin 	if (max_bytes <= (length + 1))
94774fe6c29SRuslan Bukin 		return -pte_bad_insn;
94874fe6c29SRuslan Bukin 
94974fe6c29SRuslan Bukin 	p1 = get_byte(ild, length + 1);
95074fe6c29SRuslan Bukin 
95174fe6c29SRuslan Bukin 	/* If p1[7:6] is not 11b in non-64-bit mode, this is LDS, not VEX. */
95274fe6c29SRuslan Bukin 	if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
95374fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
95474fe6c29SRuslan Bukin 
95574fe6c29SRuslan Bukin 	/* We need at least 3 bytes
95674fe6c29SRuslan Bukin 	 * - 2 for the VEX prefix and payload and
95774fe6c29SRuslan Bukin 	 * - 1 for the opcode.
95874fe6c29SRuslan Bukin 	 */
95974fe6c29SRuslan Bukin 	if (max_bytes < (length + 3))
96074fe6c29SRuslan Bukin 		return -pte_bad_insn;
96174fe6c29SRuslan Bukin 
96274fe6c29SRuslan Bukin 	ild->u.s.vex = 1;
96374fe6c29SRuslan Bukin 	if (p1 & 0x80)
96474fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
96574fe6c29SRuslan Bukin 
96674fe6c29SRuslan Bukin 	ild->map = PTI_MAP_1;
96774fe6c29SRuslan Bukin 
96874fe6c29SRuslan Bukin 	/* Eat the VEX. */
96974fe6c29SRuslan Bukin 	length += 2;
97074fe6c29SRuslan Bukin 	return prefix_vex_done(ild, length);
97174fe6c29SRuslan Bukin }
97274fe6c29SRuslan Bukin 
prefix_vex_c4(struct pt_ild * ild,uint8_t length,uint8_t rex)97374fe6c29SRuslan Bukin static int prefix_vex_c4(struct pt_ild *ild, uint8_t length, uint8_t rex)
97474fe6c29SRuslan Bukin {
97574fe6c29SRuslan Bukin 	uint8_t max_bytes;
97674fe6c29SRuslan Bukin 	uint8_t p1, p2, map;
97774fe6c29SRuslan Bukin 
97874fe6c29SRuslan Bukin 	(void) rex;
97974fe6c29SRuslan Bukin 
98074fe6c29SRuslan Bukin 	if (!ild)
98174fe6c29SRuslan Bukin 		return -pte_internal;
98274fe6c29SRuslan Bukin 
98374fe6c29SRuslan Bukin 	max_bytes = ild->max_bytes;
98474fe6c29SRuslan Bukin 
98574fe6c29SRuslan Bukin 	/* Read the next byte to validate that this is indeed VEX. */
98674fe6c29SRuslan Bukin 	if (max_bytes <= (length + 1))
98774fe6c29SRuslan Bukin 		return -pte_bad_insn;
98874fe6c29SRuslan Bukin 
98974fe6c29SRuslan Bukin 	p1 = get_byte(ild, length + 1);
99074fe6c29SRuslan Bukin 
99174fe6c29SRuslan Bukin 	/* If p1[7:6] is not 11b in non-64-bit mode, this is LES, not VEX. */
99274fe6c29SRuslan Bukin 	if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
99374fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
99474fe6c29SRuslan Bukin 
99574fe6c29SRuslan Bukin 	/* We need at least 4 bytes
99674fe6c29SRuslan Bukin 	 * - 3 for the VEX prefix and payload and
99774fe6c29SRuslan Bukin 	 * - 1 for the opcode.
99874fe6c29SRuslan Bukin 	 */
99974fe6c29SRuslan Bukin 	if (max_bytes < (length + 4))
100074fe6c29SRuslan Bukin 		return -pte_bad_insn;
100174fe6c29SRuslan Bukin 
100274fe6c29SRuslan Bukin 	p2 = get_byte(ild, length + 2);
100374fe6c29SRuslan Bukin 
100474fe6c29SRuslan Bukin 	ild->u.s.vex = 1;
100574fe6c29SRuslan Bukin 	if (p1 & 0x80)
100674fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
100774fe6c29SRuslan Bukin 	if (p2 & 0x80)
100874fe6c29SRuslan Bukin 		ild->u.s.rex_w = 1;
100974fe6c29SRuslan Bukin 
101074fe6c29SRuslan Bukin 	map = p1 & 0x1f;
101174fe6c29SRuslan Bukin 	if (PTI_MAP_INVALID <= map)
101274fe6c29SRuslan Bukin 		return -pte_bad_insn;
101374fe6c29SRuslan Bukin 
101474fe6c29SRuslan Bukin 	ild->map = map;
101574fe6c29SRuslan Bukin 	if (map == PTI_MAP_3)
101674fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
101774fe6c29SRuslan Bukin 
101874fe6c29SRuslan Bukin 	/* Eat the VEX. */
101974fe6c29SRuslan Bukin 	length += 3;
102074fe6c29SRuslan Bukin 	return prefix_vex_done(ild, length);
102174fe6c29SRuslan Bukin }
102274fe6c29SRuslan Bukin 
prefix_evex(struct pt_ild * ild,uint8_t length,uint8_t rex)102374fe6c29SRuslan Bukin static int prefix_evex(struct pt_ild *ild, uint8_t length, uint8_t rex)
102474fe6c29SRuslan Bukin {
102574fe6c29SRuslan Bukin 	uint8_t max_bytes;
102674fe6c29SRuslan Bukin 	uint8_t p1, p2, map;
102774fe6c29SRuslan Bukin 
102874fe6c29SRuslan Bukin 	(void) rex;
102974fe6c29SRuslan Bukin 
103074fe6c29SRuslan Bukin 	if (!ild)
103174fe6c29SRuslan Bukin 		return -pte_internal;
103274fe6c29SRuslan Bukin 
103374fe6c29SRuslan Bukin 	max_bytes = ild->max_bytes;
103474fe6c29SRuslan Bukin 
103574fe6c29SRuslan Bukin 	/* Read the next byte to validate that this is indeed EVEX. */
103674fe6c29SRuslan Bukin 	if (max_bytes <= (length + 1))
103774fe6c29SRuslan Bukin 		return -pte_bad_insn;
103874fe6c29SRuslan Bukin 
103974fe6c29SRuslan Bukin 	p1 = get_byte(ild, length + 1);
104074fe6c29SRuslan Bukin 
104174fe6c29SRuslan Bukin 	/* If p1[7:6] is not 11b in non-64-bit mode, this is BOUND, not EVEX. */
104274fe6c29SRuslan Bukin 	if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
104374fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
104474fe6c29SRuslan Bukin 
104574fe6c29SRuslan Bukin 	/* We need at least 5 bytes
104674fe6c29SRuslan Bukin 	 * - 4 for the EVEX prefix and payload and
104774fe6c29SRuslan Bukin 	 * - 1 for the opcode.
104874fe6c29SRuslan Bukin 	 */
104974fe6c29SRuslan Bukin 	if (max_bytes < (length + 5))
105074fe6c29SRuslan Bukin 		return -pte_bad_insn;
105174fe6c29SRuslan Bukin 
105274fe6c29SRuslan Bukin 	p2 = get_byte(ild, length + 2);
105374fe6c29SRuslan Bukin 
105474fe6c29SRuslan Bukin 	ild->u.s.vex = 1;
105574fe6c29SRuslan Bukin 	if (p1 & 0x80)
105674fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
105774fe6c29SRuslan Bukin 	if (p2 & 0x80)
105874fe6c29SRuslan Bukin 		ild->u.s.rex_w = 1;
105974fe6c29SRuslan Bukin 
106074fe6c29SRuslan Bukin 	map = p1 & 0x03;
106174fe6c29SRuslan Bukin 	ild->map = map;
106274fe6c29SRuslan Bukin 
106374fe6c29SRuslan Bukin 	if (map == PTI_MAP_3)
106474fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
106574fe6c29SRuslan Bukin 
106674fe6c29SRuslan Bukin 	/* Eat the EVEX. */
106774fe6c29SRuslan Bukin 	length += 4;
106874fe6c29SRuslan Bukin 	return prefix_vex_done(ild, length);
106974fe6c29SRuslan Bukin }
107074fe6c29SRuslan Bukin 
decode(struct pt_ild * ild)107174fe6c29SRuslan Bukin static int decode(struct pt_ild *ild)
107274fe6c29SRuslan Bukin {
107374fe6c29SRuslan Bukin 	return prefix_decode(ild, 0, 0);
107474fe6c29SRuslan Bukin }
107574fe6c29SRuslan Bukin 
set_branch_target(struct pt_insn_ext * iext,const struct pt_ild * ild)107674fe6c29SRuslan Bukin static int set_branch_target(struct pt_insn_ext *iext, const struct pt_ild *ild)
107774fe6c29SRuslan Bukin {
107874fe6c29SRuslan Bukin 	if (!iext || !ild)
107974fe6c29SRuslan Bukin 		return -pte_internal;
108074fe6c29SRuslan Bukin 
108174fe6c29SRuslan Bukin 	iext->variant.branch.is_direct = 1;
108274fe6c29SRuslan Bukin 
108374fe6c29SRuslan Bukin 	if (ild->disp_bytes == 1) {
108474fe6c29SRuslan Bukin 		const int8_t *b = (const int8_t *)
108574fe6c29SRuslan Bukin 			get_byte_ptr(ild, ild->disp_pos);
108674fe6c29SRuslan Bukin 
108774fe6c29SRuslan Bukin 		iext->variant.branch.displacement = *b;
108874fe6c29SRuslan Bukin 	} else if (ild->disp_bytes == 2) {
108974fe6c29SRuslan Bukin 		const int16_t *w = (const int16_t *)
109074fe6c29SRuslan Bukin 			get_byte_ptr(ild, ild->disp_pos);
109174fe6c29SRuslan Bukin 
109274fe6c29SRuslan Bukin 		iext->variant.branch.displacement = *w;
109374fe6c29SRuslan Bukin 	} else if (ild->disp_bytes == 4) {
109474fe6c29SRuslan Bukin 		const int32_t *d = (const int32_t *)
109574fe6c29SRuslan Bukin 			get_byte_ptr(ild, ild->disp_pos);
109674fe6c29SRuslan Bukin 
109774fe6c29SRuslan Bukin 		iext->variant.branch.displacement = *d;
109874fe6c29SRuslan Bukin 	} else
109974fe6c29SRuslan Bukin 		return -pte_bad_insn;
110074fe6c29SRuslan Bukin 
110174fe6c29SRuslan Bukin 	return 0;
110274fe6c29SRuslan Bukin }
110374fe6c29SRuslan Bukin 
pt_instruction_length_decode(struct pt_ild * ild)110474fe6c29SRuslan Bukin static int pt_instruction_length_decode(struct pt_ild *ild)
110574fe6c29SRuslan Bukin {
110674fe6c29SRuslan Bukin 	if (!ild)
110774fe6c29SRuslan Bukin 		return -pte_internal;
110874fe6c29SRuslan Bukin 
110974fe6c29SRuslan Bukin 	ild->u.i = 0;
111074fe6c29SRuslan Bukin 	ild->imm1_bytes = 0;
111174fe6c29SRuslan Bukin 	ild->imm2_bytes = 0;
111274fe6c29SRuslan Bukin 	ild->disp_bytes = 0;
111374fe6c29SRuslan Bukin 	ild->modrm_byte = 0;
111474fe6c29SRuslan Bukin 	ild->map = PTI_MAP_INVALID;
111574fe6c29SRuslan Bukin 
111674fe6c29SRuslan Bukin 	if (!ild->mode)
111774fe6c29SRuslan Bukin 		return -pte_bad_insn;
111874fe6c29SRuslan Bukin 
111974fe6c29SRuslan Bukin 	return decode(ild);
112074fe6c29SRuslan Bukin }
112174fe6c29SRuslan Bukin 
pt_instruction_decode(struct pt_insn * insn,struct pt_insn_ext * iext,const struct pt_ild * ild)112274fe6c29SRuslan Bukin static int pt_instruction_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
112374fe6c29SRuslan Bukin 				 const struct pt_ild *ild)
112474fe6c29SRuslan Bukin {
112574fe6c29SRuslan Bukin 	uint8_t opcode, map;
112674fe6c29SRuslan Bukin 
112774fe6c29SRuslan Bukin 	if (!iext || !ild)
112874fe6c29SRuslan Bukin 		return -pte_internal;
112974fe6c29SRuslan Bukin 
113074fe6c29SRuslan Bukin 	iext->iclass = PTI_INST_INVALID;
113174fe6c29SRuslan Bukin 	memset(&iext->variant, 0, sizeof(iext->variant));
113274fe6c29SRuslan Bukin 
113374fe6c29SRuslan Bukin 	insn->iclass = ptic_other;
113474fe6c29SRuslan Bukin 
113574fe6c29SRuslan Bukin 	opcode = ild->nominal_opcode;
113674fe6c29SRuslan Bukin 	map = ild->map;
113774fe6c29SRuslan Bukin 
113874fe6c29SRuslan Bukin 	if (map > PTI_MAP_1)
113974fe6c29SRuslan Bukin 		return 0;	/* uninteresting */
114074fe6c29SRuslan Bukin 	if (ild->u.s.vex)
114174fe6c29SRuslan Bukin 		return 0;	/* uninteresting */
114274fe6c29SRuslan Bukin 
114374fe6c29SRuslan Bukin 	/* PTI_INST_JCC,   70...7F, 0F (0x80...0x8F) */
114474fe6c29SRuslan Bukin 	if (opcode >= 0x70 && opcode <= 0x7F) {
114574fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
114674fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
114774fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JCC;
114874fe6c29SRuslan Bukin 
114974fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
115074fe6c29SRuslan Bukin 		}
115174fe6c29SRuslan Bukin 		return 0;
115274fe6c29SRuslan Bukin 	}
115374fe6c29SRuslan Bukin 	if (opcode >= 0x80 && opcode <= 0x8F) {
115474fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
115574fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
115674fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JCC;
115774fe6c29SRuslan Bukin 
115874fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
115974fe6c29SRuslan Bukin 		}
116074fe6c29SRuslan Bukin 		return 0;
116174fe6c29SRuslan Bukin 	}
116274fe6c29SRuslan Bukin 
116374fe6c29SRuslan Bukin 	switch (ild->nominal_opcode) {
116474fe6c29SRuslan Bukin 	case 0x9A:
116574fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
116674fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
116774fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_CALL_9A;
116874fe6c29SRuslan Bukin 		}
116974fe6c29SRuslan Bukin 		return 0;
117074fe6c29SRuslan Bukin 
117174fe6c29SRuslan Bukin 	case 0xFF:
117274fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
117374fe6c29SRuslan Bukin 			uint8_t reg = pti_get_modrm_reg(ild);
117474fe6c29SRuslan Bukin 
117574fe6c29SRuslan Bukin 			if (reg == 2) {
117674fe6c29SRuslan Bukin 				insn->iclass = ptic_call;
117774fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_CALL_FFr2;
117874fe6c29SRuslan Bukin 			} else if (reg == 3) {
117974fe6c29SRuslan Bukin 				insn->iclass = ptic_far_call;
118074fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_CALL_FFr3;
118174fe6c29SRuslan Bukin 			} else if (reg == 4) {
118274fe6c29SRuslan Bukin 				insn->iclass = ptic_jump;
118374fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_JMP_FFr4;
118474fe6c29SRuslan Bukin 			} else if (reg == 5) {
118574fe6c29SRuslan Bukin 				insn->iclass = ptic_far_jump;
118674fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_JMP_FFr5;
118774fe6c29SRuslan Bukin 			}
118874fe6c29SRuslan Bukin 		}
118974fe6c29SRuslan Bukin 		return 0;
119074fe6c29SRuslan Bukin 
119174fe6c29SRuslan Bukin 	case 0xE8:
119274fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
119374fe6c29SRuslan Bukin 			insn->iclass = ptic_call;
119474fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_CALL_E8;
119574fe6c29SRuslan Bukin 
119674fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
119774fe6c29SRuslan Bukin 		}
119874fe6c29SRuslan Bukin 		return 0;
119974fe6c29SRuslan Bukin 
120074fe6c29SRuslan Bukin 	case 0xCD:
120174fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
120274fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
120374fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INT;
120474fe6c29SRuslan Bukin 		}
120574fe6c29SRuslan Bukin 
120674fe6c29SRuslan Bukin 		return 0;
120774fe6c29SRuslan Bukin 
120874fe6c29SRuslan Bukin 	case 0xCC:
120974fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
121074fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
121174fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INT3;
121274fe6c29SRuslan Bukin 		}
121374fe6c29SRuslan Bukin 
121474fe6c29SRuslan Bukin 		return 0;
121574fe6c29SRuslan Bukin 
121674fe6c29SRuslan Bukin 	case 0xCE:
121774fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
121874fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
121974fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INTO;
122074fe6c29SRuslan Bukin 		}
122174fe6c29SRuslan Bukin 
122274fe6c29SRuslan Bukin 		return 0;
122374fe6c29SRuslan Bukin 
122474fe6c29SRuslan Bukin 	case 0xF1:
122574fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
122674fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
122774fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INT1;
122874fe6c29SRuslan Bukin 		}
122974fe6c29SRuslan Bukin 
123074fe6c29SRuslan Bukin 		return 0;
123174fe6c29SRuslan Bukin 
123274fe6c29SRuslan Bukin 	case 0xCF:
123374fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
123474fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
123574fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_IRET;
123674fe6c29SRuslan Bukin 		}
123774fe6c29SRuslan Bukin 		return 0;
123874fe6c29SRuslan Bukin 
123974fe6c29SRuslan Bukin 	case 0xE9:
124074fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
124174fe6c29SRuslan Bukin 			insn->iclass = ptic_jump;
124274fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JMP_E9;
124374fe6c29SRuslan Bukin 
124474fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
124574fe6c29SRuslan Bukin 		}
124674fe6c29SRuslan Bukin 		return 0;
124774fe6c29SRuslan Bukin 
124874fe6c29SRuslan Bukin 	case 0xEA:
124974fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
125074fe6c29SRuslan Bukin 			/* Far jumps are treated as indirect jumps. */
125174fe6c29SRuslan Bukin 			insn->iclass = ptic_far_jump;
125274fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JMP_EA;
125374fe6c29SRuslan Bukin 		}
125474fe6c29SRuslan Bukin 		return 0;
125574fe6c29SRuslan Bukin 
125674fe6c29SRuslan Bukin 	case 0xEB:
125774fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
125874fe6c29SRuslan Bukin 			insn->iclass = ptic_jump;
125974fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JMP_EB;
126074fe6c29SRuslan Bukin 
126174fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
126274fe6c29SRuslan Bukin 		}
126374fe6c29SRuslan Bukin 		return 0;
126474fe6c29SRuslan Bukin 
126574fe6c29SRuslan Bukin 	case 0xE3:
126674fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
126774fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
126874fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JrCXZ;
126974fe6c29SRuslan Bukin 
127074fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
127174fe6c29SRuslan Bukin 		}
127274fe6c29SRuslan Bukin 		return 0;
127374fe6c29SRuslan Bukin 
127474fe6c29SRuslan Bukin 	case 0xE0:
127574fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
127674fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
127774fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_LOOPNE;
127874fe6c29SRuslan Bukin 
127974fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
128074fe6c29SRuslan Bukin 		}
128174fe6c29SRuslan Bukin 		return 0;
128274fe6c29SRuslan Bukin 
128374fe6c29SRuslan Bukin 	case 0xE1:
128474fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
128574fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
128674fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_LOOPE;
128774fe6c29SRuslan Bukin 
128874fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
128974fe6c29SRuslan Bukin 		}
129074fe6c29SRuslan Bukin 		return 0;
129174fe6c29SRuslan Bukin 
129274fe6c29SRuslan Bukin 	case 0xE2:
129374fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
129474fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
129574fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_LOOP;
129674fe6c29SRuslan Bukin 
129774fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
129874fe6c29SRuslan Bukin 		}
129974fe6c29SRuslan Bukin 		return 0;
130074fe6c29SRuslan Bukin 
130174fe6c29SRuslan Bukin 	case 0x22:
130274fe6c29SRuslan Bukin 		if (map == PTI_MAP_1)
130374fe6c29SRuslan Bukin 			if (pti_get_modrm_reg(ild) == 3)
130474fe6c29SRuslan Bukin 				if (!ild->u.s.rex_r)
130574fe6c29SRuslan Bukin 					iext->iclass = PTI_INST_MOV_CR3;
130674fe6c29SRuslan Bukin 
130774fe6c29SRuslan Bukin 		return 0;
130874fe6c29SRuslan Bukin 
130974fe6c29SRuslan Bukin 	case 0xC3:
131074fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
131174fe6c29SRuslan Bukin 			insn->iclass = ptic_return;
131274fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_C3;
131374fe6c29SRuslan Bukin 		}
131474fe6c29SRuslan Bukin 		return 0;
131574fe6c29SRuslan Bukin 
131674fe6c29SRuslan Bukin 	case 0xC2:
131774fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
131874fe6c29SRuslan Bukin 			insn->iclass = ptic_return;
131974fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_C2;
132074fe6c29SRuslan Bukin 		}
132174fe6c29SRuslan Bukin 		return 0;
132274fe6c29SRuslan Bukin 
132374fe6c29SRuslan Bukin 	case 0xCB:
132474fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
132574fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
132674fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_CB;
132774fe6c29SRuslan Bukin 		}
132874fe6c29SRuslan Bukin 		return 0;
132974fe6c29SRuslan Bukin 
133074fe6c29SRuslan Bukin 	case 0xCA:
133174fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
133274fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
133374fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_CA;
133474fe6c29SRuslan Bukin 		}
133574fe6c29SRuslan Bukin 		return 0;
133674fe6c29SRuslan Bukin 
133774fe6c29SRuslan Bukin 	case 0x05:
133874fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
133974fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
134074fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSCALL;
134174fe6c29SRuslan Bukin 		}
134274fe6c29SRuslan Bukin 		return 0;
134374fe6c29SRuslan Bukin 
134474fe6c29SRuslan Bukin 	case 0x34:
134574fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
134674fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
134774fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSENTER;
134874fe6c29SRuslan Bukin 		}
134974fe6c29SRuslan Bukin 		return 0;
135074fe6c29SRuslan Bukin 
135174fe6c29SRuslan Bukin 	case 0x35:
135274fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
135374fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
135474fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSEXIT;
135574fe6c29SRuslan Bukin 		}
135674fe6c29SRuslan Bukin 		return 0;
135774fe6c29SRuslan Bukin 
135874fe6c29SRuslan Bukin 	case 0x07:
135974fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
136074fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
136174fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSRET;
136274fe6c29SRuslan Bukin 		}
136374fe6c29SRuslan Bukin 		return 0;
136474fe6c29SRuslan Bukin 
136574fe6c29SRuslan Bukin 	case 0x01:
136674fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
136774fe6c29SRuslan Bukin 			switch (ild->modrm_byte) {
136874fe6c29SRuslan Bukin 			case 0xc1:
136974fe6c29SRuslan Bukin 				insn->iclass = ptic_far_call;
137074fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_VMCALL;
137174fe6c29SRuslan Bukin 				break;
137274fe6c29SRuslan Bukin 
137374fe6c29SRuslan Bukin 			case 0xc2:
137474fe6c29SRuslan Bukin 				insn->iclass = ptic_far_return;
137574fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_VMLAUNCH;
137674fe6c29SRuslan Bukin 				break;
137774fe6c29SRuslan Bukin 
137874fe6c29SRuslan Bukin 			case 0xc3:
137974fe6c29SRuslan Bukin 				insn->iclass = ptic_far_return;
138074fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_VMRESUME;
138174fe6c29SRuslan Bukin 				break;
138274fe6c29SRuslan Bukin 
138374fe6c29SRuslan Bukin 			default:
138474fe6c29SRuslan Bukin 				break;
138574fe6c29SRuslan Bukin 			}
138674fe6c29SRuslan Bukin 		}
138774fe6c29SRuslan Bukin 		return 0;
138874fe6c29SRuslan Bukin 
138974fe6c29SRuslan Bukin 	case 0xc7:
139074fe6c29SRuslan Bukin 		if (map == PTI_MAP_1 &&
139174fe6c29SRuslan Bukin 		    pti_get_modrm_mod(ild) != 3 &&
139274fe6c29SRuslan Bukin 		    pti_get_modrm_reg(ild) == 6)
139374fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_VMPTRLD;
139474fe6c29SRuslan Bukin 
139574fe6c29SRuslan Bukin 		return 0;
139674fe6c29SRuslan Bukin 
139774fe6c29SRuslan Bukin 	case 0xae:
139874fe6c29SRuslan Bukin 		if (map == PTI_MAP_1 && ild->u.s.f3 && !ild->u.s.osz &&
139974fe6c29SRuslan Bukin 		    pti_get_modrm_reg(ild) == 4) {
140074fe6c29SRuslan Bukin 			insn->iclass = ptic_ptwrite;
140174fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_PTWRITE;
140274fe6c29SRuslan Bukin 		}
140374fe6c29SRuslan Bukin 		return 0;
140474fe6c29SRuslan Bukin 
140574fe6c29SRuslan Bukin 	default:
140674fe6c29SRuslan Bukin 		return 0;
140774fe6c29SRuslan Bukin 	}
140874fe6c29SRuslan Bukin }
140974fe6c29SRuslan Bukin 
pt_ild_decode(struct pt_insn * insn,struct pt_insn_ext * iext)141074fe6c29SRuslan Bukin int pt_ild_decode(struct pt_insn *insn, struct pt_insn_ext *iext)
141174fe6c29SRuslan Bukin {
141274fe6c29SRuslan Bukin 	struct pt_ild ild;
141374fe6c29SRuslan Bukin 	int size;
141474fe6c29SRuslan Bukin 
141574fe6c29SRuslan Bukin 	if (!insn || !iext)
141674fe6c29SRuslan Bukin 		return -pte_internal;
141774fe6c29SRuslan Bukin 
141874fe6c29SRuslan Bukin 	ild.mode = insn->mode;
141974fe6c29SRuslan Bukin 	ild.itext = insn->raw;
142074fe6c29SRuslan Bukin 	ild.max_bytes = insn->size;
142174fe6c29SRuslan Bukin 
142274fe6c29SRuslan Bukin 	size = pt_instruction_length_decode(&ild);
142374fe6c29SRuslan Bukin 	if (size < 0)
142474fe6c29SRuslan Bukin 		return size;
142574fe6c29SRuslan Bukin 
142674fe6c29SRuslan Bukin 	insn->size = (uint8_t) size;
142774fe6c29SRuslan Bukin 
142874fe6c29SRuslan Bukin 	return pt_instruction_decode(insn, iext, &ild);
142974fe6c29SRuslan Bukin }
1430