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  }