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  }