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
15package main
16
17import (
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.
35var LinuxDir string
36var GlibcDir string
37
38const TempDir = "/tmp"
39const IncludeDir = TempDir + "/include" // To hold our C headers
40const BuildDir = TempDir + "/build"     // To hold intermediate build files
41
42const GOOS = "linux"       // Only for Linux targets
43const BuildArch = "amd64"  // Must be built on this architecture
44const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements
45
46type 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.
58var 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.
159var ptracePairs = []struct{ a1, a2, archName string }{
160	{"386", "amd64", "x86"},
161	{"arm", "arm64", "armnn"},
162	{"mips", "mips64", "mipsnn"},
163	{"mipsle", "mips64le", "mipsnnle"},
164}
165
166func 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
223func 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.
230func (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.
242func (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
284func (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.
347func (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.
390func (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
428func (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
446func (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
493func (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
502func (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
517func (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
524func (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
534func (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
550func (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
567func 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.
592func 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}.
630func 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.
664func 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.
683func 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.
701const 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
710struct 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
782struct 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
849int main(int argc, char **argv) {
850	struct bitfield *mask_ptr = &masks[0];
851	return mask_ptr->val;
852}
853
854`
855