proc: Implement target.Interface for gdbserver backend
This commit is contained in:
parent
c1879472a1
commit
c8d9352522
@ -5,6 +5,13 @@ This project adheres to Semantic Versioning.
|
||||
|
||||
All changes mention the author, unless contributed by me (@derekparker).
|
||||
|
||||
## [NEWEST VERSION] RELEASE DATE
|
||||
|
||||
### Added
|
||||
|
||||
- Added support for core files (@heschik)
|
||||
- Added support for lldb-server and debugserver as backend, using debugserver by default on macOS (@aarzilli)
|
||||
|
||||
## [0.12.2] 2017-04-13
|
||||
|
||||
### Fixed
|
||||
|
17
Makefile
17
Makefile
@ -3,6 +3,7 @@ UNAME=$(shell uname)
|
||||
PREFIX=github.com/derekparker/delve
|
||||
GOVERSION=$(shell go version)
|
||||
BUILD_SHA=$(shell git rev-parse HEAD)
|
||||
LLDB_SERVER=$(shell which lldb-server)
|
||||
|
||||
ifeq "$(UNAME)" "Darwin"
|
||||
BUILD_FLAGS=-ldflags="-s -X main.Build=$(BUILD_SHA)"
|
||||
@ -21,6 +22,7 @@ ALL_PACKAGES=$(shell go list ./... | grep -v /vendor/ | grep -v /scripts)
|
||||
# See https://github.com/golang/go/issues/11887#issuecomment-126117692.
|
||||
ifeq "$(UNAME)" "Darwin"
|
||||
TEST_FLAGS=-exec=$(shell pwd)/scripts/testsign
|
||||
export PROCTEST=lldb
|
||||
DARWIN="true"
|
||||
endif
|
||||
|
||||
@ -63,9 +65,20 @@ endif
|
||||
else
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) $(ALL_PACKAGES)
|
||||
endif
|
||||
ifneq "$(shell which lldb-server)" ""
|
||||
@echo
|
||||
@echo 'Testing LLDB backend (proc)'
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/pkg/proc -backend=lldb
|
||||
@echo
|
||||
@echo 'Testing LLDB backend (integration)'
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/service/test -backend=lldb
|
||||
@echo
|
||||
@echo 'Testing LLDB backend (terminal)'
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) $(PREFIX)/pkg/terminal -backend=lldb
|
||||
endif
|
||||
|
||||
test-proc-run:
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) -test.v -test.run="$(RUN)" $(PREFIX)/pkg/proc
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) -test.v -test.run="$(RUN)" -backend=$(BACKEND) $(PREFIX)/pkg/proc
|
||||
|
||||
test-integration-run:
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) -test.run="$(RUN)" $(PREFIX)/service/test
|
||||
go test $(TEST_FLAGS) $(BUILD_FLAGS) -test.run="$(RUN)" -backend=$(BACKEND) $(PREFIX)/service/test
|
||||
|
@ -42,6 +42,9 @@ var (
|
||||
// WorkingDir is the working directory for running the program.
|
||||
WorkingDir string
|
||||
|
||||
// Backend selection
|
||||
Backend string
|
||||
|
||||
// RootCommand is the root of the command tree.
|
||||
RootCommand *cobra.Command
|
||||
|
||||
@ -92,10 +95,14 @@ func New() *cobra.Command {
|
||||
RootCommand.PersistentFlags().StringVar(&InitFile, "init", "", "Init file, executed by the terminal client.")
|
||||
RootCommand.PersistentFlags().StringVar(&BuildFlags, "build-flags", buildFlagsDefault, "Build flags, to be passed to the compiler.")
|
||||
RootCommand.PersistentFlags().StringVar(&WorkingDir, "wd", ".", "Working directory for running the program.")
|
||||
RootCommand.PersistentFlags().StringVar(&Backend, "backend", "default", `Backend selection:
|
||||
default Uses lldb on macOS, native everywhere else.
|
||||
native Native backend.
|
||||
lldb Uses lldb-server or debugserver.`)
|
||||
|
||||
// 'attach' subcommand.
|
||||
attachCommand := &cobra.Command{
|
||||
Use: "attach pid",
|
||||
Use: "attach pid [executable]",
|
||||
Short: "Attach to running process and begin debugging.",
|
||||
Long: `Attach to an already running process and begin debugging it.
|
||||
|
||||
@ -304,6 +311,7 @@ func traceCmd(cmd *cobra.Command, args []string) {
|
||||
AttachPid: traceAttachPid,
|
||||
APIVersion: 2,
|
||||
WorkingDir: WorkingDir,
|
||||
Backend: Backend,
|
||||
}, Log)
|
||||
if err := server.Run(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
@ -361,7 +369,7 @@ func attachCmd(cmd *cobra.Command, args []string) {
|
||||
fmt.Fprintf(os.Stderr, "Invalid pid: %s\n", args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(execute(pid, nil, conf, "", executingOther))
|
||||
os.Exit(execute(pid, args[1:], conf, "", executingOther))
|
||||
}
|
||||
|
||||
func coreCmd(cmd *cobra.Command, args []string) {
|
||||
@ -432,6 +440,7 @@ func execute(attachPid int, processArgs []string, conf *config.Config, coreFile
|
||||
AcceptMulti: AcceptMulti,
|
||||
APIVersion: APIVersion,
|
||||
WorkingDir: WorkingDir,
|
||||
Backend: Backend,
|
||||
CoreFile: coreFile,
|
||||
}, Log)
|
||||
default:
|
||||
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -13,6 +14,20 @@ import (
|
||||
"github.com/derekparker/delve/service/rpc2"
|
||||
)
|
||||
|
||||
var testBackend string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.StringVar(&testBackend, "backend", "", "selects backend")
|
||||
flag.Parse()
|
||||
if testBackend == "" {
|
||||
testBackend = os.Getenv("PROCTEST")
|
||||
if testBackend == "" {
|
||||
testBackend = "native"
|
||||
}
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
func assertNoError(err error, t testing.TB, s string) {
|
||||
if err != nil {
|
||||
_, file, line, _ := runtime.Caller(1)
|
||||
@ -52,7 +67,7 @@ func TestBuild(t *testing.T) {
|
||||
|
||||
buildtestdir := filepath.Join(fixtures, "buildtest")
|
||||
|
||||
cmd := exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2")
|
||||
cmd := exec.Command(dlvbin, "debug", "--headless=true", "--listen="+listenAddr, "--api-version=2", "--backend="+testBackend)
|
||||
cmd.Dir = buildtestdir
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
assertNoError(err, t, "stdout pipe")
|
||||
|
@ -107,6 +107,11 @@ func (bi *BinaryInfo) PCToLine(pc uint64) (string, int, *gosym.Func) {
|
||||
return bi.goSymTable.PCToLine(pc)
|
||||
}
|
||||
|
||||
// LineToPC converts a file:line into a memory address.
|
||||
func (bi *BinaryInfo) LineToPC(filename string, lineno int) (pc uint64, fn *gosym.Func, err error) {
|
||||
return bi.goSymTable.LineToPC(filename, lineno)
|
||||
}
|
||||
|
||||
func (bi *BinaryInfo) Close() error {
|
||||
return bi.closer.Close()
|
||||
}
|
||||
|
1416
pkg/proc/gdbserver.go
Normal file
1416
pkg/proc/gdbserver.go
Normal file
File diff suppressed because it is too large
Load Diff
1066
pkg/proc/gdbserver_conn.go
Normal file
1066
pkg/proc/gdbserver_conn.go
Normal file
File diff suppressed because it is too large
Load Diff
9
pkg/proc/gdbserver_unix.go
Normal file
9
pkg/proc/gdbserver_unix.go
Normal file
@ -0,0 +1,9 @@
|
||||
// +build linux darwin
|
||||
|
||||
package proc
|
||||
|
||||
import "syscall"
|
||||
|
||||
func backgroundSysProcAttr() *syscall.SysProcAttr {
|
||||
return &syscall.SysProcAttr{Setpgid: true, Pgid: 0, Foreground: false}
|
||||
}
|
7
pkg/proc/gdbserver_windows.go
Normal file
7
pkg/proc/gdbserver_windows.go
Normal file
@ -0,0 +1,7 @@
|
||||
package proc
|
||||
|
||||
import "syscall"
|
||||
|
||||
func backgroundSysProcAttr() *syscall.SysProcAttr {
|
||||
return nil
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -6,24 +6,40 @@ import (
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
"runtime"
|
||||
|
||||
protest "github.com/derekparker/delve/pkg/proc/test"
|
||||
)
|
||||
|
||||
func TestIssue419(t *testing.T) {
|
||||
if testBackend == "lldb" && runtime.GOOS == "darwin" {
|
||||
// debugserver bug?
|
||||
return
|
||||
}
|
||||
// SIGINT directed at the inferior should be passed along not swallowed by delve
|
||||
withTestProcess("issue419", t, func(p *Process, fixture protest.Fixture) {
|
||||
withTestProcess("issue419", t, func(p IProcess, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "main.main")
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
if p.Running() {
|
||||
time.Sleep(2 * time.Second)
|
||||
err := syscall.Kill(p.pid, syscall.SIGINT)
|
||||
if p.Pid() <= 0 {
|
||||
// if we don't stop the inferior the test will never finish
|
||||
p.RequestManualStop()
|
||||
p.Kill()
|
||||
t.Fatalf("Pid is zero or negative: %d", p.Pid())
|
||||
return
|
||||
}
|
||||
err := syscall.Kill(p.Pid(), syscall.SIGINT)
|
||||
assertNoError(err, t, "syscall.Kill")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
err := Continue(p)
|
||||
err = Continue(p)
|
||||
if _, exited := err.(ProcessExitedError); !exited {
|
||||
t.Fatalf("Unexpected error after Continue(): %v\n", err)
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ type Registers interface {
|
||||
BP() uint64
|
||||
CX() uint64
|
||||
TLS() uint64
|
||||
// GAddr returns the address of the G variable if it is known, 0 and false otherwise
|
||||
GAddr() (uint64, bool)
|
||||
Get(int) (uint64, error)
|
||||
SetPC(IThread, uint64) error
|
||||
Slice() []Register
|
||||
|
@ -105,6 +105,10 @@ func (r *Regs) TLS() uint64 {
|
||||
return r.gsBase
|
||||
}
|
||||
|
||||
func (r *Regs) GAddr() (uint64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// SetPC sets the RIP register to the value specified by `pc`.
|
||||
func (r *Regs) SetPC(t IThread, pc uint64) error {
|
||||
thread := t.(*Thread)
|
||||
|
@ -83,6 +83,10 @@ func (r *Regs) TLS() uint64 {
|
||||
return r.regs.Fs_base
|
||||
}
|
||||
|
||||
func (r *Regs) GAddr() (uint64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// SetPC sets RIP to the value specified by 'pc'.
|
||||
func (r *Regs) SetPC(t IThread, pc uint64) (err error) {
|
||||
thread := t.(*Thread)
|
||||
|
@ -124,6 +124,10 @@ func (r *Regs) TLS() uint64 {
|
||||
return r.tls
|
||||
}
|
||||
|
||||
func (r *Regs) GAddr() (uint64, bool) {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// SetPC sets the RIP register to the value specified by `pc`.
|
||||
func (r *Regs) SetPC(t IThread, pc uint64) error {
|
||||
thread := t.(*Thread)
|
||||
|
@ -209,6 +209,12 @@ func next(dbp Continuable, stepInto bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range text {
|
||||
if text[i].Inst == nil {
|
||||
fmt.Printf("error at instruction %d\n", i)
|
||||
}
|
||||
}
|
||||
|
||||
cond := sameGoroutineCondition(selg)
|
||||
|
||||
if stepInto {
|
||||
@ -377,13 +383,16 @@ func getGVariable(thread IThread) (*Variable, error) {
|
||||
return nil, fmt.Errorf("g struct offset not initialized")
|
||||
}
|
||||
|
||||
gaddrbs, err := thread.readMemory(uintptr(regs.TLS()+arch.GStructOffset()), arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
gaddr, hasgaddr := regs.GAddr()
|
||||
if !hasgaddr {
|
||||
gaddrbs, err := thread.readMemory(uintptr(regs.TLS()+arch.GStructOffset()), arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gaddr = binary.LittleEndian.Uint64(gaddrbs)
|
||||
}
|
||||
gaddr := uintptr(binary.LittleEndian.Uint64(gaddrbs))
|
||||
|
||||
return newGVariable(thread, gaddr, arch.DerefTLS())
|
||||
return newGVariable(thread, uintptr(gaddr), arch.DerefTLS())
|
||||
}
|
||||
|
||||
func newGVariable(thread IThread, gaddr uintptr, deref bool) (*Variable, error) {
|
||||
|
@ -91,3 +91,4 @@ type VariableEval interface {
|
||||
|
||||
var _ Interface = &proc.Process{}
|
||||
var _ Interface = &proc.CoreProcess{}
|
||||
var _ Interface = &proc.GdbserverProcess{}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
@ -17,6 +18,20 @@ import (
|
||||
"github.com/derekparker/delve/service/rpccommon"
|
||||
)
|
||||
|
||||
var testBackend string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.StringVar(&testBackend, "backend", "", "selects backend")
|
||||
flag.Parse()
|
||||
if testBackend == "" {
|
||||
testBackend = os.Getenv("PROCTEST")
|
||||
if testBackend == "" {
|
||||
testBackend = "native"
|
||||
}
|
||||
}
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
type FakeTerminal struct {
|
||||
*Term
|
||||
t testing.TB
|
||||
@ -81,6 +96,7 @@ func withTestTerminal(name string, t testing.TB, fn func(*FakeTerminal)) {
|
||||
server := rpccommon.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: []string{test.BuildFixture(name).Path},
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -26,6 +26,9 @@ type Config struct {
|
||||
// APIVersion selects which version of the API to serve (default: 1).
|
||||
APIVersion int
|
||||
|
||||
// CoreFile specifies the path to the core dump to open
|
||||
// CoreFile specifies the path to the core dump to open.
|
||||
CoreFile string
|
||||
|
||||
// Selects server backend.
|
||||
Backend string
|
||||
}
|
||||
|
@ -49,8 +49,10 @@ type Config struct {
|
||||
// attach.
|
||||
AttachPid int
|
||||
|
||||
// CoreFile specifies the path to the core dump to open
|
||||
// CoreFile specifies the path to the core dump to open.
|
||||
CoreFile string
|
||||
// Backend specifies the debugger backend.
|
||||
Backend string
|
||||
}
|
||||
|
||||
// New creates a new Debugger.
|
||||
@ -63,7 +65,11 @@ func New(config *Config) (*Debugger, error) {
|
||||
switch {
|
||||
case d.config.AttachPid > 0:
|
||||
log.Printf("attaching to pid %d", d.config.AttachPid)
|
||||
p, err := proc.Attach(d.config.AttachPid)
|
||||
path := ""
|
||||
if len(d.config.ProcessArgs) > 0 {
|
||||
path = d.config.ProcessArgs[0]
|
||||
}
|
||||
p, err := d.Attach(d.config.AttachPid, path)
|
||||
if err != nil {
|
||||
return nil, attachErrorMessage(d.config.AttachPid, err)
|
||||
}
|
||||
@ -79,7 +85,7 @@ func New(config *Config) (*Debugger, error) {
|
||||
|
||||
default:
|
||||
log.Printf("launching process with args: %v", d.config.ProcessArgs)
|
||||
p, err := proc.Launch(d.config.ProcessArgs, d.config.WorkingDir)
|
||||
p, err := d.Launch(d.config.ProcessArgs, d.config.WorkingDir)
|
||||
if err != nil {
|
||||
if err != proc.NotExecutableErr && err != proc.UnsupportedLinuxArchErr && err != proc.UnsupportedWindowsArchErr && err != proc.UnsupportedDarwinArchErr {
|
||||
err = fmt.Errorf("could not launch process: %s", err)
|
||||
@ -91,6 +97,49 @@ func New(config *Config) (*Debugger, error) {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func (d *Debugger) Launch(processArgs []string, wd string) (target.Interface, error) {
|
||||
switch d.config.Backend {
|
||||
case "native":
|
||||
return proc.Launch(processArgs, wd)
|
||||
case "lldb":
|
||||
return proc.LLDBLaunch(processArgs, wd)
|
||||
case "default":
|
||||
if runtime.GOOS == "darwin" {
|
||||
return proc.LLDBLaunch(processArgs, wd)
|
||||
}
|
||||
return proc.Launch(processArgs, wd)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown backend %q", d.config.Backend)
|
||||
}
|
||||
}
|
||||
|
||||
// ErrNoAttachPath is the error returned when the client tries to attach to
|
||||
// a process on macOS using the lldb backend without specifying the path to
|
||||
// the target's executable.
|
||||
var ErrNoAttachPath = errors.New("must specify executable path on macOS")
|
||||
|
||||
func (d *Debugger) Attach(pid int, path string) (target.Interface, error) {
|
||||
switch d.config.Backend {
|
||||
case "native":
|
||||
return proc.Attach(pid)
|
||||
case "lldb":
|
||||
if runtime.GOOS == "darwin" && path == "" {
|
||||
return nil, ErrNoAttachPath
|
||||
}
|
||||
return proc.LLDBAttach(pid, path)
|
||||
case "default":
|
||||
if runtime.GOOS == "darwin" {
|
||||
if path == "" {
|
||||
return nil, ErrNoAttachPath
|
||||
}
|
||||
return proc.LLDBAttach(pid, path)
|
||||
}
|
||||
return proc.Attach(pid)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown backend %q", d.config.Backend)
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessPid returns the PID of the process
|
||||
// the debugger is debugging.
|
||||
func (d *Debugger) ProcessPid() int {
|
||||
@ -142,7 +191,7 @@ func (d *Debugger) Restart() ([]api.DiscardedBreakpoint, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
p, err := proc.Launch(d.config.ProcessArgs, d.config.WorkingDir)
|
||||
p, err := d.Launch(d.config.ProcessArgs, d.config.WorkingDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not launch process: %s", err)
|
||||
}
|
||||
@ -166,8 +215,9 @@ func (d *Debugger) Restart() ([]api.DiscardedBreakpoint, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
err = d.target.Detach(true)
|
||||
d.target = p
|
||||
return discarded, nil
|
||||
return discarded, err
|
||||
}
|
||||
|
||||
// State returns the current state of the debugger.
|
||||
|
@ -115,6 +115,7 @@ func (s *ServerImpl) Run() error {
|
||||
AttachPid: s.config.AttachPid,
|
||||
WorkingDir: s.config.WorkingDir,
|
||||
CoreFile: s.config.CoreFile,
|
||||
Backend: s.config.Backend,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ func withTestClient1(name string, t *testing.T, fn func(c *rpc1.RPCClient)) {
|
||||
server := rpccommon.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: []string{protest.BuildFixture(name).Path},
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -50,6 +51,7 @@ func Test1RunWithInvalidPath(t *testing.T) {
|
||||
server := rpccommon.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: []string{"invalid_path"},
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Run(); err == nil {
|
||||
t.Fatal("Expected Run to return error for invalid program path")
|
||||
@ -138,6 +140,7 @@ func Test1Restart_attachPid(t *testing.T) {
|
||||
server := rpccommon.NewServer(&service.Config{
|
||||
Listener: nil,
|
||||
AttachPid: 999,
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Restart(); err == nil {
|
||||
t.Fatal("expected error on restart after attaching to pid but got none")
|
||||
|
@ -1,6 +1,7 @@
|
||||
package servicetest
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
@ -22,8 +23,17 @@ import (
|
||||
)
|
||||
|
||||
var normalLoadConfig = api.LoadConfig{true, 1, 64, 64, -1}
|
||||
var testBackend string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.StringVar(&testBackend, "backend", "", "selects backend")
|
||||
flag.Parse()
|
||||
if testBackend == "" {
|
||||
testBackend = os.Getenv("PROCTEST")
|
||||
if testBackend == "" {
|
||||
testBackend = "native"
|
||||
}
|
||||
}
|
||||
os.Exit(protest.RunTestsWithFixtures(m))
|
||||
}
|
||||
|
||||
@ -36,6 +46,7 @@ func withTestClient2(name string, t *testing.T, fn func(c service.Client)) {
|
||||
server := rpccommon.NewServer(&service.Config{
|
||||
Listener: listener,
|
||||
ProcessArgs: []string{protest.BuildFixture(name).Path},
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
@ -58,6 +69,7 @@ func TestRunWithInvalidPath(t *testing.T) {
|
||||
Listener: listener,
|
||||
ProcessArgs: []string{"invalid_path"},
|
||||
APIVersion: 2,
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Run(); err == nil {
|
||||
t.Fatal("Expected Run to return error for invalid program path")
|
||||
@ -147,6 +159,7 @@ func TestRestart_attachPid(t *testing.T) {
|
||||
Listener: nil,
|
||||
AttachPid: 999,
|
||||
APIVersion: 2,
|
||||
Backend: testBackend,
|
||||
}, false)
|
||||
if err := server.Restart(); err == nil {
|
||||
t.Fatal("expected error on restart after attaching to pid but got none")
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/derekparker/delve/pkg/proc"
|
||||
"github.com/derekparker/delve/service/api"
|
||||
"github.com/derekparker/delve/pkg/target"
|
||||
|
||||
protest "github.com/derekparker/delve/pkg/proc/test"
|
||||
)
|
||||
@ -53,7 +54,7 @@ func assertVariable(t *testing.T, variable *proc.Variable, expected varTest) {
|
||||
}
|
||||
}
|
||||
|
||||
func evalVariable(p *proc.Process, symbol string, cfg proc.LoadConfig) (*proc.Variable, error) {
|
||||
func evalVariable(p target.Interface, symbol string, cfg proc.LoadConfig) (*proc.Variable, error) {
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -67,7 +68,7 @@ func (tc *varTest) alternateVarTest() varTest {
|
||||
return r
|
||||
}
|
||||
|
||||
func setVariable(p *proc.Process, symbol, value string) error {
|
||||
func setVariable(p target.Interface, symbol, value string) error {
|
||||
scope, err := proc.GoroutineScope(p.CurrentThread())
|
||||
if err != nil {
|
||||
return err
|
||||
@ -77,16 +78,25 @@ func setVariable(p *proc.Process, symbol, value string) error {
|
||||
|
||||
const varTestBreakpointLineNumber = 59
|
||||
|
||||
func withTestProcess(name string, t *testing.T, fn func(p *proc.Process, fixture protest.Fixture)) {
|
||||
func withTestProcess(name string, t *testing.T, fn func(p target.Interface, fixture protest.Fixture)) {
|
||||
fixture := protest.BuildFixture(name)
|
||||
p, err := proc.Launch([]string{fixture.Path}, ".")
|
||||
var p target.Interface
|
||||
var err error
|
||||
switch testBackend {
|
||||
case "native":
|
||||
p, err = proc.Launch([]string{fixture.Path}, ".")
|
||||
case "lldb":
|
||||
p, err = proc.LLDBLaunch([]string{fixture.Path}, ".")
|
||||
default:
|
||||
t.Fatalf("unknown backend %q", testBackend)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal("Launch():", err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
p.Halt()
|
||||
p.Kill()
|
||||
p.Detach(true)
|
||||
}()
|
||||
|
||||
fn(p, fixture)
|
||||
@ -137,7 +147,7 @@ func TestVariableEvaluation(t *testing.T) {
|
||||
{"NonExistent", true, "", "", "", fmt.Errorf("could not find symbol value for NonExistent")},
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
@ -215,7 +225,7 @@ func TestVariableEvaluationShort(t *testing.T) {
|
||||
{"NonExistent", true, "", "", "", fmt.Errorf("could not find symbol value for NonExistent")},
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
@ -270,7 +280,7 @@ func TestMultilineVariableEvaluation(t *testing.T) {
|
||||
Nest: *(*main.Nest)(…`, "", "main.Nest", nil},
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
@ -343,7 +353,7 @@ func TestLocalVariables(t *testing.T) {
|
||||
{"baz", true, "\"bazburzum\"", "", "string", nil}}},
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
@ -367,7 +377,7 @@ func TestLocalVariables(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEmbeddedStruct(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables2", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
testcases := []varTest{
|
||||
{"b.val", true, "-314", "-314", "int", nil},
|
||||
{"b.A.val", true, "-314", "-314", "int", nil},
|
||||
@ -397,7 +407,7 @@ func TestEmbeddedStruct(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestComplexSetting(t *testing.T) {
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
@ -643,7 +653,7 @@ func TestEvalExpression(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables2", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
for _, tc := range testcases {
|
||||
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
|
||||
@ -667,7 +677,7 @@ func TestEvalExpression(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEvalAddrAndCast(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables2", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
c1addr, err := evalVariable(p, "&c1", pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalExpression(&c1)")
|
||||
@ -693,7 +703,7 @@ func TestEvalAddrAndCast(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMapEvaluation(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables2", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
m1v, err := evalVariable(p, "m1", pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
@ -727,7 +737,7 @@ func TestMapEvaluation(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnsafePointer(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables2", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
up1v, err := evalVariable(p, "up1", pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalVariable(up1)")
|
||||
@ -764,7 +774,7 @@ func TestIssue426(t *testing.T) {
|
||||
|
||||
// Serialization of type expressions (go/ast.Expr) containing anonymous structs or interfaces
|
||||
// differs from the serialization used by the linker to produce DWARF type information
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("testvariables2", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
for _, testcase := range testcases {
|
||||
v, err := evalVariable(p, testcase.name, pnormalLoadConfig)
|
||||
@ -815,7 +825,7 @@ func TestPackageRenames(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
withTestProcess("pkgrenames", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
withTestProcess("pkgrenames", t, func(p target.Interface, fixture protest.Fixture) {
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
for _, tc := range testcases {
|
||||
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
|
||||
|
Loading…
Reference in New Issue
Block a user