Go 1.16 support branch (#2214)
* proc: misc test fixes for Go 1.16 * proc: fix cgo stacktraces in Go 1.16 with simplified C -> Go call path * dwarf/line: make dwarf/line correct when '\\' are used Our code depends heavily on paths being '/' separated because go always produced '/' separated file paths. The call to filepath.Join will normalize the paths, on windows, to always be '\\' separated, which violated our assumptions. This didn't use to be a problem because the codepath that calls filepath.Join was never exercised by executable files produced by Go, but Go 1.16 started producing debug_line sections that use the directory table with https://go-review.googlesource.com/c/go/+/263017/. Fix this to always use path.Join after making sure, on windows, to always normalize paths to use '/' as a separator. Replace the use of filepath.IsAbs with an operating system independent version. * goversion: bump supported Go version
This commit is contained in:
parent
75f00b963c
commit
6dd686ca49
@ -3,7 +3,7 @@ package line
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"path/filepath"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/util"
|
||||
@ -193,21 +193,37 @@ func readFileEntry(info *DebugLineInfo, buf *bytes.Buffer, exitOnEmptyPath bool)
|
||||
}
|
||||
|
||||
if info.normalizeBackslash {
|
||||
entry.Path = strings.Replace(entry.Path, "\\", "/", -1)
|
||||
entry.Path = strings.ReplaceAll(entry.Path, "\\", "/")
|
||||
}
|
||||
|
||||
entry.DirIdx, _ = util.DecodeULEB128(buf)
|
||||
entry.LastModTime, _ = util.DecodeULEB128(buf)
|
||||
entry.Length, _ = util.DecodeULEB128(buf)
|
||||
if !filepath.IsAbs(entry.Path) {
|
||||
if !pathIsAbs(entry.Path) {
|
||||
if entry.DirIdx >= 0 && entry.DirIdx < uint64(len(info.IncludeDirs)) {
|
||||
entry.Path = filepath.Join(info.IncludeDirs[entry.DirIdx], entry.Path)
|
||||
entry.Path = path.Join(info.IncludeDirs[entry.DirIdx], entry.Path)
|
||||
}
|
||||
}
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
// pathIsAbs returns true if this is an absolute path.
|
||||
// We can not use path.IsAbs because it will not recognize windows paths as
|
||||
// absolute. We also can not use filepath.Abs because we want this
|
||||
// processing to be independent of the host operating system (we could be
|
||||
// reading an executable file produced on windows on a unix machine or vice
|
||||
// versa).
|
||||
func pathIsAbs(s string) bool {
|
||||
if len(s) >= 1 && s[0] == '/' {
|
||||
return true
|
||||
}
|
||||
if len(s) >= 2 && s[1] == ':' && (('a' <= s[0] && s[0] <= 'z') || ('A' <= s[0] && s[0] <= 'Z')) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// parseFileEntries5 parses the file table for DWARF 5
|
||||
func parseFileEntries5(info *DebugLineInfo, buf *bytes.Buffer) {
|
||||
fileEntryFormReader := readEntryFormat(buf, info.Logf)
|
||||
@ -217,13 +233,13 @@ func parseFileEntries5(info *DebugLineInfo, buf *bytes.Buffer) {
|
||||
fileEntryFormReader.reset()
|
||||
for fileEntryFormReader.next(buf) {
|
||||
entry := new(FileEntry)
|
||||
var path string
|
||||
var p string
|
||||
var diridx int = -1
|
||||
|
||||
switch fileEntryFormReader.contentType {
|
||||
case _DW_LNCT_path:
|
||||
if fileEntryFormReader.formCode != _DW_FORM_string {
|
||||
path = fileEntryFormReader.str
|
||||
p = fileEntryFormReader.str
|
||||
} else {
|
||||
//TODO(aarzilli): support debug_string, debug_line_str
|
||||
info.Logf("unsupported string form %#x", fileEntryFormReader.formCode)
|
||||
@ -238,10 +254,14 @@ func parseFileEntries5(info *DebugLineInfo, buf *bytes.Buffer) {
|
||||
// not implemented
|
||||
}
|
||||
|
||||
if diridx >= 0 && !filepath.IsAbs(path) && diridx < len(info.IncludeDirs) {
|
||||
path = filepath.Join(info.IncludeDirs[diridx], path)
|
||||
if info.normalizeBackslash {
|
||||
p = strings.ReplaceAll(p, "\\", "/")
|
||||
}
|
||||
entry.Path = path
|
||||
|
||||
if diridx >= 0 && !pathIsAbs(p) && diridx < len(info.IncludeDirs) {
|
||||
p = path.Join(info.IncludeDirs[diridx], p)
|
||||
}
|
||||
entry.Path = p
|
||||
info.FileNames = append(info.FileNames, entry)
|
||||
info.Lookup[entry.Path] = entry
|
||||
}
|
||||
|
@ -11,12 +11,14 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-delve/delve/pkg/dwarf/godwarf"
|
||||
"github.com/go-delve/delve/pkg/goversion"
|
||||
)
|
||||
|
||||
var userTestFile string
|
||||
@ -113,8 +115,10 @@ func testDebugLinePrologueParser(p string, t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
if len(dbl.IncludeDirs) != 1 {
|
||||
t.Fatal("Include dirs not parsed correctly")
|
||||
if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 16) {
|
||||
if len(dbl.IncludeDirs) != 1 {
|
||||
t.Fatal("Include dirs not parsed correctly")
|
||||
}
|
||||
}
|
||||
|
||||
for _, ln := range dbl.Lookup {
|
||||
@ -127,6 +131,7 @@ func testDebugLinePrologueParser(p string, t *testing.T) {
|
||||
}
|
||||
|
||||
for _, n := range dbl.FileNames {
|
||||
t.Logf("file %s\n", n.Path)
|
||||
if strings.Contains(n.Path, "/_fixtures/testnextprog.go") {
|
||||
mainFileFound = true
|
||||
break
|
||||
|
@ -8,7 +8,7 @@ var (
|
||||
MinSupportedVersionOfGoMajor = 1
|
||||
MinSupportedVersionOfGoMinor = 13
|
||||
MaxSupportedVersionOfGoMajor = 1
|
||||
MaxSupportedVersionOfGoMinor = 15
|
||||
MaxSupportedVersionOfGoMinor = 16
|
||||
goTooOldErr = fmt.Errorf("Version of Go is too old for this version of Delve (minimum supported version %d.%d, suppress this error with --check-go-version=false)", MinSupportedVersionOfGoMajor, MinSupportedVersionOfGoMinor)
|
||||
dlvTooOldErr = fmt.Errorf("Version of Delve is too old for this version of Go (maximum supported version %d.%d, suppress this error with --check-go-version=false)", MaxSupportedVersionOfGoMajor, MaxSupportedVersionOfGoMinor)
|
||||
)
|
||||
|
@ -161,7 +161,7 @@ func amd64SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool {
|
||||
it.top = false
|
||||
return true
|
||||
|
||||
case "runtime.cgocallback_gofunc":
|
||||
case "runtime.cgocallback_gofunc", "runtime.cgocallback":
|
||||
// For a detailed description of how this works read the long comment at
|
||||
// the start of $GOROOT/src/runtime/cgocall.go and the source code of
|
||||
// runtime.cgocallback_gofunc in $GOROOT/src/runtime/asm_amd64.s
|
||||
|
@ -139,7 +139,7 @@ const spAlign = 16
|
||||
func arm64SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool {
|
||||
if it.frame.Current.Fn != nil {
|
||||
switch it.frame.Current.Fn.Name {
|
||||
case "runtime.asmcgocall", "runtime.cgocallback_gofunc", "runtime.sigpanic":
|
||||
case "runtime.asmcgocall", "runtime.cgocallback_gofunc", "runtime.sigpanic", "runtime.cgocallback":
|
||||
//do nothing
|
||||
case "runtime.goexit", "runtime.rt0_go", "runtime.mcall":
|
||||
// Look for "top of stack" functions.
|
||||
@ -202,7 +202,7 @@ func arm64SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool
|
||||
callFrameRegs.Reg(callFrameRegs.SPRegNum).Uint64Val = uint64(int64(newsp))
|
||||
return false
|
||||
|
||||
case "runtime.cgocallback_gofunc":
|
||||
case "runtime.cgocallback_gofunc", "runtime.cgocallback":
|
||||
// For a detailed description of how this works read the long comment at
|
||||
// the start of $GOROOT/src/runtime/cgocall.go and the source code of
|
||||
// runtime.cgocallback_gofunc in $GOROOT/src/runtime/asm_arm64.s
|
||||
|
@ -1709,7 +1709,7 @@ func TestAcceptMulticlient(t *testing.T) {
|
||||
},
|
||||
})
|
||||
if err := server.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
panic(err)
|
||||
}
|
||||
<-disconnectChan
|
||||
server.Stop()
|
||||
|
Loading…
Reference in New Issue
Block a user