github.com/alexis81/domosgo@v0.0.0-20191016125037-5aee90a434af/Domos/src/golang.org/x/sys/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 11 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 "fmt" 21 "io" 22 "io/ioutil" 23 "os" 24 "os/exec" 25 "path/filepath" 26 "runtime" 27 "strings" 28 "unicode" 29 ) 30 31 // These will be paths to the appropriate source directories. 32 var LinuxDir string 33 var GlibcDir string 34 35 const TempDir = "/tmp" 36 const IncludeDir = TempDir + "/include" // To hold our C headers 37 const BuildDir = TempDir + "/build" // To hold intermediate build files 38 39 const GOOS = "linux" // Only for Linux targets 40 const BuildArch = "amd64" // Must be built on this architecture 41 const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements 42 43 type target struct { 44 GoArch string // Architecture name according to Go 45 LinuxArch string // Architecture name according to the Linux Kernel 46 GNUArch string // Architecture name according to GNU tools (https://wiki.debian.org/Multiarch/Tuples) 47 BigEndian bool // Default Little Endian 48 SignedChar bool // Is -fsigned-char needed (default no) 49 Bits int 50 } 51 52 // List of the 11 Linux targets supported by the go compiler. sparc64 is not 53 // currently supported, though a port is in progress. 54 var targets = []target{ 55 { 56 GoArch: "386", 57 LinuxArch: "x86", 58 GNUArch: "i686-linux-gnu", // Note "i686" not "i386" 59 Bits: 32, 60 }, 61 { 62 GoArch: "amd64", 63 LinuxArch: "x86", 64 GNUArch: "x86_64-linux-gnu", 65 Bits: 64, 66 }, 67 { 68 GoArch: "arm64", 69 LinuxArch: "arm64", 70 GNUArch: "aarch64-linux-gnu", 71 SignedChar: true, 72 Bits: 64, 73 }, 74 { 75 GoArch: "arm", 76 LinuxArch: "arm", 77 GNUArch: "arm-linux-gnueabi", 78 Bits: 32, 79 }, 80 { 81 GoArch: "mips", 82 LinuxArch: "mips", 83 GNUArch: "mips-linux-gnu", 84 BigEndian: true, 85 Bits: 32, 86 }, 87 { 88 GoArch: "mipsle", 89 LinuxArch: "mips", 90 GNUArch: "mipsel-linux-gnu", 91 Bits: 32, 92 }, 93 { 94 GoArch: "mips64", 95 LinuxArch: "mips", 96 GNUArch: "mips64-linux-gnuabi64", 97 BigEndian: true, 98 Bits: 64, 99 }, 100 { 101 GoArch: "mips64le", 102 LinuxArch: "mips", 103 GNUArch: "mips64el-linux-gnuabi64", 104 Bits: 64, 105 }, 106 { 107 GoArch: "ppc64", 108 LinuxArch: "powerpc", 109 GNUArch: "powerpc64-linux-gnu", 110 BigEndian: true, 111 Bits: 64, 112 }, 113 { 114 GoArch: "ppc64le", 115 LinuxArch: "powerpc", 116 GNUArch: "powerpc64le-linux-gnu", 117 Bits: 64, 118 }, 119 { 120 GoArch: "s390x", 121 LinuxArch: "s390", 122 GNUArch: "s390x-linux-gnu", 123 BigEndian: true, 124 SignedChar: true, 125 Bits: 64, 126 }, 127 // { 128 // GoArch: "sparc64", 129 // LinuxArch: "sparc", 130 // GNUArch: "sparc64-linux-gnu", 131 // BigEndian: true, 132 // Bits: 64, 133 // }, 134 } 135 136 // ptracePairs is a list of pairs of targets that can, in some cases, 137 // run each other's binaries. 138 var ptracePairs = []struct{ a1, a2 string }{ 139 {"386", "amd64"}, 140 {"arm", "arm64"}, 141 {"mips", "mips64"}, 142 {"mipsle", "mips64le"}, 143 } 144 145 func main() { 146 if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch { 147 fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n", 148 runtime.GOOS, runtime.GOARCH, GOOS, BuildArch) 149 return 150 } 151 152 // Check that we are using the new build system if we should 153 if os.Getenv("GOLANG_SYS_BUILD") != "docker" { 154 fmt.Println("In the new build system, mkall.go should not be called directly.") 155 fmt.Println("See README.md") 156 return 157 } 158 159 // Parse the command line options 160 if len(os.Args) != 3 { 161 fmt.Println("USAGE: go run linux/mkall.go <linux_dir> <glibc_dir>") 162 return 163 } 164 LinuxDir = os.Args[1] 165 GlibcDir = os.Args[2] 166 167 for _, t := range targets { 168 fmt.Printf("----- GENERATING: %s -----\n", t.GoArch) 169 if err := t.generateFiles(); err != nil { 170 fmt.Printf("%v\n***** FAILURE: %s *****\n\n", err, t.GoArch) 171 } else { 172 fmt.Printf("----- SUCCESS: %s -----\n\n", t.GoArch) 173 } 174 } 175 176 fmt.Printf("----- GENERATING ptrace pairs -----\n") 177 ok := true 178 for _, p := range ptracePairs { 179 if err := generatePtracePair(p.a1, p.a2); err != nil { 180 fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2) 181 ok = false 182 } 183 } 184 if ok { 185 fmt.Printf("----- SUCCESS ptrace pairs -----\n\n") 186 } 187 } 188 189 // Makes an exec.Cmd with Stderr attached to os.Stderr 190 func makeCommand(name string, args ...string) *exec.Cmd { 191 cmd := exec.Command(name, args...) 192 cmd.Stderr = os.Stderr 193 return cmd 194 } 195 196 // Runs the command, pipes output to a formatter, pipes that to an output file. 197 func (t *target) commandFormatOutput(formatter string, outputFile string, 198 name string, args ...string) (err error) { 199 mainCmd := makeCommand(name, args...) 200 201 fmtCmd := makeCommand(formatter) 202 if formatter == "mkpost" { 203 fmtCmd = makeCommand("go", "run", "mkpost.go") 204 // Set GOARCH_TARGET so mkpost knows what GOARCH is.. 205 fmtCmd.Env = append(os.Environ(), "GOARCH_TARGET="+t.GoArch) 206 // Set GOARCH to host arch for mkpost, so it can run natively. 207 for i, s := range fmtCmd.Env { 208 if strings.HasPrefix(s, "GOARCH=") { 209 fmtCmd.Env[i] = "GOARCH=" + BuildArch 210 } 211 } 212 } 213 214 // mainCmd | fmtCmd > outputFile 215 if fmtCmd.Stdin, err = mainCmd.StdoutPipe(); err != nil { 216 return 217 } 218 if fmtCmd.Stdout, err = os.Create(outputFile); err != nil { 219 return 220 } 221 222 // Make sure the formatter eventually closes 223 if err = fmtCmd.Start(); err != nil { 224 return 225 } 226 defer func() { 227 fmtErr := fmtCmd.Wait() 228 if err == nil { 229 err = fmtErr 230 } 231 }() 232 233 return mainCmd.Run() 234 } 235 236 // Generates all the files for a Linux target 237 func (t *target) generateFiles() error { 238 // Setup environment variables 239 os.Setenv("GOOS", GOOS) 240 os.Setenv("GOARCH", t.GoArch) 241 242 // Get appropriate compiler and emulator (unless on x86) 243 if t.LinuxArch != "x86" { 244 // Check/Setup cross compiler 245 compiler := t.GNUArch + "-gcc" 246 if _, err := exec.LookPath(compiler); err != nil { 247 return err 248 } 249 os.Setenv("CC", compiler) 250 251 // Check/Setup emulator (usually first component of GNUArch) 252 qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")] 253 if t.LinuxArch == "powerpc" { 254 qemuArchName = t.GoArch 255 } 256 os.Setenv("GORUN", "qemu-"+qemuArchName) 257 } else { 258 os.Setenv("CC", "gcc") 259 } 260 261 // Make the include directory and fill it with headers 262 if err := os.MkdirAll(IncludeDir, os.ModePerm); err != nil { 263 return err 264 } 265 defer os.RemoveAll(IncludeDir) 266 if err := t.makeHeaders(); err != nil { 267 return fmt.Errorf("could not make header files: %v", err) 268 } 269 fmt.Println("header files generated") 270 271 // Make each of the four files 272 if err := t.makeZSysnumFile(); err != nil { 273 return fmt.Errorf("could not make zsysnum file: %v", err) 274 } 275 fmt.Println("zsysnum file generated") 276 277 if err := t.makeZSyscallFile(); err != nil { 278 return fmt.Errorf("could not make zsyscall file: %v", err) 279 } 280 fmt.Println("zsyscall file generated") 281 282 if err := t.makeZTypesFile(); err != nil { 283 return fmt.Errorf("could not make ztypes file: %v", err) 284 } 285 fmt.Println("ztypes file generated") 286 287 if err := t.makeZErrorsFile(); err != nil { 288 return fmt.Errorf("could not make zerrors file: %v", err) 289 } 290 fmt.Println("zerrors file generated") 291 292 return nil 293 } 294 295 // Create the Linux and glibc headers in the include directory. 296 func (t *target) makeHeaders() error { 297 // Make the Linux headers we need for this architecture 298 linuxMake := makeCommand("make", "headers_install", "ARCH="+t.LinuxArch, "INSTALL_HDR_PATH="+TempDir) 299 linuxMake.Dir = LinuxDir 300 if err := linuxMake.Run(); err != nil { 301 return err 302 } 303 304 // A Temporary build directory for glibc 305 if err := os.MkdirAll(BuildDir, os.ModePerm); err != nil { 306 return err 307 } 308 defer os.RemoveAll(BuildDir) 309 310 // Make the glibc headers we need for this architecture 311 confScript := filepath.Join(GlibcDir, "configure") 312 glibcConf := makeCommand(confScript, "--prefix="+TempDir, "--host="+t.GNUArch, "--enable-kernel="+MinKernel) 313 glibcConf.Dir = BuildDir 314 if err := glibcConf.Run(); err != nil { 315 return err 316 } 317 glibcMake := makeCommand("make", "install-headers") 318 glibcMake.Dir = BuildDir 319 if err := glibcMake.Run(); err != nil { 320 return err 321 } 322 // We only need an empty stubs file 323 stubsFile := filepath.Join(IncludeDir, "gnu/stubs.h") 324 if file, err := os.Create(stubsFile); err != nil { 325 return err 326 } else { 327 file.Close() 328 } 329 330 return nil 331 } 332 333 // makes the zsysnum_linux_$GOARCH.go file 334 func (t *target) makeZSysnumFile() error { 335 zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch) 336 unistdFile := filepath.Join(IncludeDir, "asm/unistd.h") 337 338 args := append(t.cFlags(), unistdFile) 339 return t.commandFormatOutput("gofmt", zsysnumFile, "linux/mksysnum.pl", args...) 340 } 341 342 // makes the zsyscall_linux_$GOARCH.go file 343 func (t *target) makeZSyscallFile() error { 344 zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch) 345 // Find the correct architecture syscall file (might end with x.go) 346 archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch) 347 if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) { 348 shortArch := strings.TrimSuffix(t.GoArch, "le") 349 archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch) 350 } 351 352 args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch, 353 "syscall_linux.go", archSyscallFile) 354 return t.commandFormatOutput("gofmt", zsyscallFile, "./mksyscall.pl", args...) 355 } 356 357 // makes the zerrors_linux_$GOARCH.go file 358 func (t *target) makeZErrorsFile() error { 359 zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch) 360 361 return t.commandFormatOutput("gofmt", zerrorsFile, "./mkerrors.sh", t.cFlags()...) 362 } 363 364 // makes the ztypes_linux_$GOARCH.go file 365 func (t *target) makeZTypesFile() error { 366 ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch) 367 368 args := []string{"tool", "cgo", "-godefs", "--"} 369 args = append(args, t.cFlags()...) 370 args = append(args, "linux/types.go") 371 return t.commandFormatOutput("mkpost", ztypesFile, "go", args...) 372 } 373 374 // Flags that should be given to gcc and cgo for this target 375 func (t *target) cFlags() []string { 376 // Compile statically to avoid cross-architecture dynamic linking. 377 flags := []string{"-Wall", "-Werror", "-static", "-I" + IncludeDir} 378 379 // Architecture-specific flags 380 if t.SignedChar { 381 flags = append(flags, "-fsigned-char") 382 } 383 if t.LinuxArch == "x86" { 384 flags = append(flags, fmt.Sprintf("-m%d", t.Bits)) 385 } 386 387 return flags 388 } 389 390 // Flags that should be given to mksyscall for this target 391 func (t *target) mksyscallFlags() (flags []string) { 392 if t.Bits == 32 { 393 if t.BigEndian { 394 flags = append(flags, "-b32") 395 } else { 396 flags = append(flags, "-l32") 397 } 398 } 399 400 // This flag menas a 64-bit value should use (even, odd)-pair. 401 if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) { 402 flags = append(flags, "-arm") 403 } 404 return 405 } 406 407 // generatePtracePair takes a pair of GOARCH values that can run each 408 // other's binaries, such as 386 and amd64. It extracts the PtraceRegs 409 // type for each one. It writes a new file defining the types 410 // PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions 411 // Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other 412 // binary on a native system. 413 func generatePtracePair(arch1, arch2 string) error { 414 def1, err := ptraceDef(arch1) 415 if err != nil { 416 return err 417 } 418 def2, err := ptraceDef(arch2) 419 if err != nil { 420 return err 421 } 422 f, err := os.Create(fmt.Sprintf("zptrace%s_linux.go", arch1)) 423 if err != nil { 424 return err 425 } 426 buf := bufio.NewWriter(f) 427 fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%s, %s). DO NOT EDIT.\n", arch1, arch2) 428 fmt.Fprintf(buf, "\n") 429 fmt.Fprintf(buf, "// +build linux\n") 430 fmt.Fprintf(buf, "// +build %s %s\n", arch1, arch2) 431 fmt.Fprintf(buf, "\n") 432 fmt.Fprintf(buf, "package unix\n") 433 fmt.Fprintf(buf, "\n") 434 fmt.Fprintf(buf, "%s\n", `import "unsafe"`) 435 fmt.Fprintf(buf, "\n") 436 writeOnePtrace(buf, arch1, def1) 437 fmt.Fprintf(buf, "\n") 438 writeOnePtrace(buf, arch2, def2) 439 if err := buf.Flush(); err != nil { 440 return err 441 } 442 if err := f.Close(); err != nil { 443 return err 444 } 445 return nil 446 } 447 448 // ptraceDef returns the definition of PtraceRegs for arch. 449 func ptraceDef(arch string) (string, error) { 450 filename := fmt.Sprintf("ztypes_linux_%s.go", arch) 451 data, err := ioutil.ReadFile(filename) 452 if err != nil { 453 return "", fmt.Errorf("reading %s: %v", filename, err) 454 } 455 start := bytes.Index(data, []byte("type PtraceRegs struct")) 456 if start < 0 { 457 return "", fmt.Errorf("%s: no definition of PtraceRegs", filename) 458 } 459 data = data[start:] 460 end := bytes.Index(data, []byte("\n}\n")) 461 if end < 0 { 462 return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename) 463 } 464 return string(data[:end+2]), nil 465 } 466 467 // writeOnePtrace writes out the ptrace definitions for arch. 468 func writeOnePtrace(w io.Writer, arch, def string) { 469 uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:] 470 fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch) 471 fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1)) 472 fmt.Fprintf(w, "\n") 473 fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch) 474 fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch) 475 fmt.Fprintf(w, "\treturn ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))\n") 476 fmt.Fprintf(w, "}\n") 477 fmt.Fprintf(w, "\n") 478 fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch) 479 fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch) 480 fmt.Fprintf(w, "\treturn ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))\n") 481 fmt.Fprintf(w, "}\n") 482 }