mirror of
https://github.com/golang/go
synced 2024-11-11 20:01:37 -07:00
[dev.regabi] cmd/compile: finish cleanup of Debug parsing
Now that the debug settings are in a struct, use struct tags to set the usage messages and use reflection to populate debugtab, much like we did for the Flag struct. Change-Id: Id2ba30c30a9158c062527715a68bf4dd94679457 Reviewed-on: https://go-review.googlesource.com/c/go/+/272247 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
3c240f5d17
commit
eb3086e5a8
@ -2,149 +2,176 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Debug arguments, set by -d flag.
|
||||||
|
|
||||||
package gc
|
package gc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"cmd/compile/internal/ssa"
|
|
||||||
"cmd/internal/objabi"
|
"cmd/internal/objabi"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Debug arguments.
|
// Debug holds the parsed debugging configuration values.
|
||||||
// These can be specified with the -d flag, as in "-d nil"
|
var Debug = DebugFlags{
|
||||||
// to set the debug_checknil variable.
|
Fieldtrack: &objabi.Fieldtrack_enabled,
|
||||||
// Multiple options can be comma-separated.
|
}
|
||||||
// Each option accepts an optional argument, as in "gcprog=2"
|
|
||||||
var debugtab = []struct {
|
// 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"`
|
||||||
|
CompileLater int `help:"compile functions as late as possible"`
|
||||||
|
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"`
|
||||||
|
Fieldtrack *int `help:"enable field tracking"`
|
||||||
|
GCProg int `help:"print dump of GC programs"`
|
||||||
|
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"`
|
||||||
|
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"`
|
||||||
|
TypeAssert int `help:"print information about type assertion inlining"`
|
||||||
|
TypecheckInl int `help:"eager typechecking of inline function bodies"`
|
||||||
|
WB int `help:"print information about write barriers"`
|
||||||
|
|
||||||
|
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
|
name string
|
||||||
help string
|
help string
|
||||||
val interface{} // must be *int or *string
|
val interface{} // *int or *string
|
||||||
}{
|
|
||||||
{"append", "print information about append compilation", &Debug.Append},
|
|
||||||
{"checkptr", "instrument unsafe pointer conversions", &Debug.Checkptr},
|
|
||||||
{"closure", "print information about closure compilation", &Debug.Closure},
|
|
||||||
{"compilelater", "compile functions as late as possible", &Debug.CompileLater},
|
|
||||||
{"disablenil", "disable nil checks", &Debug.DisableNil},
|
|
||||||
{"dclstack", "run internal dclstack check", &Debug.DclStack},
|
|
||||||
{"dumpptrs", "show Node pointer values in Dump/dumplist output", &Debug.DumpPtrs},
|
|
||||||
{"gcprog", "print dump of GC programs", &Debug.GCProg},
|
|
||||||
{"libfuzzer", "coverage instrumentation for libfuzzer", &Debug.Libfuzzer},
|
|
||||||
{"nil", "print information about nil checks", &Debug.Nil},
|
|
||||||
{"panic", "do not hide any compiler panic", &Debug.Panic},
|
|
||||||
{"slice", "print information about slice compilation", &Debug.Slice},
|
|
||||||
{"typeassert", "print information about type assertion inlining", &Debug.TypeAssert},
|
|
||||||
{"wb", "print information about write barriers", &Debug.WB},
|
|
||||||
{"export", "print export data", &Debug.Export},
|
|
||||||
{"pctab", "print named pc-value table", &Debug.PCTab},
|
|
||||||
{"locationlists", "print information about DWARF location list creation", &Debug.LocationLists},
|
|
||||||
{"typecheckinl", "eager typechecking of inline function bodies", &Debug.TypecheckInl},
|
|
||||||
{"dwarfinl", "print information about DWARF inlined function creation", &Debug.DwarfInl},
|
|
||||||
{"softfloat", "force compiler to emit soft-float code", &Debug.SoftFloat},
|
|
||||||
{"defer", "print information about defer compilation", &Debug.Defer},
|
|
||||||
{"fieldtrack", "enable fieldtracking", &objabi.Fieldtrack_enabled},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var Debug struct {
|
var debugTab []debugField
|
||||||
Append int
|
|
||||||
Checkptr int
|
func init() {
|
||||||
Closure int
|
v := reflect.ValueOf(&Debug).Elem()
|
||||||
CompileLater int
|
t := v.Type()
|
||||||
DisableNil int
|
for i := 0; i < t.NumField(); i++ {
|
||||||
DclStack int
|
f := t.Field(i)
|
||||||
GCProg int
|
if f.Name == "any" {
|
||||||
Libfuzzer int
|
continue
|
||||||
Nil int
|
}
|
||||||
Panic int
|
name := strings.ToLower(f.Name)
|
||||||
Slice int
|
help := f.Tag.Get("help")
|
||||||
TypeAssert int
|
if help == "" {
|
||||||
WB int
|
panic(fmt.Sprintf("base.Debug.%s is missing help text", f.Name))
|
||||||
Export int
|
}
|
||||||
PCTab string
|
ptr := v.Field(i).Addr().Interface()
|
||||||
LocationLists int
|
switch ptr.(type) {
|
||||||
TypecheckInl int
|
default:
|
||||||
DwarfInl int
|
panic(fmt.Sprintf("base.Debug.%s has invalid type %v (must be int or string)", f.Name, f.Type))
|
||||||
SoftFloat int
|
case *int, *string:
|
||||||
Defer int
|
// ok
|
||||||
DumpPtrs int
|
case **int:
|
||||||
|
ptr = *ptr.(**int) // record the *int itself
|
||||||
|
}
|
||||||
|
debugTab = append(debugTab, debugField{name, help, ptr})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseDebug() {
|
// 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
|
// parse -d argument
|
||||||
if Flag.LowerD != "" {
|
if debugstr == "" {
|
||||||
Split:
|
return
|
||||||
for _, name := range strings.Split(Flag.LowerD, ",") {
|
}
|
||||||
if name == "" {
|
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
|
continue
|
||||||
}
|
}
|
||||||
// display help about the -d option itself and quit
|
switch vp := t.val.(type) {
|
||||||
if name == "help" {
|
case nil:
|
||||||
fmt.Print(debugHelpHeader)
|
// Ignore
|
||||||
maxLen := len("ssa/help")
|
case *string:
|
||||||
for _, t := range debugtab {
|
*vp = valstring
|
||||||
if len(t.name) > maxLen {
|
case *int:
|
||||||
maxLen = len(t.name)
|
if !haveInt {
|
||||||
}
|
log.Fatalf("invalid debug value %v", name)
|
||||||
}
|
}
|
||||||
for _, t := range debugtab {
|
*vp = val
|
||||||
fmt.Printf("\t%-*s\t%s\n", maxLen, t.name, t.help)
|
default:
|
||||||
}
|
panic("bad debugtab type")
|
||||||
// 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
|
continue Split
|
||||||
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 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 := ssa.PhaseOption(phase, flag, val, valstring)
|
|
||||||
if err != "" {
|
|
||||||
log.Fatalf(err)
|
|
||||||
}
|
|
||||||
continue Split
|
|
||||||
}
|
|
||||||
log.Fatalf("unknown debug key -d %s\n", name)
|
|
||||||
}
|
}
|
||||||
|
// 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,19 +63,19 @@ type CmdFlags struct {
|
|||||||
// V is added by objabi.AddVersionFlag
|
// V is added by objabi.AddVersionFlag
|
||||||
W CountFlag "help:\"debug parse tree after type checking\""
|
W CountFlag "help:\"debug parse tree after type checking\""
|
||||||
|
|
||||||
LowerC int "help:\"concurrency during compilation (1 means no concurrency)\""
|
LowerC int "help:\"concurrency during compilation (1 means no concurrency)\""
|
||||||
LowerD string "help:\"enable debugging settings; try -d help\""
|
LowerD func(string) "help:\"enable debugging settings; try -d help\""
|
||||||
LowerE CountFlag "help:\"no limit on number of errors reported\""
|
LowerE CountFlag "help:\"no limit on number of errors reported\""
|
||||||
LowerH CountFlag "help:\"halt on error\""
|
LowerH CountFlag "help:\"halt on error\""
|
||||||
LowerJ CountFlag "help:\"debug runtime-initialized variables\""
|
LowerJ CountFlag "help:\"debug runtime-initialized variables\""
|
||||||
LowerL CountFlag "help:\"disable inlining\""
|
LowerL CountFlag "help:\"disable inlining\""
|
||||||
LowerM CountFlag "help:\"print optimization decisions\""
|
LowerM CountFlag "help:\"print optimization decisions\""
|
||||||
LowerO string "help:\"write output to `file`\""
|
LowerO string "help:\"write output to `file`\""
|
||||||
LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
|
LowerP *string "help:\"set expected package import `path`\"" // &Ctxt.Pkgpath, set below
|
||||||
LowerR CountFlag "help:\"debug generated wrappers\""
|
LowerR CountFlag "help:\"debug generated wrappers\""
|
||||||
LowerT bool "help:\"enable tracing for debugging the compiler\""
|
LowerT bool "help:\"enable tracing for debugging the compiler\""
|
||||||
LowerW CountFlag "help:\"debug type checking\""
|
LowerW CountFlag "help:\"debug type checking\""
|
||||||
LowerV *bool "help:\"increase debug verbosity\""
|
LowerV *bool "help:\"increase debug verbosity\""
|
||||||
|
|
||||||
// Special characters
|
// Special characters
|
||||||
Percent int "flag:\"%\" help:\"debug non-static initializers\""
|
Percent int "flag:\"%\" help:\"debug non-static initializers\""
|
||||||
@ -137,6 +137,7 @@ func ParseFlags() {
|
|||||||
Flag.I = addImportDir
|
Flag.I = addImportDir
|
||||||
|
|
||||||
Flag.LowerC = 1
|
Flag.LowerC = 1
|
||||||
|
Flag.LowerD = parseDebug
|
||||||
Flag.LowerP = &Ctxt.Pkgpath
|
Flag.LowerP = &Ctxt.Pkgpath
|
||||||
Flag.LowerV = &Ctxt.Debugvlog
|
Flag.LowerV = &Ctxt.Debugvlog
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ func ParseFlags() {
|
|||||||
Ctxt.Flag_optimize = Flag.N == 0
|
Ctxt.Flag_optimize = Flag.N == 0
|
||||||
Ctxt.Debugasm = int(Flag.S)
|
Ctxt.Debugasm = int(Flag.S)
|
||||||
|
|
||||||
if flag.NArg() < 1 && Flag.LowerD != "help" && Flag.LowerD != "ssa/help" {
|
if flag.NArg() < 1 {
|
||||||
usage()
|
usage()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,8 +222,6 @@ func ParseFlags() {
|
|||||||
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
|
log.Fatalf("cannot use concurrent backend compilation with provided flags; invoked as %v", os.Args)
|
||||||
}
|
}
|
||||||
|
|
||||||
parseDebug()
|
|
||||||
|
|
||||||
if Flag.CompilingRuntime {
|
if Flag.CompilingRuntime {
|
||||||
// Runtime can't use -d=checkptr, at least not yet.
|
// Runtime can't use -d=checkptr, at least not yet.
|
||||||
Debug.Checkptr = 0
|
Debug.Checkptr = 0
|
||||||
@ -330,7 +329,7 @@ func concurrentBackendAllowed() bool {
|
|||||||
// while writing the object file, and that is non-concurrent.
|
// while writing the object file, and that is non-concurrent.
|
||||||
// Adding Debug_vlog, however, causes Debug.S to also print
|
// Adding Debug_vlog, however, causes Debug.S to also print
|
||||||
// while flushing the plist, which happens concurrently.
|
// while flushing the plist, which happens concurrently.
|
||||||
if Ctxt.Debugvlog || Flag.LowerD != "" || Flag.Live > 0 {
|
if Ctxt.Debugvlog || Debug.Any() || Flag.Live > 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// TODO: Test and delete this condition.
|
// TODO: Test and delete this condition.
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"cmd/compile/internal/logopt"
|
"cmd/compile/internal/logopt"
|
||||||
|
"cmd/compile/internal/ssa"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/bio"
|
"cmd/internal/bio"
|
||||||
"cmd/internal/dwarf"
|
"cmd/internal/dwarf"
|
||||||
@ -112,6 +112,7 @@ func Main(archInit func(*Arch)) {
|
|||||||
// pseudo-package used for methods with anonymous receivers
|
// pseudo-package used for methods with anonymous receivers
|
||||||
gopkg = types.NewPkg("go", "")
|
gopkg = types.NewPkg("go", "")
|
||||||
|
|
||||||
|
DebugSSA = ssa.PhaseOption
|
||||||
ParseFlags()
|
ParseFlags()
|
||||||
|
|
||||||
// Record flags that affect the build result. (And don't
|
// Record flags that affect the build result. (And don't
|
||||||
|
Loading…
Reference in New Issue
Block a user