github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/ifuzz/iset/iset.go (about) 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 4 // Package iset ("instruction set") provides base and helper types for ifuzz arch implementations. 5 package iset 6 7 import ( 8 "math/rand" 9 ) 10 11 const ( 12 ArchX86 = "x86" 13 ArchPowerPC = "powerpc" 14 ArchArm64 = "arm64" 15 ) 16 17 var Arches = make(map[string]InsnSet) 18 19 type ( 20 Mode uint 21 Type uint 22 ) 23 24 type Insn interface { 25 Info() (name string, mode Mode, pseudo, priv bool) 26 Encode(cfg *Config, r *rand.Rand) []byte 27 } 28 29 type InsnSet interface { 30 GetInsns(mode Mode, typ Type) []Insn 31 Decode(mode Mode, text []byte) (int, error) 32 DecodeExt(mode Mode, text []byte) (int, error) // XED, to keep ifuzz_test happy 33 } 34 35 type Config struct { 36 Arch string 37 Len int // number of instructions to generate 38 Mode Mode // one of ModeXXX 39 Priv bool // generate CPL=0 instructions (x86), HV/!PR mode (PPC) 40 Exec bool // generate instructions sequences interesting for execution 41 MemRegions []MemRegion // generated instructions will reference these regions 42 } 43 44 type MemRegion struct { 45 Start uint64 46 Size uint64 47 } 48 49 const ( 50 ModeLong64 Mode = iota 51 ModeProt32 52 ModeProt16 53 ModeReal16 54 ModeLast 55 ) 56 57 const ( 58 TypeExec Type = iota 59 TypePriv 60 TypeUser 61 TypeAll 62 TypeLast 63 ) 64 65 var SpecialNumbers = [...]uint64{0, 1 << 15, 1 << 16, 1 << 31, 1 << 32, 1 << 47, 1 << 47, 1 << 63} 66 67 type ModeInsns [ModeLast][TypeLast][]Insn 68 69 func (modeInsns *ModeInsns) Add(insn Insn) { 70 _, mode, pseudo, priv := insn.Info() 71 for m := Mode(0); m < ModeLast; m++ { 72 if mode&(1<<uint(m)) == 0 { 73 continue 74 } 75 set := &modeInsns[m] 76 if pseudo { 77 set[TypeExec] = append(set[TypeExec], insn) 78 } else if priv { 79 set[TypePriv] = append(set[TypePriv], insn) 80 set[TypeAll] = append(set[TypeAll], insn) 81 } else { 82 set[TypeUser] = append(set[TypeUser], insn) 83 set[TypeAll] = append(set[TypeAll], insn) 84 } 85 } 86 } 87 88 func (cfg *Config) IsCompatible(insn Insn) bool { 89 _, mode, pseudo, priv := insn.Info() 90 if cfg.Mode >= ModeLast { 91 panic("bad mode") 92 } 93 if priv && !cfg.Priv { 94 return false 95 } 96 if pseudo && !cfg.Exec { 97 return false 98 } 99 if mode&(1<<uint(cfg.Mode)) == 0 { 100 return false 101 } 102 return true 103 } 104 105 func GenerateInt(cfg *Config, r *rand.Rand, size int) uint64 { 106 if size != 1 && size != 2 && size != 4 && size != 8 { 107 panic("bad arg size") 108 } 109 var v uint64 110 switch x := r.Intn(60); { 111 case x < 10: 112 v = uint64(r.Intn(1 << 4)) 113 case x < 20: 114 v = uint64(r.Intn(1 << 16)) 115 case x < 25: 116 v = uint64(r.Int63()) % (1 << 32) 117 case x < 30: 118 v = uint64(r.Int63()) 119 case x < 40: 120 v = SpecialNumbers[r.Intn(len(SpecialNumbers))] 121 if r.Intn(5) == 0 { 122 v += uint64(r.Intn(33)) - 16 123 } 124 case x < 50 && len(cfg.MemRegions) != 0: 125 mem := cfg.MemRegions[r.Intn(len(cfg.MemRegions))] 126 switch x := r.Intn(100); { 127 case x < 25: 128 v = mem.Start 129 case x < 50: 130 v = mem.Start + mem.Size 131 case x < 75: 132 v = mem.Start + mem.Size/2 133 default: 134 v = mem.Start + uint64(r.Int63())%mem.Size 135 } 136 if r.Intn(10) == 0 { 137 v += uint64(r.Intn(33)) - 16 138 } 139 default: 140 v = uint64(r.Intn(1 << 8)) 141 } 142 if r.Intn(50) == 0 { 143 v = uint64(-int64(v)) 144 } 145 if r.Intn(50) == 0 && size != 1 { 146 v &^= 1<<12 - 1 147 } 148 return v 149 }