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