github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/load/godebug.go (about) 1 // Copyright 2023 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 package load 6 7 import ( 8 "errors" 9 "fmt" 10 "go/build" 11 "sort" 12 "strconv" 13 "strings" 14 15 "github.com/go-asm/go/cmd/go/modload" 16 "github.com/go-asm/go/godebugs" 17 ) 18 19 var ErrNotGoDebug = errors.New("not //go:debug line") 20 21 func ParseGoDebug(text string) (key, value string, err error) { 22 if !strings.HasPrefix(text, "//go:debug") { 23 return "", "", ErrNotGoDebug 24 } 25 i := strings.IndexAny(text, " \t") 26 if i < 0 { 27 if strings.TrimSpace(text) == "//go:debug" { 28 return "", "", fmt.Errorf("missing key=value") 29 } 30 return "", "", ErrNotGoDebug 31 } 32 k, v, ok := strings.Cut(strings.TrimSpace(text[i:]), "=") 33 if !ok { 34 return "", "", fmt.Errorf("missing key=value") 35 } 36 if strings.ContainsAny(k, " \t") { 37 return "", "", fmt.Errorf("key contains space") 38 } 39 if strings.ContainsAny(v, " \t") { 40 return "", "", fmt.Errorf("value contains space") 41 } 42 if strings.ContainsAny(k, ",") { 43 return "", "", fmt.Errorf("key contains comma") 44 } 45 if strings.ContainsAny(v, ",") { 46 return "", "", fmt.Errorf("value contains comma") 47 } 48 49 for _, info := range godebugs.All { 50 if k == info.Name { 51 return k, v, nil 52 } 53 } 54 return "", "", fmt.Errorf("unknown //go:debug setting %q", k) 55 } 56 57 // defaultGODEBUG returns the default GODEBUG setting for the main package p. 58 // When building a test binary, directives, testDirectives, and xtestDirectives 59 // list additional directives from the package under test. 60 func defaultGODEBUG(p *Package, directives, testDirectives, xtestDirectives []build.Directive) string { 61 if p.Name != "main" { 62 return "" 63 } 64 goVersion := modload.MainModules.GoVersion() 65 if modload.RootMode == modload.NoRoot && p.Module != nil { 66 // This is go install pkg@version or go run pkg@version. 67 // Use the Go version from the package. 68 // If there isn't one, then 69 goVersion = p.Module.GoVersion 70 if goVersion == "" { 71 goVersion = "1.20" 72 } 73 } 74 75 m := godebugForGoVersion(goVersion) 76 for _, list := range [][]build.Directive{p.Internal.Build.Directives, directives, testDirectives, xtestDirectives} { 77 for _, d := range list { 78 k, v, err := ParseGoDebug(d.Text) 79 if err != nil { 80 continue 81 } 82 if m == nil { 83 m = make(map[string]string) 84 } 85 m[k] = v 86 } 87 } 88 var keys []string 89 for k := range m { 90 keys = append(keys, k) 91 } 92 sort.Strings(keys) 93 var b strings.Builder 94 for _, k := range keys { 95 if b.Len() > 0 { 96 b.WriteString(",") 97 } 98 b.WriteString(k) 99 b.WriteString("=") 100 b.WriteString(m[k]) 101 } 102 return b.String() 103 } 104 105 func godebugForGoVersion(v string) map[string]string { 106 if strings.Count(v, ".") >= 2 { 107 i := strings.Index(v, ".") 108 j := i + 1 + strings.Index(v[i+1:], ".") 109 v = v[:j] 110 } 111 112 if !strings.HasPrefix(v, "1.") { 113 return nil 114 } 115 n, err := strconv.Atoi(v[len("1."):]) 116 if err != nil { 117 return nil 118 } 119 120 def := make(map[string]string) 121 for _, info := range godebugs.All { 122 if n < info.Changed { 123 def[info.Name] = info.Old 124 } 125 } 126 return def 127 }