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