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