diff --git a/pkg/goversion/go_version.go b/pkg/goversion/go_version.go index 655a16e6..4e959289 100644 --- a/pkg/goversion/go_version.go +++ b/pkg/goversion/go_version.go @@ -161,3 +161,18 @@ func VersionAfterOrEqual(version string, major, minor int) bool { } return ver.AfterOrEqual(GoVersion{major, minor, -1, 0, 0, ""}) } + +const producerVersionPrefix = "Go cmd/compile " + +// ProducerAfterOrEqual checks that the DW_AT_producer version is +// major.minor or a later version, or a development version. +func ProducerAfterOrEqual(producer string, major, minor int) bool { + if strings.HasPrefix(producer, producerVersionPrefix) { + producer = producer[len(producerVersionPrefix):] + } + ver, _ := Parse(producer) + if ver.IsDevel() { + return true + } + return ver.AfterOrEqual(GoVersion{major, minor, -1, 0, 0, ""}) +} diff --git a/pkg/proc/bininfo.go b/pkg/proc/bininfo.go index 93ad5272..f2fef24b 100644 --- a/pkg/proc/bininfo.go +++ b/pkg/proc/bininfo.go @@ -21,6 +21,7 @@ import ( "github.com/derekparker/delve/pkg/dwarf/line" "github.com/derekparker/delve/pkg/dwarf/op" "github.com/derekparker/delve/pkg/dwarf/reader" + "github.com/derekparker/delve/pkg/goversion" ) type BinaryInfo struct { @@ -75,7 +76,8 @@ type compileUnit struct { Name string // univocal name for non-go compile units lineInfo *line.DebugLineInfo // debug_line segment associated with this compile unit LowPC, HighPC uint64 - optimized bool // this compile unit is optimized + optimized bool // this compile unit is optimized + producer string // producer attribute } type partialUnitConstant struct { @@ -365,7 +367,7 @@ func (bi *BinaryInfo) LoadFromData(dwdata *dwarf.Data, debugFrameBytes, debugLin bi.loclistInit(debugLocBytes) - bi.loadDebugInfoMaps(debugLineBytes, nil) + bi.loadDebugInfoMaps(debugLineBytes, nil, nil) } func (bi *BinaryInfo) loclistInit(data []byte) { @@ -440,6 +442,15 @@ func (bi *BinaryInfo) findCompileUnit(pc uint64) *compileUnit { return nil } +func (bi *BinaryInfo) Producer() string { + for _, cu := range bi.compileUnits { + if cu.isgo && cu.producer != "" { + return cu.producer + } + } + return "" +} + // ELF /////////////////////////////////////////////////////////////// func (bi *BinaryInfo) LoadBinaryInfoElf(path string, wg *sync.WaitGroup) error { @@ -470,7 +481,7 @@ func (bi *BinaryInfo) LoadBinaryInfoElf(path string, wg *sync.WaitGroup) error { wg.Add(3) go bi.parseDebugFrameElf(elfFile, wg) - go bi.loadDebugInfoMaps(debugLineBytes, wg) + go bi.loadDebugInfoMaps(debugLineBytes, wg, nil) go bi.setGStructOffsetElf(elfFile, wg) return nil } @@ -582,7 +593,7 @@ func (bi *BinaryInfo) LoadBinaryInfoPE(path string, wg *sync.WaitGroup) error { wg.Add(2) go bi.parseDebugFramePE(peFile, wg) - go bi.loadDebugInfoMaps(debugLineBytes, wg) + go bi.loadDebugInfoMaps(debugLineBytes, wg, nil) // Use ArbitraryUserPointer (0x28) as pointer to pointer // to G struct per: @@ -750,11 +761,22 @@ func (bi *BinaryInfo) LoadBinaryInfoMacho(path string, wg *sync.WaitGroup) error wg.Add(2) go bi.parseDebugFrameMacho(exe, wg) - go bi.loadDebugInfoMaps(debugLineBytes, wg) - bi.gStructOffset = 0x8a0 + go bi.loadDebugInfoMaps(debugLineBytes, wg, bi.setGStructOffsetMacho) return nil } +func (bi *BinaryInfo) setGStructOffsetMacho() { + // In go1.11 it's 0x30, before 0x8a0, see: + // https://github.com/golang/go/issues/23617 + // and go commit b3a854c733257c5249c3435ffcee194f8439676a + producer := bi.Producer() + if producer != "" && goversion.ProducerAfterOrEqual(producer, 1, 11) { + bi.gStructOffset = 0x30 + return + } + bi.gStructOffset = 0x8a0 +} + func (bi *BinaryInfo) parseDebugFrameMacho(exe *macho.File, wg *sync.WaitGroup) { defer wg.Done() diff --git a/pkg/proc/types.go b/pkg/proc/types.go index cfbcd3c6..3e717c87 100644 --- a/pkg/proc/types.go +++ b/pkg/proc/types.go @@ -178,7 +178,7 @@ func (v packageVarsByAddr) Len() int { return len(v) } func (v packageVarsByAddr) Less(i int, j int) bool { return v[i].addr < v[j].addr } func (v packageVarsByAddr) Swap(i int, j int) { v[i], v[j] = v[j], v[i] } -func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGroup) { +func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGroup, cont func()) { if wg != nil { defer wg.Done() } @@ -220,9 +220,15 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou cu.lineInfo = line.Parse(compdir, bytes.NewBuffer(debugLineBytes[lineInfoOffset:])) cu.lineInfo.LogSuppressedErrors(logflags.DebugLineErrors()) } - if producer, _ := entry.Val(dwarf.AttrProducer).(string); cu.isgo && producer != "" { - semicolon := strings.Index(producer, ";") - cu.optimized = semicolon < 0 || !strings.Contains(producer[semicolon:], "-N") || !strings.Contains(producer[semicolon:], "-l") + cu.producer, _ = entry.Val(dwarf.AttrProducer).(string) + if cu.isgo { + semicolon := strings.Index(cu.producer, ";") + if semicolon < 0 { + cu.optimized = true + } else { + cu.optimized = !strings.Contains(cu.producer[semicolon:], "-N") || !strings.Contains(cu.producer[semicolon:], "-l") + cu.producer = cu.producer[:semicolon] + } } bi.compileUnits = append(bi.compileUnits, cu) @@ -395,6 +401,10 @@ func (bi *BinaryInfo) loadDebugInfoMaps(debugLineBytes []byte, wg *sync.WaitGrou } sort.Strings(bi.Sources) bi.Sources = uniq(bi.Sources) + + if cont != nil { + cont() + } } func uniq(s []string) []string {