Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compatible with GOP file breakpoints #13

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions _fixtures/goptest/aaa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "fmt"

func Ab() {
fmt.Println("Ab")
}
5 changes: 5 additions & 0 deletions _fixtures/goptest/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module testgop

go 1.21.5

require github.com/liuscraft/testgomod v0.0.0-20240114062333-3352239bb6d1 // indirect
2 changes: 2 additions & 0 deletions _fixtures/goptest/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/liuscraft/testgomod v0.0.0-20240114062333-3352239bb6d1 h1:NOSBQHu6hJ8l1etBPg5v9XCRxtsixqHDL7EPlajRqJg=
github.com/liuscraft/testgomod v0.0.0-20240114062333-3352239bb6d1/go.mod h1:Rd9S8gaMZNqQCwWXI/Tg169w9FvHWrbypL828g160i0=
33 changes: 33 additions & 0 deletions _fixtures/goptest/gop_autogen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package main

import (
"fmt"
"testgop/utils"
"github.com/liuscraft/testgomod"
utils1 "github.com/liuscraft/testgomod/utils"
)
//line main.gop:9:1
func test() {
//line main.gop:10:1
a := 1
//line main.gop:11:1
defer func() {
//line main.gop:12:1
fmt.Println(a)
}()
//line main.gop:15:1
utils1.TestCsgo()
//line main.gop:16:1
utils.TestCsgo()
//line main.gop:17:1
a = 2
}
//line main.gop:20
func main() {
//line main.gop:20:1
test()
//line main.gop:21:1
Version()
//line main.gop:22:1
fmt.Println(testgomod.Version())
}
22 changes: 22 additions & 0 deletions _fixtures/goptest/main.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import (
"fmt"
gopt "testgop/utils"

"github.com/liuscraft/testgomod"
"github.com/liuscraft/testgomod/utils"
)

func test() {
a := 1
defer func() {
fmt.Println(a)
}()

utils.TestCsgo()
gopt.TestCsgo()
a = 2
}

test()
Version()
fmt.Println(testgomod.Version())
Binary file added _fixtures/goptest/testgop
Binary file not shown.
7 changes: 7 additions & 0 deletions _fixtures/goptest/utils/csgo.gop
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package utils

import "fmt"

func TestCsgo() {
fmt.Println("2testcsgo2")
}
8 changes: 8 additions & 0 deletions _fixtures/goptest/utils/gop_autogen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package utils

import "fmt"
//line utils/csgo.gop:5:1
func TestCsgo() {
//line utils/csgo.gop:6:1
fmt.Println("2testcsgo2")
}
7 changes: 7 additions & 0 deletions _fixtures/goptest/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package main

import "fmt"

func Version() {
fmt.Println("Version")
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/spf13/pflag v1.0.5
go.starlark.net v0.0.0-20231101134539-556fd59b42f6
golang.org/x/arch v0.6.0
golang.org/x/mod v0.14.0
golang.org/x/sys v0.13.0
golang.org/x/tools v0.14.0
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -30,6 +31,5 @@ require (
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/exp v0.0.0-20230224173230-c95f2b4c22f2 // indirect
golang.org/x/mod v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
87 changes: 87 additions & 0 deletions pkg/goplus/mod/modcache/modcache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package modcache

import (
"bytes"
"errors"
"log"
"os/exec"
"path/filepath"
"strings"

"golang.org/x/mod/module"
)

// -----------------------------------------------------------------------------

var (
GOMODCACHE = getGOMODCACHE()
)

func getGOMODCACHE() string {
var buf bytes.Buffer
var stderr bytes.Buffer
cmd := exec.Command("go", "env", "GOMODCACHE")
cmd.Stdout = &buf
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
log.Panicln("GOMODCACHE not found:", err)
}
return strings.TrimRight(buf.String(), "\n")
}

// -----------------------------------------------------------------------------

var (
ErrNoNeedToDownload = errors.New("no need to download")
)

// DownloadCachePath returns download cache path of a versioned module.
func DownloadCachePath(mod module.Version) (string, error) {
if mod.Version == "" {
return mod.Path, ErrNoNeedToDownload
}
encPath, err := module.EscapePath(mod.Path)
if err != nil {
return "", err
}
return filepath.Join(GOMODCACHE, "cache/download", encPath, "@v", mod.Version+".zip"), nil
}

// Path returns cache dir of a versioned module.
func Path(mod module.Version) (string, error) {
if mod.Version == "" {
return mod.Path, nil
}
encPath, err := module.EscapePath(mod.Path)
if err != nil {
return "", err
}
return filepath.Join(GOMODCACHE, encPath+"@"+mod.Version), nil
}

// InPath returns if a path is in GOMODCACHE or not.
func InPath(path string) bool {
if strings.HasPrefix(path, GOMODCACHE) {
name := path[len(GOMODCACHE):]
return name == "" || name[0] == '/' || name[0] == '\\'
}
return false
}

// -----------------------------------------------------------------------------
75 changes: 73 additions & 2 deletions pkg/proc/bininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package proc

import (
"bytes"
"debug/buildinfo"
"debug/dwarf"
"debug/elf"
"debug/macho"
Expand All @@ -16,6 +17,7 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
Expand All @@ -29,12 +31,14 @@ import (
"github.com/go-delve/delve/pkg/dwarf/loclist"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/reader"
"github.com/go-delve/delve/pkg/goplus/mod/modcache"
"github.com/go-delve/delve/pkg/goversion"
"github.com/go-delve/delve/pkg/internal/gosym"
"github.com/go-delve/delve/pkg/logflags"
"github.com/go-delve/delve/pkg/proc/debuginfod"
"github.com/go-delve/gore"
"github.com/hashicorp/golang-lru/simplelru"
"golang.org/x/mod/module"
)

const (
Expand Down Expand Up @@ -112,6 +116,8 @@ type BinaryInfo struct {
regabi bool

logger logflags.Logger

buildModInfoMap map[string]string
}

var (
Expand Down Expand Up @@ -702,10 +708,65 @@ func (bi *BinaryInfo) LoadBinaryInfo(path string, entryPoint uint64, debugInfoDi
}

bi.DebugInfoDirectories = debugInfoDirs
bi.PackagePathMap(path)

return bi.AddImage(path, entryPoint)
}

func (bi *BinaryInfo) PackagePathMap(path string) map[string]string {
if len(bi.buildModInfoMap) == 0 {
bi.buildModInfoMap = make(map[string]string)
binfo, _ := buildinfo.ReadFile(path)
fileSplit := strings.Split((filepath.ToSlash(filepath.Dir(path)) + "/"), "/")
LiusCraft marked this conversation as resolved.
Show resolved Hide resolved
// not find abspath, use moduleName
currentDir := binfo.Path + "/"
for i := len(fileSplit) - 1; i > 0; i-- {
temp := strings.Join(fileSplit[:i], "/") + "/"
_, err := os.Open(temp + "go.mod")
LiusCraft marked this conversation as resolved.
Show resolved Hide resolved
if err == nil {
currentDir = temp
break
}
}
bi.buildModInfoMap["main"] = currentDir
bi.buildModInfoMap[binfo.Path+"/"] = currentDir

for _, m := range binfo.Deps {
curModuleName := m.Path + "/"
absPath := curModuleName
var err error
if m.Replace != nil {
if filepath.IsAbs(m.Replace.Path) {
LiusCraft marked this conversation as resolved.
Show resolved Hide resolved
absPath = m.Replace.Path
} else {
absPath = filepath.Join(currentDir, m.Replace.Path)
LiusCraft marked this conversation as resolved.
Show resolved Hide resolved
fi, err := os.Stat(absPath)
if err != nil || !fi.IsDir() {
absPath = curModuleName
}
}
} else {
aa := module.Version{
Path: m.Path,
Version: m.Version,
}
absPath, err = modcache.Path(aa)
if err != nil {
// not find? use moduleName(unique)
bi.buildModInfoMap[curModuleName] = curModuleName
continue
}
}

if runtime.GOOS == "windows" {
absPath = filepath.ToSlash(absPath)
}
bi.buildModInfoMap[curModuleName] = absPath + "/"
}
}
return bi.buildModInfoMap
}

func loadBinaryInfo(bi *BinaryInfo, image *Image, path string, entryPoint uint64) error {
var wg sync.WaitGroup
defer wg.Wait()
Expand Down Expand Up @@ -2288,17 +2349,27 @@ func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugInfoBytes, debugLineB

bi.lookupFunc = nil
bi.lookupGenericFunc = nil

for _, cu := range image.compileUnits {
if cu.lineInfo != nil {
cuName := cu.name
if runtime.GOOS == "windows" {
cuName = filepath.ToSlash(cuName)
}
for _, fileEntry := range cu.lineInfo.FileNames {
fileExt := filepath.Ext(fileEntry.Path)
if fileExt != "" && fileExt != ".go" && fileExt != ".s" && !filepath.IsAbs(fileEntry.Path) {
filePakage := strings.TrimSuffix(cuName, cu.lineInfo.IncludeDirs[fileEntry.DirIdx])
absPath := bi.buildModInfoMap[filePakage] + fileEntry.Path
cu.lineInfo.Lookup[absPath] = fileEntry
delete(cu.lineInfo.Lookup, fileEntry.Path)
fileEntry.Path = absPath
}
bi.Sources = append(bi.Sources, fileEntry.Path)
}
}
}
sort.Strings(bi.Sources)
bi.Sources = uniq(bi.Sources)

if cont != nil {
cont()
}
Expand Down
15 changes: 14 additions & 1 deletion pkg/proc/proc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,14 @@ func TestStep(t *testing.T) {
}
})
}

func TestSources(t *testing.T) {
protest.AllowRecording(t)
withTestProcess("goptest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
for i, v := range p.BinInfo().Sources {
t.Log(i, v)
}
})
}
func TestBreakpoint(t *testing.T) {
protest.AllowRecording(t)
withTestProcess("testprog", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
Expand Down Expand Up @@ -3220,6 +3227,12 @@ func TestDebugStripped2(t *testing.T) {
})
}

func TestGopInfo(t *testing.T) {
withTestProcess("goptest/", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
p.BinInfo()
})
}

func TestIssue844(t *testing.T) {
// Conditional breakpoints should not prevent next from working if their
// condition isn't met.
Expand Down
15 changes: 15 additions & 0 deletions pkg/proc/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"go/constant"
"path/filepath"
"reflect"
"strings"

Expand Down Expand Up @@ -323,7 +324,21 @@ func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe {
l = -1
} else {
it.regs.FrameBase = it.frameBase(fn)
if filepath.Ext(f) != ".go" && !filepath.IsAbs(f) {
LiusCraft marked this conversation as resolved.
Show resolved Hide resolved
LiusCraft marked this conversation as resolved.
Show resolved Hide resolved

absFile := f
for _, fe2 := range fn.cu.lineInfo.FileNames {
absFile = filepath.ToSlash(fn.cu.name + strings.TrimPrefix(fe2.Path, fn.cu.lineInfo.IncludeDirs[fe2.DirIdx]))
for _, v := range it.bi.Sources {
if strings.HasSuffix(v, absFile) {
f = v
}
}
}

}
}

r := Stackframe{Current: Location{PC: it.pc, File: f, Line: l, Fn: fn}, Regs: it.regs, Ret: ret, stackHi: it.stackhi, SystemStack: it.systemstack, lastpc: it.pc}
if r.Regs.Reg(it.regs.PCRegNum) == nil {
r.Regs.AddReg(it.regs.PCRegNum, op.DwarfRegisterFromUint64(it.pc))
Expand Down
Loading