• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 syzkaller project authors. All rights reserved.
2// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
3
4package ifuzz
5
6import (
7	"fmt"
8)
9
10// Decode decodes instruction length for the given mode.
11// It can have falsely decode incorrect instructions,
12// but should not fail to decode correct instructions.
13// nolint: gocyclo
14func Decode(mode int, text []byte) (int, error) {
15	if len(text) == 0 {
16		return 0, fmt.Errorf("zero-length instruction")
17	}
18	prefixes := prefixes32
19	var operSize, immSize, dispSize, addrSize int
20	switch mode {
21	case ModeLong64:
22		operSize, immSize, dispSize, addrSize = 4, 4, 4, 8
23		prefixes = prefixes64
24	case ModeProt32:
25		operSize, immSize, dispSize, addrSize = 4, 4, 4, 4
26	case ModeProt16, ModeReal16:
27		operSize, immSize, dispSize, addrSize = 2, 2, 2, 2
28	default:
29		panic("bad mode")
30	}
31	prefixLen := 0
32	var decodedPrefixes []byte
33	vex := false
34	if len(text) > 1 {
35		// There are only 2 32-bit instructions that look like VEX-prefixed but are actually not: LDS, LES.
36		// They always reference memory (mod!=3), but all VEX instructions have "mod=3" where LDS/LES would have mod.
37		if (text[0] == 0xc4 || text[0] == 0xc5) && (mode == ModeLong64 || text[1]&0xc0 == 0xc0) {
38			vex = true
39		}
40		// There is only one instruction that looks like XOP-prefixed but is actually not: POP.
41		// It always has reg=0, but all XOP instructions have "reg!=0" where POP would have reg.
42		if text[0] == 0x8f && text[1]&0x38 != 0 {
43			vex = true
44		}
45	}
46	var vexMap byte
47	if vex {
48		prefixLen = 3
49		if text[0] == 0xc5 {
50			prefixLen = 2
51			vexMap = 1 // V0F
52		}
53		if len(text) < prefixLen {
54			return 0, fmt.Errorf("bad VEX/XOP prefix")
55		}
56		if prefixLen == 3 {
57			vexMap = text[1] & 0x1f
58		}
59		text = text[prefixLen:]
60	} else {
61		decodedPrefixes = text
62		operSize1, immSize1, dispSize1, addrSize1 := operSize, immSize, dispSize, addrSize
63		for len(text) != 0 && prefixes[text[0]] {
64			switch text[0] {
65			case 0x66:
66				if immSize == 4 {
67					immSize1 = 2
68					operSize1 = 2
69				} else if immSize == 2 {
70					immSize1 = 4
71					operSize1 = 4
72				}
73			case 0x67:
74				if addrSize == 8 {
75					addrSize1 = 4
76				} else if addrSize == 4 {
77					dispSize1 = 2
78					addrSize1 = 2
79				} else if addrSize == 2 {
80					dispSize1 = 4
81					addrSize1 = 4
82				}
83			}
84			if text[0] & ^byte(7) == 0x48 {
85				operSize1 = 8
86				immSize1 = 4
87			}
88			text = text[1:]
89			prefixLen++
90		}
91		operSize, immSize, dispSize, addrSize = operSize1, immSize1, dispSize1, addrSize1
92		decodedPrefixes = decodedPrefixes[:prefixLen]
93		if len(text) == 0 {
94			return 0, fmt.Errorf("no opcode, only prefixes")
95		}
96	}
97nextInsn:
98	for _, insn := range modeInsns[mode][typeAll] {
99		if vex != (insn.Vex != 0) {
100			continue nextInsn
101		}
102		if vex && insn.VexMap != vexMap {
103			continue nextInsn
104		}
105		if insn.NoRepPrefix || insn.No66Prefix {
106			for _, p := range decodedPrefixes {
107				if len(insn.Prefix) != 0 && insn.Prefix[0] == p {
108					continue
109				}
110				switch p {
111				case 0xf2, 0xf3:
112					if insn.NoRepPrefix {
113						continue nextInsn
114					}
115				case 0x66:
116					if insn.No66Prefix {
117						continue nextInsn
118					}
119				}
120			}
121		}
122		text1 := text
123		for i, v := range insn.Opcode {
124			if len(text1) == 0 {
125				continue nextInsn
126			}
127			b := text1[0]
128			if insn.Srm && i == len(insn.Opcode)-1 {
129				b &^= 7
130			}
131			if b != v {
132				continue nextInsn
133			}
134			text1 = text1[1:]
135		}
136		if insn.Modrm {
137			if len(text1) == 0 {
138				continue nextInsn
139			}
140			modrm := text1[0]
141			text1 = text1[1:]
142			mod := modrm >> 6
143			rm := modrm & 7
144			if !insn.NoSibDisp {
145				disp := 0
146				if addrSize == 2 {
147					if mod == 1 {
148						disp = 1
149					} else if mod == 2 || mod == 0 && rm == 6 {
150						disp = 2
151					}
152				} else {
153					var sibbase byte
154					if mod != 3 && rm == 4 {
155						if len(text1) == 0 {
156							continue nextInsn
157						}
158						sib := text1[0]
159						text1 = text1[1:]
160						sibbase = sib & 7
161					}
162					if mod == 1 {
163						disp = 1
164					} else if mod == 2 || mod == 0 && rm == 5 || mod == 0 && sibbase == 5 {
165						disp = dispSize
166					}
167				}
168				if disp != 0 {
169					if len(text1) < disp {
170						continue nextInsn
171					}
172					text1 = text1[disp:]
173				}
174			}
175		}
176		immLen := 0
177		for _, imm := range []int8{insn.Imm, insn.Imm2} {
178			switch imm {
179			case -1:
180				immLen += immSize
181			case -2:
182				immLen += addrSize
183			case -3:
184				immLen += operSize
185			default:
186				immLen += int(imm)
187			}
188		}
189		if immLen != 0 {
190			if len(text1) < immLen {
191				continue nextInsn
192			}
193			text1 = text1[immLen:]
194		}
195		for _, v := range insn.Suffix {
196			if len(text1) == 0 || text1[0] != v {
197				continue nextInsn
198			}
199			text1 = text1[1:]
200		}
201		return prefixLen + len(text) - len(text1), nil
202	}
203	return 0, fmt.Errorf("unknown instruction")
204}
205
206var XedDecode func(mode int, text []byte) (int, error)
207
208var (
209	prefixes32 = map[byte]bool{
210		0x2E: true, 0x3E: true, 0x26: true, 0x64: true, 0x65: true,
211		0x36: true, 0x66: true, 0x67: true, 0xF3: true, 0xF2: true,
212		0xF0: true,
213	}
214	prefixes64 = map[byte]bool{
215		0x2E: true, 0x3E: true, 0x26: true, 0x64: true, 0x65: true,
216		0x36: true, 0x66: true, 0x67: true, 0xF3: true, 0xF2: true,
217		0xF0: true, 0x40: true, 0x41: true, 0x42: true, 0x43: true,
218		0x44: true, 0x45: true, 0x46: true, 0x47: true, 0x48: true,
219		0x49: true, 0x4a: true, 0x4b: true, 0x4c: true, 0x4d: true,
220		0x4e: true, 0x4f: true,
221	}
222)
223