golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/linux/mkall.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // linux/mkall.go - Generates all Linux zsysnum, zsyscall, zerror, and ztype
     6  // files for all Linux architectures supported by the go compiler. See
     7  // README.md for more information about the build system.
     8  
     9  // To run it you must have a git checkout of the Linux kernel and glibc. Once
    10  // the appropriate sources are ready, the program is run as:
    11  //     go run linux/mkall.go <linux_dir> <glibc_dir>
    12  
    13  //go:build ignore
    14  
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"bytes"
    20  	"debug/elf"
    21  	"encoding/binary"
    22  	"errors"
    23  	"fmt"
    24  	"go/build/constraint"
    25  	"io"
    26  	"os"
    27  	"os/exec"
    28  	"path/filepath"
    29  	"runtime"
    30  	"strings"
    31  	"sync"
    32  	"unicode"
    33  )
    34  
    35  // These will be paths to the appropriate source directories.
    36  var LinuxDir string
    37  var GlibcDir string
    38  
    39  const TempDir = "/tmp"
    40  
    41  const GOOS = "linux"       // Only for Linux targets
    42  const BuildArch = "amd64"  // Must be built on this architecture
    43  const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements
    44  
    45  type target struct {
    46  	GoArch     string // Architecture name according to Go
    47  	LinuxArch  string // Architecture name according to the Linux Kernel
    48  	GNUArch    string // Architecture name according to GNU tools (https://wiki.debian.org/Multiarch/Tuples)
    49  	BigEndian  bool   // Default Little Endian
    50  	SignedChar bool   // Is -fsigned-char needed (default no)
    51  	Bits       int
    52  	env        []string
    53  	stderrBuf  bytes.Buffer
    54  	compiler   string
    55  }
    56  
    57  // List of all Linux targets supported by the go compiler. Currently, sparc64 is
    58  // not fully supported, but there is enough support already to generate Go type
    59  // and error definitions.
    60  var targets = []target{
    61  	{
    62  		GoArch:    "386",
    63  		LinuxArch: "x86",
    64  		GNUArch:   "i686-linux-gnu", // Note "i686" not "i386"
    65  		Bits:      32,
    66  	},
    67  	{
    68  		GoArch:    "amd64",
    69  		LinuxArch: "x86",
    70  		GNUArch:   "x86_64-linux-gnu",
    71  		Bits:      64,
    72  	},
    73  	{
    74  		GoArch:     "arm64",
    75  		LinuxArch:  "arm64",
    76  		GNUArch:    "aarch64-linux-gnu",
    77  		SignedChar: true,
    78  		Bits:       64,
    79  	},
    80  	{
    81  		GoArch:    "arm",
    82  		LinuxArch: "arm",
    83  		GNUArch:   "arm-linux-gnueabi",
    84  		Bits:      32,
    85  	},
    86  	{
    87  		GoArch:    "loong64",
    88  		LinuxArch: "loongarch",
    89  		GNUArch:   "loongarch64-linux-gnu",
    90  		Bits:      64,
    91  	},
    92  	{
    93  		GoArch:    "mips",
    94  		LinuxArch: "mips",
    95  		GNUArch:   "mips-linux-gnu",
    96  		BigEndian: true,
    97  		Bits:      32,
    98  	},
    99  	{
   100  		GoArch:    "mipsle",
   101  		LinuxArch: "mips",
   102  		GNUArch:   "mipsel-linux-gnu",
   103  		Bits:      32,
   104  	},
   105  	{
   106  		GoArch:    "mips64",
   107  		LinuxArch: "mips",
   108  		GNUArch:   "mips64-linux-gnuabi64",
   109  		BigEndian: true,
   110  		Bits:      64,
   111  	},
   112  	{
   113  		GoArch:    "mips64le",
   114  		LinuxArch: "mips",
   115  		GNUArch:   "mips64el-linux-gnuabi64",
   116  		Bits:      64,
   117  	},
   118  	{
   119  		GoArch:    "ppc",
   120  		LinuxArch: "powerpc",
   121  		GNUArch:   "powerpc-linux-gnu",
   122  		BigEndian: true,
   123  		Bits:      32,
   124  	},
   125  	{
   126  		GoArch:    "ppc64",
   127  		LinuxArch: "powerpc",
   128  		GNUArch:   "powerpc64-linux-gnu",
   129  		BigEndian: true,
   130  		Bits:      64,
   131  	},
   132  	{
   133  		GoArch:    "ppc64le",
   134  		LinuxArch: "powerpc",
   135  		GNUArch:   "powerpc64le-linux-gnu",
   136  		Bits:      64,
   137  	},
   138  	{
   139  		GoArch:    "riscv64",
   140  		LinuxArch: "riscv",
   141  		GNUArch:   "riscv64-linux-gnu",
   142  		Bits:      64,
   143  	},
   144  	{
   145  		GoArch:     "s390x",
   146  		LinuxArch:  "s390",
   147  		GNUArch:    "s390x-linux-gnu",
   148  		BigEndian:  true,
   149  		SignedChar: true,
   150  		Bits:       64,
   151  	},
   152  	{
   153  		GoArch:    "sparc64",
   154  		LinuxArch: "sparc",
   155  		GNUArch:   "sparc64-linux-gnu",
   156  		BigEndian: true,
   157  		Bits:      64,
   158  	},
   159  }
   160  
   161  // ptracePairs is a list of pairs of targets that can, in some cases,
   162  // run each other's binaries. 'archName' is the combined name of 'a1'
   163  // and 'a2', which is used in the file name. Generally we use an 'x'
   164  // suffix in the file name to indicate that the file works for both
   165  // big-endian and little-endian, here we use 'nn' to indicate that this
   166  // file is suitable for 32-bit and 64-bit.
   167  var ptracePairs = []struct{ a1, a2, archName string }{
   168  	{"386", "amd64", "x86"},
   169  	{"arm", "arm64", "armnn"},
   170  	{"mips", "mips64", "mipsnn"},
   171  	{"mipsle", "mips64le", "mipsnnle"},
   172  }
   173  
   174  func main() {
   175  	if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch {
   176  		fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n",
   177  			runtime.GOOS, runtime.GOARCH, GOOS, BuildArch)
   178  		return
   179  	}
   180  
   181  	// Check that we are using the new build system if we should
   182  	if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
   183  		fmt.Println("In the new build system, mkall.go should not be called directly.")
   184  		fmt.Println("See README.md")
   185  		return
   186  	}
   187  
   188  	// Parse the command line options
   189  	if len(os.Args) != 3 {
   190  		fmt.Println("USAGE: go run linux/mkall.go <linux_dir> <glibc_dir>")
   191  		return
   192  	}
   193  	LinuxDir = os.Args[1]
   194  	GlibcDir = os.Args[2]
   195  
   196  	wg := sync.WaitGroup{}
   197  	for _, t := range targets {
   198  		fmt.Printf("arch %s: GENERATING\n", t.GoArch)
   199  		if err := t.setupEnvironment(); err != nil {
   200  			fmt.Printf("arch %s: could not setup environment: %v\n", t.GoArch, err)
   201  			break
   202  		}
   203  		includeDir := filepath.Join(TempDir, t.GoArch, "include")
   204  		// Make the include directory and fill it with headers
   205  		if err := os.MkdirAll(includeDir, os.ModePerm); err != nil {
   206  			fmt.Printf("arch %s: could not make directory: %v\n", t.GoArch, err)
   207  			break
   208  		}
   209  		// During header generation "/git/linux/scripts/basic/fixdep" is created by "basic/Makefile" for each
   210  		// instance of "make headers_install". This leads to a "text file is busy" error from any running
   211  		// "make headers_install" after the first one's target. Workaround is to serialize header generation
   212  		if err := t.makeHeaders(); err != nil {
   213  			fmt.Printf("arch %s: could not make header files: %v\n", t.GoArch, err)
   214  			break
   215  		}
   216  		wg.Add(1)
   217  		go func(t target) {
   218  			defer wg.Done()
   219  			fmt.Printf("arch %s: header files generated\n", t.GoArch)
   220  			if err := t.generateFiles(); err != nil {
   221  				fmt.Printf("%v\n***** FAILURE:    %s *****\n\n", err, t.GoArch)
   222  			} else {
   223  				fmt.Printf("arch %s: SUCCESS\n", t.GoArch)
   224  			}
   225  		}(t)
   226  	}
   227  	wg.Wait()
   228  
   229  	fmt.Printf("----- GENERATING: merging generated files -----\n")
   230  	if err := mergeFiles(); err != nil {
   231  		fmt.Printf("%v\n***** FAILURE:    merging generated files *****\n\n", err)
   232  	} else {
   233  		fmt.Printf("----- SUCCESS:    merging generated files -----\n\n")
   234  	}
   235  
   236  	fmt.Printf("----- GENERATING ptrace pairs -----\n")
   237  	ok := true
   238  	for _, p := range ptracePairs {
   239  		if err := generatePtracePair(p.a1, p.a2, p.archName); err != nil {
   240  			fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2)
   241  			ok = false
   242  		}
   243  	}
   244  	// generate functions PtraceGetRegSetArm64 and PtraceSetRegSetArm64.
   245  	if err := generatePtraceRegSet("arm64"); err != nil {
   246  		fmt.Printf("%v\n***** FAILURE: generatePtraceRegSet(%q) *****\n\n", err, "arm64")
   247  		ok = false
   248  	}
   249  	if ok {
   250  		fmt.Printf("----- SUCCESS ptrace pairs    -----\n\n")
   251  	}
   252  }
   253  
   254  func (t *target) printAndResetBuilder() {
   255  	if t.stderrBuf.Len() > 0 {
   256  		for _, l := range bytes.Split(t.stderrBuf.Bytes(), []byte{'\n'}) {
   257  			fmt.Printf("arch %s: stderr: %s\n", t.GoArch, l)
   258  		}
   259  		t.stderrBuf.Reset()
   260  	}
   261  }
   262  
   263  // Makes an exec.Cmd with Stderr attached to the target string Builder, and target environment
   264  func (t *target) makeCommand(name string, args ...string) *exec.Cmd {
   265  	cmd := exec.Command(name, args...)
   266  	cmd.Env = t.env
   267  	cmd.Stderr = &t.stderrBuf
   268  	return cmd
   269  }
   270  
   271  // Set GOARCH for target and build environments.
   272  func (t *target) setTargetBuildArch(cmd *exec.Cmd) {
   273  	// Set GOARCH_TARGET so command knows what GOARCH is..
   274  	var env []string
   275  	env = append(env, t.env...)
   276  	cmd.Env = append(env, "GOARCH_TARGET="+t.GoArch)
   277  	// Set GOARCH to host arch for command, so it can run natively.
   278  	for i, s := range cmd.Env {
   279  		if strings.HasPrefix(s, "GOARCH=") {
   280  			cmd.Env[i] = "GOARCH=" + BuildArch
   281  		}
   282  	}
   283  }
   284  
   285  // Runs the command, pipes output to a formatter, pipes that to an output file.
   286  func (t *target) commandFormatOutput(formatter string, outputFile string,
   287  	name string, args ...string) (err error) {
   288  	mainCmd := t.makeCommand(name, args...)
   289  	if name == "mksyscall" {
   290  		args = append([]string{"run", "mksyscall.go"}, args...)
   291  		mainCmd = t.makeCommand("go", args...)
   292  		t.setTargetBuildArch(mainCmd)
   293  	} else if name == "mksysnum" {
   294  		args = append([]string{"run", "linux/mksysnum.go"}, args...)
   295  		mainCmd = t.makeCommand("go", args...)
   296  		t.setTargetBuildArch(mainCmd)
   297  	}
   298  
   299  	fmtCmd := t.makeCommand(formatter)
   300  	if formatter == "mkpost" {
   301  		fmtCmd = t.makeCommand("go", "run", "mkpost.go")
   302  		t.setTargetBuildArch(fmtCmd)
   303  	} else if formatter == "gofmt2" {
   304  		fmtCmd = t.makeCommand("gofmt")
   305  		mainCmd.Dir = filepath.Join(TempDir, t.GoArch, "mkerrors")
   306  		if err = os.MkdirAll(mainCmd.Dir, os.ModePerm); err != nil {
   307  			return err
   308  		}
   309  	}
   310  
   311  	defer t.printAndResetBuilder()
   312  
   313  	// mainCmd | fmtCmd > outputFile
   314  	if fmtCmd.Stdin, err = mainCmd.StdoutPipe(); err != nil {
   315  		return
   316  	}
   317  	if fmtCmd.Stdout, err = os.Create(outputFile); err != nil {
   318  		return
   319  	}
   320  
   321  	// Make sure the formatter eventually closes
   322  	if err = fmtCmd.Start(); err != nil {
   323  		return
   324  	}
   325  	defer func() {
   326  		fmtErr := fmtCmd.Wait()
   327  		if err == nil {
   328  			err = fmtErr
   329  		}
   330  	}()
   331  
   332  	return mainCmd.Run()
   333  }
   334  
   335  func (t *target) setupEnvironment() error {
   336  	// Setup environment variables
   337  	t.env = append(os.Environ(), fmt.Sprintf("%s=%s", "GOOS", GOOS))
   338  	t.env = append(t.env, fmt.Sprintf("%s=%s", "GOARCH", t.GoArch))
   339  
   340  	// Get appropriate compiler and emulator (unless on x86)
   341  	if t.LinuxArch != "x86" {
   342  		// Check/Setup cross compiler
   343  		t.compiler = t.GNUArch + "-gcc"
   344  		if _, err := exec.LookPath(t.compiler); err != nil {
   345  			return err
   346  		}
   347  		t.env = append(t.env, fmt.Sprintf("%s=%s", "CC", t.compiler))
   348  
   349  		// Check/Setup emulator (usually first component of GNUArch)
   350  		qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")]
   351  		if t.LinuxArch == "powerpc" {
   352  			qemuArchName = t.GoArch
   353  		}
   354  		// Fake uname for QEMU to allow running on Host kernel version < 4.15
   355  		if t.LinuxArch == "riscv" {
   356  			t.env = append(t.env, fmt.Sprintf("%s=%s", "QEMU_UNAME", "4.15"))
   357  		}
   358  		t.env = append(t.env, fmt.Sprintf("%s=%s", "GORUN", "qemu-"+qemuArchName))
   359  	} else {
   360  		t.compiler = "gcc"
   361  		t.env = append(t.env, fmt.Sprintf("%s=%s", "CC", "gcc"))
   362  	}
   363  	return nil
   364  }
   365  
   366  // Generates all the files for a Linux target
   367  func (t *target) generateFiles() error {
   368  	// Make each of the four files
   369  	if err := t.makeZSysnumFile(); err != nil {
   370  		return fmt.Errorf("could not make zsysnum file: %v", err)
   371  	}
   372  	fmt.Printf("arch %s: zsysnum file generated\n", t.GoArch)
   373  
   374  	if err := t.makeZSyscallFile(); err != nil {
   375  		return fmt.Errorf("could not make zsyscall file: %v", err)
   376  	}
   377  	fmt.Printf("arch %s: zsyscall file generated\n", t.GoArch)
   378  
   379  	if err := t.makeZTypesFile(); err != nil {
   380  		return fmt.Errorf("could not make ztypes file: %v", err)
   381  	}
   382  	fmt.Printf("arch %s: ztypes file generated\n", t.GoArch)
   383  
   384  	if err := t.makeZErrorsFile(); err != nil {
   385  		return fmt.Errorf("could not make zerrors file: %v", err)
   386  	}
   387  	fmt.Printf("arch %s: zerrors file generated\n", t.GoArch)
   388  
   389  	return nil
   390  }
   391  
   392  // Create the Linux, glibc and ABI (C compiler convention) headers in the include directory.
   393  func (t *target) makeHeaders() error {
   394  	defer t.printAndResetBuilder()
   395  
   396  	// Make the Linux headers we need for this architecture
   397  	linuxMake := t.makeCommand("make", "headers_install", "ARCH="+t.LinuxArch, "INSTALL_HDR_PATH="+filepath.Join(TempDir, t.GoArch))
   398  	linuxMake.Dir = LinuxDir
   399  	if err := linuxMake.Run(); err != nil {
   400  		return err
   401  	}
   402  
   403  	buildDir := filepath.Join(TempDir, t.GoArch, "build")
   404  	// A Temporary build directory for glibc
   405  	if err := os.MkdirAll(buildDir, os.ModePerm); err != nil {
   406  		return err
   407  	}
   408  	defer os.RemoveAll(buildDir)
   409  
   410  	// Make the glibc headers we need for this architecture
   411  	confScript := filepath.Join(GlibcDir, "configure")
   412  	glibcArgs := []string{"--prefix=" + filepath.Join(TempDir, t.GoArch), "--host=" + t.GNUArch}
   413  	if t.LinuxArch == "loongarch" {
   414  		// The minimum version requirement of the Loongarch for the kernel in glibc
   415  		// is 5.19, if --enable-kernel is less than 5.19, glibc handles errors
   416  		glibcArgs = append(glibcArgs, "--enable-kernel=5.19.0")
   417  	} else {
   418  		glibcArgs = append(glibcArgs, "--enable-kernel="+MinKernel)
   419  	}
   420  
   421  	// CET is not supported on x86 but glibc 2.39 enables it by default, it was later reverted.
   422  	// See https://sourceware.org/git/?p=glibc.git;a=commit;h=25f1e16ef03a6a8fb1701c4647d46c564480d88c
   423  	if t.LinuxArch == "x86" {
   424  		glibcArgs = append(glibcArgs, "--enable-cet=no")
   425  	}
   426  
   427  	// glibc 2.38 requires libmvec to be disabled explicitly in aarch64
   428  	// since the installed compiler does not have SVE ACLE.
   429  	// See https://sourceware.org/pipermail/libc-alpha/2023-May/147829.html
   430  	if t.LinuxArch == "arm64" {
   431  		glibcArgs = append(glibcArgs, "--disable-mathvec")
   432  	}
   433  
   434  	glibcConf := t.makeCommand(confScript, glibcArgs...)
   435  
   436  	glibcConf.Dir = buildDir
   437  	if err := glibcConf.Run(); err != nil {
   438  		return err
   439  	}
   440  	glibcMake := t.makeCommand("make", "install-headers")
   441  	glibcMake.Dir = buildDir
   442  	if err := glibcMake.Run(); err != nil {
   443  		return err
   444  	}
   445  	// We only need an empty stubs file
   446  	stubsFile := filepath.Join(TempDir, t.GoArch, "include", "gnu", "stubs.h")
   447  	if file, err := os.Create(stubsFile); err != nil {
   448  		return err
   449  	} else {
   450  		file.Close()
   451  	}
   452  
   453  	// ABI headers will specify C compiler behavior for the target platform.
   454  	return t.makeABIHeaders()
   455  }
   456  
   457  // makeABIHeaders generates C header files based on the platform's calling convention.
   458  // While many platforms have formal Application Binary Interfaces, in practice, whatever the
   459  // dominant C compilers generate is the de-facto calling convention.
   460  //
   461  // We generate C headers instead of a Go file, so as to enable references to the ABI from Cgo.
   462  func (t *target) makeABIHeaders() (err error) {
   463  	abiDir := filepath.Join(TempDir, t.GoArch, "include", "abi")
   464  	if err = os.Mkdir(abiDir, os.ModePerm); err != nil {
   465  		return err
   466  	}
   467  
   468  	if t.compiler == "" {
   469  		return errors.New("CC (compiler) env var not set")
   470  	}
   471  
   472  	// Build a sacrificial ELF file, to mine for C compiler behavior.
   473  	binPath := filepath.Join(TempDir, t.GoArch, "tmp_abi.o")
   474  	bin, err := t.buildELF(t.compiler, cCode, binPath)
   475  	if err != nil {
   476  		return fmt.Errorf("cannot build ELF to analyze: %v", err)
   477  	}
   478  	defer bin.Close()
   479  	defer os.Remove(binPath)
   480  
   481  	// Right now, we put everything in abi.h, but we may change this later.
   482  	abiFile, err := os.Create(filepath.Join(abiDir, "abi.h"))
   483  	if err != nil {
   484  		return err
   485  	}
   486  	defer func() {
   487  		if cerr := abiFile.Close(); cerr != nil && err == nil {
   488  			err = cerr
   489  		}
   490  	}()
   491  
   492  	if err = t.writeBitFieldMasks(bin, abiFile); err != nil {
   493  		return fmt.Errorf("cannot write bitfield masks: %v", err)
   494  	}
   495  
   496  	return nil
   497  }
   498  
   499  func (t *target) buildELF(cc, src, path string) (*elf.File, error) {
   500  	// Compile the cCode source using the set compiler - we will need its .data section.
   501  	// Do not link the binary, so that we can find .data section offsets from the symbol values.
   502  	ccCmd := t.makeCommand(cc, "-o", path, "-gdwarf", "-x", "c", "-c", "-")
   503  	ccCmd.Stdin = strings.NewReader(src)
   504  	ccCmd.Stdout = os.Stdout
   505  	defer t.printAndResetBuilder()
   506  	if err := ccCmd.Run(); err != nil {
   507  		return nil, fmt.Errorf("compiler error: %v", err)
   508  	}
   509  
   510  	bin, err := elf.Open(path)
   511  	if err != nil {
   512  		return nil, fmt.Errorf("cannot read ELF file %s: %v", path, err)
   513  	}
   514  
   515  	return bin, nil
   516  }
   517  
   518  func (t *target) writeBitFieldMasks(bin *elf.File, out io.Writer) error {
   519  	symbols, err := bin.Symbols()
   520  	if err != nil {
   521  		return fmt.Errorf("getting ELF symbols: %v", err)
   522  	}
   523  	var masksSym *elf.Symbol
   524  
   525  	for _, sym := range symbols {
   526  		if sym.Name == "masks" {
   527  			masksSym = &sym
   528  		}
   529  	}
   530  
   531  	if masksSym == nil {
   532  		return errors.New("could not find the 'masks' symbol in ELF symtab")
   533  	}
   534  
   535  	dataSection := bin.Section(".data")
   536  	if dataSection == nil {
   537  		return errors.New("ELF file has no .data section")
   538  	}
   539  
   540  	data, err := dataSection.Data()
   541  	if err != nil {
   542  		return fmt.Errorf("could not read .data section: %v\n", err)
   543  	}
   544  
   545  	var bo binary.ByteOrder
   546  	if t.BigEndian {
   547  		bo = binary.BigEndian
   548  	} else {
   549  		bo = binary.LittleEndian
   550  	}
   551  
   552  	// 64 bit masks of type uint64 are stored in the data section starting at masks.Value.
   553  	// Here we are running on AMD64, but these values may be big endian or little endian,
   554  	// depending on target architecture.
   555  	for i := uint64(0); i < 64; i++ {
   556  		off := masksSym.Value + i*8
   557  		// Define each mask in native by order, so as to match target endian.
   558  		fmt.Fprintf(out, "#define BITFIELD_MASK_%d %dULL\n", i, bo.Uint64(data[off:off+8]))
   559  	}
   560  
   561  	return nil
   562  }
   563  
   564  // makes the zsysnum_linux_$GOARCH.go file
   565  func (t *target) makeZSysnumFile() error {
   566  	zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch)
   567  	unistdFile := filepath.Join(TempDir, t.GoArch, "include", "asm", "unistd.h")
   568  
   569  	args := append(t.cFlags(), unistdFile)
   570  	return t.commandFormatOutput("gofmt", zsysnumFile, "mksysnum", args...)
   571  }
   572  
   573  // makes the zsyscall_linux_$GOARCH.go file
   574  func (t *target) makeZSyscallFile() error {
   575  	zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch)
   576  	// Find the correct architecture syscall file (might end with x.go)
   577  	archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch)
   578  	if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) {
   579  		shortArch := strings.TrimSuffix(t.GoArch, "le")
   580  		archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch)
   581  	}
   582  
   583  	args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch,
   584  		"syscall_linux.go",
   585  		archSyscallFile,
   586  	)
   587  
   588  	files, err := t.archMksyscallFiles()
   589  	if err != nil {
   590  		return fmt.Errorf("failed to check GOARCH-specific mksyscall files: %v", err)
   591  	}
   592  	args = append(args, files...)
   593  
   594  	return t.commandFormatOutput("gofmt", zsyscallFile, "mksyscall", args...)
   595  }
   596  
   597  // archMksyscallFiles produces additional file arguments to mksyscall if the
   598  // build constraints in those files match those defined for target.
   599  func (t *target) archMksyscallFiles() ([]string, error) {
   600  	// These input files don't fit the typical GOOS/GOARCH file name conventions
   601  	// but are included conditionally in the arguments to mksyscall based on
   602  	// whether or not the target matches the build constraints defined in each
   603  	// file.
   604  	//
   605  	// TODO(mdlayher): it should be possible to generalize this approach to work
   606  	// over all of syscall_linux_* rather than hard-coding a few special files.
   607  	// Investigate this.
   608  	inputs := []string{
   609  		// GOARCH: all except arm* and riscv.
   610  		"syscall_linux_alarm.go",
   611  	}
   612  
   613  	var outputs []string
   614  	for _, in := range inputs {
   615  		ok, err := t.matchesMksyscallFile(in)
   616  		if err != nil {
   617  			return nil, fmt.Errorf("failed to parse file %q: %v", in, err)
   618  		}
   619  		if ok {
   620  			// Constraints match, use for this target's code generation.
   621  			outputs = append(outputs, in)
   622  		}
   623  	}
   624  
   625  	return outputs, nil
   626  }
   627  
   628  // matchesMksyscallFile reports whether the input file contains constraints
   629  // which match those defined for target.
   630  func (t *target) matchesMksyscallFile(file string) (bool, error) {
   631  	f, err := os.Open(file)
   632  	if err != nil {
   633  		return false, err
   634  	}
   635  	defer f.Close()
   636  
   637  	var (
   638  		expr  constraint.Expr
   639  		found bool
   640  	)
   641  
   642  	s := bufio.NewScanner(f)
   643  	for s.Scan() {
   644  		// Keep scanning until a valid constraint is found or we hit EOF.
   645  		// This is sufficient for the single-line //go:build constraints.
   646  		if expr, err = constraint.Parse(s.Text()); err == nil {
   647  			found = true
   648  			break
   649  		}
   650  	}
   651  	if err := s.Err(); err != nil {
   652  		return false, err
   653  	}
   654  	if !found {
   655  		return false, errors.New("no build constraints found")
   656  	}
   657  
   658  	// Do the defined constraints match target's GOOS/GOARCH?
   659  	ok := expr.Eval(func(tag string) bool {
   660  		return tag == GOOS || tag == t.GoArch
   661  	})
   662  
   663  	return ok, nil
   664  }
   665  
   666  // makes the zerrors_linux_$GOARCH.go file
   667  func (t *target) makeZErrorsFile() error {
   668  	zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch)
   669  	return t.commandFormatOutput("gofmt2", zerrorsFile, "/"+filepath.Join("build", "unix", "mkerrors.sh"), t.cFlags()...)
   670  }
   671  
   672  // makes the ztypes_linux_$GOARCH.go file
   673  func (t *target) makeZTypesFile() error {
   674  	ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch)
   675  
   676  	cgoDir := filepath.Join(TempDir, t.GoArch, "cgo")
   677  	if err := os.MkdirAll(cgoDir, os.ModePerm); err != nil {
   678  		return err
   679  	}
   680  
   681  	args := []string{"tool", "cgo", "-godefs", "-objdir=" + cgoDir, "--"}
   682  	args = append(args, t.cFlags()...)
   683  	args = append(args, "linux/types.go")
   684  	return t.commandFormatOutput("mkpost", ztypesFile, "go", args...)
   685  }
   686  
   687  // Flags that should be given to gcc and cgo for this target
   688  func (t *target) cFlags() []string {
   689  	// Compile statically to avoid cross-architecture dynamic linking.
   690  	flags := []string{"-Wall", "-Werror", "-static", "-I" + filepath.Join(TempDir, t.GoArch, "include")}
   691  
   692  	// Architecture-specific flags
   693  	if t.SignedChar {
   694  		flags = append(flags, "-fsigned-char")
   695  	}
   696  	if t.LinuxArch == "x86" {
   697  		flags = append(flags, fmt.Sprintf("-m%d", t.Bits))
   698  	}
   699  
   700  	return flags
   701  }
   702  
   703  // Flags that should be given to mksyscall for this target
   704  func (t *target) mksyscallFlags() (flags []string) {
   705  	if t.Bits == 32 {
   706  		if t.BigEndian {
   707  			flags = append(flags, "-b32")
   708  		} else {
   709  			flags = append(flags, "-l32")
   710  		}
   711  	}
   712  
   713  	// This flag means a 64-bit value should use (even, odd)-pair.
   714  	if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) {
   715  		flags = append(flags, "-arm")
   716  	}
   717  	return
   718  }
   719  
   720  // Merge all the generated files for Linux targets
   721  func mergeFiles() error {
   722  	// Setup environment variables
   723  	os.Setenv("GOOS", runtime.GOOS)
   724  	os.Setenv("GOARCH", runtime.GOARCH)
   725  
   726  	// Merge each of the four type of files
   727  	for _, ztyp := range []string{"zerrors", "zsyscall", "zsysnum", "ztypes"} {
   728  		cmd := exec.Command("go", "run", "./internal/mkmerge", "-out", fmt.Sprintf("%s_%s.go", ztyp, GOOS), fmt.Sprintf("%s_%s_*.go", ztyp, GOOS))
   729  		cmd.Stderr = os.Stderr
   730  		err := cmd.Run()
   731  		if err != nil {
   732  			return fmt.Errorf("could not merge %s files: %w", ztyp, err)
   733  		}
   734  		fmt.Printf("%s files merged\n", ztyp)
   735  	}
   736  
   737  	return nil
   738  }
   739  
   740  // generatePtracePair takes a pair of GOARCH values that can run each
   741  // other's binaries, such as 386 and amd64. It extracts the PtraceRegs
   742  // type for each one. It writes a new file defining the types
   743  // PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions
   744  // Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other
   745  // binary on a native system. 'archName' is the combined name of 'arch1'
   746  // and 'arch2', which is used in the file name.
   747  func generatePtracePair(arch1, arch2, archName string) error {
   748  	def1, err := ptraceDef(arch1)
   749  	if err != nil {
   750  		return err
   751  	}
   752  	def2, err := ptraceDef(arch2)
   753  	if err != nil {
   754  		return err
   755  	}
   756  	f, err := os.Create(fmt.Sprintf("zptrace_%s_linux.go", archName))
   757  	if err != nil {
   758  		return err
   759  	}
   760  	buf := bufio.NewWriter(f)
   761  	fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%q, %q). DO NOT EDIT.\n", arch1, arch2)
   762  	fmt.Fprintf(buf, "\n")
   763  	fmt.Fprintf(buf, "//go:build linux && (%s || %s)\n", arch1, arch2)
   764  	fmt.Fprintf(buf, "\n")
   765  	fmt.Fprintf(buf, "package unix\n")
   766  	fmt.Fprintf(buf, "\n")
   767  	fmt.Fprintf(buf, "%s\n", `import "unsafe"`)
   768  	fmt.Fprintf(buf, "\n")
   769  	writeOnePtrace(buf, arch1, def1)
   770  	fmt.Fprintf(buf, "\n")
   771  	writeOnePtrace(buf, arch2, def2)
   772  	if err := buf.Flush(); err != nil {
   773  		return err
   774  	}
   775  	if err := f.Close(); err != nil {
   776  		return err
   777  	}
   778  	return nil
   779  }
   780  
   781  // generatePtraceRegSet takes a GOARCH value to generate a file zptrace_linux_{arch}.go
   782  // containing functions PtraceGetRegSet{arch} and PtraceSetRegSet{arch}.
   783  func generatePtraceRegSet(arch string) error {
   784  	f, err := os.Create(fmt.Sprintf("zptrace_linux_%s.go", arch))
   785  	if err != nil {
   786  		return err
   787  	}
   788  	buf := bufio.NewWriter(f)
   789  	fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtraceRegSet(%q). DO NOT EDIT.\n", arch)
   790  	fmt.Fprintf(buf, "\n")
   791  	fmt.Fprintf(buf, "package unix\n")
   792  	fmt.Fprintf(buf, "\n")
   793  	fmt.Fprintf(buf, "%s\n", `import "unsafe"`)
   794  	fmt.Fprintf(buf, "\n")
   795  	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:]
   796  	fmt.Fprintf(buf, "// PtraceGetRegSet%s fetches the registers used by %s binaries.\n", uarch, arch)
   797  	fmt.Fprintf(buf, "func PtraceGetRegSet%s(pid, addr int, regsout *PtraceRegs%s) error {\n", uarch, uarch)
   798  	fmt.Fprintf(buf, "\tiovec := Iovec{(*byte)(unsafe.Pointer(regsout)), uint64(unsafe.Sizeof(*regsout))}\n")
   799  	fmt.Fprintf(buf, "\treturn ptracePtr(PTRACE_GETREGSET, pid, uintptr(addr), unsafe.Pointer(&iovec))\n")
   800  	fmt.Fprintf(buf, "}\n")
   801  	fmt.Fprintf(buf, "\n")
   802  	fmt.Fprintf(buf, "// PtraceSetRegSet%s sets the registers used by %s binaries.\n", uarch, arch)
   803  	fmt.Fprintf(buf, "func PtraceSetRegSet%s(pid, addr int, regs *PtraceRegs%s) error {\n", uarch, uarch)
   804  	fmt.Fprintf(buf, "\tiovec := Iovec{(*byte)(unsafe.Pointer(regs)), uint64(unsafe.Sizeof(*regs))}\n")
   805  	fmt.Fprintf(buf, "\treturn ptracePtr(PTRACE_SETREGSET, pid, uintptr(addr), unsafe.Pointer(&iovec))\n")
   806  	fmt.Fprintf(buf, "}\n")
   807  	if err := buf.Flush(); err != nil {
   808  		return err
   809  	}
   810  	if err := f.Close(); err != nil {
   811  		return err
   812  	}
   813  	return nil
   814  }
   815  
   816  // ptraceDef returns the definition of PtraceRegs for arch.
   817  func ptraceDef(arch string) (string, error) {
   818  	filename := fmt.Sprintf("ztypes_linux_%s.go", arch)
   819  	data, err := os.ReadFile(filename)
   820  	if err != nil {
   821  		return "", fmt.Errorf("reading %s: %v", filename, err)
   822  	}
   823  	start := bytes.Index(data, []byte("type PtraceRegs struct"))
   824  	if start < 0 {
   825  		return "", fmt.Errorf("%s: no definition of PtraceRegs", filename)
   826  	}
   827  	data = data[start:]
   828  	end := bytes.Index(data, []byte("\n}\n"))
   829  	if end < 0 {
   830  		return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename)
   831  	}
   832  	return string(data[:end+2]), nil
   833  }
   834  
   835  // writeOnePtrace writes out the ptrace definitions for arch.
   836  func writeOnePtrace(w io.Writer, arch, def string) {
   837  	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:]
   838  	fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch)
   839  	fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1))
   840  	fmt.Fprintf(w, "\n")
   841  	fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch)
   842  	fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch)
   843  	fmt.Fprintf(w, "\treturn ptracePtr(PTRACE_GETREGS, pid, 0, unsafe.Pointer(regsout))\n")
   844  	fmt.Fprintf(w, "}\n")
   845  	fmt.Fprintf(w, "\n")
   846  	fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch)
   847  	fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch)
   848  	fmt.Fprintf(w, "\treturn ptracePtr(PTRACE_SETREGS, pid, 0, unsafe.Pointer(regs))\n")
   849  	fmt.Fprintf(w, "}\n")
   850  }
   851  
   852  // cCode is compiled for the target architecture, and the resulting data section is carved for
   853  // the statically initialized bit masks.
   854  const cCode = `
   855  // Bit fields are used in some system calls and other ABIs, but their memory layout is
   856  // implementation-defined [1]. Even with formal ABIs, bit fields are a source of subtle bugs [2].
   857  // Here we generate the offsets for all 64 bits in an uint64.
   858  // 1: http://en.cppreference.com/w/c/language/bit_field
   859  // 2: https://lwn.net/Articles/478657/
   860  
   861  #include <stdint.h>
   862  
   863  struct bitfield {
   864  	union {
   865  		uint64_t val;
   866  		struct {
   867  			uint64_t u64_bit_0 : 1;
   868  			uint64_t u64_bit_1 : 1;
   869  			uint64_t u64_bit_2 : 1;
   870  			uint64_t u64_bit_3 : 1;
   871  			uint64_t u64_bit_4 : 1;
   872  			uint64_t u64_bit_5 : 1;
   873  			uint64_t u64_bit_6 : 1;
   874  			uint64_t u64_bit_7 : 1;
   875  			uint64_t u64_bit_8 : 1;
   876  			uint64_t u64_bit_9 : 1;
   877  			uint64_t u64_bit_10 : 1;
   878  			uint64_t u64_bit_11 : 1;
   879  			uint64_t u64_bit_12 : 1;
   880  			uint64_t u64_bit_13 : 1;
   881  			uint64_t u64_bit_14 : 1;
   882  			uint64_t u64_bit_15 : 1;
   883  			uint64_t u64_bit_16 : 1;
   884  			uint64_t u64_bit_17 : 1;
   885  			uint64_t u64_bit_18 : 1;
   886  			uint64_t u64_bit_19 : 1;
   887  			uint64_t u64_bit_20 : 1;
   888  			uint64_t u64_bit_21 : 1;
   889  			uint64_t u64_bit_22 : 1;
   890  			uint64_t u64_bit_23 : 1;
   891  			uint64_t u64_bit_24 : 1;
   892  			uint64_t u64_bit_25 : 1;
   893  			uint64_t u64_bit_26 : 1;
   894  			uint64_t u64_bit_27 : 1;
   895  			uint64_t u64_bit_28 : 1;
   896  			uint64_t u64_bit_29 : 1;
   897  			uint64_t u64_bit_30 : 1;
   898  			uint64_t u64_bit_31 : 1;
   899  			uint64_t u64_bit_32 : 1;
   900  			uint64_t u64_bit_33 : 1;
   901  			uint64_t u64_bit_34 : 1;
   902  			uint64_t u64_bit_35 : 1;
   903  			uint64_t u64_bit_36 : 1;
   904  			uint64_t u64_bit_37 : 1;
   905  			uint64_t u64_bit_38 : 1;
   906  			uint64_t u64_bit_39 : 1;
   907  			uint64_t u64_bit_40 : 1;
   908  			uint64_t u64_bit_41 : 1;
   909  			uint64_t u64_bit_42 : 1;
   910  			uint64_t u64_bit_43 : 1;
   911  			uint64_t u64_bit_44 : 1;
   912  			uint64_t u64_bit_45 : 1;
   913  			uint64_t u64_bit_46 : 1;
   914  			uint64_t u64_bit_47 : 1;
   915  			uint64_t u64_bit_48 : 1;
   916  			uint64_t u64_bit_49 : 1;
   917  			uint64_t u64_bit_50 : 1;
   918  			uint64_t u64_bit_51 : 1;
   919  			uint64_t u64_bit_52 : 1;
   920  			uint64_t u64_bit_53 : 1;
   921  			uint64_t u64_bit_54 : 1;
   922  			uint64_t u64_bit_55 : 1;
   923  			uint64_t u64_bit_56 : 1;
   924  			uint64_t u64_bit_57 : 1;
   925  			uint64_t u64_bit_58 : 1;
   926  			uint64_t u64_bit_59 : 1;
   927  			uint64_t u64_bit_60 : 1;
   928  			uint64_t u64_bit_61 : 1;
   929  			uint64_t u64_bit_62 : 1;
   930  			uint64_t u64_bit_63 : 1;
   931  		};
   932  	};
   933  };
   934  
   935  struct bitfield masks[] = {
   936  	{.u64_bit_0 = 1},
   937  	{.u64_bit_1 = 1},
   938  	{.u64_bit_2 = 1},
   939  	{.u64_bit_3 = 1},
   940  	{.u64_bit_4 = 1},
   941  	{.u64_bit_5 = 1},
   942  	{.u64_bit_6 = 1},
   943  	{.u64_bit_7 = 1},
   944  	{.u64_bit_8 = 1},
   945  	{.u64_bit_9 = 1},
   946  	{.u64_bit_10 = 1},
   947  	{.u64_bit_11 = 1},
   948  	{.u64_bit_12 = 1},
   949  	{.u64_bit_13 = 1},
   950  	{.u64_bit_14 = 1},
   951  	{.u64_bit_15 = 1},
   952  	{.u64_bit_16 = 1},
   953  	{.u64_bit_17 = 1},
   954  	{.u64_bit_18 = 1},
   955  	{.u64_bit_19 = 1},
   956  	{.u64_bit_20 = 1},
   957  	{.u64_bit_21 = 1},
   958  	{.u64_bit_22 = 1},
   959  	{.u64_bit_23 = 1},
   960  	{.u64_bit_24 = 1},
   961  	{.u64_bit_25 = 1},
   962  	{.u64_bit_26 = 1},
   963  	{.u64_bit_27 = 1},
   964  	{.u64_bit_28 = 1},
   965  	{.u64_bit_29 = 1},
   966  	{.u64_bit_30 = 1},
   967  	{.u64_bit_31 = 1},
   968  	{.u64_bit_32 = 1},
   969  	{.u64_bit_33 = 1},
   970  	{.u64_bit_34 = 1},
   971  	{.u64_bit_35 = 1},
   972  	{.u64_bit_36 = 1},
   973  	{.u64_bit_37 = 1},
   974  	{.u64_bit_38 = 1},
   975  	{.u64_bit_39 = 1},
   976  	{.u64_bit_40 = 1},
   977  	{.u64_bit_41 = 1},
   978  	{.u64_bit_42 = 1},
   979  	{.u64_bit_43 = 1},
   980  	{.u64_bit_44 = 1},
   981  	{.u64_bit_45 = 1},
   982  	{.u64_bit_46 = 1},
   983  	{.u64_bit_47 = 1},
   984  	{.u64_bit_48 = 1},
   985  	{.u64_bit_49 = 1},
   986  	{.u64_bit_50 = 1},
   987  	{.u64_bit_51 = 1},
   988  	{.u64_bit_52 = 1},
   989  	{.u64_bit_53 = 1},
   990  	{.u64_bit_54 = 1},
   991  	{.u64_bit_55 = 1},
   992  	{.u64_bit_56 = 1},
   993  	{.u64_bit_57 = 1},
   994  	{.u64_bit_58 = 1},
   995  	{.u64_bit_59 = 1},
   996  	{.u64_bit_60 = 1},
   997  	{.u64_bit_61 = 1},
   998  	{.u64_bit_62 = 1},
   999  	{.u64_bit_63 = 1}
  1000  };
  1001  
  1002  int main(int argc, char **argv) {
  1003  	struct bitfield *mask_ptr = &masks[0];
  1004  	return mask_ptr->val;
  1005  }
  1006  
  1007  `