rewrite generation of go_std_tables.go from Bash to Go
This makes it portable and easier to maintain for any Go developers. I also want to improve its logic, which would have been harder in shell.pull/871/head
parent
a99fbcbe43
commit
2259abb89f
@ -1,63 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# We can rewrite this bash script in Go if a dependency on bash and coreutils
|
|
||||||
# is a problem during development.
|
|
||||||
|
|
||||||
goroot=$(go env GOROOT)
|
|
||||||
go_version=$(go env GOVERSION) # not "go version", to exclude GOOS/GOARCH
|
|
||||||
|
|
||||||
runtime_and_deps=$(go list -deps runtime)
|
|
||||||
|
|
||||||
# All packages that the runtime linknames to, except runtime and its dependencies.
|
|
||||||
# This resulting list is what we need to "go list" when obfuscating the runtime,
|
|
||||||
# as they are the packages that we may be missing.
|
|
||||||
runtime_linknamed=$(comm -23 <(
|
|
||||||
sed -rn 's@//go:linkname .* ([^.]*)\.[^.]*@\1@p' "${goroot}"/src/runtime/*.go | grep -vE '^main|^runtime\.|_test$' | sort -u
|
|
||||||
) <(
|
|
||||||
# Note that we assume this is constant across platforms.
|
|
||||||
go list -deps runtime | sort -u
|
|
||||||
))
|
|
||||||
|
|
||||||
compiler_intrinsics_table="$(sed -rn 's@.*\b(addF|alias)\("([^"]*)", "([^"]*)",.*@\2 \3@p' "${goroot}"/src/cmd/compile/internal/ssagen/ssa.go | sort -u)"
|
|
||||||
compiler_intrinsics_paths="$(while read path name; do
|
|
||||||
echo ${path}
|
|
||||||
done <<<"${compiler_intrinsics_table}" | sort -u)"
|
|
||||||
|
|
||||||
gofmt >go_std_tables.go <<EOF
|
|
||||||
// Code generated by scripts/gen-go-std-tables.sh; DO NOT EDIT.
|
|
||||||
|
|
||||||
// Generated from Go version ${go_version}.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
var runtimeAndDeps = map[string]bool{
|
|
||||||
$(for path in ${runtime_and_deps}; do
|
|
||||||
echo "\"${path}\": true,"
|
|
||||||
done)
|
|
||||||
}
|
|
||||||
|
|
||||||
var runtimeLinknamed = []string{
|
|
||||||
$(for path in ${runtime_linknamed}; do
|
|
||||||
echo "\"${path}\"",
|
|
||||||
done)
|
|
||||||
// The net package linknames to the runtime, not the other way around.
|
|
||||||
// TODO: support this automatically via our script.
|
|
||||||
"net",
|
|
||||||
}
|
|
||||||
|
|
||||||
var compilerIntrinsicsPkgs = map[string]bool{
|
|
||||||
$(for path in ${compiler_intrinsics_paths}; do
|
|
||||||
echo "\"${path}\": true,"
|
|
||||||
done)
|
|
||||||
}
|
|
||||||
|
|
||||||
var compilerIntrinsicsFuncs = map[string]bool{
|
|
||||||
$(while read path name; do
|
|
||||||
echo "\"${path}.${name}\": true,"
|
|
||||||
done <<<"${compiler_intrinsics_table}")
|
|
||||||
}
|
|
||||||
|
|
||||||
var reflectSkipPkg = map[string]bool{
|
|
||||||
"fmt": true,
|
|
||||||
}
|
|
||||||
EOF
|
|
@ -0,0 +1,182 @@
|
|||||||
|
// Copyright (c) 2024, The Garble Authors.
|
||||||
|
// See LICENSE for licensing information.
|
||||||
|
|
||||||
|
// This is a program used with `go generate`, so it handles errors via panic.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"cmp"
|
||||||
|
"fmt"
|
||||||
|
"go/format"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tmplTables = template.Must(template.New("").Parse(`
|
||||||
|
// Code generated by scripts/gen_go_std_tables.go; DO NOT EDIT.
|
||||||
|
|
||||||
|
// Generated from Go version {{ .GoVersion }}.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
var runtimeAndDeps = map[string]bool{
|
||||||
|
{{- range $path := .RuntimeAndDeps }}
|
||||||
|
"{{ $path }}": true,
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
var runtimeLinknamed = []string{
|
||||||
|
{{- range $path := .RuntimeLinknamed }}
|
||||||
|
"{{ $path }}",
|
||||||
|
{{- end }}
|
||||||
|
// The net package linknames to the runtime, not the other way around.
|
||||||
|
// TODO: support this automatically via our script.
|
||||||
|
"net",
|
||||||
|
}
|
||||||
|
|
||||||
|
var compilerIntrinsicsPkgs = map[string]bool{
|
||||||
|
{{- range $path := .CompilerIntrinsicsPaths }}
|
||||||
|
"{{ $path }}": true,
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
var compilerIntrinsicsFuncs = map[string]bool{
|
||||||
|
{{- range $intr := .CompilerIntrinsics }}
|
||||||
|
"{{ $intr.Path }}.{{ $intr.Name }}": true,
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
|
||||||
|
var reflectSkipPkg = map[string]bool{
|
||||||
|
"fmt": true,
|
||||||
|
}
|
||||||
|
`))
|
||||||
|
|
||||||
|
type tmplData struct {
|
||||||
|
GoVersion string
|
||||||
|
RuntimeAndDeps []string
|
||||||
|
RuntimeLinknamed []string
|
||||||
|
CompilerIntrinsics []tmplIntrinsic
|
||||||
|
CompilerIntrinsicsPaths []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type tmplIntrinsic struct {
|
||||||
|
Path, Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t tmplIntrinsic) Compare(t2 tmplIntrinsic) int {
|
||||||
|
if c := cmp.Compare(t.Path, t2.Path); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return cmp.Compare(t.Name, t2.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t tmplIntrinsic) Equal(t2 tmplIntrinsic) bool {
|
||||||
|
return t.Compare(t2) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdGo(args ...string) string {
|
||||||
|
cmd := exec.Command("go", args...)
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(bytes.TrimSpace(out)) // no trailing newline
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFile(path string) string {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sortedLines(s string) []string {
|
||||||
|
lines := strings.Split(s, "\n")
|
||||||
|
slices.Sort(lines)
|
||||||
|
lines = slices.Compact(lines)
|
||||||
|
return lines
|
||||||
|
}
|
||||||
|
|
||||||
|
var rxLinkname = regexp.MustCompile(`^//go:linkname .* ([^.]*)\.[^.]*$`)
|
||||||
|
var rxIntrinsic = regexp.MustCompile(`\b(addF|alias)\("([^"]*)", "([^"]*)",`)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
goversion := cmdGo("env", "GOVERSION") // not "go version", to exclude GOOS/GOARCH
|
||||||
|
goroot := cmdGo("env", "GOROOT")
|
||||||
|
|
||||||
|
runtimeAndDeps := sortedLines(cmdGo("list", "-deps", "runtime"))
|
||||||
|
|
||||||
|
// All packages that the runtime linknames to, except runtime and its dependencies.
|
||||||
|
// This resulting list is what we need to "go list" when obfuscating the runtime,
|
||||||
|
// as they are the packages that we may be missing.
|
||||||
|
var runtimeLinknamed []string
|
||||||
|
runtimeGoFiles, err := filepath.Glob(filepath.Join(goroot, "src", "runtime", "*.go"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, goFile := range runtimeGoFiles {
|
||||||
|
for _, line := range strings.Split(readFile(goFile), "\n") {
|
||||||
|
m := rxLinkname.FindStringSubmatch(line)
|
||||||
|
if m == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
path := m[1]
|
||||||
|
switch path {
|
||||||
|
case "main", "runtime/metrics_test":
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
runtimeLinknamed = append(runtimeLinknamed, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
slices.Sort(runtimeLinknamed)
|
||||||
|
runtimeLinknamed = slices.Compact(runtimeLinknamed)
|
||||||
|
runtimeLinknamed = slices.DeleteFunc(runtimeLinknamed, func(path string) bool {
|
||||||
|
return slices.Contains(runtimeAndDeps, path)
|
||||||
|
})
|
||||||
|
|
||||||
|
var compilerIntrinsics []tmplIntrinsic
|
||||||
|
var compilerIntrinsicsPaths []string
|
||||||
|
for _, line := range strings.Split(readFile(filepath.Join(
|
||||||
|
goroot, "src", "cmd", "compile", "internal", "ssagen", "ssa.go",
|
||||||
|
)), "\n") {
|
||||||
|
m := rxIntrinsic.FindStringSubmatch(line)
|
||||||
|
if m == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
compilerIntrinsics = append(compilerIntrinsics, tmplIntrinsic{
|
||||||
|
Path: m[2],
|
||||||
|
Name: m[3],
|
||||||
|
})
|
||||||
|
compilerIntrinsicsPaths = append(compilerIntrinsicsPaths, m[2])
|
||||||
|
}
|
||||||
|
slices.SortFunc(compilerIntrinsics, tmplIntrinsic.Compare)
|
||||||
|
compilerIntrinsics = slices.CompactFunc(compilerIntrinsics, tmplIntrinsic.Equal)
|
||||||
|
slices.Sort(compilerIntrinsicsPaths)
|
||||||
|
compilerIntrinsicsPaths = slices.Compact(compilerIntrinsicsPaths)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
tmplTables.Execute(&buf, tmplData{
|
||||||
|
GoVersion: goversion,
|
||||||
|
RuntimeAndDeps: runtimeAndDeps,
|
||||||
|
RuntimeLinknamed: runtimeLinknamed,
|
||||||
|
CompilerIntrinsics: compilerIntrinsics,
|
||||||
|
CompilerIntrinsicsPaths: compilerIntrinsicsPaths,
|
||||||
|
})
|
||||||
|
out := buf.Bytes()
|
||||||
|
formatted, err := format.Source(out)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(string(out))
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.WriteFile("go_std_tables.go", formatted, 0o666); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue