// Copyright 2009 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. // Debug arguments, set by -d flag. package base import ( "fmt" "log" "os" "reflect" "strconv" "strings" ) // Debug holds the parsed debugging configuration values. var Debug DebugFlags // DebugFlags defines the debugging configuration values (see var Debug). // Each struct field is a different value, named for the lower-case of the field name. // Each field must be an int or string and must have a `help` struct tag. // // The -d option takes a comma-separated list of settings. // Each setting is name=value; for ints, name is short for name=1. type DebugFlags struct { Append int `help:"print information about append compilation"` Checkptr int `help:"instrument unsafe pointer conversions"` Closure int `help:"print information about closure compilation"` DclStack int `help:"run internal dclstack check"` Defer int `help:"print information about defer compilation"` DisableNil int `help:"disable nil checks"` DumpPtrs int `help:"show Node pointers values in dump output"` DwarfInl int `help:"print information about DWARF inlined function creation"` Export int `help:"print export data"` GCProg int `help:"print dump of GC programs"` InlFuncsWithClosures int `help:"allow functions with closures to be inlined"` Libfuzzer int `help:"enable coverage instrumentation for libfuzzer"` LocationLists int `help:"print information about DWARF location list creation"` Nil int `help:"print information about nil checks"` NoOpenDefer int `help:"disable open-coded defers"` PCTab string `help:"print named pc-value table"` Panic int `help:"show all compiler panics"` Slice int `help:"print information about slice compilation"` SoftFloat int `help:"force compiler to emit soft-float code"` SyncFrames int `help:"how many writer stack frames to include at sync points in unified export data"` TypeAssert int `help:"print information about type assertion inlining"` TypecheckInl int `help:"eager typechecking of inline function bodies"` Unified int `help:"enable unified IR construction"` UnifiedQuirks int `help:"enable unified IR construction's quirks mode"` WB int `help:"print information about write barriers"` ABIWrap int `help:"print information about ABI wrapper generation"` any bool // set when any of the values have been set } // Any reports whether any of the debug flags have been set. func (d *DebugFlags) Any() bool { return d.any } type debugField struct { name string help string val interface{} // *int or *string } var debugTab []debugField func init() { v := reflect.ValueOf(&Debug).Elem() t := v.Type() for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Name == "any" { continue } name := strings.ToLower(f.Name) help := f.Tag.Get("help") if help == "" { panic(fmt.Sprintf("base.Debug.%s is missing help text", f.Name)) } ptr := v.Field(i).Addr().Interface() switch ptr.(type) { default: panic(fmt.Sprintf("base.Debug.%s has invalid type %v (must be int or string)", f.Name, f.Type)) case *int, *string: // ok } debugTab = append(debugTab, debugField{name, help, ptr}) } } // DebugSSA is called to set a -d ssa/... option. // If nil, those options are reported as invalid options. // If DebugSSA returns a non-empty string, that text is reported as a compiler error. var DebugSSA func(phase, flag string, val int, valString string) string // parseDebug parses the -d debug string argument. func parseDebug(debugstr string) { // parse -d argument if debugstr == "" { return } Debug.any = true Split: for _, name := range strings.Split(debugstr, ",") { if name == "" { continue } // display help about the -d option itself and quit if name == "help" { fmt.Print(debugHelpHeader) maxLen := len("ssa/help") for _, t := range debugTab { if len(t.name) > maxLen { maxLen = len(t.name) } } for _, t := range debugTab { fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help) } // ssa options have their own help fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging") fmt.Print(debugHelpFooter) os.Exit(0) } val, valstring, haveInt := 1, "", true if i := strings.IndexAny(name, "=:"); i >= 0 { var err error name, valstring = name[:i], name[i+1:] val, err = strconv.Atoi(valstring) if err != nil { val, haveInt = 1, false } } for _, t := range debugTab { if t.name != name { continue } switch vp := t.val.(type) { case nil: // Ignore case *string: *vp = valstring case *int: if !haveInt { log.Fatalf("invalid debug value %v", name) } *vp = val default: panic("bad debugtab type") } continue Split } // special case for ssa for now if DebugSSA != nil && strings.HasPrefix(name, "ssa/") { // expect form ssa/phase/flag // e.g. -d=ssa/generic_cse/time // _ in phase name also matches space phase := name[4:] flag := "debug" // default flag is debug if i := strings.Index(phase, "/"); i >= 0 { flag = phase[i+1:] phase = phase[:i] } err := DebugSSA(phase, flag, val, valstring) if err != "" { log.Fatalf(err) } continue Split } log.Fatalf("unknown debug key -d %s\n", name) } } const debugHelpHeader = `usage: -d arg[,arg]* and arg is [=] is one of: ` const debugHelpFooter = ` is key-specific. Key "checkptr" supports values: "0": instrumentation disabled "1": conversions involving unsafe.Pointer are instrumented "2": conversions to unsafe.Pointer force heap allocation Key "pctab" supports values: "pctospadj", "pctofile", "pctoline", "pctoinline", "pctopcdata" `