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