aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/ifuzz/ifuzz.go293
-rw-r--r--pkg/ifuzz/ifuzz_test.go54
-rw-r--r--pkg/ifuzz/ifuzzimpl/ifuzzimpl.go145
-rw-r--r--pkg/ifuzz/x86/decode.go (renamed from pkg/ifuzz/decode.go)28
-rw-r--r--pkg/ifuzz/x86/encode.go (renamed from pkg/ifuzz/encode.go)21
-rw-r--r--pkg/ifuzz/x86/gen/all-enc-instructions.txt (renamed from pkg/ifuzz/gen/all-enc-instructions.txt)0
-rw-r--r--pkg/ifuzz/x86/gen/gen.go (renamed from pkg/ifuzz/gen/gen.go)40
-rw-r--r--pkg/ifuzz/x86/generated/empty.go (renamed from pkg/ifuzz/generated/empty.go)0
-rw-r--r--pkg/ifuzz/x86/generated/insns.go (renamed from pkg/ifuzz/generated/insns.go)8
-rw-r--r--pkg/ifuzz/x86/pseudo.go (renamed from pkg/ifuzz/pseudo.go)113
-rw-r--r--pkg/ifuzz/x86/x86.go186
-rw-r--r--pkg/ifuzz/x86/xed.go (renamed from pkg/ifuzz/xed.go)2
12 files changed, 508 insertions, 382 deletions
diff --git a/pkg/ifuzz/ifuzz.go b/pkg/ifuzz/ifuzz.go
index 5d6269926..1939f440e 100644
--- a/pkg/ifuzz/ifuzz.go
+++ b/pkg/ifuzz/ifuzz.go
@@ -1,14 +1,10 @@
// 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.
-//go:generate bash -c "go run gen/gen.go gen/all-enc-instructions.txt > generated/insns.go"
-
-// Package ifuzz allows to generate and mutate x86 machine code.
package ifuzz
import (
"math/rand"
- "sync"
)
const (
@@ -19,45 +15,11 @@ const (
ModeLast
)
-type Insn struct {
- Name string
- Extension string
-
- Mode int // bitmask of compatible modes
- Priv bool // CPL=0
- Pseudo bool // pseudo instructions can consist of several real instructions
-
- Opcode []byte
- Prefix []byte
- Suffix []byte
- Modrm bool
- Mod int8
- Reg int8 // -6 - segment register, -8 - control register
- Rm int8
- Srm bool // register is embed in the first byte
- NoSibDisp bool // no SIB/disp even if modrm says otherwise
- Imm int8 // immediate size, -1 - immediate size, -2 - address size, -3 - operand size
- Imm2 int8
- NoRepPrefix bool
- No66Prefix bool
- Rexw int8 // 1 must be set, -1 must not be set
- Mem32 bool // instruction always references 32-bit memory operand, 0x67 is illegal
- Mem16 bool // instruction always references 16-bit memory operand
-
- Vex byte
- VexMap byte
- VexL int8
- VexNoR bool
- VexP int8
- Avx2Gather bool
-
- generator func(cfg *Config, r *rand.Rand) []byte // for pseudo instructions
-}
-
type Config struct {
+ Arch string
Len int // number of instructions to generate
Mode int // one of ModeXXX
- Priv bool // generate CPL=0 instructions
+ Priv bool // generate CPL=0 instructions (x86), HV/!PR mode (PPC)
Exec bool // generate instructions sequences interesting for execution
MemRegions []MemRegion // generated instructions will reference these regions
}
@@ -68,241 +30,30 @@ type MemRegion struct {
}
const (
- typeExec = iota
- typePriv
- typeUser
- typeAll
- typeLast
+ TypeExec = iota
+ TypePriv
+ TypeUser
+ TypeAll
+ TypeLast
)
-var modeInsns [ModeLast][typeLast][]*Insn
-
-var (
- Insns []*Insn
- initOnce sync.Once
-)
-
-func initInsns() {
- if len(Insns) == 0 {
- panic("no instructions")
- }
- initPseudo()
- for mode := 0; mode < ModeLast; mode++ {
- for _, insn := range Insns {
- if insn.Mode&(1<<uint(mode)) == 0 {
- continue
- }
- if insn.Pseudo {
- modeInsns[mode][typeExec] = append(modeInsns[mode][typeExec], insn)
- } else if insn.Priv {
- modeInsns[mode][typePriv] = append(modeInsns[mode][typePriv], insn)
- modeInsns[mode][typeAll] = append(modeInsns[mode][typeAll], insn)
- } else {
- modeInsns[mode][typeUser] = append(modeInsns[mode][typeUser], insn)
- modeInsns[mode][typeAll] = append(modeInsns[mode][typeAll], insn)
- }
- }
- }
+type Insn interface {
+ GetName() string
+ GetMode() int
+ GetPseudo() bool
+ GetPriv() bool
+ IsCompatible(cfg *Config) bool
+ Encode(cfg *Config, r *rand.Rand) []byte
}
-// ModeInsns returns list of all instructions for the given mode.
-func ModeInsns(cfg *Config) []*Insn {
- initOnce.Do(initInsns)
- if cfg.Mode < 0 || cfg.Mode >= ModeLast {
- panic("bad mode")
- }
- var insns []*Insn
- insns = append(insns, modeInsns[cfg.Mode][typeUser]...)
- if cfg.Priv {
- insns = append(insns, modeInsns[cfg.Mode][typePriv]...)
- if cfg.Exec {
- insns = append(insns, modeInsns[cfg.Mode][typeExec]...)
- }
- }
- return insns
+type InsnSet interface {
+ GetInsns(mode, insntype int) []Insn
+ Decode(mode int, text []byte) (int, error)
+ DecodeExt(mode int, text []byte) (int, error) // XED, to keep ifuzz_test happy
}
-func Generate(cfg *Config, r *rand.Rand) []byte {
- initOnce.Do(initInsns)
- var text []byte
- for i := 0; i < cfg.Len; i++ {
- insn := randInsn(cfg, r)
- text = append(text, insn.Encode(cfg, r)...)
- }
- return text
-}
-
-func Mutate(cfg *Config, r *rand.Rand, text []byte) []byte {
- initOnce.Do(initInsns)
- insns := split(cfg, text)
- retry := false
- for stop := false; !stop || retry || len(insns) == 0; stop = r.Intn(2) == 0 {
- retry = false
- switch x := r.Intn(100); {
- case x < 10 && len(insns) != 0:
- // Delete instruction.
- i := r.Intn(len(insns))
- copy(insns[i:], insns[i+1:])
- insns = insns[:len(insns)-1]
- case x < 40 && len(insns) != 0:
- // Replace instruction with another.
- insn := randInsn(cfg, r)
- text1 := insn.Encode(cfg, r)
- i := r.Intn(len(insns))
- insns[i] = text1
- case x < 70 && len(insns) != 0:
- // Mutate instruction.
- i := r.Intn(len(insns))
- text1 := insns[i]
- for stop := false; !stop || len(text1) == 0; stop = r.Intn(2) == 0 {
- switch x := r.Intn(100); {
- case x < 5 && len(text1) != 0:
- // Delete byte.
- pos := r.Intn(len(text1))
- copy(text1[pos:], text1[pos+1:])
- text1 = text1[:len(text1)-1]
- case x < 40 && len(text1) != 0:
- // Replace a byte.
- pos := r.Intn(len(text1))
- text1[pos] = byte(r.Intn(256))
- case x < 70 && len(text1) != 0:
- // Flip a bit.
- pos := r.Intn(len(text1))
- text1[pos] ^= 1 << byte(r.Intn(8))
- default:
- // Insert a byte.
- pos := r.Intn(len(text1) + 1)
- text1 = append(text1, 0)
- copy(text1[pos+1:], text1[pos:])
- text1[pos] = byte(r.Intn(256))
- }
- }
- insns[i] = text1
- case len(insns) < cfg.Len:
- // Insert a new instruction.
- insn := randInsn(cfg, r)
- text1 := insn.Encode(cfg, r)
- i := r.Intn(len(insns) + 1)
- insns = append(insns, nil)
- copy(insns[i+1:], insns[i:])
- insns[i] = text1
- default:
- retry = true
- }
- }
- text = nil
- for _, insn := range insns {
- text = append(text, insn...)
- }
- return text
-}
-
-func randInsn(cfg *Config, r *rand.Rand) *Insn {
- var insns []*Insn
- if cfg.Priv && cfg.Exec {
- insns = modeInsns[cfg.Mode][r.Intn(3)]
- } else if cfg.Priv {
- insns = modeInsns[cfg.Mode][r.Intn(2)]
- } else {
- insns = modeInsns[cfg.Mode][typeUser]
- }
- return insns[r.Intn(len(insns))]
-}
-
-func split(cfg *Config, text []byte) [][]byte {
- text = append([]byte{}, text...)
- var insns [][]byte
- var bad []byte
- for len(text) != 0 {
- n, err := Decode(cfg.Mode, text)
- if err != nil || n == 0 {
- bad = append(bad, text[0])
- text = text[1:]
- continue
- }
- if bad != nil {
- insns = append(insns, bad)
- bad = nil
- }
- insns = append(insns, text[:n])
- text = text[n:]
- }
- if bad != nil {
- insns = append(insns, bad)
- }
- return insns
-}
-
-func generateArg(cfg *Config, r *rand.Rand, size int) []byte {
- v := generateInt(cfg, r, size)
- arg := make([]byte, size)
- for i := 0; i < size; i++ {
- arg[i] = byte(v)
- v >>= 8
- }
- return arg
-}
-
-func (insn *Insn) isCompatible(cfg *Config) bool {
- if cfg.Mode < 0 || cfg.Mode >= ModeLast {
- panic("bad mode")
- }
- if insn.Priv && !cfg.Priv {
- return false
- }
- if insn.Pseudo && !cfg.Exec {
- return false
- }
- if insn.Mode&(1<<uint(cfg.Mode)) == 0 {
- return false
- }
- return true
-}
-
-func generateInt(cfg *Config, r *rand.Rand, size int) uint64 {
- if size != 1 && size != 2 && size != 4 && size != 8 {
- panic("bad arg size")
- }
- var v uint64
- switch x := r.Intn(60); {
- case x < 10:
- v = uint64(r.Intn(1 << 4))
- case x < 20:
- v = uint64(r.Intn(1 << 16))
- case x < 25:
- v = uint64(r.Int63()) % (1 << 32)
- case x < 30:
- v = uint64(r.Int63())
- case x < 40:
- v = specialNumbers[r.Intn(len(specialNumbers))]
- if r.Intn(5) == 0 {
- v += uint64(r.Intn(33)) - 16
- }
- case x < 50 && len(cfg.MemRegions) != 0:
- mem := cfg.MemRegions[r.Intn(len(cfg.MemRegions))]
- switch x := r.Intn(100); {
- case x < 25:
- v = mem.Start
- case x < 50:
- v = mem.Start + mem.Size
- case x < 75:
- v = mem.Start + mem.Size/2
- default:
- v = mem.Start + uint64(r.Int63())%mem.Size
- }
- if r.Intn(10) == 0 {
- v += uint64(r.Intn(33)) - 16
- }
- default:
- v = uint64(r.Intn(1 << 8))
- }
- if r.Intn(50) == 0 {
- v = uint64(-int64(v))
- }
- if r.Intn(50) == 0 && size != 1 {
- v &^= 1<<12 - 1
- }
- return v
-}
+const (
+ ArchX86 = "x86"
+)
-var specialNumbers = []uint64{0, 1 << 15, 1 << 16, 1 << 31, 1 << 32, 1 << 47, 1 << 47, 1 << 63}
+var SpecialNumbers = [...]uint64{0, 1 << 15, 1 << 16, 1 << 31, 1 << 32, 1 << 47, 1 << 47, 1 << 63}
diff --git a/pkg/ifuzz/ifuzz_test.go b/pkg/ifuzz/ifuzz_test.go
index 90ca2a440..a5052e581 100644
--- a/pkg/ifuzz/ifuzz_test.go
+++ b/pkg/ifuzz/ifuzz_test.go
@@ -10,21 +10,23 @@ import (
"testing"
"time"
- . "github.com/google/syzkaller/pkg/ifuzz"
- _ "github.com/google/syzkaller/pkg/ifuzz/generated"
+ "github.com/google/syzkaller/pkg/ifuzz"
+ "github.com/google/syzkaller/pkg/ifuzz/ifuzzimpl"
+ _ "github.com/google/syzkaller/pkg/ifuzz/x86/generated"
)
-func TestMode(t *testing.T) {
- all := make(map[*Insn]bool)
- for mode := 0; mode < ModeLast; mode++ {
+func testmodearch(t *testing.T, arch string) {
+ all := make(map[ifuzz.Insn]bool)
+ for mode := 0; mode < ifuzz.ModeLast; mode++ {
for priv := 0; priv < 2; priv++ {
for exec := 0; exec < 2; exec++ {
- cfg := &Config{
+ cfg := &ifuzz.Config{
+ Arch: arch,
Mode: mode,
Priv: priv != 0,
Exec: exec != 0,
}
- insns := ModeInsns(cfg)
+ insns := ifuzzimpl.ModeInsns(cfg)
t.Logf("mode=%v priv=%v exec=%v: %v instructions", mode, priv, exec, len(insns))
for _, insn := range insns {
all[insn] = true
@@ -35,7 +37,16 @@ func TestMode(t *testing.T) {
t.Logf("total: %v instructions", len(all))
}
-func TestDecode(t *testing.T) {
+func TestMode(t *testing.T) {
+ testmodearch(t, ifuzz.ArchX86)
+}
+
+func testdecodearch(t *testing.T, arch string) {
+ insnset := ifuzzimpl.Types[arch]
+ xedEnabled := false
+ if _, err := insnset.DecodeExt(0, nil); err == nil {
+ xedEnabled = true
+ }
seed := time.Now().UnixNano()
if os.Getenv("CI") != "" {
seed = 0 // required for deterministic coverage reports
@@ -44,30 +55,31 @@ func TestDecode(t *testing.T) {
r := rand.New(rand.NewSource(seed))
for repeat := 0; repeat < 10; repeat++ {
- for mode := 0; mode < ModeLast; mode++ {
- cfg := &Config{
+ for mode := 0; mode < ifuzz.ModeLast; mode++ {
+ cfg := &ifuzz.Config{
+ Arch: arch,
Mode: mode,
Priv: true,
Exec: true,
}
failed := false
- for _, insn := range ModeInsns(cfg) {
+ for _, insn := range ifuzzimpl.ModeInsns(cfg) {
text0 := insn.Encode(cfg, r)
text := text0
repeat:
- size, err := Decode(mode, text)
+ size, err := insnset.Decode(mode, text)
if err != nil {
- t.Errorf("decoding %v %v failed (mode=%v): %v", insn.Name, hex.EncodeToString(text), mode, err)
+ t.Errorf("decoding %v %v failed (mode=%v): %v", insn.GetName(), hex.EncodeToString(text), mode, err)
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
failed = true
continue
}
- if XedDecode != nil {
- xedSize, xedErr := XedDecode(mode, text)
+ if xedEnabled {
+ xedSize, xedErr := insnset.DecodeExt(mode, text)
if xedErr != nil {
- t.Errorf("xed decoding %v %v failed (mode=%v): %v", insn.Name, hex.EncodeToString(text), mode, xedErr)
+ t.Errorf("xed decoding %v %v failed (mode=%v): %v", insn.GetName(), hex.EncodeToString(text), mode, xedErr)
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
@@ -76,7 +88,7 @@ func TestDecode(t *testing.T) {
}
if size != xedSize {
t.Errorf("decoding %v %v failed (mode=%v): decoded %v/%v, xed decoded %v/%v",
- insn.Name, hex.EncodeToString(text), mode, size, xedSize, size, len(text))
+ insn.GetName(), hex.EncodeToString(text), mode, size, xedSize, size, len(text))
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
@@ -84,13 +96,13 @@ func TestDecode(t *testing.T) {
continue
}
}
- if insn.Pseudo && size >= 0 && size < len(text) {
+ if insn.GetPseudo() && size >= 0 && size < len(text) {
text = text[size:]
goto repeat
}
if size != len(text) {
t.Errorf("decoding %v %v failed (mode=%v): decoded %v/%v",
- insn.Name, hex.EncodeToString(text), mode, size, len(text))
+ insn.GetName(), hex.EncodeToString(text), mode, size, len(text))
if len(text) != len(text0) {
t.Errorf("whole: %v", hex.EncodeToString(text0))
}
@@ -103,3 +115,7 @@ func TestDecode(t *testing.T) {
}
}
}
+
+func TestDecode(t *testing.T) {
+ testdecodearch(t, ifuzz.ArchX86)
+}
diff --git a/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go b/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go
new file mode 100644
index 000000000..f1ea64f37
--- /dev/null
+++ b/pkg/ifuzz/ifuzzimpl/ifuzzimpl.go
@@ -0,0 +1,145 @@
+// 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 ifuzzimpl
+
+import (
+ "github.com/google/syzkaller/pkg/ifuzz"
+ "math/rand"
+)
+
+var (
+ Types = make(map[string]ifuzz.InsnSet)
+)
+
+func Register(arch string, insns ifuzz.InsnSet) {
+ Types[arch] = insns
+}
+
+// ModeInsns returns list of all instructions for the given mode.
+func ModeInsns(cfg *ifuzz.Config) []ifuzz.Insn {
+ insnset := Types[cfg.Arch]
+ if cfg.Mode < 0 || cfg.Mode >= ifuzz.ModeLast {
+ panic("bad mode")
+ }
+ var insns []ifuzz.Insn
+ insns = append(insns, insnset.GetInsns(cfg.Mode, ifuzz.TypeUser)...)
+ if cfg.Priv {
+ insns = append(insns, insnset.GetInsns(cfg.Mode, ifuzz.TypePriv)...)
+ if cfg.Exec {
+ insns = append(insns, insnset.GetInsns(cfg.Mode, ifuzz.TypeExec)...)
+ }
+ }
+ return insns
+}
+
+func Generate(cfg *ifuzz.Config, r *rand.Rand) []byte {
+ var text []byte
+ for i := 0; i < cfg.Len; i++ {
+ insn := randInsn(cfg, r)
+ text = append(text, insn.Encode(cfg, r)...)
+ }
+ return text
+}
+
+func Mutate(cfg *ifuzz.Config, r *rand.Rand, text []byte) []byte {
+ insns := split(cfg, text)
+ retry := false
+ for stop := false; !stop || retry || len(insns) == 0; stop = r.Intn(2) == 0 {
+ retry = false
+ switch x := r.Intn(100); {
+ case x < 10 && len(insns) != 0:
+ // Delete instruction.
+ i := r.Intn(len(insns))
+ copy(insns[i:], insns[i+1:])
+ insns = insns[:len(insns)-1]
+ case x < 40 && len(insns) != 0:
+ // Replace instruction with another.
+ insn := randInsn(cfg, r)
+ text1 := insn.Encode(cfg, r)
+ i := r.Intn(len(insns))
+ insns[i] = text1
+ case x < 70 && len(insns) != 0:
+ // Mutate instruction.
+ i := r.Intn(len(insns))
+ text1 := insns[i]
+ for stop := false; !stop || len(text1) == 0; stop = r.Intn(2) == 0 {
+ switch x := r.Intn(100); {
+ case x < 5 && len(text1) != 0:
+ // Delete byte.
+ pos := r.Intn(len(text1))
+ copy(text1[pos:], text1[pos+1:])
+ text1 = text1[:len(text1)-1]
+ case x < 40 && len(text1) != 0:
+ // Replace a byte.
+ pos := r.Intn(len(text1))
+ text1[pos] = byte(r.Intn(256))
+ case x < 70 && len(text1) != 0:
+ // Flip a bit.
+ pos := r.Intn(len(text1))
+ text1[pos] ^= 1 << byte(r.Intn(8))
+ default:
+ // Insert a byte.
+ pos := r.Intn(len(text1) + 1)
+ text1 = append(text1, 0)
+ copy(text1[pos+1:], text1[pos:])
+ text1[pos] = byte(r.Intn(256))
+ }
+ }
+ insns[i] = text1
+ case len(insns) < cfg.Len:
+ // Insert a new instruction.
+ insn := randInsn(cfg, r)
+ text1 := insn.Encode(cfg, r)
+ i := r.Intn(len(insns) + 1)
+ insns = append(insns, nil)
+ copy(insns[i+1:], insns[i:])
+ insns[i] = text1
+ default:
+ retry = true
+ }
+ }
+ text = nil
+ for _, insn := range insns {
+ text = append(text, insn...)
+ }
+ return text
+}
+
+func randInsn(cfg *ifuzz.Config, r *rand.Rand) ifuzz.Insn {
+ insnset := Types[cfg.Arch]
+ var insns []ifuzz.Insn
+ if cfg.Priv && cfg.Exec {
+ insns = insnset.GetInsns(cfg.Mode, r.Intn(3))
+ } else if cfg.Priv {
+ insns = insnset.GetInsns(cfg.Mode, r.Intn(2))
+ } else {
+ insns = insnset.GetInsns(cfg.Mode, ifuzz.TypeUser)
+ }
+ return insns[r.Intn(len(insns))]
+}
+
+func split(cfg *ifuzz.Config, text []byte) [][]byte {
+ insnset := Types[cfg.Arch]
+ text = append([]byte{}, text...)
+ var insns [][]byte
+ var bad []byte
+ for len(text) != 0 {
+ n, err := insnset.Decode(cfg.Mode, text)
+ if err != nil || n == 0 {
+ bad = append(bad, text[0])
+ text = text[1:]
+ continue
+ }
+ if bad != nil {
+ insns = append(insns, bad)
+ bad = nil
+ }
+ insns = append(insns, text[:n])
+ text = text[n:]
+ }
+ if bad != nil {
+ insns = append(insns, bad)
+ }
+ return insns
+}
diff --git a/pkg/ifuzz/decode.go b/pkg/ifuzz/x86/decode.go
index 7fecf312c..ca611ac69 100644
--- a/pkg/ifuzz/decode.go
+++ b/pkg/ifuzz/x86/decode.go
@@ -1,29 +1,30 @@
// 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
+package x86
import (
"fmt"
+ "github.com/google/syzkaller/pkg/ifuzz"
)
// Decode decodes instruction length for the given mode.
// It can have falsely decode incorrect instructions,
// but should not fail to decode correct instructions.
// nolint: gocyclo, nestif, gocognit, funlen
-func Decode(mode int, text []byte) (int, error) {
+func (insnset *InsnSetX86) 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:
+ case ifuzz.ModeLong64:
operSize, immSize, dispSize, addrSize = 4, 4, 4, 8
prefixes = prefixes64
- case ModeProt32:
+ case ifuzz.ModeProt32:
operSize, immSize, dispSize, addrSize = 4, 4, 4, 4
- case ModeProt16, ModeReal16:
+ case ifuzz.ModeProt16, ifuzz.ModeReal16:
operSize, immSize, dispSize, addrSize = 2, 2, 2, 2
default:
panic("bad mode")
@@ -34,7 +35,7 @@ func Decode(mode int, text []byte) (int, error) {
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) {
+ if (text[0] == 0xc4 || text[0] == 0xc5) && (mode == ifuzz.ModeLong64 || text[1]&0xc0 == 0xc0) {
vex = true
}
// There is only one instruction that looks like XOP-prefixed but is actually not: POP.
@@ -95,7 +96,10 @@ func Decode(mode int, text []byte) (int, error) {
}
}
nextInsn:
- for _, insn := range modeInsns[mode][typeAll] {
+ for _, insn := range insnset.Insns {
+ if (insn.Mode & (1 << mode)) == 0 {
+ continue nextInsn
+ }
if vex != (insn.Vex != 0) {
continue nextInsn
}
@@ -220,3 +224,13 @@ var (
0x4e: true, 0x4f: true,
}
)
+
+func (insnset *InsnSetX86) DecodeExt(mode int, text []byte) (int, error) {
+ if XedDecode != nil && text != nil && len(text) > 0 {
+ return XedDecode(mode, text)
+ }
+ if XedDecode == nil {
+ return 0, fmt.Errorf("no XED")
+ }
+ return 0, nil // tells the caller XED is enabled
+}
diff --git a/pkg/ifuzz/encode.go b/pkg/ifuzz/x86/encode.go
index 5d27a29fd..b73a22c14 100644
--- a/pkg/ifuzz/encode.go
+++ b/pkg/ifuzz/x86/encode.go
@@ -5,15 +5,16 @@
// and AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions
// for details of instruction encoding.
-package ifuzz
+package x86
import (
+ "github.com/google/syzkaller/pkg/ifuzz"
"math/rand"
)
// nolint: gocyclo, nestif, gocognit, funlen
-func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte {
- if !insn.isCompatible(cfg) {
+func (insn *Insn) Encode(cfg *ifuzz.Config, r *rand.Rand) []byte {
+ if !insn.IsCompatible(cfg) {
panic("instruction is not suitable for this mode")
}
if insn.Pseudo {
@@ -22,11 +23,11 @@ func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte {
var operSize, immSize, dispSize, addrSize int
switch cfg.Mode {
- case ModeLong64:
+ case ifuzz.ModeLong64:
operSize, immSize, dispSize, addrSize = 4, 4, 4, 8
- case ModeProt32:
+ case ifuzz.ModeProt32:
operSize, immSize, dispSize, addrSize = 4, 4, 4, 4
- case ModeProt16, ModeReal16:
+ case ifuzz.ModeProt16, ifuzz.ModeReal16:
operSize, immSize, dispSize, addrSize = 2, 2, 2, 2
default:
panic("bad mode")
@@ -52,7 +53,7 @@ func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte {
if !insn.No66Prefix {
prefixes = append(prefixes, 0x66) // operand size
}
- if cfg.Mode == ModeLong64 || !insn.Mem32 {
+ if cfg.Mode == ifuzz.ModeLong64 || !insn.Mem32 {
prefixes = append(prefixes, 0x67) // address size
}
if !insn.NoRepPrefix {
@@ -69,7 +70,7 @@ func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte {
// REX
var rex byte
- if cfg.Mode == ModeLong64 && r.Intn(2) == 0 {
+ if cfg.Mode == ifuzz.ModeLong64 && r.Intn(2) == 0 {
// bit 0 - B
// bit 1 - X
// bit 2 - R
@@ -117,7 +118,7 @@ func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte {
code = append(code, insn.Vex)
vexR = byte(1)
vexX = byte(1)
- if cfg.Mode == ModeLong64 {
+ if cfg.Mode == ifuzz.ModeLong64 {
vexR = byte(r.Intn(2))
vexX = byte(r.Intn(2))
}
@@ -145,7 +146,7 @@ func (insn *Insn) Encode(cfg *Config, r *rand.Rand) []byte {
code = append(code, vexR<<7|vexX<<6|vexB<<5|insn.VexMap)
code = append(code, W<<7|vvvv<<3|L<<2|pp)
// TODO: short encoding
- if cfg.Mode != ModeLong64 {
+ if cfg.Mode != ifuzz.ModeLong64 {
vvvv |= 8
}
}
diff --git a/pkg/ifuzz/gen/all-enc-instructions.txt b/pkg/ifuzz/x86/gen/all-enc-instructions.txt
index 717ac8ec2..717ac8ec2 100644
--- a/pkg/ifuzz/gen/all-enc-instructions.txt
+++ b/pkg/ifuzz/x86/gen/all-enc-instructions.txt
diff --git a/pkg/ifuzz/gen/gen.go b/pkg/ifuzz/x86/gen/gen.go
index 654a3cf10..d1a490625 100644
--- a/pkg/ifuzz/gen/gen.go
+++ b/pkg/ifuzz/x86/gen/gen.go
@@ -1,7 +1,7 @@
// 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.
-// gen generates instruction tables (ifuzz/insns.go) from Intel XED tables.
+// gen generates instruction tables (ifuzz_types/insns.go) from Intel XED tables.
// Tables used to generate insns.go are checked in in all-enc-instructions.txt.
package main
@@ -14,6 +14,7 @@ import (
"strings"
"github.com/google/syzkaller/pkg/ifuzz"
+ "github.com/google/syzkaller/pkg/ifuzz/x86"
"github.com/google/syzkaller/pkg/serializer"
)
@@ -30,8 +31,8 @@ func main() {
skipped := 0
saved := ""
- var insns []*ifuzz.Insn
- var insn, insn1 *ifuzz.Insn
+ var insns []*x86.Insn
+ var insn, insn1 *x86.Insn
s := bufio.NewScanner(f)
for i := 1; s.Scan(); i++ {
reportError := func(msg string, args ...interface{}) {
@@ -53,7 +54,7 @@ func main() {
line = saved + line
saved = ""
if line == "{" {
- insn = new(ifuzz.Insn)
+ insn = new(x86.Insn)
continue
}
if line == "}" {
@@ -108,7 +109,7 @@ func main() {
if insn1 != nil {
insns = append(insns, insn1)
}
- insn1 = new(ifuzz.Insn)
+ insn1 = new(x86.Insn)
*insn1 = *insn
if err := parsePattern(insn1, vals); err != nil {
if _, ok := err.(errSkip); !ok {
@@ -137,7 +138,7 @@ func main() {
}
}
- var deduped []*ifuzz.Insn
+ var deduped []*x86.Insn
nextInsn:
for _, insn := range insns {
if insn.Extension == "AVX512VEX" || insn.Extension == "AVX512EVEX" {
@@ -163,12 +164,21 @@ nextInsn:
fmt.Fprintf(os.Stderr, "deduped %v instructions\n", len(insns)-len(deduped))
insns = deduped
- fmt.Printf("// Code generated by pkg/ifuzz/gen. DO NOT EDIT.\n\n")
- fmt.Printf("// +build !codeanalysis\n\n")
- fmt.Printf("package generated\n\n")
- fmt.Printf("import . \"github.com/google/syzkaller/pkg/ifuzz\"\n\n")
- fmt.Printf("func init() { Insns = insns }\n\n")
- fmt.Printf("var insns = ")
+ fmt.Printf(`
+// Code generated by pkg/ifuzz/gen. DO NOT EDIT.
+
+// +build !codeanalysis
+
+package x86
+
+import "github.com/google/syzkaller/pkg/ifuzz/x86"
+
+func init() {
+ x86.Register(insns_x86)
+}
+
+var insns_x86 = []*Insn{
+`)
serializer.Write(os.Stdout, insns)
fmt.Fprintf(os.Stderr, "handled %v, skipped %v\n", len(insns), skipped)
@@ -181,7 +191,7 @@ func (err errSkip) Error() string {
}
// nolint: gocyclo, gocognit, funlen
-func parsePattern(insn *ifuzz.Insn, vals []string) error {
+func parsePattern(insn *x86.Insn, vals []string) error {
if insn.Opcode != nil {
return fmt.Errorf("PATTERN is already parsed for the instruction")
}
@@ -490,7 +500,7 @@ func parsePattern(insn *ifuzz.Insn, vals []string) error {
return nil
}
-func parseOperands(insn *ifuzz.Insn, vals []string) error {
+func parseOperands(insn *x86.Insn, vals []string) error {
for _, v := range vals {
switch v {
case "REG0=SEG():r", "REG1=SEG():r", "REG0=SEG():w":
@@ -538,7 +548,7 @@ func parseModrm(v string) (int8, error) {
return vv, nil
}
-func addImm(insn *ifuzz.Insn, imm int8) {
+func addImm(insn *x86.Insn, imm int8) {
if insn.Imm == 0 {
insn.Imm = imm
return
diff --git a/pkg/ifuzz/generated/empty.go b/pkg/ifuzz/x86/generated/empty.go
index 35a053a49..35a053a49 100644
--- a/pkg/ifuzz/generated/empty.go
+++ b/pkg/ifuzz/x86/generated/empty.go
diff --git a/pkg/ifuzz/generated/insns.go b/pkg/ifuzz/x86/generated/insns.go
index 3a2f747fe..e66b34d72 100644
--- a/pkg/ifuzz/generated/insns.go
+++ b/pkg/ifuzz/x86/generated/insns.go
@@ -4,11 +4,13 @@
package generated
-import . "github.com/google/syzkaller/pkg/ifuzz"
+import "github.com/google/syzkaller/pkg/ifuzz/x86"
-func init() { Insns = insns }
+func init() {
+ x86.Register(insns)
+}
-var insns = []*Insn{
+var insns = []*x86.Insn{
{Name: "FADD", Extension: "X87", Mode: 15, Opcode: []uint8{216}, Modrm: true, Mod: -3, Rm: -1, Mem32: true, VexP: -1},
{Name: "FMUL", Extension: "X87", Mode: 15, Opcode: []uint8{216}, Modrm: true, Mod: -3, Reg: 1, Rm: -1, Mem32: true, VexP: -1},
{Name: "FCOMP", Extension: "X87", Mode: 15, Opcode: []uint8{216}, Modrm: true, Mod: -3, Reg: 3, Rm: -1, Mem32: true, VexP: -1},
diff --git a/pkg/ifuzz/pseudo.go b/pkg/ifuzz/x86/pseudo.go
index e9903f909..1efbcfbcc 100644
--- a/pkg/ifuzz/pseudo.go
+++ b/pkg/ifuzz/x86/pseudo.go
@@ -1,20 +1,21 @@
// 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
+package x86
import (
+ "github.com/google/syzkaller/pkg/ifuzz"
"math/rand"
)
// nolint: funlen
-func initPseudo() {
- Insns = append(Insns, &Insn{
+func (insnset *InsnSetX86) initPseudo() {
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_RDMSR",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
msr := msrs[r.Intn(len(msrs))]
gen.mov32(regECX, msr)
@@ -22,12 +23,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_WRMSR",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
msr := msrs[r.Intn(len(msrs))]
v := generateInt(cfg, r, 8)
@@ -38,12 +39,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_PCI_READ",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
addr, port, size := pciAddrPort(r)
gen.out32(0xcf8, addr)
@@ -51,12 +52,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_PCI_WRITE",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
addr, port, size := pciAddrPort(r)
val := generateInt(cfg, r, 4)
@@ -65,24 +66,24 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_PORT_READ",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
port := ports[r.Intn(len(ports))]
gen.in(port, r.Intn(3))
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_PORT_WRITE",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
port := ports[r.Intn(len(ports))]
val := generateInt(cfg, r, 4)
@@ -90,12 +91,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_XOR_CR",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
cr := controlRegisters[r.Intn(len(controlRegisters))]
var v uint32
@@ -111,12 +112,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_XOR_EFER",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
gen.mov32(regECX, eferMSR)
gen.byte(0x0f, 0x32) // rdmsr
@@ -126,18 +127,18 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_SET_BREAK",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
br := uint8(r.Intn(4))
loc := uint32(r.Intn(4))
typ := uint32(r.Intn(16))
addr := generateInt(cfg, r, 8)
- if cfg.Mode == ModeLong64 {
+ if cfg.Mode == ifuzz.ModeLong64 {
gen.mov64(regRAX, addr)
} else {
gen.mov32(regEAX, uint32(addr))
@@ -149,15 +150,15 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_LOAD_SEG",
- Mode: 1<<ModeLast - 1,
+ Mode: 1<<ifuzz.ModeLast - 1,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
sel := randSelector(r)
- if cfg.Mode == ModeReal16 {
+ if cfg.Mode == ifuzz.ModeReal16 {
sel = uint16(generateInt(cfg, r, 8)) >> 4
}
reg := uint8(r.Intn(6))
@@ -166,16 +167,16 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_FAR_JMP",
- Mode: 1<<ModeLong64 | 1<<ModeProt32 | 1<<ModeProt16,
+ Mode: 1<<ifuzz.ModeLong64 | 1<<ifuzz.ModeProt32 | 1<<ifuzz.ModeProt16,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
sel := randSelector(r)
off := generateInt(cfg, r, 4)
- if cfg.Mode == ModeLong64 {
+ if cfg.Mode == ifuzz.ModeLong64 {
gen.mov32toSPaddr(uint32(sel), 0)
gen.mov32toSPaddr(uint32(off), 2)
if r.Intn(2) == 0 {
@@ -189,7 +190,7 @@ func initPseudo() {
} else {
gen.byte(0x9a) // lcall $imm16, $imm16/32
}
- if cfg.Mode == ModeProt16 {
+ if cfg.Mode == ifuzz.ModeProt16 {
gen.imm16(uint16(off))
} else {
gen.imm32(uint32(off))
@@ -199,12 +200,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_LTR_LLDT",
- Mode: 1<<ModeLong64 | 1<<ModeProt32 | 1<<ModeProt16,
+ Mode: 1<<ifuzz.ModeLong64 | 1<<ifuzz.ModeProt32 | 1<<ifuzz.ModeProt16,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
sel := randSelector(r)
gen.mov16(regAX, sel)
@@ -216,12 +217,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_LGIDT",
- Mode: 1<<ModeLong64 | 1<<ModeProt32 | 1<<ModeProt16,
+ Mode: 1<<ifuzz.ModeLong64 | 1<<ifuzz.ModeProt32 | 1<<ifuzz.ModeProt16,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
limit := uint32(generateInt(cfg, r, 2))
base := uint32(generateInt(cfg, r, 4))
@@ -237,12 +238,12 @@ func initPseudo() {
return gen.text
},
})
- Insns = append(Insns, &Insn{
+ insnset.Insns = append(insnset.Insns, &Insn{
Name: "PSEUDO_HYPERCALL",
- Mode: 1<<ModeLong64 | 1<<ModeProt32 | 1<<ModeProt16,
+ Mode: 1<<ifuzz.ModeLong64 | 1<<ifuzz.ModeProt32 | 1<<ifuzz.ModeProt16,
Priv: true,
Pseudo: true,
- generator: func(cfg *Config, r *rand.Rand) []byte {
+ generator: func(cfg *ifuzz.Config, r *rand.Rand) []byte {
gen := makeGen(cfg, r)
switch r.Intn(2) {
case 0:
@@ -284,7 +285,7 @@ type generator struct {
text []byte
}
-func makeGen(cfg *Config, r *rand.Rand) *generator {
+func makeGen(cfg *ifuzz.Config, r *rand.Rand) *generator {
return &generator{
mode: cfg.Mode,
r: r,
@@ -310,9 +311,9 @@ func (gen *generator) imm64(v uint64) {
func (gen *generator) operand16() {
switch gen.mode {
- case ModeLong64, ModeProt32:
+ case ifuzz.ModeLong64, ifuzz.ModeProt32:
gen.byte(0x66)
- case ModeProt16, ModeReal16:
+ case ifuzz.ModeProt16, ifuzz.ModeReal16:
default:
panic("bad mode")
}
@@ -320,8 +321,8 @@ func (gen *generator) operand16() {
func (gen *generator) operand32() {
switch gen.mode {
- case ModeLong64, ModeProt32:
- case ModeProt16, ModeReal16:
+ case ifuzz.ModeLong64, ifuzz.ModeProt32:
+ case ifuzz.ModeProt16, ifuzz.ModeReal16:
gen.byte(0x66)
default:
panic("bad mode")
@@ -330,8 +331,8 @@ func (gen *generator) operand32() {
func (gen *generator) addr32() {
switch gen.mode {
- case ModeLong64, ModeProt32:
- case ModeProt16, ModeReal16:
+ case ifuzz.ModeLong64, ifuzz.ModeProt32:
+ case ifuzz.ModeProt16, ifuzz.ModeReal16:
gen.byte(0x67)
default:
panic("bad mode")
@@ -383,7 +384,7 @@ func (gen *generator) mov32(reg int, v uint32) {
}
func (gen *generator) mov64(reg int, v uint64) {
- if gen.mode != ModeLong64 {
+ if gen.mode != ifuzz.ModeLong64 {
panic("bad mode")
}
gen.byte(0x48)
diff --git a/pkg/ifuzz/x86/x86.go b/pkg/ifuzz/x86/x86.go
new file mode 100644
index 000000000..1583040ad
--- /dev/null
+++ b/pkg/ifuzz/x86/x86.go
@@ -0,0 +1,186 @@
+// 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.
+
+//go:generate bash -c "go run gen/gen.go gen/all-enc-instructions.txt > generated/insns.go"
+
+// Package x86 allows to generate and mutate x86 machine code.
+package x86
+
+import (
+ "github.com/google/syzkaller/pkg/ifuzz"
+ "github.com/google/syzkaller/pkg/ifuzz/ifuzzimpl"
+ "math/rand"
+)
+
+type Insn struct {
+ Name string
+ Extension string
+
+ Mode int // bitmask of compatible modes
+ Priv bool // CPL=0
+ Pseudo bool // pseudo instructions can consist of several real instructions
+
+ Opcode []byte
+ Prefix []byte
+ Suffix []byte
+ Modrm bool
+ Mod int8
+ Reg int8 // -6 - segment register, -8 - control register
+ Rm int8
+ Srm bool // register is embed in the first byte
+ NoSibDisp bool // no SIB/disp even if modrm says otherwise
+ Imm int8 // immediate size, -1 - immediate size, -2 - address size, -3 - operand size
+ Imm2 int8
+ NoRepPrefix bool
+ No66Prefix bool
+ Rexw int8 // 1 must be set, -1 must not be set
+ Mem32 bool // instruction always references 32-bit memory operand, 0x67 is illegal
+ Mem16 bool // instruction always references 16-bit memory operand
+
+ Vex byte
+ VexMap byte
+ VexL int8
+ VexNoR bool
+ VexP int8
+ Avx2Gather bool
+
+ generator func(cfg *ifuzz.Config, r *rand.Rand) []byte // for pseudo instructions
+}
+
+const (
+ typeExec = iota
+ typePriv
+ typeUser
+ typeAll
+ typeLast
+)
+
+type InsnSetX86 struct {
+ modeInsns [ifuzz.ModeLast][typeLast][]ifuzz.Insn
+ Insns []*Insn
+}
+
+func Register(insns []*Insn) {
+ var insnset InsnSetX86
+
+ insnset.Insns = insns
+ if len(insnset.Insns) == 0 {
+ panic("no instructions")
+ }
+ insnset.initPseudo()
+ for mode := 0; mode < ifuzz.ModeLast; mode++ {
+ for _, insn := range insnset.Insns {
+ if insn.Mode&(1<<uint(mode)) == 0 {
+ continue
+ }
+ if insn.Pseudo {
+ insnset.modeInsns[mode][typeExec] =
+ append(insnset.modeInsns[mode][typeExec], ifuzz.Insn(insn))
+ } else if insn.Priv {
+ insnset.modeInsns[mode][typePriv] =
+ append(insnset.modeInsns[mode][typePriv], ifuzz.Insn(insn))
+ insnset.modeInsns[mode][typeAll] =
+ append(insnset.modeInsns[mode][typeAll], ifuzz.Insn(insn))
+ } else {
+ insnset.modeInsns[mode][typeUser] =
+ append(insnset.modeInsns[mode][typeUser], ifuzz.Insn(insn))
+ insnset.modeInsns[mode][typeAll] =
+ append(insnset.modeInsns[mode][typeAll], ifuzz.Insn(insn))
+ }
+ }
+ }
+
+ ifuzzimpl.Register(ifuzz.ArchX86, ifuzz.InsnSet(&insnset))
+}
+
+func (insnset *InsnSetX86) GetInsns(mode, insntype int) []ifuzz.Insn {
+ return insnset.modeInsns[mode][insntype]
+}
+
+func (insn Insn) GetName() string {
+ return insn.Name
+}
+
+func (insn Insn) GetMode() int {
+ return insn.Mode
+}
+
+func (insn Insn) GetPriv() bool {
+ return insn.Priv
+}
+
+func (insn Insn) GetPseudo() bool {
+ return insn.Pseudo
+}
+
+func generateArg(cfg *ifuzz.Config, r *rand.Rand, size int) []byte {
+ v := generateInt(cfg, r, size)
+ arg := make([]byte, size)
+ for i := 0; i < size; i++ {
+ arg[i] = byte(v)
+ v >>= 8
+ }
+ return arg
+}
+
+func (insn Insn) IsCompatible(cfg *ifuzz.Config) bool {
+ if cfg.Mode < 0 || cfg.Mode >= ifuzz.ModeLast {
+ panic("bad mode")
+ }
+ if insn.Priv && !cfg.Priv {
+ return false
+ }
+ if insn.Pseudo && !cfg.Exec {
+ return false
+ }
+ if insn.Mode&(1<<uint(cfg.Mode)) == 0 {
+ return false
+ }
+ return true
+}
+
+func generateInt(cfg *ifuzz.Config, r *rand.Rand, size int) uint64 {
+ if size != 1 && size != 2 && size != 4 && size != 8 {
+ panic("bad arg size")
+ }
+ var v uint64
+ switch x := r.Intn(60); {
+ case x < 10:
+ v = uint64(r.Intn(1 << 4))
+ case x < 20:
+ v = uint64(r.Intn(1 << 16))
+ case x < 25:
+ v = uint64(r.Int63()) % (1 << 32)
+ case x < 30:
+ v = uint64(r.Int63())
+ case x < 40:
+ v = ifuzz.SpecialNumbers[r.Intn(len(ifuzz.SpecialNumbers))]
+ if r.Intn(5) == 0 {
+ v += uint64(r.Intn(33)) - 16
+ }
+ case x < 50 && len(cfg.MemRegions) != 0:
+ mem := cfg.MemRegions[r.Intn(len(cfg.MemRegions))]
+ switch x := r.Intn(100); {
+ case x < 25:
+ v = mem.Start
+ case x < 50:
+ v = mem.Start + mem.Size
+ case x < 75:
+ v = mem.Start + mem.Size/2
+ default:
+ v = mem.Start + uint64(r.Int63())%mem.Size
+ }
+ if r.Intn(10) == 0 {
+ v += uint64(r.Intn(33)) - 16
+ }
+ default:
+ v = uint64(r.Intn(1 << 8))
+ }
+ if r.Intn(50) == 0 {
+ v = uint64(-int64(v))
+ }
+ if r.Intn(50) == 0 && size != 1 {
+ v &^= 1<<12 - 1
+ }
+ return v
+}
diff --git a/pkg/ifuzz/xed.go b/pkg/ifuzz/x86/xed.go
index dfc66d82a..769ea8b68 100644
--- a/pkg/ifuzz/xed.go
+++ b/pkg/ifuzz/x86/xed.go
@@ -9,7 +9,7 @@
// +build xed
-package ifuzz
+package x86
/*
#include "xed-interface.h"