xref: /freebsd/contrib/processor-trace/libipt/src/pt_ild.c (revision 74fe6c29fb7eef3418d7919dcd41dc1a04a982a1)
1*74fe6c29SRuslan Bukin /*
2*74fe6c29SRuslan Bukin  * Copyright (c) 2013-2018, Intel Corporation
3*74fe6c29SRuslan Bukin  *
4*74fe6c29SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
5*74fe6c29SRuslan Bukin  * modification, are permitted provided that the following conditions are met:
6*74fe6c29SRuslan Bukin  *
7*74fe6c29SRuslan Bukin  *  * Redistributions of source code must retain the above copyright notice,
8*74fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer.
9*74fe6c29SRuslan Bukin  *  * Redistributions in binary form must reproduce the above copyright notice,
10*74fe6c29SRuslan Bukin  *    this list of conditions and the following disclaimer in the documentation
11*74fe6c29SRuslan Bukin  *    and/or other materials provided with the distribution.
12*74fe6c29SRuslan Bukin  *  * Neither the name of Intel Corporation nor the names of its contributors
13*74fe6c29SRuslan Bukin  *    may be used to endorse or promote products derived from this software
14*74fe6c29SRuslan Bukin  *    without specific prior written permission.
15*74fe6c29SRuslan Bukin  *
16*74fe6c29SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*74fe6c29SRuslan Bukin  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*74fe6c29SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*74fe6c29SRuslan Bukin  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20*74fe6c29SRuslan Bukin  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*74fe6c29SRuslan Bukin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*74fe6c29SRuslan Bukin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*74fe6c29SRuslan Bukin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*74fe6c29SRuslan Bukin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*74fe6c29SRuslan Bukin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*74fe6c29SRuslan Bukin  * POSSIBILITY OF SUCH DAMAGE.
27*74fe6c29SRuslan Bukin  */
28*74fe6c29SRuslan Bukin 
29*74fe6c29SRuslan Bukin #include "pt_ild.h"
30*74fe6c29SRuslan Bukin #include "pti-imm-defs.h"
31*74fe6c29SRuslan Bukin #include "pti-imm.h"
32*74fe6c29SRuslan Bukin #include "pti-modrm-defs.h"
33*74fe6c29SRuslan Bukin #include "pti-modrm.h"
34*74fe6c29SRuslan Bukin #include "pti-disp-defs.h"
35*74fe6c29SRuslan Bukin #include "pti-disp.h"
36*74fe6c29SRuslan Bukin 
37*74fe6c29SRuslan Bukin #include <string.h>
38*74fe6c29SRuslan Bukin 
39*74fe6c29SRuslan Bukin /* SET UP 3 TABLES */
40*74fe6c29SRuslan Bukin 
41*74fe6c29SRuslan Bukin static uint8_t has_disp_regular[4][4][8];
42*74fe6c29SRuslan Bukin 
43*74fe6c29SRuslan Bukin static void init_has_disp_regular_table(void)
44*74fe6c29SRuslan Bukin {
45*74fe6c29SRuslan Bukin 	uint8_t mod, rm;
46*74fe6c29SRuslan Bukin 
47*74fe6c29SRuslan Bukin 	memset(has_disp_regular, 0, sizeof(has_disp_regular));
48*74fe6c29SRuslan Bukin 
49*74fe6c29SRuslan Bukin 	/*fill eamode16 */
50*74fe6c29SRuslan Bukin 	has_disp_regular[ptem_16bit][0][6] = 2;
51*74fe6c29SRuslan Bukin 	for (rm = 0; rm < 8; rm++)
52*74fe6c29SRuslan Bukin 		for (mod = 1; mod <= 2; mod++)
53*74fe6c29SRuslan Bukin 			has_disp_regular[ptem_16bit][mod][rm] = mod;
54*74fe6c29SRuslan Bukin 
55*74fe6c29SRuslan Bukin 	/*fill eamode32/64 */
56*74fe6c29SRuslan Bukin 	has_disp_regular[ptem_32bit][0][5] = 4;
57*74fe6c29SRuslan Bukin 	has_disp_regular[ptem_64bit][0][5] = 4;
58*74fe6c29SRuslan Bukin 	for (rm = 0; rm < 8; rm++) {
59*74fe6c29SRuslan Bukin 		has_disp_regular[ptem_32bit][1][rm] = 1;
60*74fe6c29SRuslan Bukin 		has_disp_regular[ptem_32bit][2][rm] = 4;
61*74fe6c29SRuslan Bukin 
62*74fe6c29SRuslan Bukin 		has_disp_regular[ptem_64bit][1][rm] = 1;
63*74fe6c29SRuslan Bukin 		has_disp_regular[ptem_64bit][2][rm] = 4;
64*74fe6c29SRuslan Bukin 	}
65*74fe6c29SRuslan Bukin }
66*74fe6c29SRuslan Bukin 
67*74fe6c29SRuslan Bukin static uint8_t eamode_table[2][4];
68*74fe6c29SRuslan Bukin 
69*74fe6c29SRuslan Bukin static void init_eamode_table(void)
70*74fe6c29SRuslan Bukin {
71*74fe6c29SRuslan Bukin 	eamode_table[0][ptem_unknown] = ptem_unknown;
72*74fe6c29SRuslan Bukin 	eamode_table[0][ptem_16bit] = ptem_16bit;
73*74fe6c29SRuslan Bukin 	eamode_table[0][ptem_32bit] = ptem_32bit;
74*74fe6c29SRuslan Bukin 	eamode_table[0][ptem_64bit] = ptem_64bit;
75*74fe6c29SRuslan Bukin 
76*74fe6c29SRuslan Bukin 	eamode_table[1][ptem_unknown] = ptem_unknown;
77*74fe6c29SRuslan Bukin 	eamode_table[1][ptem_16bit] = ptem_32bit;
78*74fe6c29SRuslan Bukin 	eamode_table[1][ptem_32bit] = ptem_16bit;
79*74fe6c29SRuslan Bukin 	eamode_table[1][ptem_64bit] = ptem_32bit;
80*74fe6c29SRuslan Bukin }
81*74fe6c29SRuslan Bukin 
82*74fe6c29SRuslan Bukin static uint8_t has_sib_table[4][4][8];
83*74fe6c29SRuslan Bukin 
84*74fe6c29SRuslan Bukin static void init_has_sib_table(void)
85*74fe6c29SRuslan Bukin {
86*74fe6c29SRuslan Bukin 	uint8_t mod;
87*74fe6c29SRuslan Bukin 
88*74fe6c29SRuslan Bukin 	memset(has_sib_table, 0, sizeof(has_sib_table));
89*74fe6c29SRuslan Bukin 
90*74fe6c29SRuslan Bukin 	/*for eamode32/64 there is sib byte for mod!=3 and rm==4 */
91*74fe6c29SRuslan Bukin 	for (mod = 0; mod <= 2; mod++) {
92*74fe6c29SRuslan Bukin 		has_sib_table[ptem_32bit][mod][4] = 1;
93*74fe6c29SRuslan Bukin 		has_sib_table[ptem_64bit][mod][4] = 1;
94*74fe6c29SRuslan Bukin 	}
95*74fe6c29SRuslan Bukin }
96*74fe6c29SRuslan Bukin 
97*74fe6c29SRuslan Bukin /* SOME ACCESSORS */
98*74fe6c29SRuslan Bukin 
99*74fe6c29SRuslan Bukin static inline uint8_t get_byte(const struct pt_ild *ild, uint8_t i)
100*74fe6c29SRuslan Bukin {
101*74fe6c29SRuslan Bukin 	return ild->itext[i];
102*74fe6c29SRuslan Bukin }
103*74fe6c29SRuslan Bukin 
104*74fe6c29SRuslan Bukin static inline uint8_t const *get_byte_ptr(const struct pt_ild *ild, uint8_t i)
105*74fe6c29SRuslan Bukin {
106*74fe6c29SRuslan Bukin 	return ild->itext + i;
107*74fe6c29SRuslan Bukin }
108*74fe6c29SRuslan Bukin 
109*74fe6c29SRuslan Bukin static inline int mode_64b(const struct pt_ild *ild)
110*74fe6c29SRuslan Bukin {
111*74fe6c29SRuslan Bukin 	return ild->mode == ptem_64bit;
112*74fe6c29SRuslan Bukin }
113*74fe6c29SRuslan Bukin 
114*74fe6c29SRuslan Bukin static inline int mode_32b(const struct pt_ild *ild)
115*74fe6c29SRuslan Bukin {
116*74fe6c29SRuslan Bukin 	return ild->mode == ptem_32bit;
117*74fe6c29SRuslan Bukin }
118*74fe6c29SRuslan Bukin 
119*74fe6c29SRuslan Bukin static inline int bits_match(uint8_t x, uint8_t mask, uint8_t target)
120*74fe6c29SRuslan Bukin {
121*74fe6c29SRuslan Bukin 	return (x & mask) == target;
122*74fe6c29SRuslan Bukin }
123*74fe6c29SRuslan Bukin 
124*74fe6c29SRuslan Bukin static inline enum pt_exec_mode
125*74fe6c29SRuslan Bukin pti_get_nominal_eosz_non64(const struct pt_ild *ild)
126*74fe6c29SRuslan Bukin {
127*74fe6c29SRuslan Bukin 	if (mode_32b(ild)) {
128*74fe6c29SRuslan Bukin 		if (ild->u.s.osz)
129*74fe6c29SRuslan Bukin 			return ptem_16bit;
130*74fe6c29SRuslan Bukin 		return ptem_32bit;
131*74fe6c29SRuslan Bukin 	}
132*74fe6c29SRuslan Bukin 	if (ild->u.s.osz)
133*74fe6c29SRuslan Bukin 		return ptem_32bit;
134*74fe6c29SRuslan Bukin 	return ptem_16bit;
135*74fe6c29SRuslan Bukin }
136*74fe6c29SRuslan Bukin 
137*74fe6c29SRuslan Bukin static inline enum pt_exec_mode
138*74fe6c29SRuslan Bukin pti_get_nominal_eosz(const struct pt_ild *ild)
139*74fe6c29SRuslan Bukin {
140*74fe6c29SRuslan Bukin 	if (mode_64b(ild)) {
141*74fe6c29SRuslan Bukin 		if (ild->u.s.rex_w)
142*74fe6c29SRuslan Bukin 			return ptem_64bit;
143*74fe6c29SRuslan Bukin 		if (ild->u.s.osz)
144*74fe6c29SRuslan Bukin 			return ptem_16bit;
145*74fe6c29SRuslan Bukin 		return ptem_32bit;
146*74fe6c29SRuslan Bukin 	}
147*74fe6c29SRuslan Bukin 	return pti_get_nominal_eosz_non64(ild);
148*74fe6c29SRuslan Bukin }
149*74fe6c29SRuslan Bukin 
150*74fe6c29SRuslan Bukin static inline enum pt_exec_mode
151*74fe6c29SRuslan Bukin pti_get_nominal_eosz_df64(const struct pt_ild *ild)
152*74fe6c29SRuslan Bukin {
153*74fe6c29SRuslan Bukin 	if (mode_64b(ild)) {
154*74fe6c29SRuslan Bukin 		if (ild->u.s.rex_w)
155*74fe6c29SRuslan Bukin 			return ptem_64bit;
156*74fe6c29SRuslan Bukin 		if (ild->u.s.osz)
157*74fe6c29SRuslan Bukin 			return ptem_16bit;
158*74fe6c29SRuslan Bukin 		/* only this next line of code is different relative
159*74fe6c29SRuslan Bukin 		   to pti_get_nominal_eosz(), above */
160*74fe6c29SRuslan Bukin 		return ptem_64bit;
161*74fe6c29SRuslan Bukin 	}
162*74fe6c29SRuslan Bukin 	return pti_get_nominal_eosz_non64(ild);
163*74fe6c29SRuslan Bukin }
164*74fe6c29SRuslan Bukin 
165*74fe6c29SRuslan Bukin static inline enum pt_exec_mode
166*74fe6c29SRuslan Bukin pti_get_nominal_easz_non64(const struct pt_ild *ild)
167*74fe6c29SRuslan Bukin {
168*74fe6c29SRuslan Bukin 	if (mode_32b(ild)) {
169*74fe6c29SRuslan Bukin 		if (ild->u.s.asz)
170*74fe6c29SRuslan Bukin 			return ptem_16bit;
171*74fe6c29SRuslan Bukin 		return ptem_32bit;
172*74fe6c29SRuslan Bukin 	}
173*74fe6c29SRuslan Bukin 	if (ild->u.s.asz)
174*74fe6c29SRuslan Bukin 		return ptem_32bit;
175*74fe6c29SRuslan Bukin 	return ptem_16bit;
176*74fe6c29SRuslan Bukin }
177*74fe6c29SRuslan Bukin 
178*74fe6c29SRuslan Bukin static inline enum pt_exec_mode
179*74fe6c29SRuslan Bukin pti_get_nominal_easz(const struct pt_ild *ild)
180*74fe6c29SRuslan Bukin {
181*74fe6c29SRuslan Bukin 	if (mode_64b(ild)) {
182*74fe6c29SRuslan Bukin 		if (ild->u.s.asz)
183*74fe6c29SRuslan Bukin 			return ptem_32bit;
184*74fe6c29SRuslan Bukin 		return ptem_64bit;
185*74fe6c29SRuslan Bukin 	}
186*74fe6c29SRuslan Bukin 	return pti_get_nominal_easz_non64(ild);
187*74fe6c29SRuslan Bukin }
188*74fe6c29SRuslan Bukin 
189*74fe6c29SRuslan Bukin static inline int resolve_z(uint8_t *pbytes, enum pt_exec_mode eosz)
190*74fe6c29SRuslan Bukin {
191*74fe6c29SRuslan Bukin 	static const uint8_t bytes[] = { 2, 4, 4 };
192*74fe6c29SRuslan Bukin 	unsigned int idx;
193*74fe6c29SRuslan Bukin 
194*74fe6c29SRuslan Bukin 	if (!pbytes)
195*74fe6c29SRuslan Bukin 		return -pte_internal;
196*74fe6c29SRuslan Bukin 
197*74fe6c29SRuslan Bukin 	idx = (unsigned int) eosz - 1;
198*74fe6c29SRuslan Bukin 	if (sizeof(bytes) <= idx)
199*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
200*74fe6c29SRuslan Bukin 
201*74fe6c29SRuslan Bukin 	*pbytes = bytes[idx];
202*74fe6c29SRuslan Bukin 	return 0;
203*74fe6c29SRuslan Bukin }
204*74fe6c29SRuslan Bukin 
205*74fe6c29SRuslan Bukin static inline int resolve_v(uint8_t *pbytes, enum pt_exec_mode eosz)
206*74fe6c29SRuslan Bukin {
207*74fe6c29SRuslan Bukin 	static const uint8_t bytes[] = { 2, 4, 8 };
208*74fe6c29SRuslan Bukin 	unsigned int idx;
209*74fe6c29SRuslan Bukin 
210*74fe6c29SRuslan Bukin 	if (!pbytes)
211*74fe6c29SRuslan Bukin 		return -pte_internal;
212*74fe6c29SRuslan Bukin 
213*74fe6c29SRuslan Bukin 	idx = (unsigned int) eosz - 1;
214*74fe6c29SRuslan Bukin 	if (sizeof(bytes) <= idx)
215*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
216*74fe6c29SRuslan Bukin 
217*74fe6c29SRuslan Bukin 	*pbytes = bytes[idx];
218*74fe6c29SRuslan Bukin 	return 0;
219*74fe6c29SRuslan Bukin }
220*74fe6c29SRuslan Bukin 
221*74fe6c29SRuslan Bukin /*  DECODERS */
222*74fe6c29SRuslan Bukin 
223*74fe6c29SRuslan Bukin static int set_imm_bytes(struct pt_ild *ild)
224*74fe6c29SRuslan Bukin {
225*74fe6c29SRuslan Bukin 	/*: set ild->imm1_bytes and  ild->imm2_bytes for maps 0/1 */
226*74fe6c29SRuslan Bukin 	static uint8_t const *const map_map[] = {
227*74fe6c29SRuslan Bukin 		/* map 0 */ imm_bytes_map_0x0,
228*74fe6c29SRuslan Bukin 		/* map 1 */ imm_bytes_map_0x0F
229*74fe6c29SRuslan Bukin 	};
230*74fe6c29SRuslan Bukin 	uint8_t map, imm_code;
231*74fe6c29SRuslan Bukin 
232*74fe6c29SRuslan Bukin 	if (!ild)
233*74fe6c29SRuslan Bukin 		return -pte_internal;
234*74fe6c29SRuslan Bukin 
235*74fe6c29SRuslan Bukin 	map = ild->map;
236*74fe6c29SRuslan Bukin 
237*74fe6c29SRuslan Bukin 	if ((sizeof(map_map) / sizeof(*map_map)) <= map)
238*74fe6c29SRuslan Bukin 		return 0;
239*74fe6c29SRuslan Bukin 
240*74fe6c29SRuslan Bukin 	imm_code = map_map[map][ild->nominal_opcode];
241*74fe6c29SRuslan Bukin 	switch (imm_code) {
242*74fe6c29SRuslan Bukin 	case PTI_IMM_NONE:
243*74fe6c29SRuslan Bukin 	case PTI_0_IMM_WIDTH_CONST_l2:
244*74fe6c29SRuslan Bukin 	default:
245*74fe6c29SRuslan Bukin 		return 0;
246*74fe6c29SRuslan Bukin 
247*74fe6c29SRuslan Bukin 	case PTI_UIMM8_IMM_WIDTH_CONST_l2:
248*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
249*74fe6c29SRuslan Bukin 		return 0;
250*74fe6c29SRuslan Bukin 
251*74fe6c29SRuslan Bukin 	case PTI_SIMM8_IMM_WIDTH_CONST_l2:
252*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
253*74fe6c29SRuslan Bukin 		return 0;
254*74fe6c29SRuslan Bukin 
255*74fe6c29SRuslan Bukin 	case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2:
256*74fe6c29SRuslan Bukin 		/* SIMMz(eosz) */
257*74fe6c29SRuslan Bukin 		return resolve_z(&ild->imm1_bytes, pti_get_nominal_eosz(ild));
258*74fe6c29SRuslan Bukin 
259*74fe6c29SRuslan Bukin 	case PTI_UIMMv_IMM_WIDTH_OSZ_NONTERM_EOSZ_l2:
260*74fe6c29SRuslan Bukin 		/* UIMMv(eosz) */
261*74fe6c29SRuslan Bukin 		return resolve_v(&ild->imm1_bytes, pti_get_nominal_eosz(ild));
262*74fe6c29SRuslan Bukin 
263*74fe6c29SRuslan Bukin 	case PTI_UIMM16_IMM_WIDTH_CONST_l2:
264*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 2;
265*74fe6c29SRuslan Bukin 		return 0;
266*74fe6c29SRuslan Bukin 
267*74fe6c29SRuslan Bukin 	case PTI_SIMMz_IMM_WIDTH_OSZ_NONTERM_DF64_EOSZ_l2:
268*74fe6c29SRuslan Bukin 		/* push defaults to eosz64 in 64b mode, then uses SIMMz */
269*74fe6c29SRuslan Bukin 		return resolve_z(&ild->imm1_bytes,
270*74fe6c29SRuslan Bukin 				 pti_get_nominal_eosz_df64(ild));
271*74fe6c29SRuslan Bukin 
272*74fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf7_l1:
273*74fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2) {
274*74fe6c29SRuslan Bukin 			return resolve_z(&ild->imm1_bytes,
275*74fe6c29SRuslan Bukin 					 pti_get_nominal_eosz(ild));
276*74fe6c29SRuslan Bukin 		}
277*74fe6c29SRuslan Bukin 		return 0;
278*74fe6c29SRuslan Bukin 
279*74fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xc7_l1:
280*74fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 0) {
281*74fe6c29SRuslan Bukin 			return resolve_z(&ild->imm1_bytes,
282*74fe6c29SRuslan Bukin 					 pti_get_nominal_eosz(ild));
283*74fe6c29SRuslan Bukin 		}
284*74fe6c29SRuslan Bukin 		return 0;
285*74fe6c29SRuslan Bukin 
286*74fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_IMM_WIDTH_map0x0_op0xf6_l1:
287*74fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) < 2)
288*74fe6c29SRuslan Bukin 			ild->imm1_bytes = 1;
289*74fe6c29SRuslan Bukin 
290*74fe6c29SRuslan Bukin 		return 0;
291*74fe6c29SRuslan Bukin 
292*74fe6c29SRuslan Bukin 	case PTI_IMM_hasimm_map0x0_op0xc8_l1:
293*74fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0) {
294*74fe6c29SRuslan Bukin 			/*enter -> imm1=2, imm2=1 */
295*74fe6c29SRuslan Bukin 			ild->imm1_bytes = 2;
296*74fe6c29SRuslan Bukin 			ild->imm2_bytes = 1;
297*74fe6c29SRuslan Bukin 		}
298*74fe6c29SRuslan Bukin 		return 0;
299*74fe6c29SRuslan Bukin 
300*74fe6c29SRuslan Bukin 	case PTI_IMM_hasimm_map0x0F_op0x78_l1:
301*74fe6c29SRuslan Bukin 		/* AMD SSE4a (insertq/extrq use  osz/f2) vs vmread
302*74fe6c29SRuslan Bukin 		 * (no prefixes)
303*74fe6c29SRuslan Bukin 		 */
304*74fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_1) {
305*74fe6c29SRuslan Bukin 			if (ild->u.s.osz || ild->u.s.last_f2f3 == 2) {
306*74fe6c29SRuslan Bukin 				ild->imm1_bytes = 1;
307*74fe6c29SRuslan Bukin 				ild->imm2_bytes = 1;
308*74fe6c29SRuslan Bukin 			}
309*74fe6c29SRuslan Bukin 		}
310*74fe6c29SRuslan Bukin 		return 0;
311*74fe6c29SRuslan Bukin 	}
312*74fe6c29SRuslan Bukin }
313*74fe6c29SRuslan Bukin 
314*74fe6c29SRuslan Bukin static int imm_dec(struct pt_ild *ild, uint8_t length)
315*74fe6c29SRuslan Bukin {
316*74fe6c29SRuslan Bukin 	int errcode;
317*74fe6c29SRuslan Bukin 
318*74fe6c29SRuslan Bukin 	if (!ild)
319*74fe6c29SRuslan Bukin 		return -pte_internal;
320*74fe6c29SRuslan Bukin 
321*74fe6c29SRuslan Bukin 	if (ild->map == PTI_MAP_AMD3DNOW) {
322*74fe6c29SRuslan Bukin 		if (ild->max_bytes <= length)
323*74fe6c29SRuslan Bukin 			return -pte_bad_insn;
324*74fe6c29SRuslan Bukin 
325*74fe6c29SRuslan Bukin 		ild->nominal_opcode = get_byte(ild, length);
326*74fe6c29SRuslan Bukin 		return length + 1;
327*74fe6c29SRuslan Bukin 	}
328*74fe6c29SRuslan Bukin 
329*74fe6c29SRuslan Bukin 	errcode = set_imm_bytes(ild);
330*74fe6c29SRuslan Bukin 	if (errcode < 0)
331*74fe6c29SRuslan Bukin 		return errcode;
332*74fe6c29SRuslan Bukin 
333*74fe6c29SRuslan Bukin 	length += ild->imm1_bytes;
334*74fe6c29SRuslan Bukin 	length += ild->imm2_bytes;
335*74fe6c29SRuslan Bukin 	if (ild->max_bytes < length)
336*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
337*74fe6c29SRuslan Bukin 
338*74fe6c29SRuslan Bukin 	return length;
339*74fe6c29SRuslan Bukin }
340*74fe6c29SRuslan Bukin 
341*74fe6c29SRuslan Bukin static int compute_disp_dec(struct pt_ild *ild)
342*74fe6c29SRuslan Bukin {
343*74fe6c29SRuslan Bukin 	/* set ild->disp_bytes for maps 0 and 1. */
344*74fe6c29SRuslan Bukin 	static uint8_t const *const map_map[] = {
345*74fe6c29SRuslan Bukin 		/* map 0 */ disp_bytes_map_0x0,
346*74fe6c29SRuslan Bukin 		/* map 1 */ disp_bytes_map_0x0F
347*74fe6c29SRuslan Bukin 	};
348*74fe6c29SRuslan Bukin 	uint8_t map, disp_kind;
349*74fe6c29SRuslan Bukin 
350*74fe6c29SRuslan Bukin 	if (!ild)
351*74fe6c29SRuslan Bukin 		return -pte_internal;
352*74fe6c29SRuslan Bukin 
353*74fe6c29SRuslan Bukin 	if (0 < ild->disp_bytes)
354*74fe6c29SRuslan Bukin 		return 0;
355*74fe6c29SRuslan Bukin 
356*74fe6c29SRuslan Bukin 	map = ild->map;
357*74fe6c29SRuslan Bukin 
358*74fe6c29SRuslan Bukin 	if ((sizeof(map_map) / sizeof(*map_map)) <= map)
359*74fe6c29SRuslan Bukin 		return 0;
360*74fe6c29SRuslan Bukin 
361*74fe6c29SRuslan Bukin 	disp_kind = map_map[map][ild->nominal_opcode];
362*74fe6c29SRuslan Bukin 	switch (disp_kind) {
363*74fe6c29SRuslan Bukin 	case PTI_DISP_NONE:
364*74fe6c29SRuslan Bukin 		ild->disp_bytes = 0;
365*74fe6c29SRuslan Bukin 		return 0;
366*74fe6c29SRuslan Bukin 
367*74fe6c29SRuslan Bukin 	case PTI_PRESERVE_DEFAULT:
368*74fe6c29SRuslan Bukin 		/* nothing to do */
369*74fe6c29SRuslan Bukin 		return 0;
370*74fe6c29SRuslan Bukin 
371*74fe6c29SRuslan Bukin 	case PTI_BRDISP8:
372*74fe6c29SRuslan Bukin 		ild->disp_bytes = 1;
373*74fe6c29SRuslan Bukin 		return 0;
374*74fe6c29SRuslan Bukin 
375*74fe6c29SRuslan Bukin 	case PTI_DISP_BUCKET_0_l1:
376*74fe6c29SRuslan Bukin 		/* BRDISPz(eosz) for 16/32 modes, and BRDISP32 for 64b mode */
377*74fe6c29SRuslan Bukin 		if (mode_64b(ild)) {
378*74fe6c29SRuslan Bukin 			ild->disp_bytes = 4;
379*74fe6c29SRuslan Bukin 			return 0;
380*74fe6c29SRuslan Bukin 		}
381*74fe6c29SRuslan Bukin 
382*74fe6c29SRuslan Bukin 		return resolve_z(&ild->disp_bytes,
383*74fe6c29SRuslan Bukin 				 pti_get_nominal_eosz(ild));
384*74fe6c29SRuslan Bukin 
385*74fe6c29SRuslan Bukin 	case PTI_MEMDISPv_DISP_WIDTH_ASZ_NONTERM_EASZ_l2:
386*74fe6c29SRuslan Bukin 		/* MEMDISPv(easz) */
387*74fe6c29SRuslan Bukin 		return resolve_v(&ild->disp_bytes, pti_get_nominal_easz(ild));
388*74fe6c29SRuslan Bukin 
389*74fe6c29SRuslan Bukin 	case PTI_BRDISPz_BRDISP_WIDTH_OSZ_NONTERM_EOSZ_l2:
390*74fe6c29SRuslan Bukin 		/* BRDISPz(eosz) for 16/32/64 modes */
391*74fe6c29SRuslan Bukin 		return resolve_z(&ild->disp_bytes, pti_get_nominal_eosz(ild));
392*74fe6c29SRuslan Bukin 
393*74fe6c29SRuslan Bukin 	case PTI_RESOLVE_BYREG_DISP_map0x0_op0xc7_l1:
394*74fe6c29SRuslan Bukin 		/* reg=0 -> preserve, reg=7 -> BRDISPz(eosz) */
395*74fe6c29SRuslan Bukin 		if (ild->map == PTI_MAP_0 && pti_get_modrm_reg(ild) == 7) {
396*74fe6c29SRuslan Bukin 			return resolve_z(&ild->disp_bytes,
397*74fe6c29SRuslan Bukin 					 pti_get_nominal_eosz(ild));
398*74fe6c29SRuslan Bukin 		}
399*74fe6c29SRuslan Bukin 		return 0;
400*74fe6c29SRuslan Bukin 
401*74fe6c29SRuslan Bukin 	default:
402*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
403*74fe6c29SRuslan Bukin 	}
404*74fe6c29SRuslan Bukin }
405*74fe6c29SRuslan Bukin 
406*74fe6c29SRuslan Bukin static int disp_dec(struct pt_ild *ild, uint8_t length)
407*74fe6c29SRuslan Bukin {
408*74fe6c29SRuslan Bukin 	uint8_t disp_bytes;
409*74fe6c29SRuslan Bukin 	int errcode;
410*74fe6c29SRuslan Bukin 
411*74fe6c29SRuslan Bukin 	if (!ild)
412*74fe6c29SRuslan Bukin 		return -pte_internal;
413*74fe6c29SRuslan Bukin 
414*74fe6c29SRuslan Bukin 	errcode = compute_disp_dec(ild);
415*74fe6c29SRuslan Bukin 	if (errcode < 0)
416*74fe6c29SRuslan Bukin 		return errcode;
417*74fe6c29SRuslan Bukin 
418*74fe6c29SRuslan Bukin 	disp_bytes = ild->disp_bytes;
419*74fe6c29SRuslan Bukin 	if (disp_bytes == 0)
420*74fe6c29SRuslan Bukin 		return imm_dec(ild, length);
421*74fe6c29SRuslan Bukin 
422*74fe6c29SRuslan Bukin 	if (length + disp_bytes > ild->max_bytes)
423*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
424*74fe6c29SRuslan Bukin 
425*74fe6c29SRuslan Bukin 	/*Record only position; must be able to re-read itext bytes for actual
426*74fe6c29SRuslan Bukin 	   value. (SMC/CMC issue). */
427*74fe6c29SRuslan Bukin 	ild->disp_pos = length;
428*74fe6c29SRuslan Bukin 
429*74fe6c29SRuslan Bukin 	return imm_dec(ild, length + disp_bytes);
430*74fe6c29SRuslan Bukin }
431*74fe6c29SRuslan Bukin 
432*74fe6c29SRuslan Bukin static int sib_dec(struct pt_ild *ild, uint8_t length)
433*74fe6c29SRuslan Bukin {
434*74fe6c29SRuslan Bukin 	uint8_t sib;
435*74fe6c29SRuslan Bukin 
436*74fe6c29SRuslan Bukin 	if (!ild)
437*74fe6c29SRuslan Bukin 		return -pte_internal;
438*74fe6c29SRuslan Bukin 
439*74fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
440*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
441*74fe6c29SRuslan Bukin 
442*74fe6c29SRuslan Bukin 	sib = get_byte(ild, length);
443*74fe6c29SRuslan Bukin 	if ((sib & 0x07) == 0x05 && pti_get_modrm_mod(ild) == 0)
444*74fe6c29SRuslan Bukin 		ild->disp_bytes = 4;
445*74fe6c29SRuslan Bukin 
446*74fe6c29SRuslan Bukin 	return disp_dec(ild, length + 1);
447*74fe6c29SRuslan Bukin }
448*74fe6c29SRuslan Bukin 
449*74fe6c29SRuslan Bukin static int modrm_dec(struct pt_ild *ild, uint8_t length)
450*74fe6c29SRuslan Bukin {
451*74fe6c29SRuslan Bukin 	static uint8_t const *const has_modrm_2d[2] = {
452*74fe6c29SRuslan Bukin 		has_modrm_map_0x0,
453*74fe6c29SRuslan Bukin 		has_modrm_map_0x0F
454*74fe6c29SRuslan Bukin 	};
455*74fe6c29SRuslan Bukin 	int has_modrm = PTI_MODRM_FALSE;
456*74fe6c29SRuslan Bukin 	pti_map_enum_t map;
457*74fe6c29SRuslan Bukin 
458*74fe6c29SRuslan Bukin 	if (!ild)
459*74fe6c29SRuslan Bukin 		return -pte_internal;
460*74fe6c29SRuslan Bukin 
461*74fe6c29SRuslan Bukin 	map = pti_get_map(ild);
462*74fe6c29SRuslan Bukin 	if (map >= PTI_MAP_2)
463*74fe6c29SRuslan Bukin 		has_modrm = PTI_MODRM_TRUE;
464*74fe6c29SRuslan Bukin 	else
465*74fe6c29SRuslan Bukin 		has_modrm = has_modrm_2d[map][ild->nominal_opcode];
466*74fe6c29SRuslan Bukin 
467*74fe6c29SRuslan Bukin 	if (has_modrm == PTI_MODRM_FALSE || has_modrm == PTI_MODRM_UNDEF)
468*74fe6c29SRuslan Bukin 		return disp_dec(ild, length);
469*74fe6c29SRuslan Bukin 
470*74fe6c29SRuslan Bukin 	/* really >= here because we have not eaten the byte yet */
471*74fe6c29SRuslan Bukin 	if (length >= ild->max_bytes)
472*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
473*74fe6c29SRuslan Bukin 
474*74fe6c29SRuslan Bukin 	ild->modrm_byte = get_byte(ild, length);
475*74fe6c29SRuslan Bukin 
476*74fe6c29SRuslan Bukin 	if (has_modrm != PTI_MODRM_IGNORE_MOD) {
477*74fe6c29SRuslan Bukin 		/* set disp_bytes and sib using simple tables */
478*74fe6c29SRuslan Bukin 
479*74fe6c29SRuslan Bukin 		uint8_t eamode = eamode_table[ild->u.s.asz][ild->mode];
480*74fe6c29SRuslan Bukin 		uint8_t mod = (uint8_t) pti_get_modrm_mod(ild);
481*74fe6c29SRuslan Bukin 		uint8_t rm = (uint8_t) pti_get_modrm_rm(ild);
482*74fe6c29SRuslan Bukin 		uint8_t has_sib;
483*74fe6c29SRuslan Bukin 
484*74fe6c29SRuslan Bukin 		ild->disp_bytes = has_disp_regular[eamode][mod][rm];
485*74fe6c29SRuslan Bukin 
486*74fe6c29SRuslan Bukin 		has_sib = has_sib_table[eamode][mod][rm];
487*74fe6c29SRuslan Bukin 		if (has_sib)
488*74fe6c29SRuslan Bukin 			return sib_dec(ild, length + 1);
489*74fe6c29SRuslan Bukin 	}
490*74fe6c29SRuslan Bukin 
491*74fe6c29SRuslan Bukin 	return disp_dec(ild, length + 1);
492*74fe6c29SRuslan Bukin }
493*74fe6c29SRuslan Bukin 
494*74fe6c29SRuslan Bukin static inline int get_next_as_opcode(struct pt_ild *ild, uint8_t length)
495*74fe6c29SRuslan Bukin {
496*74fe6c29SRuslan Bukin 	if (!ild)
497*74fe6c29SRuslan Bukin 		return -pte_internal;
498*74fe6c29SRuslan Bukin 
499*74fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
500*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
501*74fe6c29SRuslan Bukin 
502*74fe6c29SRuslan Bukin 	ild->nominal_opcode = get_byte(ild, length);
503*74fe6c29SRuslan Bukin 
504*74fe6c29SRuslan Bukin 	return modrm_dec(ild, length + 1);
505*74fe6c29SRuslan Bukin }
506*74fe6c29SRuslan Bukin 
507*74fe6c29SRuslan Bukin static int opcode_dec(struct pt_ild *ild, uint8_t length)
508*74fe6c29SRuslan Bukin {
509*74fe6c29SRuslan Bukin 	uint8_t b, m;
510*74fe6c29SRuslan Bukin 
511*74fe6c29SRuslan Bukin 	if (!ild)
512*74fe6c29SRuslan Bukin 		return -pte_internal;
513*74fe6c29SRuslan Bukin 
514*74fe6c29SRuslan Bukin 	/*no need to check max_bytes - it was checked in previous scanners */
515*74fe6c29SRuslan Bukin 	b = get_byte(ild, length);
516*74fe6c29SRuslan Bukin 	if (b != 0x0F) {	/* 1B opcodes, map 0 */
517*74fe6c29SRuslan Bukin 		ild->map = PTI_MAP_0;
518*74fe6c29SRuslan Bukin 		ild->nominal_opcode = b;
519*74fe6c29SRuslan Bukin 
520*74fe6c29SRuslan Bukin 		return modrm_dec(ild, length + 1);
521*74fe6c29SRuslan Bukin 	}
522*74fe6c29SRuslan Bukin 
523*74fe6c29SRuslan Bukin 	length++;		/* eat the 0x0F */
524*74fe6c29SRuslan Bukin 
525*74fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
526*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
527*74fe6c29SRuslan Bukin 
528*74fe6c29SRuslan Bukin 	/* 0x0F opcodes MAPS 1,2,3 */
529*74fe6c29SRuslan Bukin 	m = get_byte(ild, length);
530*74fe6c29SRuslan Bukin 	if (m == 0x38) {
531*74fe6c29SRuslan Bukin 		ild->map = PTI_MAP_2;
532*74fe6c29SRuslan Bukin 
533*74fe6c29SRuslan Bukin 		return get_next_as_opcode(ild, length + 1);
534*74fe6c29SRuslan Bukin 	} else if (m == 0x3A) {
535*74fe6c29SRuslan Bukin 		ild->map = PTI_MAP_3;
536*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
537*74fe6c29SRuslan Bukin 
538*74fe6c29SRuslan Bukin 		return get_next_as_opcode(ild, length + 1);
539*74fe6c29SRuslan Bukin 	} else if (bits_match(m, 0xf8, 0x38)) {
540*74fe6c29SRuslan Bukin 		ild->map = PTI_MAP_INVALID;
541*74fe6c29SRuslan Bukin 
542*74fe6c29SRuslan Bukin 		return get_next_as_opcode(ild, length + 1);
543*74fe6c29SRuslan Bukin 	} else if (m == 0x0F) {	/* 3dNow */
544*74fe6c29SRuslan Bukin 		ild->map = PTI_MAP_AMD3DNOW;
545*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
546*74fe6c29SRuslan Bukin 		/* real opcode is in immediate later on, but we need an
547*74fe6c29SRuslan Bukin 		 * opcode now. */
548*74fe6c29SRuslan Bukin 		ild->nominal_opcode = 0x0F;
549*74fe6c29SRuslan Bukin 
550*74fe6c29SRuslan Bukin 		return modrm_dec(ild, length + 1);
551*74fe6c29SRuslan Bukin 	} else {	/* map 1 (simple two byte opcodes) */
552*74fe6c29SRuslan Bukin 		ild->nominal_opcode = m;
553*74fe6c29SRuslan Bukin 		ild->map = PTI_MAP_1;
554*74fe6c29SRuslan Bukin 
555*74fe6c29SRuslan Bukin 		return modrm_dec(ild, length + 1);
556*74fe6c29SRuslan Bukin 	}
557*74fe6c29SRuslan Bukin }
558*74fe6c29SRuslan Bukin 
559*74fe6c29SRuslan Bukin typedef int (*prefix_decoder)(struct pt_ild *ild, uint8_t length, uint8_t rex);
560*74fe6c29SRuslan Bukin static prefix_decoder prefix_table[256];
561*74fe6c29SRuslan Bukin 
562*74fe6c29SRuslan Bukin static inline int prefix_decode(struct pt_ild *ild, uint8_t length, uint8_t rex)
563*74fe6c29SRuslan Bukin {
564*74fe6c29SRuslan Bukin 	uint8_t byte;
565*74fe6c29SRuslan Bukin 
566*74fe6c29SRuslan Bukin 	if (!ild)
567*74fe6c29SRuslan Bukin 		return -pte_internal;
568*74fe6c29SRuslan Bukin 
569*74fe6c29SRuslan Bukin 	if (ild->max_bytes <= length)
570*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
571*74fe6c29SRuslan Bukin 
572*74fe6c29SRuslan Bukin 	byte = get_byte(ild, length);
573*74fe6c29SRuslan Bukin 
574*74fe6c29SRuslan Bukin 	return prefix_table[byte](ild, length, rex);
575*74fe6c29SRuslan Bukin }
576*74fe6c29SRuslan Bukin 
577*74fe6c29SRuslan Bukin static inline int prefix_next(struct pt_ild *ild, uint8_t length, uint8_t rex)
578*74fe6c29SRuslan Bukin {
579*74fe6c29SRuslan Bukin 	return prefix_decode(ild, length + 1, rex);
580*74fe6c29SRuslan Bukin }
581*74fe6c29SRuslan Bukin 
582*74fe6c29SRuslan Bukin static int prefix_osz(struct pt_ild *ild, uint8_t length, uint8_t rex)
583*74fe6c29SRuslan Bukin {
584*74fe6c29SRuslan Bukin 	(void) rex;
585*74fe6c29SRuslan Bukin 
586*74fe6c29SRuslan Bukin 	if (!ild)
587*74fe6c29SRuslan Bukin 		return -pte_internal;
588*74fe6c29SRuslan Bukin 
589*74fe6c29SRuslan Bukin 	ild->u.s.osz = 1;
590*74fe6c29SRuslan Bukin 
591*74fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
592*74fe6c29SRuslan Bukin }
593*74fe6c29SRuslan Bukin 
594*74fe6c29SRuslan Bukin static int prefix_asz(struct pt_ild *ild, uint8_t length, uint8_t rex)
595*74fe6c29SRuslan Bukin {
596*74fe6c29SRuslan Bukin 	(void) rex;
597*74fe6c29SRuslan Bukin 
598*74fe6c29SRuslan Bukin 	if (!ild)
599*74fe6c29SRuslan Bukin 		return -pte_internal;
600*74fe6c29SRuslan Bukin 
601*74fe6c29SRuslan Bukin 	ild->u.s.asz = 1;
602*74fe6c29SRuslan Bukin 
603*74fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
604*74fe6c29SRuslan Bukin }
605*74fe6c29SRuslan Bukin 
606*74fe6c29SRuslan Bukin static int prefix_lock(struct pt_ild *ild, uint8_t length, uint8_t rex)
607*74fe6c29SRuslan Bukin {
608*74fe6c29SRuslan Bukin 	(void) rex;
609*74fe6c29SRuslan Bukin 
610*74fe6c29SRuslan Bukin 	if (!ild)
611*74fe6c29SRuslan Bukin 		return -pte_internal;
612*74fe6c29SRuslan Bukin 
613*74fe6c29SRuslan Bukin 	ild->u.s.lock = 1;
614*74fe6c29SRuslan Bukin 
615*74fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
616*74fe6c29SRuslan Bukin }
617*74fe6c29SRuslan Bukin 
618*74fe6c29SRuslan Bukin static int prefix_f2(struct pt_ild *ild, uint8_t length, uint8_t rex)
619*74fe6c29SRuslan Bukin {
620*74fe6c29SRuslan Bukin 	(void) rex;
621*74fe6c29SRuslan Bukin 
622*74fe6c29SRuslan Bukin 	if (!ild)
623*74fe6c29SRuslan Bukin 		return -pte_internal;
624*74fe6c29SRuslan Bukin 
625*74fe6c29SRuslan Bukin 	ild->u.s.f2 = 1;
626*74fe6c29SRuslan Bukin 	ild->u.s.last_f2f3 = 2;
627*74fe6c29SRuslan Bukin 
628*74fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
629*74fe6c29SRuslan Bukin }
630*74fe6c29SRuslan Bukin 
631*74fe6c29SRuslan Bukin static int prefix_f3(struct pt_ild *ild, uint8_t length, uint8_t rex)
632*74fe6c29SRuslan Bukin {
633*74fe6c29SRuslan Bukin 	(void) rex;
634*74fe6c29SRuslan Bukin 
635*74fe6c29SRuslan Bukin 	if (!ild)
636*74fe6c29SRuslan Bukin 		return -pte_internal;
637*74fe6c29SRuslan Bukin 
638*74fe6c29SRuslan Bukin 	ild->u.s.f3 = 1;
639*74fe6c29SRuslan Bukin 	ild->u.s.last_f2f3 = 3;
640*74fe6c29SRuslan Bukin 
641*74fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
642*74fe6c29SRuslan Bukin }
643*74fe6c29SRuslan Bukin 
644*74fe6c29SRuslan Bukin static int prefix_ignore(struct pt_ild *ild, uint8_t length, uint8_t rex)
645*74fe6c29SRuslan Bukin {
646*74fe6c29SRuslan Bukin 	(void) rex;
647*74fe6c29SRuslan Bukin 
648*74fe6c29SRuslan Bukin 	return prefix_next(ild, length, 0);
649*74fe6c29SRuslan Bukin }
650*74fe6c29SRuslan Bukin 
651*74fe6c29SRuslan Bukin static int prefix_done(struct pt_ild *ild, uint8_t length, uint8_t rex)
652*74fe6c29SRuslan Bukin {
653*74fe6c29SRuslan Bukin 	if (!ild)
654*74fe6c29SRuslan Bukin 		return -pte_internal;
655*74fe6c29SRuslan Bukin 
656*74fe6c29SRuslan Bukin 	if (rex & 0x04)
657*74fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
658*74fe6c29SRuslan Bukin 	if (rex & 0x08)
659*74fe6c29SRuslan Bukin 		ild->u.s.rex_w = 1;
660*74fe6c29SRuslan Bukin 
661*74fe6c29SRuslan Bukin 	return opcode_dec(ild, length);
662*74fe6c29SRuslan Bukin }
663*74fe6c29SRuslan Bukin 
664*74fe6c29SRuslan Bukin static int prefix_rex(struct pt_ild *ild, uint8_t length, uint8_t rex)
665*74fe6c29SRuslan Bukin {
666*74fe6c29SRuslan Bukin 	(void) rex;
667*74fe6c29SRuslan Bukin 
668*74fe6c29SRuslan Bukin 	if (!ild)
669*74fe6c29SRuslan Bukin 		return -pte_internal;
670*74fe6c29SRuslan Bukin 
671*74fe6c29SRuslan Bukin 	if (mode_64b(ild))
672*74fe6c29SRuslan Bukin 		return prefix_next(ild, length, get_byte(ild, length));
673*74fe6c29SRuslan Bukin 	else
674*74fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
675*74fe6c29SRuslan Bukin }
676*74fe6c29SRuslan Bukin 
677*74fe6c29SRuslan Bukin static inline int prefix_vex_done(struct pt_ild *ild, uint8_t length)
678*74fe6c29SRuslan Bukin {
679*74fe6c29SRuslan Bukin 	if (!ild)
680*74fe6c29SRuslan Bukin 		return -pte_internal;
681*74fe6c29SRuslan Bukin 
682*74fe6c29SRuslan Bukin 	ild->nominal_opcode = get_byte(ild, length);
683*74fe6c29SRuslan Bukin 
684*74fe6c29SRuslan Bukin 	return modrm_dec(ild, length + 1);
685*74fe6c29SRuslan Bukin }
686*74fe6c29SRuslan Bukin 
687*74fe6c29SRuslan Bukin static int prefix_vex_c5(struct pt_ild *ild, uint8_t length, uint8_t rex)
688*74fe6c29SRuslan Bukin {
689*74fe6c29SRuslan Bukin 	uint8_t max_bytes;
690*74fe6c29SRuslan Bukin 	uint8_t p1;
691*74fe6c29SRuslan Bukin 
692*74fe6c29SRuslan Bukin 	(void) rex;
693*74fe6c29SRuslan Bukin 
694*74fe6c29SRuslan Bukin 	if (!ild)
695*74fe6c29SRuslan Bukin 		return -pte_internal;
696*74fe6c29SRuslan Bukin 
697*74fe6c29SRuslan Bukin 	max_bytes = ild->max_bytes;
698*74fe6c29SRuslan Bukin 
699*74fe6c29SRuslan Bukin 	/* Read the next byte to validate that this is indeed VEX. */
700*74fe6c29SRuslan Bukin 	if (max_bytes <= (length + 1))
701*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
702*74fe6c29SRuslan Bukin 
703*74fe6c29SRuslan Bukin 	p1 = get_byte(ild, length + 1);
704*74fe6c29SRuslan Bukin 
705*74fe6c29SRuslan Bukin 	/* If p1[7:6] is not 11b in non-64-bit mode, this is LDS, not VEX. */
706*74fe6c29SRuslan Bukin 	if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
707*74fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
708*74fe6c29SRuslan Bukin 
709*74fe6c29SRuslan Bukin 	/* We need at least 3 bytes
710*74fe6c29SRuslan Bukin 	 * - 2 for the VEX prefix and payload and
711*74fe6c29SRuslan Bukin 	 * - 1 for the opcode.
712*74fe6c29SRuslan Bukin 	 */
713*74fe6c29SRuslan Bukin 	if (max_bytes < (length + 3))
714*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
715*74fe6c29SRuslan Bukin 
716*74fe6c29SRuslan Bukin 	ild->u.s.vex = 1;
717*74fe6c29SRuslan Bukin 	if (p1 & 0x80)
718*74fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
719*74fe6c29SRuslan Bukin 
720*74fe6c29SRuslan Bukin 	ild->map = PTI_MAP_1;
721*74fe6c29SRuslan Bukin 
722*74fe6c29SRuslan Bukin 	/* Eat the VEX. */
723*74fe6c29SRuslan Bukin 	length += 2;
724*74fe6c29SRuslan Bukin 	return prefix_vex_done(ild, length);
725*74fe6c29SRuslan Bukin }
726*74fe6c29SRuslan Bukin 
727*74fe6c29SRuslan Bukin static int prefix_vex_c4(struct pt_ild *ild, uint8_t length, uint8_t rex)
728*74fe6c29SRuslan Bukin {
729*74fe6c29SRuslan Bukin 	uint8_t max_bytes;
730*74fe6c29SRuslan Bukin 	uint8_t p1, p2, map;
731*74fe6c29SRuslan Bukin 
732*74fe6c29SRuslan Bukin 	(void) rex;
733*74fe6c29SRuslan Bukin 
734*74fe6c29SRuslan Bukin 	if (!ild)
735*74fe6c29SRuslan Bukin 		return -pte_internal;
736*74fe6c29SRuslan Bukin 
737*74fe6c29SRuslan Bukin 	max_bytes = ild->max_bytes;
738*74fe6c29SRuslan Bukin 
739*74fe6c29SRuslan Bukin 	/* Read the next byte to validate that this is indeed VEX. */
740*74fe6c29SRuslan Bukin 	if (max_bytes <= (length + 1))
741*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
742*74fe6c29SRuslan Bukin 
743*74fe6c29SRuslan Bukin 	p1 = get_byte(ild, length + 1);
744*74fe6c29SRuslan Bukin 
745*74fe6c29SRuslan Bukin 	/* If p1[7:6] is not 11b in non-64-bit mode, this is LES, not VEX. */
746*74fe6c29SRuslan Bukin 	if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
747*74fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
748*74fe6c29SRuslan Bukin 
749*74fe6c29SRuslan Bukin 	/* We need at least 4 bytes
750*74fe6c29SRuslan Bukin 	 * - 3 for the VEX prefix and payload and
751*74fe6c29SRuslan Bukin 	 * - 1 for the opcode.
752*74fe6c29SRuslan Bukin 	 */
753*74fe6c29SRuslan Bukin 	if (max_bytes < (length + 4))
754*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
755*74fe6c29SRuslan Bukin 
756*74fe6c29SRuslan Bukin 	p2 = get_byte(ild, length + 2);
757*74fe6c29SRuslan Bukin 
758*74fe6c29SRuslan Bukin 	ild->u.s.vex = 1;
759*74fe6c29SRuslan Bukin 	if (p1 & 0x80)
760*74fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
761*74fe6c29SRuslan Bukin 	if (p2 & 0x80)
762*74fe6c29SRuslan Bukin 		ild->u.s.rex_w = 1;
763*74fe6c29SRuslan Bukin 
764*74fe6c29SRuslan Bukin 	map = p1 & 0x1f;
765*74fe6c29SRuslan Bukin 	if (PTI_MAP_INVALID <= map)
766*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
767*74fe6c29SRuslan Bukin 
768*74fe6c29SRuslan Bukin 	ild->map = map;
769*74fe6c29SRuslan Bukin 	if (map == PTI_MAP_3)
770*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
771*74fe6c29SRuslan Bukin 
772*74fe6c29SRuslan Bukin 	/* Eat the VEX. */
773*74fe6c29SRuslan Bukin 	length += 3;
774*74fe6c29SRuslan Bukin 	return prefix_vex_done(ild, length);
775*74fe6c29SRuslan Bukin }
776*74fe6c29SRuslan Bukin 
777*74fe6c29SRuslan Bukin static int prefix_evex(struct pt_ild *ild, uint8_t length, uint8_t rex)
778*74fe6c29SRuslan Bukin {
779*74fe6c29SRuslan Bukin 	uint8_t max_bytes;
780*74fe6c29SRuslan Bukin 	uint8_t p1, p2, map;
781*74fe6c29SRuslan Bukin 
782*74fe6c29SRuslan Bukin 	(void) rex;
783*74fe6c29SRuslan Bukin 
784*74fe6c29SRuslan Bukin 	if (!ild)
785*74fe6c29SRuslan Bukin 		return -pte_internal;
786*74fe6c29SRuslan Bukin 
787*74fe6c29SRuslan Bukin 	max_bytes = ild->max_bytes;
788*74fe6c29SRuslan Bukin 
789*74fe6c29SRuslan Bukin 	/* Read the next byte to validate that this is indeed EVEX. */
790*74fe6c29SRuslan Bukin 	if (max_bytes <= (length + 1))
791*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
792*74fe6c29SRuslan Bukin 
793*74fe6c29SRuslan Bukin 	p1 = get_byte(ild, length + 1);
794*74fe6c29SRuslan Bukin 
795*74fe6c29SRuslan Bukin 	/* If p1[7:6] is not 11b in non-64-bit mode, this is BOUND, not EVEX. */
796*74fe6c29SRuslan Bukin 	if (!mode_64b(ild) && !bits_match(p1, 0xc0, 0xc0))
797*74fe6c29SRuslan Bukin 		return opcode_dec(ild, length);
798*74fe6c29SRuslan Bukin 
799*74fe6c29SRuslan Bukin 	/* We need at least 5 bytes
800*74fe6c29SRuslan Bukin 	 * - 4 for the EVEX prefix and payload and
801*74fe6c29SRuslan Bukin 	 * - 1 for the opcode.
802*74fe6c29SRuslan Bukin 	 */
803*74fe6c29SRuslan Bukin 	if (max_bytes < (length + 5))
804*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
805*74fe6c29SRuslan Bukin 
806*74fe6c29SRuslan Bukin 	p2 = get_byte(ild, length + 2);
807*74fe6c29SRuslan Bukin 
808*74fe6c29SRuslan Bukin 	ild->u.s.vex = 1;
809*74fe6c29SRuslan Bukin 	if (p1 & 0x80)
810*74fe6c29SRuslan Bukin 		ild->u.s.rex_r = 1;
811*74fe6c29SRuslan Bukin 	if (p2 & 0x80)
812*74fe6c29SRuslan Bukin 		ild->u.s.rex_w = 1;
813*74fe6c29SRuslan Bukin 
814*74fe6c29SRuslan Bukin 	map = p1 & 0x03;
815*74fe6c29SRuslan Bukin 	ild->map = map;
816*74fe6c29SRuslan Bukin 
817*74fe6c29SRuslan Bukin 	if (map == PTI_MAP_3)
818*74fe6c29SRuslan Bukin 		ild->imm1_bytes = 1;
819*74fe6c29SRuslan Bukin 
820*74fe6c29SRuslan Bukin 	/* Eat the EVEX. */
821*74fe6c29SRuslan Bukin 	length += 4;
822*74fe6c29SRuslan Bukin 	return prefix_vex_done(ild, length);
823*74fe6c29SRuslan Bukin }
824*74fe6c29SRuslan Bukin 
825*74fe6c29SRuslan Bukin static void init_prefix_table(void)
826*74fe6c29SRuslan Bukin {
827*74fe6c29SRuslan Bukin 	unsigned int byte;
828*74fe6c29SRuslan Bukin 
829*74fe6c29SRuslan Bukin 	for (byte = 0; byte <= 0xff; ++byte)
830*74fe6c29SRuslan Bukin 		prefix_table[byte] = prefix_done;
831*74fe6c29SRuslan Bukin 
832*74fe6c29SRuslan Bukin 	prefix_table[0x66] = prefix_osz;
833*74fe6c29SRuslan Bukin 	prefix_table[0x67] = prefix_asz;
834*74fe6c29SRuslan Bukin 
835*74fe6c29SRuslan Bukin 	/* Segment prefixes. */
836*74fe6c29SRuslan Bukin 	prefix_table[0x2e] = prefix_ignore;
837*74fe6c29SRuslan Bukin 	prefix_table[0x3e] = prefix_ignore;
838*74fe6c29SRuslan Bukin 	prefix_table[0x26] = prefix_ignore;
839*74fe6c29SRuslan Bukin 	prefix_table[0x36] = prefix_ignore;
840*74fe6c29SRuslan Bukin 	prefix_table[0x64] = prefix_ignore;
841*74fe6c29SRuslan Bukin 	prefix_table[0x65] = prefix_ignore;
842*74fe6c29SRuslan Bukin 
843*74fe6c29SRuslan Bukin 	prefix_table[0xf0] = prefix_lock;
844*74fe6c29SRuslan Bukin 	prefix_table[0xf2] = prefix_f2;
845*74fe6c29SRuslan Bukin 	prefix_table[0xf3] = prefix_f3;
846*74fe6c29SRuslan Bukin 
847*74fe6c29SRuslan Bukin 	for (byte = 0x40; byte <= 0x4f; ++byte)
848*74fe6c29SRuslan Bukin 		prefix_table[byte] = prefix_rex;
849*74fe6c29SRuslan Bukin 
850*74fe6c29SRuslan Bukin 	prefix_table[0xc4] = prefix_vex_c4;
851*74fe6c29SRuslan Bukin 	prefix_table[0xc5] = prefix_vex_c5;
852*74fe6c29SRuslan Bukin 	prefix_table[0x62] = prefix_evex;
853*74fe6c29SRuslan Bukin }
854*74fe6c29SRuslan Bukin 
855*74fe6c29SRuslan Bukin static int decode(struct pt_ild *ild)
856*74fe6c29SRuslan Bukin {
857*74fe6c29SRuslan Bukin 	return prefix_decode(ild, 0, 0);
858*74fe6c29SRuslan Bukin }
859*74fe6c29SRuslan Bukin 
860*74fe6c29SRuslan Bukin static int set_branch_target(struct pt_insn_ext *iext, const struct pt_ild *ild)
861*74fe6c29SRuslan Bukin {
862*74fe6c29SRuslan Bukin 	if (!iext || !ild)
863*74fe6c29SRuslan Bukin 		return -pte_internal;
864*74fe6c29SRuslan Bukin 
865*74fe6c29SRuslan Bukin 	iext->variant.branch.is_direct = 1;
866*74fe6c29SRuslan Bukin 
867*74fe6c29SRuslan Bukin 	if (ild->disp_bytes == 1) {
868*74fe6c29SRuslan Bukin 		const int8_t *b = (const int8_t *)
869*74fe6c29SRuslan Bukin 			get_byte_ptr(ild, ild->disp_pos);
870*74fe6c29SRuslan Bukin 
871*74fe6c29SRuslan Bukin 		iext->variant.branch.displacement = *b;
872*74fe6c29SRuslan Bukin 	} else if (ild->disp_bytes == 2) {
873*74fe6c29SRuslan Bukin 		const int16_t *w = (const int16_t *)
874*74fe6c29SRuslan Bukin 			get_byte_ptr(ild, ild->disp_pos);
875*74fe6c29SRuslan Bukin 
876*74fe6c29SRuslan Bukin 		iext->variant.branch.displacement = *w;
877*74fe6c29SRuslan Bukin 	} else if (ild->disp_bytes == 4) {
878*74fe6c29SRuslan Bukin 		const int32_t *d = (const int32_t *)
879*74fe6c29SRuslan Bukin 			get_byte_ptr(ild, ild->disp_pos);
880*74fe6c29SRuslan Bukin 
881*74fe6c29SRuslan Bukin 		iext->variant.branch.displacement = *d;
882*74fe6c29SRuslan Bukin 	} else
883*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
884*74fe6c29SRuslan Bukin 
885*74fe6c29SRuslan Bukin 	return 0;
886*74fe6c29SRuslan Bukin }
887*74fe6c29SRuslan Bukin 
888*74fe6c29SRuslan Bukin /*  MAIN ENTRY POINTS */
889*74fe6c29SRuslan Bukin 
890*74fe6c29SRuslan Bukin void pt_ild_init(void)
891*74fe6c29SRuslan Bukin {	/* initialization */
892*74fe6c29SRuslan Bukin 	init_has_disp_regular_table();
893*74fe6c29SRuslan Bukin 	init_has_sib_table();
894*74fe6c29SRuslan Bukin 	init_eamode_table();
895*74fe6c29SRuslan Bukin 	init_prefix_table();
896*74fe6c29SRuslan Bukin }
897*74fe6c29SRuslan Bukin 
898*74fe6c29SRuslan Bukin static int pt_instruction_length_decode(struct pt_ild *ild)
899*74fe6c29SRuslan Bukin {
900*74fe6c29SRuslan Bukin 	if (!ild)
901*74fe6c29SRuslan Bukin 		return -pte_internal;
902*74fe6c29SRuslan Bukin 
903*74fe6c29SRuslan Bukin 	ild->u.i = 0;
904*74fe6c29SRuslan Bukin 	ild->imm1_bytes = 0;
905*74fe6c29SRuslan Bukin 	ild->imm2_bytes = 0;
906*74fe6c29SRuslan Bukin 	ild->disp_bytes = 0;
907*74fe6c29SRuslan Bukin 	ild->modrm_byte = 0;
908*74fe6c29SRuslan Bukin 	ild->map = PTI_MAP_INVALID;
909*74fe6c29SRuslan Bukin 
910*74fe6c29SRuslan Bukin 	if (!ild->mode)
911*74fe6c29SRuslan Bukin 		return -pte_bad_insn;
912*74fe6c29SRuslan Bukin 
913*74fe6c29SRuslan Bukin 	return decode(ild);
914*74fe6c29SRuslan Bukin }
915*74fe6c29SRuslan Bukin 
916*74fe6c29SRuslan Bukin static int pt_instruction_decode(struct pt_insn *insn, struct pt_insn_ext *iext,
917*74fe6c29SRuslan Bukin 				 const struct pt_ild *ild)
918*74fe6c29SRuslan Bukin {
919*74fe6c29SRuslan Bukin 	uint8_t opcode, map;
920*74fe6c29SRuslan Bukin 
921*74fe6c29SRuslan Bukin 	if (!iext || !ild)
922*74fe6c29SRuslan Bukin 		return -pte_internal;
923*74fe6c29SRuslan Bukin 
924*74fe6c29SRuslan Bukin 	iext->iclass = PTI_INST_INVALID;
925*74fe6c29SRuslan Bukin 	memset(&iext->variant, 0, sizeof(iext->variant));
926*74fe6c29SRuslan Bukin 
927*74fe6c29SRuslan Bukin 	insn->iclass = ptic_other;
928*74fe6c29SRuslan Bukin 
929*74fe6c29SRuslan Bukin 	opcode = ild->nominal_opcode;
930*74fe6c29SRuslan Bukin 	map = ild->map;
931*74fe6c29SRuslan Bukin 
932*74fe6c29SRuslan Bukin 	if (map > PTI_MAP_1)
933*74fe6c29SRuslan Bukin 		return 0;	/* uninteresting */
934*74fe6c29SRuslan Bukin 	if (ild->u.s.vex)
935*74fe6c29SRuslan Bukin 		return 0;	/* uninteresting */
936*74fe6c29SRuslan Bukin 
937*74fe6c29SRuslan Bukin 	/* PTI_INST_JCC,   70...7F, 0F (0x80...0x8F) */
938*74fe6c29SRuslan Bukin 	if (opcode >= 0x70 && opcode <= 0x7F) {
939*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
940*74fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
941*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JCC;
942*74fe6c29SRuslan Bukin 
943*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
944*74fe6c29SRuslan Bukin 		}
945*74fe6c29SRuslan Bukin 		return 0;
946*74fe6c29SRuslan Bukin 	}
947*74fe6c29SRuslan Bukin 	if (opcode >= 0x80 && opcode <= 0x8F) {
948*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
949*74fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
950*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JCC;
951*74fe6c29SRuslan Bukin 
952*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
953*74fe6c29SRuslan Bukin 		}
954*74fe6c29SRuslan Bukin 		return 0;
955*74fe6c29SRuslan Bukin 	}
956*74fe6c29SRuslan Bukin 
957*74fe6c29SRuslan Bukin 	switch (ild->nominal_opcode) {
958*74fe6c29SRuslan Bukin 	case 0x9A:
959*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
960*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
961*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_CALL_9A;
962*74fe6c29SRuslan Bukin 		}
963*74fe6c29SRuslan Bukin 		return 0;
964*74fe6c29SRuslan Bukin 
965*74fe6c29SRuslan Bukin 	case 0xFF:
966*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
967*74fe6c29SRuslan Bukin 			uint8_t reg = pti_get_modrm_reg(ild);
968*74fe6c29SRuslan Bukin 
969*74fe6c29SRuslan Bukin 			if (reg == 2) {
970*74fe6c29SRuslan Bukin 				insn->iclass = ptic_call;
971*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_CALL_FFr2;
972*74fe6c29SRuslan Bukin 			} else if (reg == 3) {
973*74fe6c29SRuslan Bukin 				insn->iclass = ptic_far_call;
974*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_CALL_FFr3;
975*74fe6c29SRuslan Bukin 			} else if (reg == 4) {
976*74fe6c29SRuslan Bukin 				insn->iclass = ptic_jump;
977*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_JMP_FFr4;
978*74fe6c29SRuslan Bukin 			} else if (reg == 5) {
979*74fe6c29SRuslan Bukin 				insn->iclass = ptic_far_jump;
980*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_JMP_FFr5;
981*74fe6c29SRuslan Bukin 			}
982*74fe6c29SRuslan Bukin 		}
983*74fe6c29SRuslan Bukin 		return 0;
984*74fe6c29SRuslan Bukin 
985*74fe6c29SRuslan Bukin 	case 0xE8:
986*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
987*74fe6c29SRuslan Bukin 			insn->iclass = ptic_call;
988*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_CALL_E8;
989*74fe6c29SRuslan Bukin 
990*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
991*74fe6c29SRuslan Bukin 		}
992*74fe6c29SRuslan Bukin 		return 0;
993*74fe6c29SRuslan Bukin 
994*74fe6c29SRuslan Bukin 	case 0xCD:
995*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
996*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
997*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INT;
998*74fe6c29SRuslan Bukin 		}
999*74fe6c29SRuslan Bukin 
1000*74fe6c29SRuslan Bukin 		return 0;
1001*74fe6c29SRuslan Bukin 
1002*74fe6c29SRuslan Bukin 	case 0xCC:
1003*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1004*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
1005*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INT3;
1006*74fe6c29SRuslan Bukin 		}
1007*74fe6c29SRuslan Bukin 
1008*74fe6c29SRuslan Bukin 		return 0;
1009*74fe6c29SRuslan Bukin 
1010*74fe6c29SRuslan Bukin 	case 0xCE:
1011*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1012*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
1013*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INTO;
1014*74fe6c29SRuslan Bukin 		}
1015*74fe6c29SRuslan Bukin 
1016*74fe6c29SRuslan Bukin 		return 0;
1017*74fe6c29SRuslan Bukin 
1018*74fe6c29SRuslan Bukin 	case 0xF1:
1019*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1020*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
1021*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_INT1;
1022*74fe6c29SRuslan Bukin 		}
1023*74fe6c29SRuslan Bukin 
1024*74fe6c29SRuslan Bukin 		return 0;
1025*74fe6c29SRuslan Bukin 
1026*74fe6c29SRuslan Bukin 	case 0xCF:
1027*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1028*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
1029*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_IRET;
1030*74fe6c29SRuslan Bukin 		}
1031*74fe6c29SRuslan Bukin 		return 0;
1032*74fe6c29SRuslan Bukin 
1033*74fe6c29SRuslan Bukin 	case 0xE9:
1034*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1035*74fe6c29SRuslan Bukin 			insn->iclass = ptic_jump;
1036*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JMP_E9;
1037*74fe6c29SRuslan Bukin 
1038*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
1039*74fe6c29SRuslan Bukin 		}
1040*74fe6c29SRuslan Bukin 		return 0;
1041*74fe6c29SRuslan Bukin 
1042*74fe6c29SRuslan Bukin 	case 0xEA:
1043*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1044*74fe6c29SRuslan Bukin 			/* Far jumps are treated as indirect jumps. */
1045*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_jump;
1046*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JMP_EA;
1047*74fe6c29SRuslan Bukin 		}
1048*74fe6c29SRuslan Bukin 		return 0;
1049*74fe6c29SRuslan Bukin 
1050*74fe6c29SRuslan Bukin 	case 0xEB:
1051*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1052*74fe6c29SRuslan Bukin 			insn->iclass = ptic_jump;
1053*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JMP_EB;
1054*74fe6c29SRuslan Bukin 
1055*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
1056*74fe6c29SRuslan Bukin 		}
1057*74fe6c29SRuslan Bukin 		return 0;
1058*74fe6c29SRuslan Bukin 
1059*74fe6c29SRuslan Bukin 	case 0xE3:
1060*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1061*74fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
1062*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_JrCXZ;
1063*74fe6c29SRuslan Bukin 
1064*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
1065*74fe6c29SRuslan Bukin 		}
1066*74fe6c29SRuslan Bukin 		return 0;
1067*74fe6c29SRuslan Bukin 
1068*74fe6c29SRuslan Bukin 	case 0xE0:
1069*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1070*74fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
1071*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_LOOPNE;
1072*74fe6c29SRuslan Bukin 
1073*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
1074*74fe6c29SRuslan Bukin 		}
1075*74fe6c29SRuslan Bukin 		return 0;
1076*74fe6c29SRuslan Bukin 
1077*74fe6c29SRuslan Bukin 	case 0xE1:
1078*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1079*74fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
1080*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_LOOPE;
1081*74fe6c29SRuslan Bukin 
1082*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
1083*74fe6c29SRuslan Bukin 		}
1084*74fe6c29SRuslan Bukin 		return 0;
1085*74fe6c29SRuslan Bukin 
1086*74fe6c29SRuslan Bukin 	case 0xE2:
1087*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1088*74fe6c29SRuslan Bukin 			insn->iclass = ptic_cond_jump;
1089*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_LOOP;
1090*74fe6c29SRuslan Bukin 
1091*74fe6c29SRuslan Bukin 			return set_branch_target(iext, ild);
1092*74fe6c29SRuslan Bukin 		}
1093*74fe6c29SRuslan Bukin 		return 0;
1094*74fe6c29SRuslan Bukin 
1095*74fe6c29SRuslan Bukin 	case 0x22:
1096*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1)
1097*74fe6c29SRuslan Bukin 			if (pti_get_modrm_reg(ild) == 3)
1098*74fe6c29SRuslan Bukin 				if (!ild->u.s.rex_r)
1099*74fe6c29SRuslan Bukin 					iext->iclass = PTI_INST_MOV_CR3;
1100*74fe6c29SRuslan Bukin 
1101*74fe6c29SRuslan Bukin 		return 0;
1102*74fe6c29SRuslan Bukin 
1103*74fe6c29SRuslan Bukin 	case 0xC3:
1104*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1105*74fe6c29SRuslan Bukin 			insn->iclass = ptic_return;
1106*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_C3;
1107*74fe6c29SRuslan Bukin 		}
1108*74fe6c29SRuslan Bukin 		return 0;
1109*74fe6c29SRuslan Bukin 
1110*74fe6c29SRuslan Bukin 	case 0xC2:
1111*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1112*74fe6c29SRuslan Bukin 			insn->iclass = ptic_return;
1113*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_C2;
1114*74fe6c29SRuslan Bukin 		}
1115*74fe6c29SRuslan Bukin 		return 0;
1116*74fe6c29SRuslan Bukin 
1117*74fe6c29SRuslan Bukin 	case 0xCB:
1118*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1119*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
1120*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_CB;
1121*74fe6c29SRuslan Bukin 		}
1122*74fe6c29SRuslan Bukin 		return 0;
1123*74fe6c29SRuslan Bukin 
1124*74fe6c29SRuslan Bukin 	case 0xCA:
1125*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_0) {
1126*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
1127*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_RET_CA;
1128*74fe6c29SRuslan Bukin 		}
1129*74fe6c29SRuslan Bukin 		return 0;
1130*74fe6c29SRuslan Bukin 
1131*74fe6c29SRuslan Bukin 	case 0x05:
1132*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
1133*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
1134*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSCALL;
1135*74fe6c29SRuslan Bukin 		}
1136*74fe6c29SRuslan Bukin 		return 0;
1137*74fe6c29SRuslan Bukin 
1138*74fe6c29SRuslan Bukin 	case 0x34:
1139*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
1140*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_call;
1141*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSENTER;
1142*74fe6c29SRuslan Bukin 		}
1143*74fe6c29SRuslan Bukin 		return 0;
1144*74fe6c29SRuslan Bukin 
1145*74fe6c29SRuslan Bukin 	case 0x35:
1146*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
1147*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
1148*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSEXIT;
1149*74fe6c29SRuslan Bukin 		}
1150*74fe6c29SRuslan Bukin 		return 0;
1151*74fe6c29SRuslan Bukin 
1152*74fe6c29SRuslan Bukin 	case 0x07:
1153*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
1154*74fe6c29SRuslan Bukin 			insn->iclass = ptic_far_return;
1155*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_SYSRET;
1156*74fe6c29SRuslan Bukin 		}
1157*74fe6c29SRuslan Bukin 		return 0;
1158*74fe6c29SRuslan Bukin 
1159*74fe6c29SRuslan Bukin 	case 0x01:
1160*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1) {
1161*74fe6c29SRuslan Bukin 			switch (ild->modrm_byte) {
1162*74fe6c29SRuslan Bukin 			case 0xc1:
1163*74fe6c29SRuslan Bukin 				insn->iclass = ptic_far_call;
1164*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_VMCALL;
1165*74fe6c29SRuslan Bukin 				break;
1166*74fe6c29SRuslan Bukin 
1167*74fe6c29SRuslan Bukin 			case 0xc2:
1168*74fe6c29SRuslan Bukin 				insn->iclass = ptic_far_return;
1169*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_VMLAUNCH;
1170*74fe6c29SRuslan Bukin 				break;
1171*74fe6c29SRuslan Bukin 
1172*74fe6c29SRuslan Bukin 			case 0xc3:
1173*74fe6c29SRuslan Bukin 				insn->iclass = ptic_far_return;
1174*74fe6c29SRuslan Bukin 				iext->iclass = PTI_INST_VMRESUME;
1175*74fe6c29SRuslan Bukin 				break;
1176*74fe6c29SRuslan Bukin 
1177*74fe6c29SRuslan Bukin 			default:
1178*74fe6c29SRuslan Bukin 				break;
1179*74fe6c29SRuslan Bukin 			}
1180*74fe6c29SRuslan Bukin 		}
1181*74fe6c29SRuslan Bukin 		return 0;
1182*74fe6c29SRuslan Bukin 
1183*74fe6c29SRuslan Bukin 	case 0xc7:
1184*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1 &&
1185*74fe6c29SRuslan Bukin 		    pti_get_modrm_mod(ild) != 3 &&
1186*74fe6c29SRuslan Bukin 		    pti_get_modrm_reg(ild) == 6)
1187*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_VMPTRLD;
1188*74fe6c29SRuslan Bukin 
1189*74fe6c29SRuslan Bukin 		return 0;
1190*74fe6c29SRuslan Bukin 
1191*74fe6c29SRuslan Bukin 	case 0xae:
1192*74fe6c29SRuslan Bukin 		if (map == PTI_MAP_1 && ild->u.s.f3 && !ild->u.s.osz &&
1193*74fe6c29SRuslan Bukin 		    pti_get_modrm_reg(ild) == 4) {
1194*74fe6c29SRuslan Bukin 			insn->iclass = ptic_ptwrite;
1195*74fe6c29SRuslan Bukin 			iext->iclass = PTI_INST_PTWRITE;
1196*74fe6c29SRuslan Bukin 		}
1197*74fe6c29SRuslan Bukin 		return 0;
1198*74fe6c29SRuslan Bukin 
1199*74fe6c29SRuslan Bukin 	default:
1200*74fe6c29SRuslan Bukin 		return 0;
1201*74fe6c29SRuslan Bukin 	}
1202*74fe6c29SRuslan Bukin }
1203*74fe6c29SRuslan Bukin 
1204*74fe6c29SRuslan Bukin int pt_ild_decode(struct pt_insn *insn, struct pt_insn_ext *iext)
1205*74fe6c29SRuslan Bukin {
1206*74fe6c29SRuslan Bukin 	struct pt_ild ild;
1207*74fe6c29SRuslan Bukin 	int size;
1208*74fe6c29SRuslan Bukin 
1209*74fe6c29SRuslan Bukin 	if (!insn || !iext)
1210*74fe6c29SRuslan Bukin 		return -pte_internal;
1211*74fe6c29SRuslan Bukin 
1212*74fe6c29SRuslan Bukin 	ild.mode = insn->mode;
1213*74fe6c29SRuslan Bukin 	ild.itext = insn->raw;
1214*74fe6c29SRuslan Bukin 	ild.max_bytes = insn->size;
1215*74fe6c29SRuslan Bukin 
1216*74fe6c29SRuslan Bukin 	size = pt_instruction_length_decode(&ild);
1217*74fe6c29SRuslan Bukin 	if (size < 0)
1218*74fe6c29SRuslan Bukin 		return size;
1219*74fe6c29SRuslan Bukin 
1220*74fe6c29SRuslan Bukin 	insn->size = (uint8_t) size;
1221*74fe6c29SRuslan Bukin 
1222*74fe6c29SRuslan Bukin 	return pt_instruction_decode(insn, iext, &ild);
1223*74fe6c29SRuslan Bukin }
1224