1
2
3
4
5
6
7
8
9
10
11
12
13
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
36 var LinuxDir string
37 var GlibcDir string
38
39 const TempDir = "/tmp"
40
41 const GOOS = "linux"
42 const BuildArch = "amd64"
43 const MinKernel = "2.6.23"
44
45 type target struct {
46 GoArch string
47 LinuxArch string
48 GNUArch string
49 BigEndian bool
50 SignedChar bool
51 Bits int
52 env []string
53 stderrBuf bytes.Buffer
54 compiler string
55 }
56
57
58
59
60 var targets = []target{
61 {
62 GoArch: "386",
63 LinuxArch: "x86",
64 GNUArch: "i686-linux-gnu",
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
162
163
164
165
166
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
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
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
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
210
211
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
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
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
272 func (t *target) setTargetBuildArch(cmd *exec.Cmd) {
273
274 var env []string
275 env = append(env, t.env...)
276 cmd.Env = append(env, "GOARCH_TARGET="+t.GoArch)
277
278 for i, s := range cmd.Env {
279 if strings.HasPrefix(s, "GOARCH=") {
280 cmd.Env[i] = "GOARCH=" + BuildArch
281 }
282 }
283 }
284
285
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
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
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
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
341 if t.LinuxArch != "x86" {
342
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
350 qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")]
351 if t.LinuxArch == "powerpc" {
352 qemuArchName = t.GoArch
353 }
354
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
367 func (t *target) generateFiles() error {
368
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
393 func (t *target) makeHeaders() error {
394 defer t.printAndResetBuilder()
395
396
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
405 if err := os.MkdirAll(buildDir, os.ModePerm); err != nil {
406 return err
407 }
408 defer os.RemoveAll(buildDir)
409
410
411 confScript := filepath.Join(GlibcDir, "configure")
412 glibcArgs := []string{"--prefix=" + filepath.Join(TempDir, t.GoArch), "--host=" + t.GNUArch}
413 if t.LinuxArch == "loongarch" {
414
415
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
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
440 return t.makeABIHeaders()
441 }
442
443
444
445
446
447
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
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
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
487
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
539
540
541 for i := uint64(0); i < 64; i++ {
542 off := masksSym.Value + i*8
543
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
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
560 func (t *target) makeZSyscallFile() error {
561 zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch)
562
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
584
585 func (t *target) archMksyscallFiles() ([]string, error) {
586
587
588
589
590
591
592
593
594 inputs := []string{
595
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
607 outputs = append(outputs, in)
608 }
609 }
610
611 return outputs, nil
612 }
613
614
615
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
631
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
645 ok := expr.Eval(func(tag string) bool {
646 return tag == GOOS || tag == t.GoArch
647 })
648
649 return ok, nil
650 }
651
652
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
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
674 func (t *target) cFlags() []string {
675
676 flags := []string{"-Wall", "-Werror", "-static", "-I" + filepath.Join(TempDir, t.GoArch, "include")}
677
678
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
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
700 if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) {
701 flags = append(flags, "-arm")
702 }
703 return
704 }
705
706
707 func mergeFiles() error {
708
709 os.Setenv("GOOS", runtime.GOOS)
710 os.Setenv("GOARCH", runtime.GOARCH)
711
712
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
727
728
729
730
731
732
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
768
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
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
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
839
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 `
994
View as plain text