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