proc/*: minor miscellaneous code cleanups (#2790)
* made Pid a method of Target instead of a method of Process * changed argument of NewTarget to ProcessInternal, since that's the interface that backends have to implement * removed warnings about ProcessInternal since there is no way for users of pkg/proc to access those methods anyway * made RecordingManipulation an optional interface for backends, Target supplies its own dummy implementation when the backend doesn't * inlined small interfaces that only existed to be inlined in proc.Process anyway * removed unused function findExecutable in the Windows and no-native darwin backends * removed (*EvalScope).EvalVariable, an old synonym for EvalExpression
This commit is contained in:
parent
88dca53e5c
commit
01b01423ae
@ -164,8 +164,6 @@ type process struct {
|
||||
breakpoints proc.BreakpointMap
|
||||
}
|
||||
|
||||
var _ proc.ProcessInternal = &process{}
|
||||
|
||||
// thread represents a thread in the core file being debugged.
|
||||
type thread struct {
|
||||
th osThread
|
||||
@ -222,7 +220,7 @@ func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, e
|
||||
return nil, ErrNoThreads
|
||||
}
|
||||
|
||||
return proc.NewTarget(p, currentThread, proc.NewTargetConfig{
|
||||
return proc.NewTarget(p, p.pid, currentThread, proc.NewTargetConfig{
|
||||
Path: exePath,
|
||||
DebugInfoDirs: debugInfoDirs,
|
||||
DisableAsyncPreempt: false,
|
||||
@ -459,11 +457,6 @@ func (p *process) Valid() (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Pid returns the process ID of this process.
|
||||
func (p *process) Pid() int {
|
||||
return p.pid
|
||||
}
|
||||
|
||||
// ResumeNotify is a no-op on core files as we cannot
|
||||
// control execution.
|
||||
func (p *process) ResumeNotify(chan<- struct{}) {
|
||||
|
||||
@ -297,7 +297,7 @@ func TestCore(t *testing.T) {
|
||||
if mainFrame == nil {
|
||||
t.Fatalf("Couldn't find main in stack %v", panickingStack)
|
||||
}
|
||||
msg, err := proc.FrameToScope(p, p.Memory(), nil, *mainFrame).EvalVariable("msg", proc.LoadConfig{MaxStringLen: 64})
|
||||
msg, err := proc.FrameToScope(p, p.Memory(), nil, *mainFrame).EvalExpression("msg", proc.LoadConfig{MaxStringLen: 64})
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't EvalVariable(msg, ...): %v", err)
|
||||
}
|
||||
@ -429,11 +429,11 @@ mainSearch:
|
||||
|
||||
scope := proc.FrameToScope(p, p.Memory(), nil, *mainFrame)
|
||||
loadConfig := proc.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1}
|
||||
v1, err := scope.EvalVariable("t", loadConfig)
|
||||
v1, err := scope.EvalExpression("t", loadConfig)
|
||||
assertNoError(err, t, "EvalVariable(t)")
|
||||
assertNoError(v1.Unreadable, t, "unreadable variable 't'")
|
||||
t.Logf("t = %#v\n", v1)
|
||||
v2, err := scope.EvalVariable("s", loadConfig)
|
||||
v2, err := scope.EvalExpression("s", loadConfig)
|
||||
assertNoError(err, t, "EvalVariable(s)")
|
||||
assertNoError(v2.Unreadable, t, "unreadable variable 's'")
|
||||
t.Logf("s = %#v\n", v2)
|
||||
|
||||
@ -155,7 +155,7 @@ func (t *Target) Dump(out elfwriter.WriteCloserSeeker, flags DumpFlags, state *D
|
||||
notes = append(notes, elfwriter.Note{
|
||||
Type: elfwriter.DelveHeaderNoteType,
|
||||
Name: "Delve Header",
|
||||
Data: []byte(fmt.Sprintf("%s/%s\n%s\n%s%d\n%s%#x\n", bi.GOOS, bi.Arch.Name, version.DelveVersion.String(), elfwriter.DelveHeaderTargetPidPrefix, t.Pid(), elfwriter.DelveHeaderEntryPointPrefix, entryPoint)),
|
||||
Data: []byte(fmt.Sprintf("%s/%s\n%s\n%s%d\n%s%#x\n", bi.GOOS, bi.Arch.Name, version.DelveVersion.String(), elfwriter.DelveHeaderTargetPidPrefix, t.pid, elfwriter.DelveHeaderEntryPointPrefix, entryPoint)),
|
||||
})
|
||||
|
||||
threads := t.ThreadList()
|
||||
|
||||
@ -423,11 +423,6 @@ func (scope *EvalScope) setValue(dstv, srcv *Variable, srcExpr string) error {
|
||||
return fmt.Errorf("can not set variables of type %s (not implemented)", dstv.Kind.String())
|
||||
}
|
||||
|
||||
// EvalVariable returns the value of the given expression (backwards compatibility).
|
||||
func (scope *EvalScope) EvalVariable(name string, cfg LoadConfig) (*Variable, error) {
|
||||
return scope.EvalExpression(name, cfg)
|
||||
}
|
||||
|
||||
// SetVariable sets the value of the named variable
|
||||
func (scope *EvalScope) SetVariable(name, value string) error {
|
||||
t, err := parser.ParseExpr(name)
|
||||
|
||||
@ -170,7 +170,7 @@ type gdbProcess struct {
|
||||
onDetach func() // called after a successful detach
|
||||
}
|
||||
|
||||
var _ proc.ProcessInternal = &gdbProcess{}
|
||||
var _ proc.RecordingManipulationInternal = &gdbProcess{}
|
||||
|
||||
// gdbThread represents an operating system thread.
|
||||
type gdbThread struct {
|
||||
@ -704,7 +704,7 @@ func (p *gdbProcess) initialize(path string, debugInfoDirs []string, stopReason
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
tgt, err := proc.NewTarget(p, p.currentThread, proc.NewTargetConfig{
|
||||
tgt, err := proc.NewTarget(p, p.conn.pid, p.currentThread, proc.NewTargetConfig{
|
||||
Path: path,
|
||||
DebugInfoDirs: debugInfoDirs,
|
||||
DisableAsyncPreempt: runtime.GOOS == "darwin",
|
||||
|
||||
@ -13,9 +13,20 @@ import (
|
||||
// There is one exception to this rule: it is safe to call RequestManualStop
|
||||
// concurrently with ContinueOnce.
|
||||
type Process interface {
|
||||
Info
|
||||
ProcessManipulation
|
||||
RecordingManipulation
|
||||
// ResumeNotify specifies a channel that will be closed the next time
|
||||
// ContinueOnce finishes resuming the target.
|
||||
ResumeNotify(chan<- struct{})
|
||||
BinInfo() *BinaryInfo
|
||||
EntryPoint() (uint64, error)
|
||||
|
||||
// RequestManualStop attempts to stop all the process' threads.
|
||||
RequestManualStop() error
|
||||
// CheckAndClearManualStopRequest returns true the first time it's called
|
||||
// after a call to RequestManualStop.
|
||||
CheckAndClearManualStopRequest() bool
|
||||
|
||||
FindThread(threadID int) (Thread, bool)
|
||||
ThreadList() []Thread
|
||||
|
||||
Breakpoints() *BreakpointMap
|
||||
|
||||
@ -23,22 +34,16 @@ type Process interface {
|
||||
Memory() MemoryReadWriter
|
||||
}
|
||||
|
||||
// ProcessInternal holds a set of methods that are not meant to be called by
|
||||
// anyone except for an instance of `proc.Target`. These methods are not
|
||||
// safe to use by themselves and should never be called directly outside of
|
||||
// the `proc` package.
|
||||
// This is temporary and in support of an ongoing refactor.
|
||||
// ProcessInternal holds a set of methods that need to be implemented by a
|
||||
// Delve backend. Methods in the Process interface are safe to be called by
|
||||
// clients of the 'proc' library, while all other methods are only called
|
||||
// directly within 'proc'.
|
||||
type ProcessInternal interface {
|
||||
Process
|
||||
// Valid returns true if this Process can be used. When it returns false it
|
||||
// also returns an error describing why the Process is invalid (either
|
||||
// ErrProcessExited or ErrProcessDetached).
|
||||
Valid() (bool, error)
|
||||
// Restart restarts the recording from the specified position, or from the
|
||||
// last checkpoint if pos == "".
|
||||
// If pos starts with 'c' it's a checkpoint ID, otherwise it's an event
|
||||
// number.
|
||||
// Returns the new current thread after the restart has completed.
|
||||
Restart(pos string) (Thread, error)
|
||||
Detach(bool) error
|
||||
ContinueOnce() (trapthread Thread, stopReason StopReason, err error)
|
||||
|
||||
@ -47,6 +52,7 @@ type ProcessInternal interface {
|
||||
|
||||
SupportsBPF() bool
|
||||
SetUProbe(string, int64, []ebpf.UProbeArgMap) error
|
||||
GetBufferedTracepoints() []ebpf.RawUProbeParams
|
||||
|
||||
// DumpProcessNotes returns ELF core notes describing the process and its threads.
|
||||
// Implementing this method is optional.
|
||||
@ -54,8 +60,6 @@ type ProcessInternal interface {
|
||||
// MemoryMap returns the memory map of the target process. This method must be implemented if CanDump is true.
|
||||
MemoryMap() ([]MemoryMapEntry, error)
|
||||
|
||||
GetBufferedTracepoints() []ebpf.RawUProbeParams
|
||||
|
||||
// StartCallInjection notifies the backend that we are about to inject a function call.
|
||||
StartCallInjection() (func(), error)
|
||||
}
|
||||
@ -79,6 +83,19 @@ type RecordingManipulation interface {
|
||||
ClearCheckpoint(id int) error
|
||||
}
|
||||
|
||||
// RecordingManipulationInternal is an interface that a Delve backend can
|
||||
// implement if it is a recording.
|
||||
type RecordingManipulationInternal interface {
|
||||
RecordingManipulation
|
||||
|
||||
// Restart restarts the recording from the specified position, or from the
|
||||
// last checkpoint if pos == "".
|
||||
// If pos starts with 'c' it's a checkpoint ID, otherwise it's an event
|
||||
// number.
|
||||
// Returns the new current thread after the restart has completed.
|
||||
Restart(pos string) (Thread, error)
|
||||
}
|
||||
|
||||
// Direction is the direction of execution for the target process.
|
||||
type Direction int8
|
||||
|
||||
@ -95,31 +112,3 @@ type Checkpoint struct {
|
||||
When string
|
||||
Where string
|
||||
}
|
||||
|
||||
// Info is an interface that provides general information on the target.
|
||||
type Info interface {
|
||||
Pid() int
|
||||
// ResumeNotify specifies a channel that will be closed the next time
|
||||
// ContinueOnce finishes resuming the target.
|
||||
ResumeNotify(chan<- struct{})
|
||||
BinInfo() *BinaryInfo
|
||||
EntryPoint() (uint64, error)
|
||||
|
||||
ThreadInfo
|
||||
}
|
||||
|
||||
// ThreadInfo is an interface for getting information on active threads
|
||||
// in the process.
|
||||
type ThreadInfo interface {
|
||||
FindThread(threadID int) (Thread, bool)
|
||||
ThreadList() []Thread
|
||||
}
|
||||
|
||||
// ProcessManipulation is an interface for changing the execution state of a process.
|
||||
type ProcessManipulation interface {
|
||||
// RequestManualStop attempts to stop all the process' threads.
|
||||
RequestManualStop() error
|
||||
// CheckAndClearManualStopRequest returns true the first time it's called
|
||||
// after a call to RequestManualStop.
|
||||
CheckAndClearManualStopRequest() bool
|
||||
}
|
||||
|
||||
@ -12,10 +12,10 @@ import (
|
||||
func (p *nativeProcess) MemoryMap() ([]proc.MemoryMapEntry, error) {
|
||||
const VmFlagsPrefix = "VmFlags:"
|
||||
|
||||
smapsbuf, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/smaps", p.Pid()))
|
||||
smapsbuf, err := ioutil.ReadFile(fmt.Sprintf("/proc/%d/smaps", p.pid))
|
||||
if err != nil {
|
||||
// Older versions of Linux don't have smaps but have maps which is in a similar format.
|
||||
smapsbuf, err = ioutil.ReadFile(fmt.Sprintf("/proc/%d/maps", p.Pid()))
|
||||
smapsbuf, err = ioutil.ReadFile(fmt.Sprintf("/proc/%d/maps", p.pid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -37,10 +37,6 @@ type osProcessDetails struct{}
|
||||
|
||||
func (os *osProcessDetails) Close() {}
|
||||
|
||||
func findExecutable(path string, pid int) string {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
func killProcess(pid int) error {
|
||||
panic(ErrNativeBackendDisabled)
|
||||
}
|
||||
|
||||
@ -46,8 +46,6 @@ type nativeProcess struct {
|
||||
exited, detached bool
|
||||
}
|
||||
|
||||
var _ proc.ProcessInternal = &nativeProcess{}
|
||||
|
||||
// newProcess returns an initialized Process struct. Before returning,
|
||||
// it will also launch a goroutine in order to handle ptrace(2)
|
||||
// functions. For more information, see the documentation on
|
||||
@ -72,40 +70,6 @@ func (dbp *nativeProcess) BinInfo() *proc.BinaryInfo {
|
||||
return dbp.bi
|
||||
}
|
||||
|
||||
// Recorded always returns false for the native proc backend.
|
||||
func (dbp *nativeProcess) Recorded() (bool, string) { return false, "" }
|
||||
|
||||
// Restart will always return an error in the native proc backend, only for
|
||||
// recorded traces.
|
||||
func (dbp *nativeProcess) Restart(string) (proc.Thread, error) { return nil, proc.ErrNotRecorded }
|
||||
|
||||
// ChangeDirection will always return an error in the native proc backend, only for
|
||||
// recorded traces.
|
||||
func (dbp *nativeProcess) ChangeDirection(dir proc.Direction) error {
|
||||
if dir != proc.Forward {
|
||||
return proc.ErrNotRecorded
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDirection will always return Forward.
|
||||
func (p *nativeProcess) GetDirection() proc.Direction { return proc.Forward }
|
||||
|
||||
// When will always return an empty string and nil, not supported on native proc backend.
|
||||
func (dbp *nativeProcess) When() (string, error) { return "", nil }
|
||||
|
||||
// Checkpoint will always return an error on the native proc backend,
|
||||
// only supported for recorded traces.
|
||||
func (dbp *nativeProcess) Checkpoint(string) (int, error) { return -1, proc.ErrNotRecorded }
|
||||
|
||||
// Checkpoints will always return an error on the native proc backend,
|
||||
// only supported for recorded traces.
|
||||
func (dbp *nativeProcess) Checkpoints() ([]proc.Checkpoint, error) { return nil, proc.ErrNotRecorded }
|
||||
|
||||
// ClearCheckpoint will always return an error on the native proc backend,
|
||||
// only supported in recorded traces.
|
||||
func (dbp *nativeProcess) ClearCheckpoint(int) error { return proc.ErrNotRecorded }
|
||||
|
||||
// StartCallInjection notifies the backend that we are about to inject a function call.
|
||||
func (dbp *nativeProcess) StartCallInjection() (func(), error) { return func() {}, nil }
|
||||
|
||||
@ -143,7 +107,7 @@ func (dbp *nativeProcess) Valid() (bool, error) {
|
||||
return false, proc.ErrProcessDetached
|
||||
}
|
||||
if dbp.exited {
|
||||
return false, proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return false, proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
@ -154,11 +118,6 @@ func (dbp *nativeProcess) ResumeNotify(ch chan<- struct{}) {
|
||||
dbp.resumeChan = ch
|
||||
}
|
||||
|
||||
// Pid returns the process ID.
|
||||
func (dbp *nativeProcess) Pid() int {
|
||||
return dbp.pid
|
||||
}
|
||||
|
||||
// ThreadList returns a list of threads in the process.
|
||||
func (dbp *nativeProcess) ThreadList() []proc.Thread {
|
||||
r := make([]proc.Thread, 0, len(dbp.threads))
|
||||
@ -188,7 +147,7 @@ func (dbp *nativeProcess) Breakpoints() *proc.BreakpointMap {
|
||||
// sends SIGSTOP to all threads.
|
||||
func (dbp *nativeProcess) RequestManualStop() error {
|
||||
if dbp.exited {
|
||||
return proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
dbp.stopMu.Lock()
|
||||
defer dbp.stopMu.Unlock()
|
||||
@ -245,7 +204,7 @@ func (dbp *nativeProcess) EraseBreakpoint(bp *proc.Breakpoint) error {
|
||||
// This could be the result of a breakpoint or signal.
|
||||
func (dbp *nativeProcess) ContinueOnce() (proc.Thread, proc.StopReason, error) {
|
||||
if dbp.exited {
|
||||
return nil, proc.StopExited, proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return nil, proc.StopExited, proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
|
||||
for {
|
||||
@ -306,7 +265,7 @@ func (dbp *nativeProcess) initialize(path string, debugInfoDirs []string) (*proc
|
||||
if !dbp.childProcess {
|
||||
stopReason = proc.StopAttached
|
||||
}
|
||||
tgt, err := proc.NewTarget(dbp, dbp.memthread, proc.NewTargetConfig{
|
||||
tgt, err := proc.NewTarget(dbp, dbp.pid, dbp.memthread, proc.NewTargetConfig{
|
||||
Path: path,
|
||||
DebugInfoDirs: debugInfoDirs,
|
||||
DisableAsyncPreempt: runtime.GOOS == "windows" || runtime.GOOS == "freebsd",
|
||||
|
||||
@ -435,7 +435,7 @@ func (dbp *nativeProcess) resume() error {
|
||||
// stop stops all running threads and sets breakpoints
|
||||
func (dbp *nativeProcess) stop(trapthread *nativeThread) (*nativeThread, error) {
|
||||
if dbp.exited {
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
for _, th := range dbp.threads {
|
||||
if !th.Stopped() {
|
||||
|
||||
@ -352,7 +352,7 @@ func (dbp *nativeProcess) resume() error {
|
||||
// stop stops all running threads and sets breakpoints
|
||||
func (dbp *nativeProcess) stop(trapthread *nativeThread) (*nativeThread, error) {
|
||||
if dbp.exited {
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
// set breakpoints on all threads
|
||||
for _, th := range dbp.threads {
|
||||
|
||||
@ -540,7 +540,7 @@ func (dbp *nativeProcess) resume() error {
|
||||
// stop stops all running threads and sets breakpoints
|
||||
func (dbp *nativeProcess) stop(trapthread *nativeThread) (*nativeThread, error) {
|
||||
if dbp.exited {
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
|
||||
for _, th := range dbp.threads {
|
||||
@ -772,7 +772,7 @@ func (dbp *nativeProcess) SetUProbe(fnName string, goidOffset int64, args []ebpf
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = dbp.os.ebpf.AttachUprobe(dbp.Pid(), debugname, off)
|
||||
err = dbp.os.ebpf.AttachUprobe(dbp.pid, debugname, off)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -783,7 +783,7 @@ func (dbp *nativeProcess) SetUProbe(fnName string, goidOffset int64, args []ebpf
|
||||
return err
|
||||
}
|
||||
|
||||
return dbp.os.ebpf.AttachUprobe(dbp.Pid(), debugname, off)
|
||||
return dbp.os.ebpf.AttachUprobe(dbp.pid, debugname, off)
|
||||
}
|
||||
|
||||
func killProcess(pid int) error {
|
||||
|
||||
@ -235,10 +235,6 @@ func (dbp *nativeProcess) addThread(hThread syscall.Handle, threadID int, attach
|
||||
return thread, nil
|
||||
}
|
||||
|
||||
func findExecutable(path string, pid int) string {
|
||||
return path
|
||||
}
|
||||
|
||||
type waitForDebugEventFlags int
|
||||
|
||||
const (
|
||||
@ -428,7 +424,7 @@ func (dbp *nativeProcess) resume() error {
|
||||
// stop stops all running threads threads and sets breakpoints
|
||||
func (dbp *nativeProcess) stop(trapthread *nativeThread) (*nativeThread, error) {
|
||||
if dbp.exited {
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.Pid()}
|
||||
return nil, proc.ErrProcessExited{Pid: dbp.pid}
|
||||
}
|
||||
|
||||
dbp.os.running = false
|
||||
|
||||
@ -1164,7 +1164,7 @@ func evalVariableOrError(p *proc.Target, symbol string) (*proc.Variable, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return scope.EvalVariable(symbol, normalLoadConfig)
|
||||
return scope.EvalExpression(symbol, normalLoadConfig)
|
||||
}
|
||||
|
||||
func evalVariable(p *proc.Target, t testing.TB, symbol string) *proc.Variable {
|
||||
@ -1310,7 +1310,7 @@ func TestFrameEvaluation(t *testing.T) {
|
||||
scope, err := proc.ConvertEvalScope(p, g.ID, frame, 0)
|
||||
assertNoError(err, t, "ConvertEvalScope()")
|
||||
t.Logf("scope = %v", scope)
|
||||
v, err := scope.EvalVariable("i", normalLoadConfig)
|
||||
v, err := scope.EvalExpression("i", normalLoadConfig)
|
||||
t.Logf("v = %v", v)
|
||||
if err != nil {
|
||||
t.Logf("Goroutine %d: %v\n", g.ID, err)
|
||||
@ -1338,7 +1338,7 @@ func TestFrameEvaluation(t *testing.T) {
|
||||
for i := 0; i <= 3; i++ {
|
||||
scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0)
|
||||
assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1))
|
||||
v, err := scope.EvalVariable("n", normalLoadConfig)
|
||||
v, err := scope.EvalExpression("n", normalLoadConfig)
|
||||
assertNoError(err, t, fmt.Sprintf("EvalVariable() on frame %d", i+1))
|
||||
n, _ := constant.Int64Val(v.Value)
|
||||
t.Logf("frame %d n %d\n", i+1, n)
|
||||
@ -1367,7 +1367,7 @@ func TestThreadFrameEvaluation(t *testing.T) {
|
||||
// be a thread scope.
|
||||
scope, err := proc.ConvertEvalScope(p, 0, 0, 0)
|
||||
assertNoError(err, t, "ConvertEvalScope() on frame 0")
|
||||
_, err = scope.EvalVariable("s", normalLoadConfig)
|
||||
_, err = scope.EvalExpression("s", normalLoadConfig)
|
||||
assertNoError(err, t, "EvalVariable(\"s\") on frame 0")
|
||||
})
|
||||
}
|
||||
@ -1520,10 +1520,10 @@ func TestBreakpointCountsWithDetection(t *testing.T) {
|
||||
}
|
||||
scope, err := proc.GoroutineScope(p, th)
|
||||
assertNoError(err, t, "Scope()")
|
||||
v, err := scope.EvalVariable("i", normalLoadConfig)
|
||||
v, err := scope.EvalExpression("i", normalLoadConfig)
|
||||
assertNoError(err, t, "evalVariable")
|
||||
i, _ := constant.Int64Val(v.Value)
|
||||
v, err = scope.EvalVariable("id", normalLoadConfig)
|
||||
v, err = scope.EvalExpression("id", normalLoadConfig)
|
||||
assertNoError(err, t, "evalVariable")
|
||||
id, _ := constant.Int64Val(v.Value)
|
||||
m[id] = i
|
||||
@ -4253,11 +4253,11 @@ func TestReadDeferArgs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
avar, err := scope.EvalVariable("a", normalLoadConfig)
|
||||
avar, err := scope.EvalExpression("a", normalLoadConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bvar, err := scope.EvalVariable("b", normalLoadConfig)
|
||||
bvar, err := scope.EvalExpression("b", normalLoadConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ func (check *scopeCheck) checkVar(v *proc.Variable, t *testing.T) {
|
||||
}
|
||||
|
||||
func (varCheck *varCheck) checkInScope(line int, scope *proc.EvalScope, t *testing.T) {
|
||||
v, err := scope.EvalVariable(varCheck.name, normalLoadConfig)
|
||||
v, err := scope.EvalExpression(varCheck.name, normalLoadConfig)
|
||||
assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", varCheck.name))
|
||||
varCheck.check(line, v, t, "EvalExpression")
|
||||
|
||||
|
||||
@ -36,8 +36,12 @@ const (
|
||||
// Target represents the process being debugged.
|
||||
type Target struct {
|
||||
Process
|
||||
RecordingManipulation
|
||||
|
||||
proc ProcessInternal
|
||||
proc ProcessInternal
|
||||
recman RecordingManipulationInternal
|
||||
|
||||
pid int
|
||||
|
||||
// StopReason describes the reason why the target process is stopped.
|
||||
// A process could be stopped for multiple simultaneous reasons, in which
|
||||
@ -169,7 +173,8 @@ func DisableAsyncPreemptEnv() []string {
|
||||
}
|
||||
|
||||
// NewTarget returns an initialized Target object.
|
||||
func NewTarget(p Process, currentThread Thread, cfg NewTargetConfig) (*Target, error) {
|
||||
// The p argument can optionally implement the RecordingManipulation interface.
|
||||
func NewTarget(p ProcessInternal, pid int, currentThread Thread, cfg NewTargetConfig) (*Target, error) {
|
||||
entryPoint, err := p.EntryPoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -187,13 +192,21 @@ func NewTarget(p Process, currentThread Thread, cfg NewTargetConfig) (*Target, e
|
||||
|
||||
t := &Target{
|
||||
Process: p,
|
||||
proc: p.(ProcessInternal),
|
||||
proc: p,
|
||||
fncallForG: make(map[int]*callInjection),
|
||||
StopReason: cfg.StopReason,
|
||||
currentThread: currentThread,
|
||||
CanDump: cfg.CanDump,
|
||||
pid: pid,
|
||||
}
|
||||
|
||||
if recman, ok := p.(RecordingManipulationInternal); ok {
|
||||
t.recman = recman
|
||||
} else {
|
||||
t.recman = &dummyRecordingManipulation{}
|
||||
}
|
||||
t.RecordingManipulation = t.recman
|
||||
|
||||
g, _ := GetG(currentThread)
|
||||
t.selectedGoroutine = g
|
||||
|
||||
@ -210,6 +223,11 @@ func NewTarget(p Process, currentThread Thread, cfg NewTargetConfig) (*Target, e
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Pid returns the pid of the target process.
|
||||
func (t *Target) Pid() int {
|
||||
return t.pid
|
||||
}
|
||||
|
||||
// IsCgo returns the value of runtime.iscgo
|
||||
func (t *Target) IsCgo() bool {
|
||||
if t.iscgo != nil {
|
||||
@ -265,7 +283,7 @@ func (t *Target) ClearCaches() {
|
||||
// Restarting of a normal process happens at a higher level (debugger.Restart).
|
||||
func (t *Target) Restart(from string) error {
|
||||
t.ClearCaches()
|
||||
currentThread, err := t.proc.Restart(from)
|
||||
currentThread, err := t.recman.Restart(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -544,3 +562,40 @@ func (t *Target) dwrapUnwrap(fn *Function) *Function {
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
type dummyRecordingManipulation struct {
|
||||
}
|
||||
|
||||
// Recorded always returns false for the native proc backend.
|
||||
func (*dummyRecordingManipulation) Recorded() (bool, string) { return false, "" }
|
||||
|
||||
// ChangeDirection will always return an error in the native proc backend, only for
|
||||
// recorded traces.
|
||||
func (*dummyRecordingManipulation) ChangeDirection(dir Direction) error {
|
||||
if dir != Forward {
|
||||
return ErrNotRecorded
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDirection will always return Forward.
|
||||
func (*dummyRecordingManipulation) GetDirection() Direction { return Forward }
|
||||
|
||||
// When will always return an empty string and nil, not supported on native proc backend.
|
||||
func (*dummyRecordingManipulation) When() (string, error) { return "", nil }
|
||||
|
||||
// Checkpoint will always return an error on the native proc backend,
|
||||
// only supported for recorded traces.
|
||||
func (*dummyRecordingManipulation) Checkpoint(string) (int, error) { return -1, ErrNotRecorded }
|
||||
|
||||
// Checkpoints will always return an error on the native proc backend,
|
||||
// only supported for recorded traces.
|
||||
func (*dummyRecordingManipulation) Checkpoints() ([]Checkpoint, error) { return nil, ErrNotRecorded }
|
||||
|
||||
// ClearCheckpoint will always return an error on the native proc backend,
|
||||
// only supported in recorded traces.
|
||||
func (*dummyRecordingManipulation) ClearCheckpoint(int) error { return ErrNotRecorded }
|
||||
|
||||
// Restart will always return an error in the native proc backend, only for
|
||||
// recorded traces.
|
||||
func (*dummyRecordingManipulation) Restart(string) (Thread, error) { return nil, ErrNotRecorded }
|
||||
|
||||
@ -1332,7 +1332,7 @@ func (d *Debugger) collectBreakpointInformation(state *api.DebuggerState) error
|
||||
bpi.Variables = make([]api.Variable, len(bp.Variables))
|
||||
}
|
||||
for i := range bp.Variables {
|
||||
v, err := s.EvalVariable(bp.Variables[i], proc.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1})
|
||||
v, err := s.EvalExpression(bp.Variables[i], proc.LoadConfig{FollowPointers: true, MaxVariableRecurse: 1, MaxStringLen: 64, MaxArrayValues: 64, MaxStructFields: -1})
|
||||
if err != nil {
|
||||
bpi.Variables[i] = api.Variable{Name: bp.Variables[i], Unreadable: fmt.Sprintf("eval error: %v", err)}
|
||||
} else {
|
||||
@ -1516,7 +1516,7 @@ func (d *Debugger) Function(goid, frame, deferredCall int, cfg proc.LoadConfig)
|
||||
|
||||
// EvalVariableInScope will attempt to evaluate the variable represented by 'symbol'
|
||||
// in the scope provided.
|
||||
func (d *Debugger) EvalVariableInScope(goid, frame, deferredCall int, symbol string, cfg proc.LoadConfig) (*proc.Variable, error) {
|
||||
func (d *Debugger) EvalVariableInScope(goid, frame, deferredCall int, expr string, cfg proc.LoadConfig) (*proc.Variable, error) {
|
||||
d.targetMutex.Lock()
|
||||
defer d.targetMutex.Unlock()
|
||||
|
||||
@ -1524,7 +1524,7 @@ func (d *Debugger) EvalVariableInScope(goid, frame, deferredCall int, symbol str
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.EvalVariable(symbol, cfg)
|
||||
return s.EvalExpression(expr, cfg)
|
||||
}
|
||||
|
||||
// LoadResliced will attempt to 'reslice' a map, array or slice so that the values
|
||||
|
||||
@ -101,7 +101,7 @@ func evalVariable(p *proc.Target, symbol string, cfg proc.LoadConfig) (*proc.Var
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return scope.EvalVariable(symbol, cfg)
|
||||
return scope.EvalExpression(symbol, cfg)
|
||||
}
|
||||
|
||||
func (tc *varTest) alternateVarTest() varTest {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user