
Change FindLocation so it can return a substitute location expression and propagate it to pkg/terminal/command. When breakpoints are set using the syntax :<lineno> or +<lineno> produce a substitute location expression that doesn't depend on having a valid scope and can be used to restore the breakpoint. Fixes #3423
143 lines
3.3 KiB
Go
143 lines
3.3 KiB
Go
package service_test
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/go-delve/delve/service/api"
|
|
"github.com/go-delve/delve/service/rpc1"
|
|
"github.com/go-delve/delve/service/rpc2"
|
|
)
|
|
|
|
func assertNoError(err error, t *testing.T, s string) {
|
|
if err != nil {
|
|
_, file, line, _ := runtime.Caller(1)
|
|
fname := filepath.Base(file)
|
|
t.Fatalf("failed assertion at %s:%d: %s - %s\n", fname, line, s, err)
|
|
}
|
|
}
|
|
|
|
func assertError(err error, t *testing.T, s string) {
|
|
if err == nil {
|
|
_, file, line, _ := runtime.Caller(1)
|
|
fname := filepath.Base(file)
|
|
t.Fatalf("failed assertion at %s:%d: %s (no error)\n", fname, line, s)
|
|
}
|
|
|
|
if strings.Contains(err.Error(), "Internal debugger error") {
|
|
_, file, line, _ := runtime.Caller(1)
|
|
fname := filepath.Base(file)
|
|
t.Fatalf("failed assertion at %s:%d: %s internal debugger error: %v\n", fname, line, s, err)
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
runtime.GOMAXPROCS(2)
|
|
}
|
|
|
|
type nextTest struct {
|
|
begin, end int
|
|
}
|
|
|
|
func testProgPath(t *testing.T, name string) string {
|
|
fp, err := filepath.Abs(fmt.Sprintf("_fixtures/%s.go", name))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(fp); err != nil {
|
|
fp, err = filepath.Abs(fmt.Sprintf("../../_fixtures/%s.go", name))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
sympath, err := filepath.EvalSymlinks(fp)
|
|
if err == nil {
|
|
fp = strings.ReplaceAll(sympath, "\\", "/")
|
|
}
|
|
return fp
|
|
}
|
|
|
|
type BreakpointLister interface {
|
|
ListBreakpoints() ([]*api.Breakpoint, error)
|
|
}
|
|
|
|
func countBreakpoints(t *testing.T, c interface{}) int {
|
|
var bps []*api.Breakpoint
|
|
var err error
|
|
switch c := c.(type) {
|
|
case *rpc2.RPCClient:
|
|
bps, err = c.ListBreakpoints(false)
|
|
case *rpc1.RPCClient:
|
|
bps, err = c.ListBreakpoints()
|
|
}
|
|
assertNoError(err, t, "ListBreakpoints()")
|
|
bpcount := 0
|
|
for _, bp := range bps {
|
|
if bp.ID >= 0 {
|
|
bpcount++
|
|
}
|
|
}
|
|
return bpcount
|
|
}
|
|
|
|
type locationFinder1 interface {
|
|
FindLocation(api.EvalScope, string) ([]api.Location, error)
|
|
}
|
|
|
|
type locationFinder2 interface {
|
|
FindLocation(api.EvalScope, string, bool, [][2]string) ([]api.Location, string, error)
|
|
}
|
|
|
|
func findLocationHelper(t *testing.T, c interface{}, loc string, shouldErr bool, count int, checkAddr uint64) []uint64 {
|
|
var locs []api.Location
|
|
var err error
|
|
|
|
switch c := c.(type) {
|
|
case locationFinder1:
|
|
locs, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc)
|
|
case locationFinder2:
|
|
locs, _, err = c.FindLocation(api.EvalScope{GoroutineID: -1}, loc, false, nil)
|
|
default:
|
|
t.Errorf("unexpected type %T passed to findLocationHelper", c)
|
|
}
|
|
|
|
t.Logf("FindLocation(\"%s\") → %v\n", loc, locs)
|
|
|
|
if shouldErr {
|
|
if err == nil {
|
|
t.Fatalf("Resolving location <%s> didn't return an error: %v", loc, locs)
|
|
}
|
|
} else {
|
|
if err != nil {
|
|
t.Fatalf("Error resolving location <%s>: %v", loc, err)
|
|
}
|
|
}
|
|
|
|
if (count >= 0) && (len(locs) != count) {
|
|
t.Fatalf("Wrong number of breakpoints returned for location <%s> (got %d, expected %d)", loc, len(locs), count)
|
|
}
|
|
|
|
if checkAddr != 0 && checkAddr != locs[0].PC {
|
|
t.Fatalf("Wrong address returned for location <%s> (got %#x, expected %#x)", loc, locs[0].PC, checkAddr)
|
|
}
|
|
|
|
addrs := make([]uint64, len(locs))
|
|
for i := range locs {
|
|
addrs[i] = locs[i].PC
|
|
}
|
|
return addrs
|
|
}
|
|
|
|
func getCurinstr(d3 api.AsmInstructions) *api.AsmInstruction {
|
|
for i := range d3 {
|
|
if d3[i].AtPC {
|
|
return &d3[i]
|
|
}
|
|
}
|
|
return nil
|
|
}
|