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