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  }