Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/base/debug.go

Documentation: cmd/compile/internal/base

     1  // Copyright 2009 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  // Debug arguments, set by -d flag.
     6  
     7  package base
     8  
     9  import (
    10  	"fmt"
    11  	"log"
    12  	"os"
    13  	"reflect"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  // Debug holds the parsed debugging configuration values.
    19  var Debug DebugFlags
    20  
    21  // DebugFlags defines the debugging configuration values (see var Debug).
    22  // Each struct field is a different value, named for the lower-case of the field name.
    23  // Each field must be an int or string and must have a `help` struct tag.
    24  //
    25  // The -d option takes a comma-separated list of settings.
    26  // Each setting is name=value; for ints, name is short for name=1.
    27  type DebugFlags struct {
    28  	Append               int    `help:"print information about append compilation"`
    29  	Checkptr             int    `help:"instrument unsafe pointer conversions"`
    30  	Closure              int    `help:"print information about closure compilation"`
    31  	DclStack             int    `help:"run internal dclstack check"`
    32  	Defer                int    `help:"print information about defer compilation"`
    33  	DisableNil           int    `help:"disable nil checks"`
    34  	DumpPtrs             int    `help:"show Node pointers values in dump output"`
    35  	DwarfInl             int    `help:"print information about DWARF inlined function creation"`
    36  	Export               int    `help:"print export data"`
    37  	GCProg               int    `help:"print dump of GC programs"`
    38  	InlFuncsWithClosures int    `help:"allow functions with closures to be inlined"`
    39  	Libfuzzer            int    `help:"enable coverage instrumentation for libfuzzer"`
    40  	LocationLists        int    `help:"print information about DWARF location list creation"`
    41  	Nil                  int    `help:"print information about nil checks"`
    42  	NoOpenDefer          int    `help:"disable open-coded defers"`
    43  	PCTab                string `help:"print named pc-value table"`
    44  	Panic                int    `help:"show all compiler panics"`
    45  	Slice                int    `help:"print information about slice compilation"`
    46  	SoftFloat            int    `help:"force compiler to emit soft-float code"`
    47  	TypeAssert           int    `help:"print information about type assertion inlining"`
    48  	TypecheckInl         int    `help:"eager typechecking of inline function bodies"`
    49  	WB                   int    `help:"print information about write barriers"`
    50  	ABIWrap              int    `help:"print information about ABI wrapper generation"`
    51  
    52  	any bool // set when any of the values have been set
    53  }
    54  
    55  // Any reports whether any of the debug flags have been set.
    56  func (d *DebugFlags) Any() bool { return d.any }
    57  
    58  type debugField struct {
    59  	name string
    60  	help string
    61  	val  interface{} // *int or *string
    62  }
    63  
    64  var debugTab []debugField
    65  
    66  func init() {
    67  	v := reflect.ValueOf(&Debug).Elem()
    68  	t := v.Type()
    69  	for i := 0; i < t.NumField(); i++ {
    70  		f := t.Field(i)
    71  		if f.Name == "any" {
    72  			continue
    73  		}
    74  		name := strings.ToLower(f.Name)
    75  		help := f.Tag.Get("help")
    76  		if help == "" {
    77  			panic(fmt.Sprintf("base.Debug.%s is missing help text", f.Name))
    78  		}
    79  		ptr := v.Field(i).Addr().Interface()
    80  		switch ptr.(type) {
    81  		default:
    82  			panic(fmt.Sprintf("base.Debug.%s has invalid type %v (must be int or string)", f.Name, f.Type))
    83  		case *int, *string:
    84  			// ok
    85  		}
    86  		debugTab = append(debugTab, debugField{name, help, ptr})
    87  	}
    88  }
    89  
    90  // DebugSSA is called to set a -d ssa/... option.
    91  // If nil, those options are reported as invalid options.
    92  // If DebugSSA returns a non-empty string, that text is reported as a compiler error.
    93  var DebugSSA func(phase, flag string, val int, valString string) string
    94  
    95  // parseDebug parses the -d debug string argument.
    96  func parseDebug(debugstr string) {
    97  	// parse -d argument
    98  	if debugstr == "" {
    99  		return
   100  	}
   101  	Debug.any = true
   102  Split:
   103  	for _, name := range strings.Split(debugstr, ",") {
   104  		if name == "" {
   105  			continue
   106  		}
   107  		// display help about the -d option itself and quit
   108  		if name == "help" {
   109  			fmt.Print(debugHelpHeader)
   110  			maxLen := len("ssa/help")
   111  			for _, t := range debugTab {
   112  				if len(t.name) > maxLen {
   113  					maxLen = len(t.name)
   114  				}
   115  			}
   116  			for _, t := range debugTab {
   117  				fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
   118  			}
   119  			// ssa options have their own help
   120  			fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging")
   121  			fmt.Print(debugHelpFooter)
   122  			os.Exit(0)
   123  		}
   124  		val, valstring, haveInt := 1, "", true
   125  		if i := strings.IndexAny(name, "=:"); i >= 0 {
   126  			var err error
   127  			name, valstring = name[:i], name[i+1:]
   128  			val, err = strconv.Atoi(valstring)
   129  			if err != nil {
   130  				val, haveInt = 1, false
   131  			}
   132  		}
   133  		for _, t := range debugTab {
   134  			if t.name != name {
   135  				continue
   136  			}
   137  			switch vp := t.val.(type) {
   138  			case nil:
   139  				// Ignore
   140  			case *string:
   141  				*vp = valstring
   142  			case *int:
   143  				if !haveInt {
   144  					log.Fatalf("invalid debug value %v", name)
   145  				}
   146  				*vp = val
   147  			default:
   148  				panic("bad debugtab type")
   149  			}
   150  			continue Split
   151  		}
   152  		// special case for ssa for now
   153  		if DebugSSA != nil && strings.HasPrefix(name, "ssa/") {
   154  			// expect form ssa/phase/flag
   155  			// e.g. -d=ssa/generic_cse/time
   156  			// _ in phase name also matches space
   157  			phase := name[4:]
   158  			flag := "debug" // default flag is debug
   159  			if i := strings.Index(phase, "/"); i >= 0 {
   160  				flag = phase[i+1:]
   161  				phase = phase[:i]
   162  			}
   163  			err := DebugSSA(phase, flag, val, valstring)
   164  			if err != "" {
   165  				log.Fatalf(err)
   166  			}
   167  			continue Split
   168  		}
   169  		log.Fatalf("unknown debug key -d %s\n", name)
   170  	}
   171  }
   172  
   173  const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
   174  
   175  <key> is one of:
   176  
   177  `
   178  
   179  const debugHelpFooter = `
   180  <value> is key-specific.
   181  
   182  Key "checkptr" supports values:
   183  	"0": instrumentation disabled
   184  	"1": conversions involving unsafe.Pointer are instrumented
   185  	"2": conversions to unsafe.Pointer force heap allocation
   186  
   187  Key "pctab" supports values:
   188  	"pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata"
   189  `
   190  

View as plain text