proc: refactor Continue to work on any Process implementation
This commit is contained in:
parent
510b7db2a7
commit
3dacc25d2e
@ -107,7 +107,7 @@ func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (bp *Breakpoint) checkCondition(thread *Thread) (bool, error) {
|
||||
func (bp *Breakpoint) checkCondition(thread IThread) (bool, error) {
|
||||
if bp.Cond == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
239
pkg/proc/proc.go
239
pkg/proc/proc.go
@ -1,6 +1,7 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"debug/gosym"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -319,17 +320,17 @@ func (dbp *Process) Status() *WaitStatus {
|
||||
}
|
||||
|
||||
// Next continues execution until the next source line.
|
||||
func (dbp *Process) Next() (err error) {
|
||||
if dbp.exited {
|
||||
func Next(dbp Continuable) (err error) {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{}
|
||||
}
|
||||
for i := range dbp.breakpoints {
|
||||
if dbp.breakpoints[i].Internal() {
|
||||
for _, bp := range dbp.Breakpoints() {
|
||||
if bp.Internal() {
|
||||
return fmt.Errorf("next while nexting")
|
||||
}
|
||||
}
|
||||
|
||||
if err = dbp.next(false); err != nil {
|
||||
if err = next(dbp, false); err != nil {
|
||||
switch err.(type) {
|
||||
case ThreadBlockedError, NoReturnAddr: // Noop
|
||||
default:
|
||||
@ -338,91 +339,119 @@ func (dbp *Process) Next() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
return dbp.Continue()
|
||||
return Continue(dbp)
|
||||
}
|
||||
|
||||
func (dbp *Process) ContinueOnce() (IThread, error) {
|
||||
if dbp.exited {
|
||||
return nil, &ProcessExitedError{}
|
||||
}
|
||||
|
||||
if err := dbp.resume(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbp.allGCache = nil
|
||||
for _, th := range dbp.threads {
|
||||
th.clearBreakpointState()
|
||||
}
|
||||
|
||||
trapthread, err := dbp.trapWait(-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := dbp.Halt(); err != nil {
|
||||
return nil, dbp.exitGuard(err)
|
||||
}
|
||||
if err := dbp.setCurrentBreakpoints(trapthread); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return trapthread, err
|
||||
}
|
||||
|
||||
// Continuable is the subinterface of target.Interface used to implement
|
||||
// Continue/Next/etc.
|
||||
type Continuable interface {
|
||||
ContinueOnce() (trapthread IThread, err error)
|
||||
CurrentThread() IThread
|
||||
SelectedGoroutine() *G
|
||||
Breakpoints() map[uint64]*Breakpoint
|
||||
ThreadList() []IThread
|
||||
SwitchThread(int) error
|
||||
BinInfo() *BinaryInfo
|
||||
ClearInternalBreakpoints() error
|
||||
FirstPCAfterPrologue(fn *gosym.Func, sameline bool) (uint64, error)
|
||||
SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error)
|
||||
Exited() bool
|
||||
}
|
||||
|
||||
// Continue continues execution of the debugged
|
||||
// process. It will continue until it hits a breakpoint
|
||||
// or is otherwise stopped.
|
||||
func (dbp *Process) Continue() error {
|
||||
if dbp.exited {
|
||||
return &ProcessExitedError{}
|
||||
}
|
||||
func Continue(dbp Continuable) error {
|
||||
for {
|
||||
if err := dbp.resume(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbp.allGCache = nil
|
||||
for _, th := range dbp.threads {
|
||||
th.clearBreakpointState()
|
||||
}
|
||||
|
||||
trapthread, err := dbp.trapWait(-1)
|
||||
trapthread, err := dbp.ContinueOnce()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dbp.Halt(); err != nil {
|
||||
return dbp.exitGuard(err)
|
||||
}
|
||||
if err := dbp.setCurrentBreakpoints(trapthread); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dbp.pickCurrentThread(trapthread); err != nil {
|
||||
|
||||
threads := dbp.ThreadList()
|
||||
|
||||
if err := pickCurrentThread(dbp, trapthread, threads); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
curthread := dbp.CurrentThread()
|
||||
curbp, curbpActive, _ := curthread.Breakpoint()
|
||||
|
||||
switch {
|
||||
case dbp.currentThread.CurrentBreakpoint == nil:
|
||||
case curbp == nil:
|
||||
// runtime.Breakpoint or manual stop
|
||||
if dbp.currentThread.onRuntimeBreakpoint() {
|
||||
if onRuntimeBreakpoint(curthread) {
|
||||
// Single-step current thread until we exit runtime.breakpoint and
|
||||
// runtime.Breakpoint.
|
||||
// On go < 1.8 it was sufficient to single-step twice on go1.8 a change
|
||||
// to the compiler requires 4 steps.
|
||||
for {
|
||||
if err = dbp.currentThread.StepInstruction(); err != nil {
|
||||
if err = curthread.StepInstruction(); err != nil {
|
||||
return err
|
||||
}
|
||||
loc, err := dbp.currentThread.Location()
|
||||
loc, err := curthread.Location()
|
||||
if err != nil || loc.Fn == nil || (loc.Fn.Name != "runtime.breakpoint" && loc.Fn.Name != "runtime.Breakpoint") {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return dbp.conditionErrors()
|
||||
case dbp.currentThread.onTriggeredInternalBreakpoint():
|
||||
if dbp.currentThread.CurrentBreakpoint.Kind == StepBreakpoint {
|
||||
return conditionErrors(threads)
|
||||
case curbpActive && curbp.Internal():
|
||||
if curbp.Kind == StepBreakpoint {
|
||||
// See description of proc.(*Process).next for the meaning of StepBreakpoints
|
||||
if err := dbp.conditionErrors(); err != nil {
|
||||
if err := conditionErrors(threads); err != nil {
|
||||
return err
|
||||
}
|
||||
pc, err := dbp.currentThread.PC()
|
||||
regs, err := curthread.Registers(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
regs, err := dbp.currentThread.Registers(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
text, err := disassemble(dbp.currentThread, regs, dbp.breakpoints, dbp.BinInfo(), pc, pc+maxInstructionLength)
|
||||
pc := regs.PC()
|
||||
text, err := disassemble(curthread, regs, dbp.Breakpoints(), dbp.BinInfo(), pc, pc+maxInstructionLength)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// here we either set a breakpoint into the destination of the CALL
|
||||
// instruction or we determined that the called function is hidden,
|
||||
// either way we need to resume execution
|
||||
if err = dbp.setStepIntoBreakpoint(text, sameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
|
||||
if err = setStepIntoBreakpoint(dbp, text, sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := dbp.ClearInternalBreakpoints(); err != nil {
|
||||
return err
|
||||
}
|
||||
return dbp.conditionErrors()
|
||||
return conditionErrors(threads)
|
||||
}
|
||||
case dbp.currentThread.onTriggeredBreakpoint():
|
||||
onNextGoroutine, err := dbp.currentThread.onNextGoroutine()
|
||||
case curbpActive:
|
||||
onNextGoroutine, err := onNextGoroutine(curthread, dbp.Breakpoints())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -432,19 +461,19 @@ func (dbp *Process) Continue() error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return dbp.conditionErrors()
|
||||
return conditionErrors(threads)
|
||||
default:
|
||||
// not a manual stop, not on runtime.Breakpoint, not on a breakpoint, just repeat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (dbp *Process) conditionErrors() error {
|
||||
func conditionErrors(threads []IThread) error {
|
||||
var condErr error
|
||||
for _, th := range dbp.threads {
|
||||
if th.CurrentBreakpoint != nil && th.BreakpointConditionError != nil {
|
||||
for _, th := range threads {
|
||||
if bp, _, bperr := th.Breakpoint(); bp != nil && bperr != nil {
|
||||
if condErr == nil {
|
||||
condErr = th.BreakpointConditionError
|
||||
condErr = bperr
|
||||
} else {
|
||||
return fmt.Errorf("multiple errors evaluating conditions")
|
||||
}
|
||||
@ -457,36 +486,36 @@ func (dbp *Process) conditionErrors() error {
|
||||
// - a thread with onTriggeredInternalBreakpoint() == true
|
||||
// - a thread with onTriggeredBreakpoint() == true (prioritizing trapthread)
|
||||
// - trapthread
|
||||
func (dbp *Process) pickCurrentThread(trapthread *Thread) error {
|
||||
for _, th := range dbp.threads {
|
||||
if th.onTriggeredInternalBreakpoint() {
|
||||
return dbp.SwitchThread(th.ID)
|
||||
func pickCurrentThread(dbp Continuable, trapthread IThread, threads []IThread) error {
|
||||
for _, th := range threads {
|
||||
if bp, active, _ := th.Breakpoint(); active && bp.Internal() {
|
||||
return dbp.SwitchThread(th.ThreadID())
|
||||
}
|
||||
}
|
||||
if trapthread.onTriggeredBreakpoint() {
|
||||
return dbp.SwitchThread(trapthread.ID)
|
||||
if _, active, _ := trapthread.Breakpoint(); active {
|
||||
return dbp.SwitchThread(trapthread.ThreadID())
|
||||
}
|
||||
for _, th := range dbp.threads {
|
||||
if th.onTriggeredBreakpoint() {
|
||||
return dbp.SwitchThread(th.ID)
|
||||
for _, th := range threads {
|
||||
if _, active, _ := th.Breakpoint(); active {
|
||||
return dbp.SwitchThread(th.ThreadID())
|
||||
}
|
||||
}
|
||||
return dbp.SwitchThread(trapthread.ID)
|
||||
return dbp.SwitchThread(trapthread.ThreadID())
|
||||
}
|
||||
|
||||
// Step will continue until another source line is reached.
|
||||
// Will step into functions.
|
||||
func (dbp *Process) Step() (err error) {
|
||||
if dbp.exited {
|
||||
func Step(dbp Continuable) (err error) {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{}
|
||||
}
|
||||
for i := range dbp.breakpoints {
|
||||
if dbp.breakpoints[i].Internal() {
|
||||
for _, bp := range dbp.Breakpoints() {
|
||||
if bp.Internal() {
|
||||
return fmt.Errorf("next while nexting")
|
||||
}
|
||||
}
|
||||
|
||||
if err = dbp.next(true); err != nil {
|
||||
if err = next(dbp, true); err != nil {
|
||||
switch err.(type) {
|
||||
case ThreadBlockedError, NoReturnAddr: // Noop
|
||||
default:
|
||||
@ -495,7 +524,7 @@ func (dbp *Process) Step() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
return dbp.Continue()
|
||||
return Continue(dbp)
|
||||
}
|
||||
|
||||
// Returns an expression that evaluates to true when the current goroutine is g
|
||||
@ -529,7 +558,7 @@ func (dbp *Process) StepInstruction() (err error) {
|
||||
if _, err := dbp.SetBreakpoint(dbp.selectedGoroutine.PC, NextBreakpoint, sameGoroutineCondition(dbp.selectedGoroutine)); err != nil {
|
||||
return err
|
||||
}
|
||||
return dbp.Continue()
|
||||
return Continue(dbp)
|
||||
}
|
||||
dbp.allGCache = nil
|
||||
if dbp.exited {
|
||||
@ -545,10 +574,12 @@ func (dbp *Process) StepInstruction() (err error) {
|
||||
|
||||
// StepOut will continue until the current goroutine exits the
|
||||
// function currently being executed or a deferred function is executed
|
||||
func (dbp *Process) StepOut() error {
|
||||
cond := sameGoroutineCondition(dbp.selectedGoroutine)
|
||||
func StepOut(dbp Continuable) error {
|
||||
selg := dbp.SelectedGoroutine()
|
||||
curthread := dbp.CurrentThread()
|
||||
cond := sameGoroutineCondition(selg)
|
||||
|
||||
topframe, err := topframe(dbp.selectedGoroutine, dbp.currentThread)
|
||||
topframe, err := topframe(selg, curthread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -557,10 +588,10 @@ func (dbp *Process) StepOut() error {
|
||||
|
||||
var deferpc uint64 = 0
|
||||
if filepath.Ext(topframe.Current.File) == ".go" {
|
||||
if dbp.selectedGoroutine != nil {
|
||||
deferPCEntry := dbp.selectedGoroutine.DeferPC()
|
||||
if selg != nil {
|
||||
deferPCEntry := selg.DeferPC()
|
||||
if deferPCEntry != 0 {
|
||||
_, _, deferfn := dbp.bi.goSymTable.PCToLine(deferPCEntry)
|
||||
_, _, deferfn := dbp.BinInfo().PCToLine(deferPCEntry)
|
||||
deferpc, err = dbp.FirstPCAfterPrologue(deferfn, false)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -591,12 +622,12 @@ func (dbp *Process) StepOut() error {
|
||||
}
|
||||
|
||||
if topframe.Ret != 0 {
|
||||
if err := dbp.setInternalBreakpoints(topframe.Current.PC, []uint64{topframe.Ret}, NextBreakpoint, cond); err != nil {
|
||||
if err := setInternalBreakpoints(dbp, topframe.Current.PC, []uint64{topframe.Ret}, NextBreakpoint, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return dbp.Continue()
|
||||
return Continue(dbp)
|
||||
}
|
||||
|
||||
// SwitchThread changes from current thread to the thread specified by `tid`.
|
||||
@ -633,29 +664,42 @@ func (dbp *Process) SwitchGoroutine(gid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the argument of GoroutinesInfo implements AllGCache GoroutinesInfo
|
||||
// will use the pointer returned by AllGCache as a cache.
|
||||
type AllGCache interface {
|
||||
AllGCache() *[]*G
|
||||
}
|
||||
|
||||
func (dbp *Process) AllGCache() *[]*G {
|
||||
return &dbp.allGCache
|
||||
}
|
||||
|
||||
// GoroutinesInfo returns an array of G structures representing the information
|
||||
// Delve cares about from the internal runtime G structure.
|
||||
func (dbp *Process) GoroutinesInfo() ([]*G, error) {
|
||||
if dbp.exited {
|
||||
func GoroutinesInfo(dbp EvalScopeConvertible) ([]*G, error) {
|
||||
if dbp.Exited() {
|
||||
return nil, &ProcessExitedError{}
|
||||
}
|
||||
if dbp.allGCache != nil {
|
||||
return dbp.allGCache, nil
|
||||
if dbp, ok := dbp.(AllGCache); ok {
|
||||
if allGCache := dbp.AllGCache(); *allGCache != nil {
|
||||
return *allGCache, nil
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
threadg = map[int]*Thread{}
|
||||
threadg = map[int]IThread{}
|
||||
allg []*G
|
||||
rdr = dbp.bi.DwarfReader()
|
||||
rdr = dbp.BinInfo().DwarfReader()
|
||||
)
|
||||
|
||||
for i := range dbp.threads {
|
||||
if dbp.threads[i].blocked() {
|
||||
threads := dbp.ThreadList()
|
||||
for _, th := range threads {
|
||||
if threadBlocked(th) {
|
||||
continue
|
||||
}
|
||||
g, _ := GetG(dbp.threads[i])
|
||||
g, _ := GetG(th)
|
||||
if g != nil {
|
||||
threadg[g.ID] = dbp.threads[i]
|
||||
threadg[g.ID] = th
|
||||
}
|
||||
}
|
||||
|
||||
@ -663,7 +707,7 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
allglenBytes, err := dbp.currentThread.readMemory(uintptr(addr), 8)
|
||||
allglenBytes, err := dbp.CurrentThread().readMemory(uintptr(addr), 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -678,11 +722,11 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
faddr, err := dbp.currentThread.readMemory(uintptr(allgentryaddr), dbp.bi.arch.PtrSize())
|
||||
faddr, err := dbp.CurrentThread().readMemory(uintptr(allgentryaddr), dbp.BinInfo().arch.PtrSize())
|
||||
allgptr := binary.LittleEndian.Uint64(faddr)
|
||||
|
||||
for i := uint64(0); i < allglen; i++ {
|
||||
gvar, err := newGVariable(dbp.currentThread, uintptr(allgptr+(i*uint64(dbp.bi.arch.PtrSize()))), true)
|
||||
gvar, err := newGVariable(dbp.CurrentThread(), uintptr(allgptr+(i*uint64(dbp.BinInfo().arch.PtrSize()))), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -703,7 +747,11 @@ func (dbp *Process) GoroutinesInfo() ([]*G, error) {
|
||||
allg = append(allg, g)
|
||||
}
|
||||
}
|
||||
dbp.allGCache = allg
|
||||
if dbp, ok := dbp.(AllGCache); ok {
|
||||
allGCache := dbp.AllGCache()
|
||||
*allGCache = allg
|
||||
}
|
||||
|
||||
return allg, nil
|
||||
}
|
||||
|
||||
@ -884,19 +932,14 @@ func (scope *EvalScope) getGoInformation() (ver GoVersion, isextld bool, err err
|
||||
return
|
||||
}
|
||||
|
||||
type GoroutinesInfo interface {
|
||||
SelectedGoroutine() *G
|
||||
GoroutinesInfo() ([]*G, error)
|
||||
}
|
||||
|
||||
// FindGoroutine returns a G struct representing the goroutine
|
||||
// specified by `gid`.
|
||||
func FindGoroutine(dbp GoroutinesInfo, gid int) (*G, error) {
|
||||
func FindGoroutine(dbp EvalScopeConvertible, gid int) (*G, error) {
|
||||
if gid == -1 {
|
||||
return dbp.SelectedGoroutine(), nil
|
||||
}
|
||||
|
||||
gs, err := dbp.GoroutinesInfo()
|
||||
gs, err := GoroutinesInfo(dbp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -911,9 +954,11 @@ func FindGoroutine(dbp GoroutinesInfo, gid int) (*G, error) {
|
||||
// EvalScopeConvertible is a subset of target.Interface with the methods
|
||||
// used by ConvertEvalScope/GoroutinesInfo/etc.
|
||||
type EvalScopeConvertible interface {
|
||||
GoroutinesInfo
|
||||
Exited() bool
|
||||
SelectedGoroutine() *G
|
||||
CurrentThread() IThread
|
||||
BinInfo() *BinaryInfo
|
||||
ThreadList() []IThread
|
||||
}
|
||||
|
||||
// ConvertEvalScope returns a new EvalScope in the context of the
|
||||
|
@ -101,7 +101,7 @@ func currentLineNumber(p *Process, t *testing.T) (string, int) {
|
||||
|
||||
func TestExit(t *testing.T) {
|
||||
withTestProcess("continuetestprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
pe, ok := err.(ProcessExitedError)
|
||||
if !ok {
|
||||
t.Fatalf("Continue() returned unexpected error type %s", err)
|
||||
@ -119,8 +119,8 @@ func TestExitAfterContinue(t *testing.T) {
|
||||
withTestProcess("continuetestprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "main.sayhi")
|
||||
assertNoError(err, t, "setFunctionBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "First Continue()")
|
||||
err = p.Continue()
|
||||
assertNoError(Continue(p), t, "First Continue()")
|
||||
err = Continue(p)
|
||||
pe, ok := err.(ProcessExitedError)
|
||||
if !ok {
|
||||
t.Fatalf("Continue() returned unexpected error type %s", pe)
|
||||
@ -159,7 +159,7 @@ func TestHalt(t *testing.T) {
|
||||
withTestProcess("loopprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "main.loop")
|
||||
assertNoError(err, t, "SetBreakpoint")
|
||||
assertNoError(p.Continue(), t, "Continue")
|
||||
assertNoError(Continue(p), t, "Continue")
|
||||
for _, th := range p.threads {
|
||||
if th.running != false {
|
||||
t.Fatal("expected running = false for thread", th.ID)
|
||||
@ -178,7 +178,7 @@ func TestHalt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}()
|
||||
assertNoError(p.Continue(), t, "Continue")
|
||||
assertNoError(Continue(p), t, "Continue")
|
||||
<-stopChan
|
||||
// Loop through threads and make sure they are all
|
||||
// actually stopped, err will not be nil if the process
|
||||
@ -203,7 +203,7 @@ func TestStep(t *testing.T) {
|
||||
|
||||
_, err := p.SetBreakpoint(helloworldaddr, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
regs := getRegisters(p, t)
|
||||
rip := regs.PC()
|
||||
@ -225,7 +225,7 @@ func TestBreakpoint(t *testing.T) {
|
||||
|
||||
bp, err := p.SetBreakpoint(helloworldaddr, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
pc, err := p.PC()
|
||||
if err != nil {
|
||||
@ -255,7 +255,7 @@ func TestBreakpointInSeperateGoRoutine(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -340,7 +340,7 @@ func testseq(program string, contFunc contFunc, testcases []nextTest, initialLoc
|
||||
bp, err = p.SetBreakpoint(pc, UserBreakpoint, nil)
|
||||
}
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
p.currentThread.SetPC(bp.Addr)
|
||||
|
||||
@ -353,9 +353,9 @@ func testseq(program string, contFunc contFunc, testcases []nextTest, initialLoc
|
||||
|
||||
switch contFunc {
|
||||
case contNext:
|
||||
assertNoError(p.Next(), t, "Next() returned an error")
|
||||
assertNoError(Next(p), t, "Next() returned an error")
|
||||
case contStep:
|
||||
assertNoError(p.Step(), t, "Step() returned an error")
|
||||
assertNoError(Step(p), t, "Step() returned an error")
|
||||
}
|
||||
|
||||
f, ln = currentLineNumber(p, t)
|
||||
@ -427,7 +427,7 @@ func TestNextConcurrent(t *testing.T) {
|
||||
withTestProcess("parallel_next", t, func(p *Process, fixture protest.Fixture) {
|
||||
bp, err := setFunctionBreakpoint(p, "main.sayhi")
|
||||
assertNoError(err, t, "SetBreakpoint")
|
||||
assertNoError(p.Continue(), t, "Continue")
|
||||
assertNoError(Continue(p), t, "Continue")
|
||||
f, ln := currentLineNumber(p, t)
|
||||
initV, err := evalVariable(p, "n")
|
||||
initVval, _ := constant.Int64Val(initV.Value)
|
||||
@ -443,7 +443,7 @@ func TestNextConcurrent(t *testing.T) {
|
||||
if ln != tc.begin {
|
||||
t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
|
||||
}
|
||||
assertNoError(p.Next(), t, "Next() returned an error")
|
||||
assertNoError(Next(p), t, "Next() returned an error")
|
||||
f, ln = currentLineNumber(p, t)
|
||||
if ln != tc.end {
|
||||
t.Fatalf("Program did not continue to correct next location expected %d was %s:%d", tc.end, filepath.Base(f), ln)
|
||||
@ -468,7 +468,7 @@ func TestNextConcurrentVariant2(t *testing.T) {
|
||||
withTestProcess("parallel_next", t, func(p *Process, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "main.sayhi")
|
||||
assertNoError(err, t, "SetBreakpoint")
|
||||
assertNoError(p.Continue(), t, "Continue")
|
||||
assertNoError(Continue(p), t, "Continue")
|
||||
f, ln := currentLineNumber(p, t)
|
||||
initV, err := evalVariable(p, "n")
|
||||
initVval, _ := constant.Int64Val(initV.Value)
|
||||
@ -482,7 +482,7 @@ func TestNextConcurrentVariant2(t *testing.T) {
|
||||
if ln != tc.begin {
|
||||
t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
|
||||
}
|
||||
assertNoError(p.Next(), t, "Next() returned an error")
|
||||
assertNoError(Next(p), t, "Next() returned an error")
|
||||
var vval int64
|
||||
for {
|
||||
v, err := evalVariable(p, "n")
|
||||
@ -497,7 +497,7 @@ func TestNextConcurrentVariant2(t *testing.T) {
|
||||
if vval == initVval {
|
||||
t.Fatal("Initial breakpoint triggered twice for the same goroutine")
|
||||
}
|
||||
assertNoError(p.Continue(), t, "Continue 2")
|
||||
assertNoError(Continue(p), t, "Continue 2")
|
||||
}
|
||||
}
|
||||
f, ln = currentLineNumber(p, t)
|
||||
@ -550,7 +550,7 @@ func TestNextNetHTTP(t *testing.T) {
|
||||
}
|
||||
http.Get("http://localhost:9191")
|
||||
}()
|
||||
if err := p.Continue(); err != nil {
|
||||
if err := Continue(p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f, ln := currentLineNumber(p, t)
|
||||
@ -559,7 +559,7 @@ func TestNextNetHTTP(t *testing.T) {
|
||||
t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln)
|
||||
}
|
||||
|
||||
assertNoError(p.Next(), t, "Next() returned an error")
|
||||
assertNoError(Next(p), t, "Next() returned an error")
|
||||
|
||||
f, ln = currentLineNumber(p, t)
|
||||
if ln != tc.end {
|
||||
@ -571,7 +571,7 @@ func TestNextNetHTTP(t *testing.T) {
|
||||
|
||||
func TestRuntimeBreakpoint(t *testing.T) {
|
||||
withTestProcess("testruntimebreakpoint", t, func(p *Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -607,7 +607,7 @@ func TestFindReturnAddress(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -632,7 +632,7 @@ func TestFindReturnAddressTopOfStackFn(t *testing.T) {
|
||||
if _, err := p.SetBreakpoint(fn.Entry, UserBreakpoint, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := p.Continue(); err != nil {
|
||||
if err := Continue(p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := returnAddress(p.currentThread); err == nil {
|
||||
@ -656,7 +656,7 @@ func TestSwitchThread(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -701,11 +701,11 @@ func TestCGONext(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = p.Next()
|
||||
err = Next(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -736,7 +736,7 @@ func TestStacktrace(t *testing.T) {
|
||||
assertNoError(err, t, "BreakByLocation()")
|
||||
|
||||
for i := range stacks {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
locations, err := ThreadStacktrace(p.currentThread, 40)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
|
||||
@ -757,13 +757,13 @@ func TestStacktrace(t *testing.T) {
|
||||
}
|
||||
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
p.Continue()
|
||||
Continue(p)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStacktrace2(t *testing.T) {
|
||||
withTestProcess("retstack", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
locations, err := ThreadStacktrace(p.currentThread, 40)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
@ -774,7 +774,7 @@ func TestStacktrace2(t *testing.T) {
|
||||
t.Fatalf("Stack error at main.f()\n%v\n", locations)
|
||||
}
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
locations, err = ThreadStacktrace(p.currentThread, 40)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
if !stackMatch([]loc{{-1, "main.g"}, {17, "main.main"}}, locations, false) {
|
||||
@ -817,7 +817,7 @@ func TestStacktraceGoroutine(t *testing.T) {
|
||||
bp, err := setFunctionBreakpoint(p, "main.stacktraceme")
|
||||
assertNoError(err, t, "BreakByLocation()")
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
gs, err := p.GoroutinesInfo()
|
||||
assertNoError(err, t, "GoroutinesInfo")
|
||||
@ -867,7 +867,7 @@ func TestStacktraceGoroutine(t *testing.T) {
|
||||
}
|
||||
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
p.Continue()
|
||||
Continue(p)
|
||||
})
|
||||
}
|
||||
|
||||
@ -892,7 +892,7 @@ func testGSupportFunc(name string, t *testing.T, p *Process, fixture protest.Fix
|
||||
bp, err := setFunctionBreakpoint(p, "main.main")
|
||||
assertNoError(err, t, name+": BreakByLocation()")
|
||||
|
||||
assertNoError(p.Continue(), t, name+": Continue()")
|
||||
assertNoError(Continue(p), t, name+": Continue()")
|
||||
|
||||
g, err := GetG(p.currentThread)
|
||||
assertNoError(err, t, name+": GetG()")
|
||||
@ -935,7 +935,7 @@ func TestContinueMulti(t *testing.T) {
|
||||
mainCount := 0
|
||||
sayhiCount := 0
|
||||
for {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
if p.Exited() {
|
||||
break
|
||||
}
|
||||
@ -993,7 +993,7 @@ func TestBreakpointOnFunctionEntry(t *testing.T) {
|
||||
assertNoError(err, t, "FindFunctionLocation()")
|
||||
_, err = p.SetBreakpoint(addr, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
_, ln := currentLineNumber(p, t)
|
||||
if ln != 17 {
|
||||
t.Fatalf("Wrong line number: %d (expected: 17)\n", ln)
|
||||
@ -1003,7 +1003,7 @@ func TestBreakpointOnFunctionEntry(t *testing.T) {
|
||||
|
||||
func TestProcessReceivesSIGCHLD(t *testing.T) {
|
||||
withTestProcess("sigchldprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
_, ok := err.(ProcessExitedError)
|
||||
if !ok {
|
||||
t.Fatalf("Continue() returned unexpected error type %s", err)
|
||||
@ -1017,7 +1017,7 @@ func TestIssue239(t *testing.T) {
|
||||
assertNoError(err, t, "LineToPC()")
|
||||
_, err = p.SetBreakpoint(pos, UserBreakpoint, nil)
|
||||
assertNoError(err, t, fmt.Sprintf("SetBreakpoint(%d)", pos))
|
||||
assertNoError(p.Continue(), t, fmt.Sprintf("Continue()"))
|
||||
assertNoError(Continue(p), t, fmt.Sprintf("Continue()"))
|
||||
})
|
||||
}
|
||||
|
||||
@ -1074,7 +1074,7 @@ func TestVariableEvaluation(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(Continue(p), t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
v, err := evalVariable(p, tc.name)
|
||||
@ -1126,7 +1126,7 @@ func TestFrameEvaluation(t *testing.T) {
|
||||
withTestProcess("goroutinestackprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "main.stacktraceme")
|
||||
assertNoError(err, t, "setFunctionBreakpoint")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
// Testing evaluation on goroutines
|
||||
gs, err := p.GoroutinesInfo()
|
||||
@ -1171,7 +1171,7 @@ func TestFrameEvaluation(t *testing.T) {
|
||||
}
|
||||
|
||||
// Testing evaluation on frames
|
||||
assertNoError(p.Continue(), t, "Continue() 2")
|
||||
assertNoError(Continue(p), t, "Continue() 2")
|
||||
g, err := GetG(p.currentThread)
|
||||
assertNoError(err, t, "GetG()")
|
||||
|
||||
@ -1191,7 +1191,7 @@ func TestFrameEvaluation(t *testing.T) {
|
||||
|
||||
func TestPointerSetting(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(Continue(p), t, "Continue() returned an error")
|
||||
|
||||
pval := func(n int64) {
|
||||
variable, err := evalVariable(p, "p1")
|
||||
@ -1220,7 +1220,7 @@ func TestPointerSetting(t *testing.T) {
|
||||
|
||||
func TestVariableFunctionScoping(t *testing.T) {
|
||||
withTestProcess("testvariables", t, func(p *Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
_, err = evalVariable(p, "a1")
|
||||
@ -1230,7 +1230,7 @@ func TestVariableFunctionScoping(t *testing.T) {
|
||||
assertNoError(err, t, "Unable to find variable a1")
|
||||
|
||||
// Move scopes, a1 exists here by a2 does not
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
_, err = evalVariable(p, "a1")
|
||||
@ -1245,7 +1245,7 @@ func TestVariableFunctionScoping(t *testing.T) {
|
||||
|
||||
func TestRecursiveStructure(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
v, err := evalVariable(p, "aas")
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
t.Logf("v: %v\n", v)
|
||||
@ -1255,7 +1255,7 @@ func TestRecursiveStructure(t *testing.T) {
|
||||
func TestIssue316(t *testing.T) {
|
||||
// A pointer loop that includes one interface should not send dlv into an infinite loop
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
_, err := evalVariable(p, "iface5")
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
})
|
||||
@ -1264,7 +1264,7 @@ func TestIssue316(t *testing.T) {
|
||||
func TestIssue325(t *testing.T) {
|
||||
// nil pointer dereference when evaluating interfaces to function pointers
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
iface2fn1v, err := evalVariable(p, "iface2fn1")
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
t.Logf("iface2fn1: %v\n", iface2fn1v)
|
||||
@ -1283,7 +1283,7 @@ func TestBreakpointCounts(t *testing.T) {
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
for {
|
||||
if err := p.Continue(); err != nil {
|
||||
if err := Continue(p); err != nil {
|
||||
if _, exited := err.(ProcessExitedError); exited {
|
||||
break
|
||||
}
|
||||
@ -1312,7 +1312,7 @@ func BenchmarkArray(b *testing.B) {
|
||||
// each bencharr struct is 128 bytes, bencharr is 64 elements long
|
||||
b.SetBytes(int64(64 * 128))
|
||||
withTestProcess("testvariables2", b, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
assertNoError(Continue(p), b, "Continue()")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := evalVariable(p, "bencharr")
|
||||
assertNoError(err, b, "EvalVariable()")
|
||||
@ -1334,7 +1334,7 @@ func TestBreakpointCountsWithDetection(t *testing.T) {
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
for {
|
||||
if err := p.Continue(); err != nil {
|
||||
if err := Continue(p); err != nil {
|
||||
if _, exited := err.(ProcessExitedError); exited {
|
||||
break
|
||||
}
|
||||
@ -1387,7 +1387,7 @@ func BenchmarkArrayPointer(b *testing.B) {
|
||||
// each read will read 64 bencharr structs plus the 64 pointers of benchparr
|
||||
b.SetBytes(int64(64*128 + 64*8))
|
||||
withTestProcess("testvariables2", b, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
assertNoError(Continue(p), b, "Continue()")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := evalVariable(p, "bencharr")
|
||||
assertNoError(err, b, "EvalVariable()")
|
||||
@ -1401,7 +1401,7 @@ func BenchmarkMap(b *testing.B) {
|
||||
// reading strings and the map structure imposes a overhead that we ignore here
|
||||
b.SetBytes(int64(41 * (2*8 + 9)))
|
||||
withTestProcess("testvariables2", b, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
assertNoError(Continue(p), b, "Continue()")
|
||||
for i := 0; i < b.N; i++ {
|
||||
_, err := evalVariable(p, "m1")
|
||||
assertNoError(err, b, "EvalVariable()")
|
||||
@ -1411,7 +1411,7 @@ func BenchmarkMap(b *testing.B) {
|
||||
|
||||
func BenchmarkGoroutinesInfo(b *testing.B) {
|
||||
withTestProcess("testvariables2", b, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
assertNoError(Continue(p), b, "Continue()")
|
||||
for i := 0; i < b.N; i++ {
|
||||
p.allGCache = nil
|
||||
_, err := p.GoroutinesInfo()
|
||||
@ -1428,8 +1428,8 @@ func TestIssue262(t *testing.T) {
|
||||
_, err = p.SetBreakpoint(addr, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
err = p.Continue()
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
err = Continue(p)
|
||||
if err == nil {
|
||||
t.Fatalf("No error on second continue")
|
||||
}
|
||||
@ -1450,13 +1450,13 @@ func TestIssue305(t *testing.T) {
|
||||
_, err = p.SetBreakpoint(addr, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
assertNoError(p.Next(), t, "Next() 1")
|
||||
assertNoError(p.Next(), t, "Next() 2")
|
||||
assertNoError(p.Next(), t, "Next() 3")
|
||||
assertNoError(p.Next(), t, "Next() 4")
|
||||
assertNoError(p.Next(), t, "Next() 5")
|
||||
assertNoError(Next(p), t, "Next() 1")
|
||||
assertNoError(Next(p), t, "Next() 2")
|
||||
assertNoError(Next(p), t, "Next() 3")
|
||||
assertNoError(Next(p), t, "Next() 4")
|
||||
assertNoError(Next(p), t, "Next() 5")
|
||||
})
|
||||
}
|
||||
|
||||
@ -1464,7 +1464,7 @@ func TestPointerLoops(t *testing.T) {
|
||||
// Pointer loops through map entries, pointers and slices
|
||||
// Regression test for issue #341
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
for _, expr := range []string{"mapinf", "ptrinf", "sliceinf"} {
|
||||
t.Logf("requesting %s", expr)
|
||||
v, err := evalVariable(p, expr)
|
||||
@ -1476,7 +1476,7 @@ func TestPointerLoops(t *testing.T) {
|
||||
|
||||
func BenchmarkLocalVariables(b *testing.B) {
|
||||
withTestProcess("testvariables", b, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), b, "Continue() returned an error")
|
||||
assertNoError(Continue(p), b, "Continue() returned an error")
|
||||
scope, err := GoroutineScope(p.currentThread)
|
||||
assertNoError(err, b, "Scope()")
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -1498,7 +1498,7 @@ func TestCondBreakpoint(t *testing.T) {
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "7"},
|
||||
}
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
nvar, err := evalVariable(p, "n")
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
@ -1522,7 +1522,7 @@ func TestCondBreakpointError(t *testing.T) {
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "7"},
|
||||
}
|
||||
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
if err == nil {
|
||||
t.Fatalf("No error on first Continue()")
|
||||
}
|
||||
@ -1537,7 +1537,7 @@ func TestCondBreakpointError(t *testing.T) {
|
||||
Y: &ast.BasicLit{Kind: token.INT, Value: "7"},
|
||||
}
|
||||
|
||||
err = p.Continue()
|
||||
err = Continue(p)
|
||||
if err != nil {
|
||||
if _, exited := err.(ProcessExitedError); !exited {
|
||||
t.Fatalf("Unexpected error on second Continue(): %v", err)
|
||||
@ -1557,7 +1557,7 @@ func TestCondBreakpointError(t *testing.T) {
|
||||
func TestIssue356(t *testing.T) {
|
||||
// slice with a typedef does not get printed correctly
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(Continue(p), t, "Continue() returned an error")
|
||||
mmvar, err := evalVariable(p, "mainMenu")
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
if mmvar.Kind != reflect.Slice {
|
||||
@ -1569,9 +1569,9 @@ func TestIssue356(t *testing.T) {
|
||||
func TestStepIntoFunction(t *testing.T) {
|
||||
withTestProcess("teststep", t, func(p *Process, fixture protest.Fixture) {
|
||||
// Continue until breakpoint
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(Continue(p), t, "Continue() returned an error")
|
||||
// Step into function
|
||||
assertNoError(p.Step(), t, "Step() returned an error")
|
||||
assertNoError(Step(p), t, "Step() returned an error")
|
||||
// We should now be inside the function.
|
||||
loc, err := p.CurrentLocation()
|
||||
if err != nil {
|
||||
@ -1596,7 +1596,7 @@ func TestIssue384(t *testing.T) {
|
||||
assertNoError(err, t, "LineToPC()")
|
||||
_, err = p.SetBreakpoint(start, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
_, err = evalVariable(p, "st")
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
})
|
||||
@ -1609,8 +1609,8 @@ func TestIssue332_Part1(t *testing.T) {
|
||||
assertNoError(err, t, "LineToPC()")
|
||||
_, err = p.SetBreakpoint(start, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(p.Next(), t, "first Next()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
assertNoError(Next(p), t, "first Next()")
|
||||
locations, err := ThreadStacktrace(p.currentThread, 2)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
if locations[0].Call.Fn == nil {
|
||||
@ -1635,11 +1635,11 @@ func TestIssue332_Part2(t *testing.T) {
|
||||
assertNoError(err, t, "LineToPC()")
|
||||
_, err = p.SetBreakpoint(start, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
// step until we enter changeMe
|
||||
for {
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertNoError(Step(p), t, "Step()")
|
||||
locations, err := ThreadStacktrace(p.currentThread, 2)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
if locations[0].Call.Fn == nil {
|
||||
@ -1662,10 +1662,10 @@ func TestIssue332_Part2(t *testing.T) {
|
||||
t.Fatalf("Step did not skip the prologue: current pc: %x, first instruction after prologue: %x", pc, pcAfterPrologue)
|
||||
}
|
||||
|
||||
assertNoError(p.Next(), t, "first Next()")
|
||||
assertNoError(p.Next(), t, "second Next()")
|
||||
assertNoError(p.Next(), t, "third Next()")
|
||||
err = p.Continue()
|
||||
assertNoError(Next(p), t, "first Next()")
|
||||
assertNoError(Next(p), t, "second Next()")
|
||||
assertNoError(Next(p), t, "third Next()")
|
||||
err = Continue(p)
|
||||
if _, exited := err.(ProcessExitedError); !exited {
|
||||
assertNoError(err, t, "final Continue()")
|
||||
}
|
||||
@ -1686,9 +1686,9 @@ func TestIssue414(t *testing.T) {
|
||||
assertNoError(err, t, "LineToPC()")
|
||||
_, err = p.SetBreakpoint(start, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
for {
|
||||
err := p.Step()
|
||||
err := Step(p)
|
||||
if err != nil {
|
||||
if _, exited := err.(ProcessExitedError); exited {
|
||||
break
|
||||
@ -1701,7 +1701,7 @@ func TestIssue414(t *testing.T) {
|
||||
|
||||
func TestPackageVariables(t *testing.T) {
|
||||
withTestProcess("testvariables", t, func(p *Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
assertNoError(err, t, "Continue()")
|
||||
scope, err := GoroutineScope(p.currentThread)
|
||||
assertNoError(err, t, "Scope()")
|
||||
@ -1734,7 +1734,7 @@ func TestIssue149(t *testing.T) {
|
||||
|
||||
func TestPanicBreakpoint(t *testing.T) {
|
||||
withTestProcess("panic", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
bp := p.CurrentBreakpoint()
|
||||
if bp == nil || bp.Name != "unrecovered-panic" {
|
||||
t.Fatalf("not on unrecovered-panic breakpoint: %v", p.CurrentBreakpoint())
|
||||
@ -1744,7 +1744,7 @@ func TestPanicBreakpoint(t *testing.T) {
|
||||
|
||||
func TestCmdLineArgs(t *testing.T) {
|
||||
expectSuccess := func(p *Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
bp := p.CurrentBreakpoint()
|
||||
if bp != nil && bp.Name == "unrecovered-panic" {
|
||||
t.Fatalf("testing args failed on unrecovered-panic breakpoint: %v", p.CurrentBreakpoint())
|
||||
@ -1760,7 +1760,7 @@ func TestCmdLineArgs(t *testing.T) {
|
||||
}
|
||||
|
||||
expectPanic := func(p *Process, fixture protest.Fixture) {
|
||||
p.Continue()
|
||||
Continue(p)
|
||||
bp := p.CurrentBreakpoint()
|
||||
if bp == nil || bp.Name != "unrecovered-panic" {
|
||||
t.Fatalf("not on unrecovered-panic breakpoint: %v", p.CurrentBreakpoint())
|
||||
@ -1805,7 +1805,7 @@ func TestIssue462(t *testing.T) {
|
||||
p.RequestManualStop()
|
||||
}()
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
_, err := ThreadStacktrace(p.currentThread, 40)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
})
|
||||
@ -1829,7 +1829,7 @@ func TestNextParked(t *testing.T) {
|
||||
var parkedg *G
|
||||
LookForParkedG:
|
||||
for {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
if _, exited := err.(ProcessExitedError); exited {
|
||||
t.Log("could not find parked goroutine")
|
||||
return
|
||||
@ -1849,7 +1849,7 @@ func TestNextParked(t *testing.T) {
|
||||
|
||||
assertNoError(p.SwitchGoroutine(parkedg.ID), t, "SwitchGoroutine()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
assertNoError(p.Next(), t, "Next()")
|
||||
assertNoError(Next(p), t, "Next()")
|
||||
|
||||
if p.selectedGoroutine.ID != parkedg.ID {
|
||||
t.Fatalf("Next did not continue on the selected goroutine, expected %d got %d", parkedg.ID, p.selectedGoroutine.ID)
|
||||
@ -1866,7 +1866,7 @@ func TestStepParked(t *testing.T) {
|
||||
var parkedg *G
|
||||
LookForParkedG:
|
||||
for {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
if _, exited := err.(ProcessExitedError); exited {
|
||||
t.Log("could not find parked goroutine")
|
||||
return
|
||||
@ -1896,7 +1896,7 @@ func TestStepParked(t *testing.T) {
|
||||
|
||||
assertNoError(p.SwitchGoroutine(parkedg.ID), t, "SwitchGoroutine()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertNoError(Step(p), t, "Step()")
|
||||
|
||||
if p.selectedGoroutine.ID != parkedg.ID {
|
||||
t.Fatalf("Step did not continue on the selected goroutine, expected %d got %d", parkedg.ID, p.selectedGoroutine.ID)
|
||||
@ -1965,10 +1965,10 @@ func TestIssue573(t *testing.T) {
|
||||
f := p.BinInfo().goSymTable.LookupFunc("main.foo")
|
||||
_, err := p.SetBreakpoint(f.Entry, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(p.Step(), t, "Step() #1")
|
||||
assertNoError(p.Step(), t, "Step() #2") // Bug exits here.
|
||||
assertNoError(p.Step(), t, "Step() #3") // Third step ought to be possible; program ought not have exited.
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
assertNoError(Step(p), t, "Step() #1")
|
||||
assertNoError(Step(p), t, "Step() #2") // Bug exits here.
|
||||
assertNoError(Step(p), t, "Step() #3") // Third step ought to be possible; program ought not have exited.
|
||||
})
|
||||
}
|
||||
|
||||
@ -2085,8 +2085,8 @@ func TestIssue561(t *testing.T) {
|
||||
// where a breakpoint is also set.
|
||||
withTestProcess("issue561", t, func(p *Process, fixture protest.Fixture) {
|
||||
setFileBreakpoint(p, t, fixture, 10)
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
assertNoError(Step(p), t, "Step()")
|
||||
_, ln := currentLineNumber(p, t)
|
||||
if ln != 5 {
|
||||
t.Fatalf("wrong line number after Step, expected 5 got %d", ln)
|
||||
@ -2098,7 +2098,7 @@ func TestStepOut(t *testing.T) {
|
||||
withTestProcess("testnextprog", t, func(p *Process, fixture protest.Fixture) {
|
||||
bp, err := setFunctionBreakpoint(p, "main.helloworld")
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
|
||||
f, lno := currentLineNumber(p, t)
|
||||
@ -2106,7 +2106,7 @@ func TestStepOut(t *testing.T) {
|
||||
t.Fatalf("wrong line number %s:%d, expected %d", f, lno, 13)
|
||||
}
|
||||
|
||||
assertNoError(p.StepOut(), t, "StepOut()")
|
||||
assertNoError(StepOut(p), t, "StepOut()")
|
||||
|
||||
f, lno = currentLineNumber(p, t)
|
||||
if lno != 35 {
|
||||
@ -2122,7 +2122,7 @@ func TestStepConcurrentDirect(t *testing.T) {
|
||||
bp, err := p.SetBreakpoint(pc, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
_, err = p.ClearBreakpoint(bp.Addr)
|
||||
assertNoError(err, t, "ClearBreakpoint()")
|
||||
|
||||
@ -2171,7 +2171,7 @@ func TestStepConcurrentDirect(t *testing.T) {
|
||||
if i == 0 {
|
||||
count++
|
||||
}
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertNoError(Step(p), t, "Step()")
|
||||
}
|
||||
|
||||
if count != 100 {
|
||||
@ -2207,7 +2207,7 @@ func TestStepConcurrentPtr(t *testing.T) {
|
||||
kvals := map[int]int64{}
|
||||
count := 0
|
||||
for {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
_, exited := err.(ProcessExitedError)
|
||||
if exited {
|
||||
break
|
||||
@ -2235,12 +2235,12 @@ func TestStepConcurrentPtr(t *testing.T) {
|
||||
}
|
||||
kvals[gid] = k
|
||||
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertNoError(Step(p), t, "Step()")
|
||||
for nextInProgress(p) {
|
||||
if p.selectedGoroutine.ID == gid {
|
||||
t.Fatalf("step did not step into function call (but internal breakpoints still active?) (%d %d)", gid, p.selectedGoroutine.ID)
|
||||
}
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
}
|
||||
|
||||
if p.selectedGoroutine.ID != gid {
|
||||
@ -2272,7 +2272,7 @@ func TestStepOutDefer(t *testing.T) {
|
||||
assertNoError(err, t, "FindFileLocation()")
|
||||
bp, err := p.SetBreakpoint(pc, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
|
||||
f, lno := currentLineNumber(p, t)
|
||||
@ -2280,7 +2280,7 @@ func TestStepOutDefer(t *testing.T) {
|
||||
t.Fatalf("worng line number %s:%d, expected %d", f, lno, 5)
|
||||
}
|
||||
|
||||
assertNoError(p.StepOut(), t, "StepOut()")
|
||||
assertNoError(StepOut(p), t, "StepOut()")
|
||||
|
||||
f, l, _ := p.BinInfo().goSymTable.PCToLine(currentPC(p, t))
|
||||
if f == fixture.Source || l == 6 {
|
||||
@ -2295,10 +2295,10 @@ func TestStepOutDeferReturnAndDirectCall(t *testing.T) {
|
||||
// Here we test the case where the function is called by a deferreturn
|
||||
withTestProcess("defercall", t, func(p *Process, fixture protest.Fixture) {
|
||||
bp := setFileBreakpoint(p, t, fixture, 11)
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
|
||||
assertNoError(p.StepOut(), t, "StepOut()")
|
||||
assertNoError(StepOut(p), t, "StepOut()")
|
||||
|
||||
f, ln := currentLineNumber(p, t)
|
||||
if ln != 28 {
|
||||
@ -2314,7 +2314,7 @@ func TestStepOnCallPtrInstr(t *testing.T) {
|
||||
_, err = p.SetBreakpoint(pc, UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
|
||||
found := false
|
||||
|
||||
@ -2340,7 +2340,7 @@ func TestStepOnCallPtrInstr(t *testing.T) {
|
||||
t.Fatal("Could not find CALL instruction")
|
||||
}
|
||||
|
||||
assertNoError(p.Step(), t, "Step()")
|
||||
assertNoError(Step(p), t, "Step()")
|
||||
|
||||
f, ln := currentLineNumber(p, t)
|
||||
if ln != 5 {
|
||||
@ -2355,7 +2355,7 @@ func TestIssue594(t *testing.T) {
|
||||
// In particular the target should be able to cause a nil pointer
|
||||
// dereference panic and recover from it.
|
||||
withTestProcess("issue594", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
f, ln := currentLineNumber(p, t)
|
||||
if ln != 21 {
|
||||
t.Fatalf("Program stopped at %s:%d, expected :21", f, ln)
|
||||
@ -2369,10 +2369,10 @@ func TestStepOutPanicAndDirectCall(t *testing.T) {
|
||||
// Here we test the case where the function is called by a panic
|
||||
withTestProcess("defercall", t, func(p *Process, fixture protest.Fixture) {
|
||||
bp := setFileBreakpoint(p, t, fixture, 17)
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
p.ClearBreakpoint(bp.Addr)
|
||||
|
||||
assertNoError(p.StepOut(), t, "StepOut()")
|
||||
assertNoError(StepOut(p), t, "StepOut()")
|
||||
|
||||
f, ln := currentLineNumber(p, t)
|
||||
if ln != 5 {
|
||||
@ -2391,7 +2391,7 @@ func TestWorkDir(t *testing.T) {
|
||||
addr, _, err := p.BinInfo().goSymTable.LineToPC(fixture.Source, 14)
|
||||
assertNoError(err, t, "LineToPC")
|
||||
p.SetBreakpoint(addr, UserBreakpoint, nil)
|
||||
p.Continue()
|
||||
Continue(p)
|
||||
v, err := evalVariable(p, "pwd")
|
||||
assertNoError(err, t, "EvalVariable")
|
||||
str := constant.StringVal(v.Value)
|
||||
@ -2412,7 +2412,7 @@ func TestNegativeIntEvaluation(t *testing.T) {
|
||||
{"ni32", "int32", int64(-5)},
|
||||
}
|
||||
withTestProcess("testvariables2", t, func(p *Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
for _, tc := range testcases {
|
||||
v, err := evalVariable(p, tc.name)
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
@ -2431,11 +2431,11 @@ func TestIssue683(t *testing.T) {
|
||||
withTestProcess("issue683", t, func(p *Process, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "main.main")
|
||||
assertNoError(err, t, "setFunctionBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "First Continue()")
|
||||
assertNoError(Continue(p), t, "First Continue()")
|
||||
for i := 0; i < 20; i++ {
|
||||
// eventually an error about the source file not being found will be
|
||||
// returned, the important thing is that we shouldn't panic
|
||||
err := p.Step()
|
||||
err := Step(p)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
@ -2446,8 +2446,8 @@ func TestIssue683(t *testing.T) {
|
||||
func TestIssue664(t *testing.T) {
|
||||
withTestProcess("issue664", t, func(p *Process, fixture protest.Fixture) {
|
||||
setFileBreakpoint(p, t, fixture, 4)
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(p.Next(), t, "Next()")
|
||||
assertNoError(Continue(p), t, "Continue()")
|
||||
assertNoError(Next(p), t, "Next()")
|
||||
f, ln := currentLineNumber(p, t)
|
||||
if ln != 5 {
|
||||
t.Fatalf("Did not continue to line 5: %s:%d", f, ln)
|
||||
@ -2462,7 +2462,7 @@ func BenchmarkTrace(b *testing.B) {
|
||||
assertNoError(err, b, "setFunctionBreakpoint()")
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
assertNoError(p.Continue(), b, "Continue()")
|
||||
assertNoError(Continue(p), b, "Continue()")
|
||||
s, err := GoroutineScope(p.currentThread)
|
||||
assertNoError(err, b, "Scope()")
|
||||
_, err = s.FunctionArguments(LoadConfig{false, 0, 64, 0, 3})
|
||||
@ -2480,9 +2480,9 @@ func TestNextInDeferReturn(t *testing.T) {
|
||||
withTestProcess("defercall", t, func(p *Process, fixture protest.Fixture) {
|
||||
_, err := setFunctionBreakpoint(p, "runtime.deferreturn")
|
||||
assertNoError(err, t, "setFunctionBreakpoint()")
|
||||
assertNoError(p.Continue(), t, "First Continue()")
|
||||
assertNoError(Continue(p), t, "First Continue()")
|
||||
for i := 0; i < 20; i++ {
|
||||
assertNoError(p.Next(), t, fmt.Sprintf("Next() %d", i))
|
||||
assertNoError(Next(p), t, fmt.Sprintf("Next() %d", i))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -2519,7 +2519,7 @@ func TestStacktraceWithBarriers(t *testing.T) {
|
||||
assertNoError(err, t, "setFunctionBreakpoint()")
|
||||
stackBarrierGoids := []int{}
|
||||
for len(stackBarrierGoids) == 0 {
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
if _, exited := err.(ProcessExitedError); exited {
|
||||
t.Logf("Could not run test")
|
||||
return
|
||||
@ -2555,7 +2555,7 @@ func TestStacktraceWithBarriers(t *testing.T) {
|
||||
|
||||
t.Logf("stack barrier goids: %v\n", stackBarrierGoids)
|
||||
|
||||
assertNoError(p.StepOut(), t, "StepOut()")
|
||||
assertNoError(StepOut(p), t, "StepOut()")
|
||||
|
||||
gs, err := p.GoroutinesInfo()
|
||||
assertNoError(err, t, "GoroutinesInfo()")
|
||||
@ -2628,7 +2628,7 @@ func TestAttachDetach(t *testing.T) {
|
||||
http.Get("http://localhost:9191")
|
||||
}()
|
||||
|
||||
assertNoError(p.Continue(), t, "Continue")
|
||||
assertNoError(Continue(p), t, "Continue")
|
||||
|
||||
f, ln := currentLineNumber(p, t)
|
||||
if ln != 11 {
|
||||
|
@ -23,7 +23,7 @@ func TestIssue419(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}()
|
||||
err := p.Continue()
|
||||
err := Continue(p)
|
||||
if _, exited := err.(ProcessExitedError); !exited {
|
||||
t.Fatalf("Unexpected error after Continue(): %v\n", err)
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ type IThread interface {
|
||||
Registers(floatingPoint bool) (Registers, error)
|
||||
Arch() Arch
|
||||
BinInfo() *BinaryInfo
|
||||
StepInstruction() error
|
||||
}
|
||||
|
||||
// Location represents the location of a thread.
|
||||
@ -149,12 +150,12 @@ func (tbe ThreadBlockedError) Error() string {
|
||||
}
|
||||
|
||||
// returns topmost frame of g or thread if g is nil
|
||||
func topframe(g *G, thread *Thread) (Stackframe, error) {
|
||||
func topframe(g *G, thread IThread) (Stackframe, error) {
|
||||
var frames []Stackframe
|
||||
var err error
|
||||
|
||||
if g == nil {
|
||||
if thread.blocked() {
|
||||
if threadBlocked(thread) {
|
||||
return Stackframe{}, ThreadBlockedError{}
|
||||
}
|
||||
frames, err = ThreadStacktrace(thread, 0)
|
||||
@ -177,8 +178,10 @@ func topframe(g *G, thread *Thread) (Stackframe, error) {
|
||||
// a breakpoint of kind StepBreakpoint is set on the CALL instruction,
|
||||
// Continue will take care of setting a breakpoint to the destination
|
||||
// once the CALL is reached.
|
||||
func (dbp *Process) next(stepInto bool) error {
|
||||
topframe, err := topframe(dbp.selectedGoroutine, dbp.currentThread)
|
||||
func next(dbp Continuable, stepInto bool) error {
|
||||
selg := dbp.SelectedGoroutine()
|
||||
curthread := dbp.CurrentThread()
|
||||
topframe, err := topframe(selg, curthread)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -191,22 +194,22 @@ func (dbp *Process) next(stepInto bool) error {
|
||||
}()
|
||||
|
||||
csource := filepath.Ext(topframe.Current.File) != ".go"
|
||||
var thread memoryReadWriter = dbp.currentThread
|
||||
var thread memoryReadWriter = curthread
|
||||
var regs Registers
|
||||
if dbp.selectedGoroutine != nil && dbp.selectedGoroutine.thread != nil {
|
||||
thread = dbp.selectedGoroutine.thread
|
||||
regs, err = dbp.selectedGoroutine.thread.Registers(false)
|
||||
if selg != nil && selg.Thread() != nil {
|
||||
thread = selg.Thread()
|
||||
regs, err = selg.Thread().Registers(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
text, err := disassemble(thread, regs, dbp.breakpoints, dbp.BinInfo(), topframe.FDE.Begin(), topframe.FDE.End())
|
||||
text, err := disassemble(thread, regs, dbp.Breakpoints(), dbp.BinInfo(), topframe.FDE.Begin(), topframe.FDE.End())
|
||||
if err != nil && stepInto {
|
||||
return err
|
||||
}
|
||||
|
||||
cond := sameGoroutineCondition(dbp.selectedGoroutine)
|
||||
cond := sameGoroutineCondition(selg)
|
||||
|
||||
if stepInto {
|
||||
for _, instr := range text {
|
||||
@ -215,7 +218,7 @@ func (dbp *Process) next(stepInto bool) error {
|
||||
}
|
||||
|
||||
if instr.DestLoc != nil && instr.DestLoc.Fn != nil {
|
||||
if err := dbp.setStepIntoBreakpoint([]AsmInstruction{instr}, cond); err != nil {
|
||||
if err := setStepIntoBreakpoint(dbp, []AsmInstruction{instr}, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
@ -242,10 +245,10 @@ func (dbp *Process) next(stepInto bool) error {
|
||||
|
||||
// Set breakpoint on the most recently deferred function (if any)
|
||||
var deferpc uint64 = 0
|
||||
if dbp.selectedGoroutine != nil {
|
||||
deferPCEntry := dbp.selectedGoroutine.DeferPC()
|
||||
if selg != nil {
|
||||
deferPCEntry := selg.DeferPC()
|
||||
if deferPCEntry != 0 {
|
||||
_, _, deferfn := dbp.bi.goSymTable.PCToLine(deferPCEntry)
|
||||
_, _, deferfn := dbp.BinInfo().PCToLine(deferPCEntry)
|
||||
var err error
|
||||
deferpc, err = dbp.FirstPCAfterPrologue(deferfn, false)
|
||||
if err != nil {
|
||||
@ -267,7 +270,7 @@ func (dbp *Process) next(stepInto bool) error {
|
||||
}
|
||||
|
||||
// Add breakpoints on all the lines in the current function
|
||||
pcs, err := dbp.bi.lineInfo.AllPCsBetween(topframe.FDE.Begin(), topframe.FDE.End()-1, topframe.Current.File)
|
||||
pcs, err := dbp.BinInfo().lineInfo.AllPCsBetween(topframe.FDE.Begin(), topframe.FDE.End()-1, topframe.Current.File)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -282,8 +285,8 @@ func (dbp *Process) next(stepInto bool) error {
|
||||
}
|
||||
|
||||
if !covered {
|
||||
fn := dbp.bi.goSymTable.PCToFunc(topframe.Ret)
|
||||
if dbp.selectedGoroutine != nil && fn != nil && fn.Name == "runtime.goexit" {
|
||||
fn := dbp.BinInfo().goSymTable.PCToFunc(topframe.Ret)
|
||||
if selg != nil && fn != nil && fn.Name == "runtime.goexit" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@ -292,10 +295,10 @@ func (dbp *Process) next(stepInto bool) error {
|
||||
// Add a breakpoint on the return address for the current frame
|
||||
pcs = append(pcs, topframe.Ret)
|
||||
success = true
|
||||
return dbp.setInternalBreakpoints(topframe.Current.PC, pcs, NextBreakpoint, cond)
|
||||
return setInternalBreakpoints(dbp, topframe.Current.PC, pcs, NextBreakpoint, cond)
|
||||
}
|
||||
|
||||
func (dbp *Process) setStepIntoBreakpoint(text []AsmInstruction, cond ast.Expr) error {
|
||||
func setStepIntoBreakpoint(dbp Continuable, text []AsmInstruction, cond ast.Expr) error {
|
||||
if len(text) <= 0 {
|
||||
return nil
|
||||
}
|
||||
@ -337,7 +340,7 @@ func (dbp *Process) setStepIntoBreakpoint(text []AsmInstruction, cond ast.Expr)
|
||||
|
||||
// setInternalBreakpoints sets a breakpoint to all addresses specified in pcs
|
||||
// skipping over curpc and curpc-1
|
||||
func (dbp *Process) setInternalBreakpoints(curpc uint64, pcs []uint64, kind BreakpointKind, cond ast.Expr) error {
|
||||
func setInternalBreakpoints(dbp Continuable, curpc uint64, pcs []uint64, kind BreakpointKind, cond ast.Expr) error {
|
||||
for i := range pcs {
|
||||
if pcs[i] == curpc || pcs[i] == curpc-1 {
|
||||
continue
|
||||
@ -495,7 +498,7 @@ func (thread *Thread) SetCurrentBreakpoint() error {
|
||||
return err
|
||||
}
|
||||
thread.BreakpointConditionMet, thread.BreakpointConditionError = bp.checkCondition(thread)
|
||||
if thread.onTriggeredBreakpoint() {
|
||||
if thread.CurrentBreakpoint != nil && thread.BreakpointConditionMet {
|
||||
if g, err := GetG(thread); err == nil {
|
||||
thread.CurrentBreakpoint.HitCount[g.ID]++
|
||||
}
|
||||
@ -511,15 +514,7 @@ func (thread *Thread) clearBreakpointState() {
|
||||
thread.BreakpointConditionError = nil
|
||||
}
|
||||
|
||||
func (thread *Thread) onTriggeredBreakpoint() bool {
|
||||
return (thread.CurrentBreakpoint != nil) && thread.BreakpointConditionMet
|
||||
}
|
||||
|
||||
func (thread *Thread) onTriggeredInternalBreakpoint() bool {
|
||||
return thread.onTriggeredBreakpoint() && thread.CurrentBreakpoint.Internal()
|
||||
}
|
||||
|
||||
func (thread *Thread) onRuntimeBreakpoint() bool {
|
||||
func onRuntimeBreakpoint(thread IThread) bool {
|
||||
loc, err := thread.Location()
|
||||
if err != nil {
|
||||
return false
|
||||
@ -528,11 +523,11 @@ func (thread *Thread) onRuntimeBreakpoint() bool {
|
||||
}
|
||||
|
||||
// onNextGorutine returns true if this thread is on the goroutine requested by the current 'next' command
|
||||
func (thread *Thread) onNextGoroutine() (bool, error) {
|
||||
func onNextGoroutine(thread IThread, breakpoints map[uint64]*Breakpoint) (bool, error) {
|
||||
var bp *Breakpoint
|
||||
for i := range thread.dbp.breakpoints {
|
||||
if thread.dbp.breakpoints[i].Internal() {
|
||||
bp = thread.dbp.breakpoints[i]
|
||||
for i := range breakpoints {
|
||||
if breakpoints[i].Internal() {
|
||||
bp = breakpoints[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -81,13 +81,14 @@ func (t *Thread) resume() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Thread) blocked() bool {
|
||||
func threadBlocked(t IThread) bool {
|
||||
// TODO(dp) cache the func pc to remove this lookup
|
||||
pc, err := t.PC()
|
||||
regs, err := t.Registers(false)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
fn := t.dbp.bi.goSymTable.PCToFunc(pc)
|
||||
pc := regs.PC()
|
||||
fn := t.BinInfo().goSymTable.PCToFunc(pc)
|
||||
if fn == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -67,9 +67,13 @@ func (t *Thread) singleStep() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Thread) blocked() bool {
|
||||
pc, _ := t.PC()
|
||||
fn := t.dbp.bi.goSymTable.PCToFunc(pc)
|
||||
func threadBlocked(t IThread) bool {
|
||||
regs, err := t.Registers(false)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
pc := regs.PC()
|
||||
fn := t.BinInfo().goSymTable.PCToFunc(pc)
|
||||
if fn != nil && ((fn.Name == "runtime.futex") || (fn.Name == "runtime.usleep") || (fn.Name == "runtime.clone")) {
|
||||
return true
|
||||
}
|
||||
|
@ -103,14 +103,15 @@ func (t *Thread) resume() error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Thread) blocked() bool {
|
||||
func threadBlocked(t IThread) bool {
|
||||
// TODO: Probably incorrect - what are the runtime functions that
|
||||
// indicate blocking on Windows?
|
||||
pc, err := t.PC()
|
||||
regs, err := t.Registers(false)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
fn := t.dbp.bi.goSymTable.PCToFunc(pc)
|
||||
pc := regs.PC()
|
||||
fn := t.BinInfo().goSymTable.PCToFunc(pc)
|
||||
if fn == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -60,16 +60,12 @@ type ThreadInfo interface {
|
||||
|
||||
// GoroutineInfo is an interface for getting information on running goroutines.
|
||||
type GoroutineInfo interface {
|
||||
GoroutinesInfo() ([]*proc.G, error)
|
||||
SelectedGoroutine() *proc.G
|
||||
}
|
||||
|
||||
// ProcessManipulation is an interface for changing the execution state of a process.
|
||||
type ProcessManipulation interface {
|
||||
Continue() error
|
||||
Next() error
|
||||
Step() error
|
||||
StepOut() error
|
||||
ContinueOnce() (trapthread proc.IThread, err error)
|
||||
StepInstruction() error
|
||||
SwitchThread(int) error
|
||||
SwitchGoroutine(int) error
|
||||
|
@ -412,7 +412,7 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
|
||||
switch command.Name {
|
||||
case api.Continue:
|
||||
log.Print("continuing")
|
||||
err = d.target.Continue()
|
||||
err = proc.Continue(d.target)
|
||||
if err != nil {
|
||||
if exitedErr, exited := err.(proc.ProcessExitedError); exited {
|
||||
state := &api.DebuggerState{}
|
||||
@ -432,16 +432,16 @@ func (d *Debugger) Command(command *api.DebuggerCommand) (*api.DebuggerState, er
|
||||
|
||||
case api.Next:
|
||||
log.Print("nexting")
|
||||
err = d.target.Next()
|
||||
err = proc.Next(d.target)
|
||||
case api.Step:
|
||||
log.Print("stepping")
|
||||
err = d.target.Step()
|
||||
err = proc.Step(d.target)
|
||||
case api.StepInstruction:
|
||||
log.Print("single stepping")
|
||||
err = d.target.StepInstruction()
|
||||
case api.StepOut:
|
||||
log.Print("step out")
|
||||
err = d.target.StepOut()
|
||||
err = proc.StepOut(d.target)
|
||||
case api.SwitchThread:
|
||||
log.Printf("switching to thread %d", command.ThreadID)
|
||||
err = d.target.SwitchThread(command.ThreadID)
|
||||
@ -714,7 +714,7 @@ func (d *Debugger) Goroutines() ([]*api.Goroutine, error) {
|
||||
defer d.processMutex.Unlock()
|
||||
|
||||
goroutines := []*api.Goroutine{}
|
||||
gs, err := d.target.GoroutinesInfo()
|
||||
gs, err := proc.GoroutinesInfo(d.target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ func TestVariableEvaluation(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
@ -216,7 +216,7 @@ func TestVariableEvaluationShort(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
@ -271,7 +271,7 @@ func TestMultilineVariableEvaluation(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
@ -344,7 +344,7 @@ func TestLocalVariables(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
for _, tc := range testcases {
|
||||
@ -377,7 +377,7 @@ func TestEmbeddedStruct(t *testing.T) {
|
||||
{"b.s", true, "\"hello\"", "\"hello\"", "string", nil},
|
||||
{"b2", true, "main.B {main.A: main.A {val: 42}, *main.C: *main.C nil, a: main.A {val: 47}, ptr: *main.A nil}", "main.B {main.A: (*main.A)(0x…", "main.B", nil},
|
||||
}
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
assertNoError(proc.Continue(p), t, "Continue()")
|
||||
|
||||
for _, tc := range testcases {
|
||||
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
|
||||
@ -398,7 +398,7 @@ func TestEmbeddedStruct(t *testing.T) {
|
||||
|
||||
func TestComplexSetting(t *testing.T) {
|
||||
withTestProcess("testvariables", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
err := p.Continue()
|
||||
err := proc.Continue(p)
|
||||
assertNoError(err, t, "Continue() returned an error")
|
||||
|
||||
h := func(setExpr, value string) {
|
||||
@ -644,7 +644,7 @@ func TestEvalExpression(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
for _, tc := range testcases {
|
||||
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
|
||||
if tc.err == nil {
|
||||
@ -668,7 +668,7 @@ func TestEvalExpression(t *testing.T) {
|
||||
|
||||
func TestEvalAddrAndCast(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
c1addr, err := evalVariable(p, "&c1", pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalExpression(&c1)")
|
||||
c1addrstr := api.ConvertVar(c1addr).SinglelineString()
|
||||
@ -694,7 +694,7 @@ func TestEvalAddrAndCast(t *testing.T) {
|
||||
|
||||
func TestMapEvaluation(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
m1v, err := evalVariable(p, "m1", pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalVariable()")
|
||||
m1 := api.ConvertVar(m1v)
|
||||
@ -728,7 +728,7 @@ func TestMapEvaluation(t *testing.T) {
|
||||
|
||||
func TestUnsafePointer(t *testing.T) {
|
||||
withTestProcess("testvariables2", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
up1v, err := evalVariable(p, "up1", pnormalLoadConfig)
|
||||
assertNoError(err, t, "EvalVariable(up1)")
|
||||
up1 := api.ConvertVar(up1v)
|
||||
@ -765,7 +765,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) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
for _, testcase := range testcases {
|
||||
v, err := evalVariable(p, testcase.name, pnormalLoadConfig)
|
||||
assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", testcase.name))
|
||||
@ -816,7 +816,7 @@ func TestPackageRenames(t *testing.T) {
|
||||
}
|
||||
|
||||
withTestProcess("pkgrenames", t, func(p *proc.Process, fixture protest.Fixture) {
|
||||
assertNoError(p.Continue(), t, "Continue() returned an error")
|
||||
assertNoError(proc.Continue(p), t, "Continue() returned an error")
|
||||
for _, tc := range testcases {
|
||||
variable, err := evalVariable(p, tc.name, pnormalLoadConfig)
|
||||
if tc.err == nil {
|
||||
|
Loading…
Reference in New Issue
Block a user