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