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