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