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  }