mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-24 11:59:58 +00:00
213 lines
5.2 KiB
Go
213 lines
5.2 KiB
Go
// Copyright 2017 syzkaller project authors. All rights reserved.
|
|
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
|
|
|
|
package ifuzz
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// Decode decodes instruction length for the given mode.
|
|
// It can have falsely decode incorrect instructions,
|
|
// but should not fail to decode correct instructions.
|
|
func Decode(mode int, text []byte) (int, error) {
|
|
if len(text) == 0 {
|
|
return 0, fmt.Errorf("zero-length instruction")
|
|
}
|
|
prefixes := prefixes32
|
|
var operSize, immSize, dispSize, addrSize int
|
|
switch mode {
|
|
case ModeLong64:
|
|
operSize, immSize, dispSize, addrSize = 4, 4, 4, 8
|
|
prefixes = prefixes64
|
|
case ModeProt32:
|
|
operSize, immSize, dispSize, addrSize = 4, 4, 4, 4
|
|
case ModeProt16, ModeReal16:
|
|
operSize, immSize, dispSize, addrSize = 2, 2, 2, 2
|
|
default:
|
|
panic("bad mode")
|
|
}
|
|
prefixLen := 0
|
|
var decodedPrefixes []byte
|
|
vex := false
|
|
if len(text) > 1 {
|
|
// There are only 2 32-bit instructions that look like VEX-prefixed but are actually not: LDS, LES.
|
|
// They always reference memory (mod!=3), but all VEX instructions have "mod=3" where LDS/LES would have mod.
|
|
if (text[0] == 0xc4 || text[0] == 0xc5) && (mode == ModeLong64 || text[1]&0xc0 == 0xc0) {
|
|
vex = true
|
|
}
|
|
// There is only one instruction that looks like XOP-prefixed but is actually not: POP.
|
|
// It always has reg=0, but all XOP instructions have "reg!=0" where POP would have reg.
|
|
if text[0] == 0x8f && text[1]&0x38 != 0 {
|
|
vex = true
|
|
}
|
|
}
|
|
var vexMap byte
|
|
if vex {
|
|
prefixLen = 3
|
|
if text[0] == 0xc5 {
|
|
prefixLen = 2
|
|
vexMap = 1 // V0F
|
|
}
|
|
if len(text) < prefixLen {
|
|
return 0, fmt.Errorf("bad VEX/XOP prefix")
|
|
}
|
|
if prefixLen == 3 {
|
|
vexMap = text[1] & 0x1f
|
|
}
|
|
text = text[prefixLen:]
|
|
} else {
|
|
decodedPrefixes = text
|
|
operSize1, immSize1, dispSize1, addrSize1 := operSize, immSize, dispSize, addrSize
|
|
for len(text) != 0 && prefixes[text[0]] {
|
|
switch text[0] {
|
|
case 0x66:
|
|
if immSize == 4 {
|
|
immSize1 = 2
|
|
operSize1 = 2
|
|
} else if immSize == 2 {
|
|
immSize1 = 4
|
|
operSize1 = 4
|
|
}
|
|
case 0x67:
|
|
if addrSize == 8 {
|
|
addrSize1 = 4
|
|
} else if addrSize == 4 {
|
|
dispSize1 = 2
|
|
addrSize1 = 2
|
|
} else if addrSize == 2 {
|
|
dispSize1 = 4
|
|
addrSize1 = 4
|
|
}
|
|
}
|
|
if text[0] & ^byte(7) == 0x48 {
|
|
operSize1 = 8
|
|
immSize1 = 4
|
|
}
|
|
text = text[1:]
|
|
prefixLen++
|
|
}
|
|
operSize, immSize, dispSize, addrSize = operSize1, immSize1, dispSize1, addrSize1
|
|
decodedPrefixes = decodedPrefixes[:prefixLen]
|
|
if len(text) == 0 {
|
|
return 0, fmt.Errorf("no opcode, only prefixes")
|
|
}
|
|
}
|
|
nextInsn:
|
|
for _, insn := range modeInsns[mode][typeAll] {
|
|
if vex != (insn.Vex != 0) {
|
|
continue nextInsn
|
|
}
|
|
if vex && insn.VexMap != vexMap {
|
|
continue nextInsn
|
|
}
|
|
if insn.NoRepPrefix || insn.No66Prefix {
|
|
for _, p := range decodedPrefixes {
|
|
if len(insn.Prefix) != 0 && insn.Prefix[0] == p {
|
|
continue
|
|
}
|
|
switch p {
|
|
case 0xf2, 0xf3:
|
|
if insn.NoRepPrefix {
|
|
continue nextInsn
|
|
}
|
|
case 0x66:
|
|
if insn.No66Prefix {
|
|
continue nextInsn
|
|
}
|
|
}
|
|
}
|
|
}
|
|
text1 := text
|
|
for i, v := range insn.Opcode {
|
|
if len(text1) == 0 {
|
|
continue nextInsn
|
|
}
|
|
b := text1[0]
|
|
if insn.Srm && i == len(insn.Opcode)-1 {
|
|
b &^= 7
|
|
}
|
|
if b != v {
|
|
continue nextInsn
|
|
}
|
|
text1 = text1[1:]
|
|
}
|
|
if insn.Modrm {
|
|
if len(text1) == 0 {
|
|
continue nextInsn
|
|
}
|
|
modrm := text1[0]
|
|
text1 = text1[1:]
|
|
mod := modrm >> 6
|
|
rm := modrm & 7
|
|
if !insn.NoSibDisp {
|
|
disp := 0
|
|
if addrSize == 2 {
|
|
if mod == 1 {
|
|
disp = 1
|
|
} else if mod == 2 || mod == 0 && rm == 6 {
|
|
disp = 2
|
|
}
|
|
} else {
|
|
var sibbase byte
|
|
if mod != 3 && rm == 4 {
|
|
if len(text1) == 0 {
|
|
continue nextInsn
|
|
}
|
|
sib := text1[0]
|
|
text1 = text1[1:]
|
|
sibbase = sib & 7
|
|
}
|
|
if mod == 1 {
|
|
disp = 1
|
|
} else if mod == 2 || mod == 0 && rm == 5 || mod == 0 && sibbase == 5 {
|
|
disp = dispSize
|
|
}
|
|
}
|
|
if disp != 0 {
|
|
if len(text1) < disp {
|
|
continue nextInsn
|
|
}
|
|
text1 = text1[disp:]
|
|
}
|
|
}
|
|
}
|
|
immLen := 0
|
|
for _, imm := range []int8{insn.Imm, insn.Imm2} {
|
|
switch imm {
|
|
case -1:
|
|
immLen += immSize
|
|
case -2:
|
|
immLen += addrSize
|
|
case -3:
|
|
immLen += operSize
|
|
default:
|
|
immLen += int(imm)
|
|
}
|
|
}
|
|
if immLen != 0 {
|
|
if len(text1) < immLen {
|
|
continue nextInsn
|
|
}
|
|
text1 = text1[immLen:]
|
|
}
|
|
for _, v := range insn.Suffix {
|
|
if len(text1) == 0 || text1[0] != v {
|
|
continue nextInsn
|
|
}
|
|
text1 = text1[1:]
|
|
}
|
|
return prefixLen + len(text) - len(text1), nil
|
|
}
|
|
return 0, fmt.Errorf("unknown instruction")
|
|
}
|
|
|
|
var XedDecode func(mode int, text []byte) (int, error)
|
|
|
|
var (
|
|
prefixes32 = map[byte]bool{0x2E: true, 0x3E: true, 0x26: true, 0x64: true, 0x65: true, 0x36: true, 0x66: true, 0x67: true, 0xF3: true, 0xF2: true, 0xF0: true}
|
|
prefixes64 = map[byte]bool{0x2E: true, 0x3E: true, 0x26: true, 0x64: true, 0x65: true, 0x36: true, 0x66: true, 0x67: true, 0xF3: true, 0xF2: true, 0xF0: true,
|
|
0x40: true, 0x41: true, 0x42: true, 0x43: true, 0x44: true, 0x45: true, 0x46: true, 0x47: true,
|
|
0x48: true, 0x49: true, 0x4a: true, 0x4b: true, 0x4c: true, 0x4d: true, 0x4e: true, 0x4f: true}
|
|
)
|