github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/ifuzz/arm64/arm64.go (about) 1 // Copyright 2024 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 //go:generate bash -c "go run gen/gen.go gen/json/arm64.json | gofmt > generated/insns.go" 5 6 // Package arm64 allows to generate and mutate arm64 machine code. 7 package arm64 8 9 import ( 10 "encoding/binary" 11 "fmt" 12 "math/rand" 13 14 "github.com/google/syzkaller/pkg/ifuzz/iset" 15 ) 16 17 type InsnField struct { 18 Name string 19 Start uint // Little endian bit order. 20 Length uint 21 } 22 23 type Insn struct { 24 Name string 25 OpcodeMask uint32 26 Opcode uint32 27 Fields []InsnField 28 AsUInt32 uint32 29 Operands []uint32 30 Pseudo bool 31 Priv bool 32 Generator func(cfg *iset.Config, r *rand.Rand) []byte // for pseudo instructions 33 } 34 35 type InsnSet struct { 36 modeInsns iset.ModeInsns 37 Insns []*Insn 38 } 39 40 func Register(insns []*Insn) { 41 if len(insns) == 0 { 42 panic("no instructions") 43 } 44 insnset := &InsnSet{ 45 Insns: append(insns, pseudo...), 46 } 47 for _, insn := range insnset.Insns { 48 insnset.modeInsns.Add(insn) 49 } 50 iset.Arches[iset.ArchArm64] = insnset 51 templates = insns 52 } 53 54 func (insnset *InsnSet) GetInsns(mode iset.Mode, typ iset.Type) []iset.Insn { 55 return insnset.modeInsns[mode][typ] 56 } 57 58 func (insn *Insn) Info() (string, iset.Mode, bool, bool) { 59 return insn.Name, 1 << iset.ModeLong64, insn.Pseudo, insn.Priv 60 } 61 62 func (insn *Insn) Encode(cfg *iset.Config, r *rand.Rand) []byte { 63 if insn.Pseudo { 64 return insn.Generator(cfg, r) 65 } 66 ret := make([]byte, 4) 67 binary.LittleEndian.PutUint32(ret, insn.AsUInt32) 68 return ret 69 } 70 71 func (insnset *InsnSet) Decode(mode iset.Mode, text []byte) (int, error) { 72 if len(text) < 4 { 73 return 0, fmt.Errorf("must be at least 4 bytes") 74 } 75 opcode := binary.LittleEndian.Uint32(text[:4]) 76 _, err := ParseInsn(opcode) 77 if err != nil { 78 return 0, fmt.Errorf("failed to decode %x", opcode) 79 } 80 return 4, nil 81 } 82 83 func (insnset *InsnSet) DecodeExt(mode iset.Mode, text []byte) (int, error) { 84 return 0, fmt.Errorf("no external decoder") 85 } 86 87 var templates []*Insn 88 89 func (insn *Insn) initFromValue(val uint32) { 90 operands := []uint32{} 91 for _, field := range insn.Fields { 92 extracted := extractBits(val, field.Start, field.Length) 93 operands = append(operands, extracted) 94 } 95 insn.Operands = operands 96 insn.AsUInt32 = val 97 } 98 99 func (insn *Insn) matchesValue(val uint32) bool { 100 opcode := val & insn.OpcodeMask 101 return opcode == insn.Opcode 102 } 103 104 func ParseInsn(val uint32) (Insn, error) { 105 for _, tmpl := range templates { 106 if tmpl.matchesValue(val) { 107 newInsn := *tmpl 108 newInsn.initFromValue(val) 109 return newInsn, nil 110 } 111 } 112 unknown := Insn{ 113 Name: "unknown", 114 } 115 return unknown, fmt.Errorf("unrecognized instruction: %08x", val) 116 }