github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/ifuzz/arm64/gen/gen.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 // gen generates instruction tables (ifuzz_types/insns.go) from ARM64 JSON. 5 package main 6 7 import ( 8 "bytes" 9 "encoding/json" 10 "fmt" 11 "os" 12 "strconv" 13 "strings" 14 15 "github.com/google/syzkaller/pkg/ifuzz/arm64" 16 "github.com/google/syzkaller/pkg/osutil" 17 "github.com/google/syzkaller/pkg/serializer" 18 "github.com/google/syzkaller/pkg/tool" 19 ) 20 21 func main() { 22 if len(os.Args) != 3 { 23 tool.Failf("usage: gen arm64.json output.file") 24 } 25 jsonStr, err := os.ReadFile(os.Args[1]) 26 if err != nil { 27 tool.Failf("failed to open input file: %v", err) 28 } 29 insns := JSONToInsns(jsonStr) 30 31 out := new(bytes.Buffer) 32 fmt.Fprintf(out, `// Code generated by pkg/ifuzz/gen. DO NOT EDIT. 33 34 // go:build !codeanalysis 35 36 package generated 37 38 import ( 39 . "github.com/google/syzkaller/pkg/ifuzz/arm64" 40 ) 41 42 func init() { 43 Register(insns_arm64) 44 } 45 46 var insns_arm64 = 47 `) 48 serializer.Write(out, insns) 49 if err := osutil.WriteFileAtomically(os.Args[2], out.Bytes()); err != nil { 50 tool.Fail(err) 51 } 52 53 fmt.Fprintf(os.Stderr, "handled %v\n", len(insns)) 54 } 55 56 type insnDesc struct { 57 Name string 58 Bits string 59 Arch string 60 Syntax string 61 Code string 62 Alias string 63 } 64 65 func isPrivateInsn(insn arm64.Insn) bool { 66 switch insn.Name { 67 case "AT", "DC", "IC", "SYS", "SYSL", "TLBI": 68 return true 69 } 70 return false 71 } 72 73 func JSONToInsns(jsonStr []byte) []*arm64.Insn { 74 var insnDescriptions []insnDesc 75 err := json.Unmarshal(jsonStr, &insnDescriptions) 76 if err != nil { 77 return nil 78 } 79 ret := []*arm64.Insn{} 80 for _, desc := range insnDescriptions { 81 mask := uint32(0) 82 opcode := uint32(0) 83 curBit := uint(31) 84 fields := []arm64.InsnField{} 85 pieces := strings.Split(desc.Bits, "|") 86 for _, piece := range pieces { 87 size := uint(1) 88 pair := strings.Split(piece, ":") 89 var pattern = piece 90 if len(pair) == 2 { 91 size64, err := strconv.ParseUint(pair[1], 10, 0) 92 if err != nil { 93 return nil 94 } 95 size = uint(size64) 96 pattern = pair[0] 97 } 98 updateOpcode := true 99 opPart := uint32(0) 100 maskPart := uint32(0) 101 if pattern[0:1] != "(" { 102 number, err := strconv.ParseUint(pattern, 2, 32) 103 if err != nil { 104 // This is a named region. 105 field := arm64.InsnField{ 106 Name: pattern, 107 Start: curBit, 108 Length: size, 109 } 110 fields = append(fields, field) 111 updateOpcode = false 112 } else { 113 // This is a binary mask. 114 opPart = uint32(number) 115 maskPart = ((1 << size) - 1) 116 } 117 } 118 opcode <<= size 119 mask <<= size 120 curBit -= size 121 if updateOpcode { 122 opcode |= opPart 123 mask |= maskPart 124 } 125 } 126 templ := arm64.Insn{ 127 Name: desc.Name, 128 OpcodeMask: mask, 129 Opcode: opcode, 130 Fields: fields, 131 AsUInt32: opcode, 132 } 133 templ.Priv = isPrivateInsn(templ) 134 insn := new(arm64.Insn) 135 *insn = templ 136 ret = append(ret, insn) 137 } 138 return ret 139 }