--- /dev/null
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+
+// This is based on the implementation of src/cmd/internal/obj/stringer.go.
+// This is a mini version of the stringer tool customized for the Cnames
+// table in the architecture support for obj.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "regexp"
+ "strings"
+)
+
+var (
+ input = flag.String("i", "", "input file name")
+ output = flag.String("o", "", "output file name")
+ pkg = flag.String("p", "", "package name")
+)
+
+var cnameExp = regexp.MustCompile(`^\tC_([A-Za-z0-9_]+)`)
+
+func main() {
+ flag.Parse()
+ if *input == "" || *output == "" || *pkg == "" {
+ flag.Usage()
+ os.Exit(2)
+ }
+
+ start := ""
+ switch *pkg {
+ case "arm64":
+ start = "var cnames7 = []string{\n\t\"\", // C_NONE starts from 1\n"
+ case "loong64", "mips":
+ start = "var cnames0 = []string{\n"
+ case "ppc64":
+ start = "var cnames9 = []string{\n"
+ case "s390x":
+ start = "var cnamesz = []string{\n"
+ default:
+ fmt.Printf("Only supports generating Cnames for arm64,loong64,mips,ppc64,s390x.")
+ os.Exit(0)
+ }
+
+ in, err := os.Open(*input)
+ if err != nil {
+ log.Fatal(err)
+ }
+ fd, err := os.Create(*output)
+ if err != nil {
+ log.Fatal(err)
+ }
+ out := bufio.NewWriter(fd)
+ closeOut := func() {
+ if err = out.Flush(); err != nil {
+ log.Fatal(err)
+ }
+
+ if err = fd.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }
+ defer closeOut()
+
+ on := false
+ s := bufio.NewScanner(in)
+ for s.Scan() {
+ line := s.Text()
+ if !on {
+ // First relevant line contains "C_NONE = iota".
+ // If we find it, delete the "=" so we don't stop immediately.
+ const first = "C_NONE"
+ if !strings.Contains(line, first) {
+ continue
+ }
+
+ const suffix = "= iota"
+ index := strings.Index(line, suffix)
+ if index < 0 {
+ continue
+ }
+ line = line[:index]
+
+ // It's on. Start with the header.
+ fmt.Fprintf(out, header, *input, *output, *pkg, *pkg)
+ fmt.Fprintf(out, start)
+ on = true
+ }
+
+ // Strip comments so their text won't defeat our heuristic.
+ index := strings.Index(line, "//")
+ if index > 0 {
+ line = line[:index]
+ }
+ index = strings.Index(line, "/*")
+ if index > 0 {
+ comments := line[index:]
+ if !strings.Contains(comments, "*/") {
+ log.Fatalf("invalid comment: %s\n", comments)
+ }
+ line = line[:index]
+ }
+
+ // Termination condition: Any line with an = changes the sequence,
+ // so stop there, and stop at a closing brace.
+ if strings.HasPrefix(line, "}") || strings.ContainsRune(line, '=') {
+ break
+ }
+
+ sub := cnameExp.FindStringSubmatch(line)
+ if len(sub) < 2 {
+ continue
+ } else {
+ fmt.Fprintf(out, "\t%q,\n", sub[1])
+ }
+ }
+ fmt.Fprintln(out, "}")
+ if s.Err() != nil {
+ log.Fatal(err)
+ }
+}
+
+const header = `// Code generated by mkcnames -i %s -o %s -p %s; DO NOT EDIT.
+
+package %s
+
+// This order should be strictly consistent to that in a.out.go.
+`