github.com/tristanisham/sys@v0.0.0-20240326010300-a16cbabb7555/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 glibcConf := t.makeCommand(confScript, glibcArgs...) 421 422 glibcConf.Dir = buildDir 423 if err := glibcConf.Run(); err != nil { 424 return err 425 } 426 glibcMake := t.makeCommand("make", "install-headers") 427 glibcMake.Dir = buildDir 428 if err := glibcMake.Run(); err != nil { 429 return err 430 } 431 // We only need an empty stubs file 432 stubsFile := filepath.Join(TempDir, t.GoArch, "include", "gnu", "stubs.h") 433 if file, err := os.Create(stubsFile); err != nil { 434 return err 435 } else { 436 file.Close() 437 } 438 439 // ABI headers will specify C compiler behavior for the target platform. 440 return t.makeABIHeaders() 441 } 442 443 // makeABIHeaders generates C header files based on the platform's calling convention. 444 // While many platforms have formal Application Binary Interfaces, in practice, whatever the 445 // dominant C compilers generate is the de-facto calling convention. 446 // 447 // We generate C headers instead of a Go file, so as to enable references to the ABI from Cgo. 448 func (t *target) makeABIHeaders() (err error) { 449 abiDir := filepath.Join(TempDir, t.GoArch, "include", "abi") 450 if err = os.Mkdir(abiDir, os.ModePerm); err != nil { 451 return err 452 } 453 454 if t.compiler == "" { 455 return errors.New("CC (compiler) env var not set") 456 } 457 458 // Build a sacrificial ELF file, to mine for C compiler behavior. 459 binPath := filepath.Join(TempDir, t.GoArch, "tmp_abi.o") 460 bin, err := t.buildELF(t.compiler, cCode, binPath) 461 if err != nil { 462 return fmt.Errorf("cannot build ELF to analyze: %v", err) 463 } 464 defer bin.Close() 465 defer os.Remove(binPath) 466 467 // Right now, we put everything in abi.h, but we may change this later. 468 abiFile, err := os.Create(filepath.Join(abiDir, "abi.h")) 469 if err != nil { 470 return err 471 } 472 defer func() { 473 if cerr := abiFile.Close(); cerr != nil && err == nil { 474 err = cerr 475 } 476 }() 477 478 if err = t.writeBitFieldMasks(bin, abiFile); err != nil { 479 return fmt.Errorf("cannot write bitfield masks: %v", err) 480 } 481 482 return nil 483 } 484 485 func (t *target) buildELF(cc, src, path string) (*elf.File, error) { 486 // Compile the cCode source using the set compiler - we will need its .data section. 487 // Do not link the binary, so that we can find .data section offsets from the symbol values. 488 ccCmd := t.makeCommand(cc, "-o", path, "-gdwarf", "-x", "c", "-c", "-") 489 ccCmd.Stdin = strings.NewReader(src) 490 ccCmd.Stdout = os.Stdout 491 defer t.printAndResetBuilder() 492 if err := ccCmd.Run(); err != nil { 493 return nil, fmt.Errorf("compiler error: %v", err) 494 } 495 496 bin, err := elf.Open(path) 497 if err != nil { 498 return nil, fmt.Errorf("cannot read ELF file %s: %v", path, err) 499 } 500 501 return bin, nil 502 } 503 504 func (t *target) writeBitFieldMasks(bin *elf.File, out io.Writer) error { 505 symbols, err := bin.Symbols() 506 if err != nil { 507 return fmt.Errorf("getting ELF symbols: %v", err) 508 } 509 var masksSym *elf.Symbol 510 511 for _, sym := range symbols { 512 if sym.Name == "masks" { 513 masksSym = &sym 514 } 515 } 516 517 if masksSym == nil { 518 return errors.New("could not find the 'masks' symbol in ELF symtab") 519 } 520 521 dataSection := bin.Section(".data") 522 if dataSection == nil { 523 return errors.New("ELF file has no .data section") 524 } 525 526 data, err := dataSection.Data() 527 if err != nil { 528 return fmt.Errorf("could not read .data section: %v\n", err) 529 } 530 531 var bo binary.ByteOrder 532 if t.BigEndian { 533 bo = binary.BigEndian 534 } else { 535 bo = binary.LittleEndian 536 } 537 538 // 64 bit masks of type uint64 are stored in the data section starting at masks.Value. 539 // Here we are running on AMD64, but these values may be big endian or little endian, 540 // depending on target architecture. 541 for i := uint64(0); i < 64; i++ { 542 off := masksSym.Value + i*8 543 // Define each mask in native by order, so as to match target endian. 544 fmt.Fprintf(out, "#define BITFIELD_MASK_%d %dULL\n", i, bo.Uint64(data[off:off+8])) 545 } 546 547 return nil 548 } 549 550 // makes the zsysnum_linux_$GOARCH.go file 551 func (t *target) makeZSysnumFile() error { 552 zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch) 553 unistdFile := filepath.Join(TempDir, t.GoArch, "include", "asm", "unistd.h") 554 555 args := append(t.cFlags(), unistdFile) 556 return t.commandFormatOutput("gofmt", zsysnumFile, "mksysnum", args...) 557 } 558 559 // makes the zsyscall_linux_$GOARCH.go file 560 func (t *target) makeZSyscallFile() error { 561 zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch) 562 // Find the correct architecture syscall file (might end with x.go) 563 archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch) 564 if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) { 565 shortArch := strings.TrimSuffix(t.GoArch, "le") 566 archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch) 567 } 568 569 args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch, 570 "syscall_linux.go", 571 archSyscallFile, 572 ) 573 574 files, err := t.archMksyscallFiles() 575 if err != nil { 576 return fmt.Errorf("failed to check GOARCH-specific mksyscall files: %v", err) 577 } 578 args = append(args, files...) 579 580 return t.commandFormatOutput("gofmt", zsyscallFile, "mksyscall", args...) 581 } 582 583 // archMksyscallFiles produces additional file arguments to mksyscall if the 584 // build constraints in those files match those defined for target. 585 func (t *target) archMksyscallFiles() ([]string, error) { 586 // These input files don't fit the typical GOOS/GOARCH file name conventions 587 // but are included conditionally in the arguments to mksyscall based on 588 // whether or not the target matches the build constraints defined in each 589 // file. 590 // 591 // TODO(mdlayher): it should be possible to generalize this approach to work 592 // over all of syscall_linux_* rather than hard-coding a few special files. 593 // Investigate this. 594 inputs := []string{ 595 // GOARCH: all except arm* and riscv. 596 "syscall_linux_alarm.go", 597 } 598 599 var outputs []string 600 for _, in := range inputs { 601 ok, err := t.matchesMksyscallFile(in) 602 if err != nil { 603 return nil, fmt.Errorf("failed to parse file %q: %v", in, err) 604 } 605 if ok { 606 // Constraints match, use for this target's code generation. 607 outputs = append(outputs, in) 608 } 609 } 610 611 return outputs, nil 612 } 613 614 // matchesMksyscallFile reports whether the input file contains constraints 615 // which match those defined for target. 616 func (t *target) matchesMksyscallFile(file string) (bool, error) { 617 f, err := os.Open(file) 618 if err != nil { 619 return false, err 620 } 621 defer f.Close() 622 623 var ( 624 expr constraint.Expr 625 found bool 626 ) 627 628 s := bufio.NewScanner(f) 629 for s.Scan() { 630 // Keep scanning until a valid constraint is found or we hit EOF. 631 // This is sufficient for the single-line //go:build constraints. 632 if expr, err = constraint.Parse(s.Text()); err == nil { 633 found = true 634 break 635 } 636 } 637 if err := s.Err(); err != nil { 638 return false, err 639 } 640 if !found { 641 return false, errors.New("no build constraints found") 642 } 643 644 // Do the defined constraints match target's GOOS/GOARCH? 645 ok := expr.Eval(func(tag string) bool { 646 return tag == GOOS || tag == t.GoArch 647 }) 648 649 return ok, nil 650 } 651 652 // makes the zerrors_linux_$GOARCH.go file 653 func (t *target) makeZErrorsFile() error { 654 zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch) 655 return t.commandFormatOutput("gofmt2", zerrorsFile, "/"+filepath.Join("build", "unix", "mkerrors.sh"), t.cFlags()...) 656 } 657 658 // makes the ztypes_linux_$GOARCH.go file 659 func (t *target) makeZTypesFile() error { 660 ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch) 661 662 cgoDir := filepath.Join(TempDir, t.GoArch, "cgo") 663 if err := os.MkdirAll(cgoDir, os.ModePerm); err != nil { 664 return err 665 } 666 667 args := []string{"tool", "cgo", "-godefs", "-objdir=" + cgoDir, "--"} 668 args = append(args, t.cFlags()...) 669 args = append(args, "linux/types.go") 670 return t.commandFormatOutput("mkpost", ztypesFile, "go", args...) 671 } 672 673 // Flags that should be given to gcc and cgo for this target 674 func (t *target) cFlags() []string { 675 // Compile statically to avoid cross-architecture dynamic linking. 676 flags := []string{"-Wall", "-Werror", "-static", "-I" + filepath.Join(TempDir, t.GoArch, "include")} 677 678 // Architecture-specific flags 679 if t.SignedChar { 680 flags = append(flags, "-fsigned-char") 681 } 682 if t.LinuxArch == "x86" { 683 flags = append(flags, fmt.Sprintf("-m%d", t.Bits)) 684 } 685 686 return flags 687 } 688 689 // Flags that should be given to mksyscall for this target 690 func (t *target) mksyscallFlags() (flags []string) { 691 if t.Bits == 32 { 692 if t.BigEndian { 693 flags = append(flags, "-b32") 694 } else { 695 flags = append(flags, "-l32") 696 } 697 } 698 699 // This flag means a 64-bit value should use (even, odd)-pair. 700 if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) { 701 flags = append(flags, "-arm") 702 } 703 return 704 } 705 706 // Merge all the generated files for Linux targets 707 func mergeFiles() error { 708 // Setup environment variables 709 os.Setenv("GOOS", runtime.GOOS) 710 os.Setenv("GOARCH", runtime.GOARCH) 711 712 // Merge each of the four type of files 713 for _, ztyp := range []string{"zerrors", "zsyscall", "zsysnum", "ztypes"} { 714 cmd := exec.Command("go", "run", "./internal/mkmerge", "-out", fmt.Sprintf("%s_%s.go", ztyp, GOOS), fmt.Sprintf("%s_%s_*.go", ztyp, GOOS)) 715 cmd.Stderr = os.Stderr 716 err := cmd.Run() 717 if err != nil { 718 return fmt.Errorf("could not merge %s files: %w", ztyp, err) 719 } 720 fmt.Printf("%s files merged\n", ztyp) 721 } 722 723 return nil 724 } 725 726 // generatePtracePair takes a pair of GOARCH values that can run each 727 // other's binaries, such as 386 and amd64. It extracts the PtraceRegs 728 // type for each one. It writes a new file defining the types 729 // PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions 730 // Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other 731 // binary on a native system. 'archName' is the combined name of 'arch1' 732 // and 'arch2', which is used in the file name. 733 func generatePtracePair(arch1, arch2, archName string) error { 734 def1, err := ptraceDef(arch1) 735 if err != nil { 736 return err 737 } 738 def2, err := ptraceDef(arch2) 739 if err != nil { 740 return err 741 } 742 f, err := os.Create(fmt.Sprintf("zptrace_%s_linux.go", archName)) 743 if err != nil { 744 return err 745 } 746 buf := bufio.NewWriter(f) 747 fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%q, %q). DO NOT EDIT.\n", arch1, arch2) 748 fmt.Fprintf(buf, "\n") 749 fmt.Fprintf(buf, "//go:build linux && (%s || %s)\n", arch1, arch2) 750 fmt.Fprintf(buf, "\n") 751 fmt.Fprintf(buf, "package unix\n") 752 fmt.Fprintf(buf, "\n") 753 fmt.Fprintf(buf, "%s\n", `import "unsafe"`) 754 fmt.Fprintf(buf, "\n") 755 writeOnePtrace(buf, arch1, def1) 756 fmt.Fprintf(buf, "\n") 757 writeOnePtrace(buf, arch2, def2) 758 if err := buf.Flush(); err != nil { 759 return err 760 } 761 if err := f.Close(); err != nil { 762 return err 763 } 764 return nil 765 } 766 767 // generatePtraceRegSet takes a GOARCH value to generate a file zptrace_linux_{arch}.go 768 // containing functions PtraceGetRegSet{arch} and PtraceSetRegSet{arch}. 769 func generatePtraceRegSet(arch string) error { 770 f, err := os.Create(fmt.Sprintf("zptrace_linux_%s.go", arch)) 771 if err != nil { 772 return err 773 } 774 buf := bufio.NewWriter(f) 775 fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtraceRegSet(%q). DO NOT EDIT.\n", arch) 776 fmt.Fprintf(buf, "\n") 777 fmt.Fprintf(buf, "package unix\n") 778 fmt.Fprintf(buf, "\n") 779 fmt.Fprintf(buf, "%s\n", `import "unsafe"`) 780 fmt.Fprintf(buf, "\n") 781 uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:] 782 fmt.Fprintf(buf, "// PtraceGetRegSet%s fetches the registers used by %s binaries.\n", uarch, arch) 783 fmt.Fprintf(buf, "func PtraceGetRegSet%s(pid, addr int, regsout *PtraceRegs%s) error {\n", uarch, uarch) 784 fmt.Fprintf(buf, "\tiovec := Iovec{(*byte)(unsafe.Pointer(regsout)), uint64(unsafe.Sizeof(*regsout))}\n") 785 fmt.Fprintf(buf, "\treturn ptracePtr(PTRACE_GETREGSET, pid, uintptr(addr), unsafe.Pointer(&iovec))\n") 786 fmt.Fprintf(buf, "}\n") 787 fmt.Fprintf(buf, "\n") 788 fmt.Fprintf(buf, "// PtraceSetRegSet%s sets the registers used by %s binaries.\n", uarch, arch) 789 fmt.Fprintf(buf, "func PtraceSetRegSet%s(pid, addr int, regs *PtraceRegs%s) error {\n", uarch, uarch) 790 fmt.Fprintf(buf, "\tiovec := Iovec{(*byte)(unsafe.Pointer(regs)), uint64(unsafe.Sizeof(*regs))}\n") 791 fmt.Fprintf(buf, "\treturn ptracePtr(PTRACE_SETREGSET, pid, uintptr(addr), unsafe.Pointer(&iovec))\n") 792 fmt.Fprintf(buf, "}\n") 793 if err := buf.Flush(); err != nil { 794 return err 795 } 796 if err := f.Close(); err != nil { 797 return err 798 } 799 return nil 800 } 801 802 // ptraceDef returns the definition of PtraceRegs for arch. 803 func ptraceDef(arch string) (string, error) { 804 filename := fmt.Sprintf("ztypes_linux_%s.go", arch) 805 data, err := os.ReadFile(filename) 806 if err != nil { 807 return "", fmt.Errorf("reading %s: %v", filename, err) 808 } 809 start := bytes.Index(data, []byte("type PtraceRegs struct")) 810 if start < 0 { 811 return "", fmt.Errorf("%s: no definition of PtraceRegs", filename) 812 } 813 data = data[start:] 814 end := bytes.Index(data, []byte("\n}\n")) 815 if end < 0 { 816 return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename) 817 } 818 return string(data[:end+2]), nil 819 } 820 821 // writeOnePtrace writes out the ptrace definitions for arch. 822 func writeOnePtrace(w io.Writer, arch, def string) { 823 uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:] 824 fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch) 825 fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1)) 826 fmt.Fprintf(w, "\n") 827 fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch) 828 fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch) 829 fmt.Fprintf(w, "\treturn ptracePtr(PTRACE_GETREGS, pid, 0, unsafe.Pointer(regsout))\n") 830 fmt.Fprintf(w, "}\n") 831 fmt.Fprintf(w, "\n") 832 fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch) 833 fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch) 834 fmt.Fprintf(w, "\treturn ptracePtr(PTRACE_SETREGS, pid, 0, unsafe.Pointer(regs))\n") 835 fmt.Fprintf(w, "}\n") 836 } 837 838 // cCode is compiled for the target architecture, and the resulting data section is carved for 839 // the statically initialized bit masks. 840 const cCode = ` 841 // Bit fields are used in some system calls and other ABIs, but their memory layout is 842 // implementation-defined [1]. Even with formal ABIs, bit fields are a source of subtle bugs [2]. 843 // Here we generate the offsets for all 64 bits in an uint64. 844 // 1: http://en.cppreference.com/w/c/language/bit_field 845 // 2: https://lwn.net/Articles/478657/ 846 847 #include <stdint.h> 848 849 struct bitfield { 850 union { 851 uint64_t val; 852 struct { 853 uint64_t u64_bit_0 : 1; 854 uint64_t u64_bit_1 : 1; 855 uint64_t u64_bit_2 : 1; 856 uint64_t u64_bit_3 : 1; 857 uint64_t u64_bit_4 : 1; 858 uint64_t u64_bit_5 : 1; 859 uint64_t u64_bit_6 : 1; 860 uint64_t u64_bit_7 : 1; 861 uint64_t u64_bit_8 : 1; 862 uint64_t u64_bit_9 : 1; 863 uint64_t u64_bit_10 : 1; 864 uint64_t u64_bit_11 : 1; 865 uint64_t u64_bit_12 : 1; 866 uint64_t u64_bit_13 : 1; 867 uint64_t u64_bit_14 : 1; 868 uint64_t u64_bit_15 : 1; 869 uint64_t u64_bit_16 : 1; 870 uint64_t u64_bit_17 : 1; 871 uint64_t u64_bit_18 : 1; 872 uint64_t u64_bit_19 : 1; 873 uint64_t u64_bit_20 : 1; 874 uint64_t u64_bit_21 : 1; 875 uint64_t u64_bit_22 : 1; 876 uint64_t u64_bit_23 : 1; 877 uint64_t u64_bit_24 : 1; 878 uint64_t u64_bit_25 : 1; 879 uint64_t u64_bit_26 : 1; 880 uint64_t u64_bit_27 : 1; 881 uint64_t u64_bit_28 : 1; 882 uint64_t u64_bit_29 : 1; 883 uint64_t u64_bit_30 : 1; 884 uint64_t u64_bit_31 : 1; 885 uint64_t u64_bit_32 : 1; 886 uint64_t u64_bit_33 : 1; 887 uint64_t u64_bit_34 : 1; 888 uint64_t u64_bit_35 : 1; 889 uint64_t u64_bit_36 : 1; 890 uint64_t u64_bit_37 : 1; 891 uint64_t u64_bit_38 : 1; 892 uint64_t u64_bit_39 : 1; 893 uint64_t u64_bit_40 : 1; 894 uint64_t u64_bit_41 : 1; 895 uint64_t u64_bit_42 : 1; 896 uint64_t u64_bit_43 : 1; 897 uint64_t u64_bit_44 : 1; 898 uint64_t u64_bit_45 : 1; 899 uint64_t u64_bit_46 : 1; 900 uint64_t u64_bit_47 : 1; 901 uint64_t u64_bit_48 : 1; 902 uint64_t u64_bit_49 : 1; 903 uint64_t u64_bit_50 : 1; 904 uint64_t u64_bit_51 : 1; 905 uint64_t u64_bit_52 : 1; 906 uint64_t u64_bit_53 : 1; 907 uint64_t u64_bit_54 : 1; 908 uint64_t u64_bit_55 : 1; 909 uint64_t u64_bit_56 : 1; 910 uint64_t u64_bit_57 : 1; 911 uint64_t u64_bit_58 : 1; 912 uint64_t u64_bit_59 : 1; 913 uint64_t u64_bit_60 : 1; 914 uint64_t u64_bit_61 : 1; 915 uint64_t u64_bit_62 : 1; 916 uint64_t u64_bit_63 : 1; 917 }; 918 }; 919 }; 920 921 struct bitfield masks[] = { 922 {.u64_bit_0 = 1}, 923 {.u64_bit_1 = 1}, 924 {.u64_bit_2 = 1}, 925 {.u64_bit_3 = 1}, 926 {.u64_bit_4 = 1}, 927 {.u64_bit_5 = 1}, 928 {.u64_bit_6 = 1}, 929 {.u64_bit_7 = 1}, 930 {.u64_bit_8 = 1}, 931 {.u64_bit_9 = 1}, 932 {.u64_bit_10 = 1}, 933 {.u64_bit_11 = 1}, 934 {.u64_bit_12 = 1}, 935 {.u64_bit_13 = 1}, 936 {.u64_bit_14 = 1}, 937 {.u64_bit_15 = 1}, 938 {.u64_bit_16 = 1}, 939 {.u64_bit_17 = 1}, 940 {.u64_bit_18 = 1}, 941 {.u64_bit_19 = 1}, 942 {.u64_bit_20 = 1}, 943 {.u64_bit_21 = 1}, 944 {.u64_bit_22 = 1}, 945 {.u64_bit_23 = 1}, 946 {.u64_bit_24 = 1}, 947 {.u64_bit_25 = 1}, 948 {.u64_bit_26 = 1}, 949 {.u64_bit_27 = 1}, 950 {.u64_bit_28 = 1}, 951 {.u64_bit_29 = 1}, 952 {.u64_bit_30 = 1}, 953 {.u64_bit_31 = 1}, 954 {.u64_bit_32 = 1}, 955 {.u64_bit_33 = 1}, 956 {.u64_bit_34 = 1}, 957 {.u64_bit_35 = 1}, 958 {.u64_bit_36 = 1}, 959 {.u64_bit_37 = 1}, 960 {.u64_bit_38 = 1}, 961 {.u64_bit_39 = 1}, 962 {.u64_bit_40 = 1}, 963 {.u64_bit_41 = 1}, 964 {.u64_bit_42 = 1}, 965 {.u64_bit_43 = 1}, 966 {.u64_bit_44 = 1}, 967 {.u64_bit_45 = 1}, 968 {.u64_bit_46 = 1}, 969 {.u64_bit_47 = 1}, 970 {.u64_bit_48 = 1}, 971 {.u64_bit_49 = 1}, 972 {.u64_bit_50 = 1}, 973 {.u64_bit_51 = 1}, 974 {.u64_bit_52 = 1}, 975 {.u64_bit_53 = 1}, 976 {.u64_bit_54 = 1}, 977 {.u64_bit_55 = 1}, 978 {.u64_bit_56 = 1}, 979 {.u64_bit_57 = 1}, 980 {.u64_bit_58 = 1}, 981 {.u64_bit_59 = 1}, 982 {.u64_bit_60 = 1}, 983 {.u64_bit_61 = 1}, 984 {.u64_bit_62 = 1}, 985 {.u64_bit_63 = 1} 986 }; 987 988 int main(int argc, char **argv) { 989 struct bitfield *mask_ptr = &masks[0]; 990 return mask_ptr->val; 991 } 992 993 `