1
0
mirror of https://github.com/golang/go synced 2024-11-12 04:40:22 -07:00

cmd/compile, cmd/link: record compiler flags in DW_AT_producer

This adds a whitelisted subset of compiler flags to the DW_AT_producer
DWARF attribute of each package compilation unit DIE. This is common
practice in DWARF and can help debuggers determine the quality of the
produced debugging information.

Fixes #22168.

Change-Id: I1b994ef2262aa9b88b68eb6e883695d1103acc58
Reviewed-on: https://go-review.googlesource.com/71430
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Austin Clements 2017-10-17 17:09:54 -04:00
parent 193088b246
commit 2c1d2e06af
4 changed files with 81 additions and 1 deletions

View File

@ -11,6 +11,7 @@ import (
"bytes"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/dwarf"
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/src"
@ -239,6 +240,11 @@ func Main(archInit func(*Arch)) {
flag.StringVar(&benchfile, "bench", "", "append benchmark times to `file`")
objabi.Flagparse(usage)
// Record flags that affect the build result. (And don't
// record flags that don't, since that would cause spurious
// changes in the binary.)
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists")
Ctxt.Flag_shared = flag_dynlink || flag_shared
Ctxt.Flag_dynlink = flag_dynlink
Ctxt.Flag_optimize = Debug['N'] == 0
@ -1195,3 +1201,55 @@ func concurrentBackendAllowed() bool {
}
return true
}
// recordFlags records the specified command-line flags to be placed
// in the DWARF info.
func recordFlags(flags ...string) {
if myimportpath == "" {
// We can't record the flags if we don't know what the
// package name is.
return
}
type BoolFlag interface {
IsBoolFlag() bool
}
type CountFlag interface {
IsCountFlag() bool
}
var cmd bytes.Buffer
for _, name := range flags {
f := flag.Lookup(name)
if f == nil {
continue
}
getter := f.Value.(flag.Getter)
if getter.String() == f.DefValue {
// Flag has default value, so omit it.
continue
}
if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
val, ok := getter.Get().(bool)
if ok && val {
fmt.Fprintf(&cmd, " -%s", f.Name)
continue
}
}
if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
val, ok := getter.Get().(int)
if ok && val == 1 {
fmt.Fprintf(&cmd, " -%s", f.Name)
continue
}
}
fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
}
if cmd.Len() == 0 {
return
}
s := Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + myimportpath)
s.Type = objabi.SDWARFINFO
Ctxt.Data = append(Ctxt.Data, s)
s.P = cmd.Bytes()[1:]
}

View File

@ -21,10 +21,14 @@ const LocPrefix = "go.loc."
// RangePrefix is the prefix for all the symbols containing DWARF range lists.
const RangePrefix = "go.range."
// InfoConstPrefix is the prefix for all symbols containing DWARF info
// ConstInfoPrefix is the prefix for all symbols containing DWARF info
// entries that contain constants.
const ConstInfoPrefix = "go.constinfo."
// CUInfoPrefix is the prefix for symbols containing information to
// populate the DWARF compilation unit info entries.
const CUInfoPrefix = "go.cuinfo."
// Sym represents a symbol.
type Sym interface {
Len() int64

View File

@ -94,10 +94,18 @@ func (c *count) Set(s string) error {
return nil
}
func (c *count) Get() interface{} {
return int(*c)
}
func (c *count) IsBoolFlag() bool {
return true
}
func (c *count) IsCountFlag() bool {
return true
}
type fn0 func()
func (f fn0) Set(s string) error {

View File

@ -1059,7 +1059,17 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo
// the linker directory. If we move CU construction into the
// compiler, this should happen naturally.
newattr(dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir)
producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+lib.Pkg, 0)
producer := "Go cmd/compile " + objabi.Version
if len(producerExtra.P) > 0 {
// We put a semicolon before the flags to clearly
// separate them from the version, which can be long
// and have lots of weird things in it in development
// versions. We promise not to put a semicolon in the
// version, so it should be safe for readers to scan
// forward to the semicolon.
producer += "; " + string(producerExtra.P)
}
newattr(dwinfo, dwarf.DW_AT_producer, dwarf.DW_CLS_STRING, int64(len(producer)), producer)
// Write .debug_line Line Number Program Header (sec 6.2.4)