gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/breakpoints.go (about)

     1  package proc
     2  
     3  import (
     4  	"debug/dwarf"
     5  	"errors"
     6  	"fmt"
     7  	"go/ast"
     8  	"go/constant"
     9  	"go/parser"
    10  	"go/token"
    11  	"reflect"
    12  
    13  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/godwarf"
    14  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/op"
    15  	"gitlab.com/Raven-IO/raven-delve/pkg/dwarf/reader"
    16  	"gitlab.com/Raven-IO/raven-delve/pkg/goversion"
    17  	"gitlab.com/Raven-IO/raven-delve/pkg/proc/internal/ebpf"
    18  )
    19  
    20  const (
    21  	// UnrecoveredPanic is the name given to the unrecovered panic breakpoint.
    22  	UnrecoveredPanic = "unrecovered-panic"
    23  
    24  	// FatalThrow is the name given to the breakpoint triggered when the target
    25  	// process dies because of a fatal runtime error.
    26  	FatalThrow = "runtime-fatal-throw"
    27  
    28  	// HardcodedBreakpoint is the name given to hardcoded breakpoints (for
    29  	// example: calls to runtime.Breakpoint)
    30  	HardcodedBreakpoint = "hardcoded-breakpoint"
    31  
    32  	unrecoveredPanicID    = -1
    33  	fatalThrowID          = -2
    34  	hardcodedBreakpointID = -3
    35  
    36  	NoLogicalID = -1000 // Logical breakpoint ID for breakpoints internal breakpoints.
    37  )
    38  
    39  // Breakpoint represents a physical breakpoint. Stores information on the break
    40  // point including the byte of data that originally was stored at that
    41  // address.
    42  type Breakpoint struct {
    43  	// File & line information for printing.
    44  	FunctionName string
    45  	File         string
    46  	Line         int
    47  
    48  	Addr         uint64 // Address breakpoint is set for.
    49  	OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction.
    50  
    51  	WatchExpr     string
    52  	WatchType     WatchType
    53  	HWBreakIndex  uint8 // hardware breakpoint index
    54  	watchStackOff int64 // for watchpoints of stack variables, offset of the address from top of the stack
    55  
    56  	// Breaklets is the list of overlapping breakpoints on this physical breakpoint.
    57  	// There can be at most one UserBreakpoint in this list but multiple internal breakpoints are allowed.
    58  	Breaklets []*Breaklet
    59  
    60  	// Breakpoint information
    61  	Logical *LogicalBreakpoint
    62  
    63  	// ReturnInfo describes how to collect return variables when this
    64  	// breakpoint is hit as a return breakpoint.
    65  	returnInfo *returnBreakpointInfo
    66  }
    67  
    68  // Breaklet represents one of multiple breakpoints that can overlap on a
    69  // single physical breakpoint.
    70  type Breaklet struct {
    71  	// Kind describes whether this is a stepping breakpoint (for next'ing or
    72  	// stepping).
    73  	Kind BreakpointKind
    74  
    75  	LogicalID int // ID of the logical breakpoint that owns this physical breakpoint
    76  
    77  	// Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true
    78  	Cond ast.Expr
    79  
    80  	// DeferReturns: when kind == NextDeferBreakpoint this breakpoint
    81  	// will also check if the caller is runtime.gopanic or if the return
    82  	// address is in the DeferReturns array.
    83  	// Next uses NextDeferBreakpoints for the breakpoint it sets on the
    84  	// deferred function, DeferReturns is populated with the
    85  	// addresses of calls to runtime.deferreturn in the current
    86  	// function. This ensures that the breakpoint on the deferred
    87  	// function only triggers on panic or on the defer call to
    88  	// the function, not when the function is called directly
    89  	DeferReturns []uint64
    90  
    91  	// checkPanicCall checks that the breakpoint happened while the function was
    92  	// called by a panic. It is only checked for WatchOutOfScopeBreakpoint Kind.
    93  	checkPanicCall bool
    94  
    95  	// callback is called if every other condition for this breaklet is met,
    96  	// the return value will determine if the breaklet should be considered
    97  	// active.
    98  	// The callback can have side-effects.
    99  	callback func(th Thread, p *Target) (bool, error)
   100  
   101  	// For WatchOutOfScopeBreakpoints and StackResizeBreakpoints the watchpoint
   102  	// field contains the watchpoint related to this out of scope sentinel.
   103  	watchpoint *Breakpoint
   104  }
   105  
   106  // BreakpointKind determines the behavior of delve when the
   107  // breakpoint is reached.
   108  type BreakpointKind uint16
   109  
   110  const (
   111  	// UserBreakpoint is a user set breakpoint
   112  	UserBreakpoint BreakpointKind = (1 << iota)
   113  	// NextBreakpoint is a breakpoint set by Next, Continue
   114  	// will stop on it and delete it
   115  	NextBreakpoint
   116  	// NextDeferBreakpoint is a breakpoint set by Next on the
   117  	// first deferred function. In addition to checking their condition
   118  	// breakpoints of this kind will also check that the function has been
   119  	// called by runtime.gopanic or through runtime.deferreturn.
   120  	NextDeferBreakpoint
   121  	// StepBreakpoint is a breakpoint set by Step on a CALL instruction,
   122  	// Continue will set a new breakpoint (of NextBreakpoint kind) on the
   123  	// destination of CALL, delete this breakpoint and then continue again
   124  	StepBreakpoint
   125  
   126  	// WatchOutOfScopeBreakpoint is a breakpoint used to detect when a watched
   127  	// stack variable goes out of scope.
   128  	WatchOutOfScopeBreakpoint
   129  
   130  	// StackResizeBreakpoint is a breakpoint used to detect stack resizes to
   131  	// adjust the watchpoint of stack variables.
   132  	StackResizeBreakpoint
   133  
   134  	// PluginOpenBreakpoint is a breakpoint used to detect that a plugin has
   135  	// been loaded and we should try to enable suspended breakpoints.
   136  	PluginOpenBreakpoint
   137  
   138  	// StepIntoNewProc is a breakpoint used to step into a newly created
   139  	// goroutine.
   140  	StepIntoNewProcBreakpoint
   141  
   142  	steppingMask = NextBreakpoint | NextDeferBreakpoint | StepBreakpoint | StepIntoNewProcBreakpoint
   143  )
   144  
   145  // WatchType is the watchpoint type
   146  type WatchType uint8
   147  
   148  const (
   149  	WatchRead WatchType = 1 << iota
   150  	WatchWrite
   151  )
   152  
   153  // Read returns true if the hardware breakpoint should trigger on memory reads.
   154  func (wtype WatchType) Read() bool {
   155  	return wtype&WatchRead != 0
   156  }
   157  
   158  // Write returns true if the hardware breakpoint should trigger on memory writes.
   159  func (wtype WatchType) Write() bool {
   160  	return wtype&WatchWrite != 0
   161  }
   162  
   163  // Size returns the size in bytes of the hardware breakpoint.
   164  func (wtype WatchType) Size() int {
   165  	return int(wtype >> 4)
   166  }
   167  
   168  // withSize returns a new HWBreakType with the size set to the specified value
   169  func (wtype WatchType) withSize(sz uint8) WatchType {
   170  	return WatchType((sz << 4) | uint8(wtype&0xf))
   171  }
   172  
   173  var ErrHWBreakUnsupported = errors.New("hardware breakpoints not implemented")
   174  
   175  func (bp *Breakpoint) String() string {
   176  	return fmt.Sprintf("Breakpoint %d at %#v %s:%d", bp.LogicalID(), bp.Addr, bp.File, bp.Line)
   177  }
   178  
   179  func (bp *Breakpoint) LogicalID() int {
   180  	for _, breaklet := range bp.Breaklets {
   181  		if breaklet.Kind == UserBreakpoint {
   182  			return breaklet.LogicalID
   183  		}
   184  	}
   185  	return NoLogicalID
   186  }
   187  
   188  // VerboseDescr returns a string describing parts of the breakpoint struct
   189  // that aren't otherwise user visible, for debugging purposes.
   190  func (bp *Breakpoint) VerboseDescr() []string {
   191  	r := []string{}
   192  
   193  	r = append(r, fmt.Sprintf("OriginalData=%#x", bp.OriginalData))
   194  
   195  	if bp.WatchType != 0 {
   196  		r = append(r, fmt.Sprintf("HWBreakIndex=%#x watchStackOff=%#x", bp.HWBreakIndex, bp.watchStackOff))
   197  	}
   198  
   199  	lbp := bp.Logical
   200  
   201  	for _, breaklet := range bp.Breaklets {
   202  		switch breaklet.Kind {
   203  		case UserBreakpoint:
   204  			r = append(r, fmt.Sprintf("User Cond=%q HitCond=%v", exprToString(breaklet.Cond), lbp.HitCond))
   205  		case NextBreakpoint:
   206  			r = append(r, fmt.Sprintf("Next Cond=%q", exprToString(breaklet.Cond)))
   207  		case NextDeferBreakpoint:
   208  			r = append(r, fmt.Sprintf("NextDefer Cond=%q DeferReturns=%#x", exprToString(breaklet.Cond), breaklet.DeferReturns))
   209  		case StepBreakpoint:
   210  			r = append(r, fmt.Sprintf("Step Cond=%q", exprToString(breaklet.Cond)))
   211  		case WatchOutOfScopeBreakpoint:
   212  			r = append(r, fmt.Sprintf("WatchOutOfScope Cond=%q checkPanicCall=%v", exprToString(breaklet.Cond), breaklet.checkPanicCall))
   213  		case StackResizeBreakpoint:
   214  			r = append(r, fmt.Sprintf("StackResizeBreakpoint Cond=%q", exprToString(breaklet.Cond)))
   215  		case PluginOpenBreakpoint:
   216  			r = append(r, "PluginOpenBreakpoint")
   217  		case StepIntoNewProcBreakpoint:
   218  			r = append(r, "StepIntoNewProcBreakpoint")
   219  		default:
   220  			r = append(r, fmt.Sprintf("Unknown %d", breaklet.Kind))
   221  		}
   222  	}
   223  	return r
   224  }
   225  
   226  // BreakpointExistsError is returned when trying to set a breakpoint at
   227  // an address that already has a breakpoint set for it.
   228  type BreakpointExistsError struct {
   229  	File string
   230  	Line int
   231  	Addr uint64
   232  }
   233  
   234  func (bpe BreakpointExistsError) Error() string {
   235  	return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.File, bpe.Line, bpe.Addr)
   236  }
   237  
   238  // InvalidAddressError represents the result of
   239  // attempting to set a breakpoint at an invalid address.
   240  type InvalidAddressError struct {
   241  	Address uint64
   242  }
   243  
   244  func (iae InvalidAddressError) Error() string {
   245  	return fmt.Sprintf("Invalid address %#v\n", iae.Address)
   246  }
   247  
   248  type returnBreakpointInfo struct {
   249  	retFrameCond ast.Expr
   250  	fn           *Function
   251  	frameOffset  int64
   252  	spOffset     int64
   253  }
   254  
   255  // CheckCondition evaluates bp's condition on thread.
   256  func (bp *Breakpoint) checkCondition(tgt *Target, thread Thread, bpstate *BreakpointState) {
   257  	*bpstate = BreakpointState{Breakpoint: bp, Active: false, Stepping: false, SteppingInto: false, CondError: nil}
   258  	for _, breaklet := range bp.Breaklets {
   259  		bpstate.checkCond(tgt, breaklet, thread)
   260  	}
   261  }
   262  
   263  func (bpstate *BreakpointState) checkCond(tgt *Target, breaklet *Breaklet, thread Thread) {
   264  	var condErr error
   265  	active := true
   266  	if breaklet.Cond != nil {
   267  		active, condErr = evalBreakpointCondition(tgt, thread, breaklet.Cond)
   268  	}
   269  
   270  	if condErr != nil && bpstate.CondError == nil {
   271  		bpstate.CondError = condErr
   272  	}
   273  	if !active {
   274  		return
   275  	}
   276  
   277  	switch breaklet.Kind {
   278  	case UserBreakpoint:
   279  		var goroutineID int64
   280  		lbp := bpstate.Breakpoint.Logical
   281  		if lbp != nil {
   282  			if g, err := GetG(thread); err == nil {
   283  				goroutineID = g.ID
   284  				lbp.HitCount[goroutineID]++
   285  			}
   286  			lbp.TotalHitCount++
   287  		}
   288  		active = checkHitCond(lbp, goroutineID)
   289  
   290  	case StepBreakpoint, NextBreakpoint, NextDeferBreakpoint:
   291  		nextDeferOk := true
   292  		if breaklet.Kind&NextDeferBreakpoint != 0 {
   293  			var err error
   294  			frames, err := ThreadStacktrace(tgt, thread, 2)
   295  			if err == nil {
   296  				nextDeferOk, _ = isPanicCall(frames)
   297  				if !nextDeferOk {
   298  					nextDeferOk, _ = isDeferReturnCall(frames, breaklet.DeferReturns)
   299  				}
   300  			}
   301  		}
   302  		active = active && nextDeferOk
   303  
   304  	case WatchOutOfScopeBreakpoint:
   305  		if breaklet.checkPanicCall {
   306  			frames, err := ThreadStacktrace(tgt, thread, 2)
   307  			if err == nil {
   308  				ipc, _ := isPanicCall(frames)
   309  				active = active && ipc
   310  			}
   311  		}
   312  
   313  	case StackResizeBreakpoint, PluginOpenBreakpoint, StepIntoNewProcBreakpoint:
   314  		// no further checks
   315  
   316  	default:
   317  		bpstate.CondError = fmt.Errorf("internal error unknown breakpoint kind %v", breaklet.Kind)
   318  	}
   319  
   320  	if active {
   321  		if breaklet.callback != nil {
   322  			var err error
   323  			active, err = breaklet.callback(thread, tgt)
   324  			if err != nil && bpstate.CondError == nil {
   325  				bpstate.CondError = err
   326  			}
   327  		}
   328  		bpstate.Active = active
   329  	}
   330  
   331  	if bpstate.Active {
   332  		switch breaklet.Kind {
   333  		case NextBreakpoint, NextDeferBreakpoint:
   334  			bpstate.Stepping = true
   335  		case StepBreakpoint:
   336  			bpstate.Stepping = true
   337  			bpstate.SteppingInto = true
   338  		}
   339  	}
   340  }
   341  
   342  // checkHitCond evaluates bp's hit condition on thread.
   343  func checkHitCond(lbp *LogicalBreakpoint, goroutineID int64) bool {
   344  	if lbp == nil || lbp.HitCond == nil {
   345  		return true
   346  	}
   347  	hitCount := int(lbp.TotalHitCount)
   348  	if lbp.HitCondPerG && goroutineID > 0 {
   349  		hitCount = int(lbp.HitCount[goroutineID])
   350  	}
   351  	// Evaluate the breakpoint condition.
   352  	switch lbp.HitCond.Op {
   353  	case token.EQL:
   354  		return hitCount == lbp.HitCond.Val
   355  	case token.NEQ:
   356  		return hitCount != lbp.HitCond.Val
   357  	case token.GTR:
   358  		return hitCount > lbp.HitCond.Val
   359  	case token.LSS:
   360  		return hitCount < lbp.HitCond.Val
   361  	case token.GEQ:
   362  		return hitCount >= lbp.HitCond.Val
   363  	case token.LEQ:
   364  		return hitCount <= lbp.HitCond.Val
   365  	case token.REM:
   366  		return hitCount%lbp.HitCond.Val == 0
   367  	}
   368  	return false
   369  }
   370  
   371  func isPanicCall(frames []Stackframe) (bool, int) {
   372  	// In Go prior to 1.17 the call stack for a panic is:
   373  	//  0. deferred function call
   374  	//  1. runtime.callN
   375  	//  2. runtime.gopanic
   376  	// in Go after 1.17 it is either:
   377  	//  0. deferred function call
   378  	//  1. deferred call wrapper
   379  	//  2. runtime.gopanic
   380  	// or:
   381  	//  0. deferred function call
   382  	//  1. runtime.gopanic
   383  	if len(frames) >= 3 && frames[2].Current.Fn != nil && frames[2].Current.Fn.Name == "runtime.gopanic" {
   384  		return true, 2
   385  	}
   386  	if len(frames) >= 2 && frames[1].Current.Fn != nil && frames[1].Current.Fn.Name == "runtime.gopanic" {
   387  		return true, 1
   388  	}
   389  	return false, 0
   390  }
   391  
   392  func isDeferReturnCall(frames []Stackframe, deferReturns []uint64) (bool, uint64) {
   393  	if len(frames) >= 2 && (len(deferReturns) > 0) {
   394  		// On Go 1.18 and later runtime.deferreturn doesn't use jmpdefer anymore,
   395  		// it's a normal function making normal calls to deferred functions.
   396  		if frames[1].Current.Fn != nil && frames[1].Current.Fn.Name == "runtime.deferreturn" {
   397  			return true, 0
   398  		}
   399  	}
   400  	if len(frames) >= 1 {
   401  		for _, pc := range deferReturns {
   402  			if frames[0].Ret == pc {
   403  				return true, pc
   404  			}
   405  		}
   406  	}
   407  	return false, 0
   408  }
   409  
   410  // IsStepping returns true if bp is an stepping breakpoint.
   411  // User-set breakpoints can overlap with stepping breakpoints, in that case
   412  // both IsUser and IsStepping will be true.
   413  func (bp *Breakpoint) IsStepping() bool {
   414  	for _, breaklet := range bp.Breaklets {
   415  		if breaklet.Kind&steppingMask != 0 {
   416  			return true
   417  		}
   418  	}
   419  	return false
   420  }
   421  
   422  // IsUser returns true if bp is a user-set breakpoint.
   423  // User-set breakpoints can overlap with stepping breakpoints, in that case
   424  // both IsUser and IsStepping will be true.
   425  func (bp *Breakpoint) IsUser() bool {
   426  	for _, breaklet := range bp.Breaklets {
   427  		if breaklet.Kind == UserBreakpoint {
   428  			return true
   429  		}
   430  	}
   431  	return false
   432  }
   433  
   434  // UserBreaklet returns the user breaklet for this breakpoint, or nil if
   435  // none exist.
   436  func (bp *Breakpoint) UserBreaklet() *Breaklet {
   437  	for _, breaklet := range bp.Breaklets {
   438  		if breaklet.Kind == UserBreakpoint {
   439  			return breaklet
   440  		}
   441  	}
   442  	return nil
   443  }
   444  
   445  func evalBreakpointCondition(tgt *Target, thread Thread, cond ast.Expr) (bool, error) {
   446  	if cond == nil {
   447  		return true, nil
   448  	}
   449  	scope, err := GoroutineScope(tgt, thread)
   450  	if err != nil {
   451  		scope, err = ThreadScope(tgt, thread)
   452  		if err != nil {
   453  			return true, err
   454  		}
   455  	}
   456  	v, err := scope.evalAST(cond)
   457  	if err != nil {
   458  		return true, fmt.Errorf("error evaluating expression: %v", err)
   459  	}
   460  	if v.Kind != reflect.Bool {
   461  		return true, errors.New("condition expression not boolean")
   462  	}
   463  	v.loadValue(loadFullValue)
   464  	if v.Unreadable != nil {
   465  		return true, fmt.Errorf("condition expression unreadable: %v", v.Unreadable)
   466  	}
   467  	return constant.BoolVal(v.Value), nil
   468  }
   469  
   470  // NoBreakpointError is returned when trying to
   471  // clear a breakpoint that does not exist.
   472  type NoBreakpointError struct {
   473  	Addr uint64
   474  }
   475  
   476  func (nbp NoBreakpointError) Error() string {
   477  	return fmt.Sprintf("no breakpoint at %#v", nbp.Addr)
   478  }
   479  
   480  // BreakpointMap represents an (address, breakpoint) map.
   481  type BreakpointMap struct {
   482  	M map[uint64]*Breakpoint
   483  
   484  	// Logical is a map of logical breakpoints.
   485  	Logical map[int]*LogicalBreakpoint
   486  
   487  	// WatchOutOfScope is the list of watchpoints that went out of scope during
   488  	// the last resume operation
   489  	WatchOutOfScope []*Breakpoint
   490  }
   491  
   492  // NewBreakpointMap creates a new BreakpointMap.
   493  func NewBreakpointMap() BreakpointMap {
   494  	return BreakpointMap{
   495  		M: make(map[uint64]*Breakpoint),
   496  	}
   497  }
   498  
   499  // SetBreakpoint sets a breakpoint at addr, and stores it in the process wide
   500  // break point table.
   501  func (t *Target) SetBreakpoint(logicalID int, addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error) {
   502  	return t.setBreakpointInternal(logicalID, addr, kind, 0, cond)
   503  }
   504  
   505  // SetEBPFTracepoint will attach a uprobe to the function
   506  // specified by 'fnName'.
   507  func (t *Target) SetEBPFTracepoint(fnName string) error {
   508  	// Not every OS/arch that we support has support for eBPF,
   509  	// so check early and return an error if this is called on an
   510  	// unsupported system.
   511  	if !t.proc.SupportsBPF() {
   512  		return errors.New("eBPF is not supported")
   513  	}
   514  	fns, err := t.BinInfo().FindFunction(fnName)
   515  	if err != nil {
   516  		return err
   517  	}
   518  
   519  	// Get information on the Goroutine so we can tell the
   520  	// eBPF program where to find it in order to get the
   521  	// goroutine ID.
   522  	rdr := t.BinInfo().Images[0].DwarfReader()
   523  	rdr.SeekToTypeNamed("runtime.g")
   524  	typ, err := t.BinInfo().findType("runtime.g")
   525  	if err != nil {
   526  		return errors.New("could not find type for runtime.g")
   527  	}
   528  	var goidOffset int64
   529  	switch t := typ.(type) {
   530  	case *godwarf.StructType:
   531  		for _, field := range t.Field {
   532  			if field.Name == "goid" {
   533  				goidOffset = field.ByteOffset
   534  				break
   535  			}
   536  		}
   537  	}
   538  
   539  	for _, fn := range fns {
   540  		err := t.setEBPFTracepointOnFunc(fn, goidOffset)
   541  		if err != nil {
   542  			return err
   543  		}
   544  	}
   545  	return nil
   546  }
   547  
   548  func (t *Target) setEBPFTracepointOnFunc(fn *Function, goidOffset int64) error {
   549  	// Start putting together the argument map. This will tell the eBPF program
   550  	// all of the arguments we want to trace and how to find them.
   551  
   552  	// Start looping through each argument / return parameter for the function we
   553  	// are setting the uprobe on. Parse location information so that we can pass it
   554  	// along to the eBPF program.
   555  	dwarfTree, err := fn.cu.image.getDwarfTree(fn.offset)
   556  	if err != nil {
   557  		return err
   558  	}
   559  	variablesFlags := reader.VariablesOnlyVisible
   560  	if t.BinInfo().Producer() != "" && goversion.ProducerAfterOrEqual(t.BinInfo().Producer(), 1, 15) {
   561  		variablesFlags |= reader.VariablesTrustDeclLine
   562  	}
   563  	_, l := t.BinInfo().EntryLineForFunc(fn)
   564  
   565  	var args []ebpf.UProbeArgMap
   566  	varEntries := reader.Variables(dwarfTree, fn.Entry, l, variablesFlags)
   567  	for _, entry := range varEntries {
   568  		_, dt, err := readVarEntry(entry.Tree, fn.cu.image)
   569  		if err != nil {
   570  			return err
   571  		}
   572  
   573  		offset, pieces, _, err := t.BinInfo().Location(entry, dwarf.AttrLocation, fn.Entry, op.DwarfRegisters{}, nil)
   574  		if err != nil {
   575  			return err
   576  		}
   577  		paramPieces := make([]int, 0, len(pieces))
   578  		for _, piece := range pieces {
   579  			if piece.Kind == op.RegPiece {
   580  				paramPieces = append(paramPieces, int(piece.Val))
   581  			}
   582  		}
   583  		isret, _ := entry.Val(dwarf.AttrVarParam).(bool)
   584  		offset += int64(t.BinInfo().Arch.PtrSize())
   585  		args = append(args, ebpf.UProbeArgMap{
   586  			Offset: offset,
   587  			Size:   dt.Size(),
   588  			Kind:   dt.Common().ReflectKind,
   589  			Pieces: paramPieces,
   590  			InReg:  len(pieces) > 0,
   591  			Ret:    isret,
   592  		})
   593  	}
   594  
   595  	//TODO(aarzilli): inlined calls?
   596  
   597  	// Finally, set the uprobe on the function.
   598  	return t.proc.SetUProbe(fn.Name, goidOffset, args)
   599  }
   600  
   601  // SetWatchpoint sets a data breakpoint at addr and stores it in the
   602  // process wide break point table.
   603  func (t *Target) SetWatchpoint(logicalID int, scope *EvalScope, expr string, wtype WatchType, cond ast.Expr) (*Breakpoint, error) {
   604  	if (wtype&WatchWrite == 0) && (wtype&WatchRead == 0) {
   605  		return nil, errors.New("at least one of read and write must be set for watchpoint")
   606  	}
   607  
   608  	n, err := parser.ParseExpr(expr)
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  	xv, err := scope.evalAST(n)
   613  	if err != nil {
   614  		return nil, err
   615  	}
   616  	if xv.Addr == 0 || xv.Flags&VariableFakeAddress != 0 || xv.DwarfType == nil {
   617  		return nil, fmt.Errorf("can not watch %q", expr)
   618  	}
   619  	if xv.Unreadable != nil {
   620  		return nil, fmt.Errorf("expression %q is unreadable: %v", expr, xv.Unreadable)
   621  	}
   622  	if xv.Kind == reflect.UnsafePointer || xv.Kind == reflect.Invalid {
   623  		return nil, fmt.Errorf("can not watch variable of type %s", xv.Kind.String())
   624  	}
   625  	sz := xv.DwarfType.Size()
   626  	if sz <= 0 || sz > int64(t.BinInfo().Arch.PtrSize()) {
   627  		//TODO(aarzilli): it is reasonable to expect to be able to watch string
   628  		//and interface variables and we could support it by watching certain
   629  		//member fields here.
   630  		return nil, fmt.Errorf("can not watch variable of type %s", xv.DwarfType.String())
   631  	}
   632  
   633  	stackWatch := scope.g != nil && !scope.g.SystemStack && xv.Addr >= scope.g.stack.lo && xv.Addr < scope.g.stack.hi
   634  
   635  	if stackWatch && wtype&WatchRead != 0 {
   636  		// In theory this would work except for the fact that the runtime will
   637  		// read them randomly to resize stacks so it doesn't make sense to do
   638  		// this.
   639  		return nil, errors.New("can not watch stack allocated variable for reads")
   640  	}
   641  
   642  	bp, err := t.setBreakpointInternal(logicalID, xv.Addr, UserBreakpoint, wtype.withSize(uint8(sz)), cond)
   643  	if err != nil {
   644  		return bp, err
   645  	}
   646  	bp.WatchExpr = expr
   647  
   648  	if stackWatch {
   649  		bp.watchStackOff = int64(bp.Addr) - int64(scope.g.stack.hi)
   650  		err := t.setStackWatchBreakpoints(scope, bp)
   651  		if err != nil {
   652  			return bp, err
   653  		}
   654  	}
   655  
   656  	return bp, nil
   657  }
   658  
   659  func (t *Target) setBreakpointInternal(logicalID int, addr uint64, kind BreakpointKind, wtype WatchType, cond ast.Expr) (*Breakpoint, error) {
   660  	if valid, err := t.Valid(); !valid {
   661  		recorded, _ := t.recman.Recorded()
   662  		if !recorded {
   663  			return nil, err
   664  		}
   665  	}
   666  	bpmap := t.Breakpoints()
   667  	newBreaklet := &Breaklet{Kind: kind, Cond: cond}
   668  	if kind == UserBreakpoint {
   669  		newBreaklet.LogicalID = logicalID
   670  	}
   671  
   672  	setLogicalBreakpoint := func(bp *Breakpoint) {
   673  		if kind != UserBreakpoint || bp.Logical != nil {
   674  			return
   675  		}
   676  		if bpmap.Logical == nil {
   677  			bpmap.Logical = make(map[int]*LogicalBreakpoint)
   678  		}
   679  		lbp := bpmap.Logical[logicalID]
   680  		if lbp == nil {
   681  			lbp = &LogicalBreakpoint{LogicalID: logicalID}
   682  			lbp.HitCount = make(map[int64]uint64)
   683  			lbp.Enabled = true
   684  			bpmap.Logical[logicalID] = lbp
   685  		}
   686  		bp.Logical = lbp
   687  		breaklet := bp.UserBreaklet()
   688  		if breaklet != nil && breaklet.Cond == nil {
   689  			breaklet.Cond = lbp.Cond
   690  		}
   691  		if lbp.File == "" && lbp.Line == 0 {
   692  			lbp.File = bp.File
   693  			lbp.Line = bp.Line
   694  		} else if bp.File != lbp.File || bp.Line != lbp.Line {
   695  			lbp.File = "<multiple locations>"
   696  			lbp.Line = 0
   697  		}
   698  		fn := t.BinInfo().PCToFunc(bp.Addr)
   699  		if fn != nil {
   700  			lbp.FunctionName = fn.NameWithoutTypeParams()
   701  		}
   702  	}
   703  
   704  	if bp, ok := bpmap.M[addr]; ok {
   705  		if !bp.canOverlap(kind) {
   706  			return bp, BreakpointExistsError{bp.File, bp.Line, bp.Addr}
   707  		}
   708  		bp.Breaklets = append(bp.Breaklets, newBreaklet)
   709  		setLogicalBreakpoint(bp)
   710  		return bp, nil
   711  	}
   712  
   713  	f, l, fn := t.BinInfo().PCToLine(addr)
   714  
   715  	fnName := ""
   716  	if fn != nil {
   717  		fnName = fn.Name
   718  	}
   719  
   720  	hwidx := uint8(0)
   721  	if wtype != 0 {
   722  		m := make(map[uint8]bool)
   723  		for _, bp := range bpmap.M {
   724  			if bp.WatchType != 0 {
   725  				m[bp.HWBreakIndex] = true
   726  			}
   727  		}
   728  		for hwidx = 0; true; hwidx++ {
   729  			if !m[hwidx] {
   730  				break
   731  			}
   732  		}
   733  	}
   734  
   735  	newBreakpoint := &Breakpoint{
   736  		FunctionName: fnName,
   737  		WatchType:    wtype,
   738  		HWBreakIndex: hwidx,
   739  		File:         f,
   740  		Line:         l,
   741  		Addr:         addr,
   742  	}
   743  
   744  	err := t.proc.WriteBreakpoint(newBreakpoint)
   745  	if err != nil {
   746  		return nil, err
   747  	}
   748  
   749  	newBreakpoint.Breaklets = append(newBreakpoint.Breaklets, newBreaklet)
   750  	setLogicalBreakpoint(newBreakpoint)
   751  
   752  	bpmap.M[addr] = newBreakpoint
   753  
   754  	return newBreakpoint, nil
   755  }
   756  
   757  // canOverlap returns true if a breakpoint of kind can be overlapped to the
   758  // already existing breaklets in bp.
   759  // At most one user breakpoint can be set but multiple internal breakpoints are allowed.
   760  // All other internal breakpoints are allowed to overlap freely.
   761  func (bp *Breakpoint) canOverlap(kind BreakpointKind) bool {
   762  	if kind == UserBreakpoint {
   763  		return !bp.IsUser()
   764  	}
   765  	return true
   766  }
   767  
   768  // ClearBreakpoint clears the breakpoint at addr.
   769  func (t *Target) ClearBreakpoint(addr uint64) error {
   770  	if valid, err := t.Valid(); !valid {
   771  		recorded, _ := t.recman.Recorded()
   772  		if !recorded {
   773  			return err
   774  		}
   775  	}
   776  	bp, ok := t.Breakpoints().M[addr]
   777  	if !ok {
   778  		return NoBreakpointError{Addr: addr}
   779  	}
   780  
   781  	for i := range bp.Breaklets {
   782  		if bp.Breaklets[i].Kind == UserBreakpoint {
   783  			bp.Breaklets[i] = nil
   784  			if bp.WatchExpr == "" {
   785  				bp.Logical = nil
   786  			}
   787  		}
   788  	}
   789  
   790  	_, err := t.finishClearBreakpoint(bp)
   791  	if err != nil {
   792  		return err
   793  	}
   794  
   795  	if bp.WatchExpr != "" && bp.watchStackOff != 0 {
   796  		// stack watchpoint, must remove all its WatchOutOfScopeBreakpoints/StackResizeBreakpoints
   797  		err := t.clearStackWatchBreakpoints(bp)
   798  		if err != nil {
   799  			return err
   800  		}
   801  	}
   802  
   803  	return nil
   804  }
   805  
   806  // ClearSteppingBreakpoints removes all stepping breakpoints from the map,
   807  // calling clearBreakpoint on each one.
   808  func (t *Target) ClearSteppingBreakpoints() error {
   809  	bpmap := t.Breakpoints()
   810  	threads := t.ThreadList()
   811  	for _, bp := range bpmap.M {
   812  		for i := range bp.Breaklets {
   813  			if bp.Breaklets[i].Kind&steppingMask != 0 {
   814  				bp.Breaklets[i] = nil
   815  			}
   816  		}
   817  		cleared, err := t.finishClearBreakpoint(bp)
   818  		if err != nil {
   819  			return err
   820  		}
   821  		if cleared {
   822  			for _, thread := range threads {
   823  				if thread.Breakpoint().Breakpoint == bp {
   824  					thread.Breakpoint().Clear()
   825  				}
   826  			}
   827  		}
   828  	}
   829  	return nil
   830  }
   831  
   832  // finishClearBreakpoint clears nil breaklets from the breaklet list of bp
   833  // and if it is empty erases the breakpoint.
   834  // Returns true if the breakpoint was deleted
   835  func (t *Target) finishClearBreakpoint(bp *Breakpoint) (bool, error) {
   836  	oldBreaklets := bp.Breaklets
   837  	bp.Breaklets = bp.Breaklets[:0]
   838  	for _, breaklet := range oldBreaklets {
   839  		if breaklet != nil {
   840  			bp.Breaklets = append(bp.Breaklets, breaklet)
   841  		}
   842  	}
   843  	if len(bp.Breaklets) > 0 {
   844  		return false, nil
   845  	}
   846  	if err := t.proc.EraseBreakpoint(bp); err != nil {
   847  		return false, err
   848  	}
   849  
   850  	delete(t.Breakpoints().M, bp.Addr)
   851  	if bp.WatchExpr != "" && bp.Logical != nil {
   852  		delete(t.Breakpoints().Logical, bp.Logical.LogicalID)
   853  	}
   854  	return true, nil
   855  }
   856  
   857  // HasSteppingBreakpoints returns true if bpmap has at least one stepping
   858  // breakpoint set.
   859  func (bpmap *BreakpointMap) HasSteppingBreakpoints() bool {
   860  	for _, bp := range bpmap.M {
   861  		if bp.IsStepping() {
   862  			return true
   863  		}
   864  	}
   865  	return false
   866  }
   867  
   868  // HasHWBreakpoints returns true if there are hardware breakpoints.
   869  func (bpmap *BreakpointMap) HasHWBreakpoints() bool {
   870  	for _, bp := range bpmap.M {
   871  		if bp.WatchType != 0 {
   872  			return true
   873  		}
   874  	}
   875  	return false
   876  }
   877  
   878  // BreakpointState describes the state of a breakpoint in a thread.
   879  type BreakpointState struct {
   880  	*Breakpoint
   881  	// Active is true if the condition of any breaklet is met.
   882  	Active bool
   883  	// Stepping is true if one of the active breaklets is a stepping
   884  	// breakpoint.
   885  	Stepping bool
   886  	// SteppingInto is true if one of the active stepping breaklets has Kind ==
   887  	// StepBreakpoint.
   888  	SteppingInto bool
   889  	// CondError contains any error encountered while evaluating the
   890  	// breakpoint's condition.
   891  	CondError error
   892  }
   893  
   894  // Clear zeros the struct.
   895  func (bpstate *BreakpointState) Clear() {
   896  	bpstate.Breakpoint = nil
   897  	bpstate.Active = false
   898  	bpstate.Stepping = false
   899  	bpstate.SteppingInto = false
   900  	bpstate.CondError = nil
   901  }
   902  
   903  func (bpstate *BreakpointState) String() string {
   904  	s := bpstate.Breakpoint.String()
   905  	if bpstate.Active {
   906  		s += " active"
   907  	}
   908  	if bpstate.Stepping {
   909  		s += " stepping"
   910  	}
   911  	return s
   912  }
   913  
   914  func configureReturnBreakpoint(bi *BinaryInfo, bp *Breakpoint, topframe *Stackframe, retFrameCond ast.Expr) {
   915  	if topframe.Current.Fn == nil {
   916  		return
   917  	}
   918  	bp.returnInfo = &returnBreakpointInfo{
   919  		retFrameCond: retFrameCond,
   920  		fn:           topframe.Current.Fn,
   921  		frameOffset:  topframe.FrameOffset(),
   922  		spOffset:     topframe.FrameOffset() - int64(bi.Arch.PtrSize()), // must be the value that SP had at the entry point of the function
   923  	}
   924  }
   925  
   926  func (rbpi *returnBreakpointInfo) Collect(t *Target, thread Thread) []*Variable {
   927  	if rbpi == nil {
   928  		return nil
   929  	}
   930  
   931  	g, err := GetG(thread)
   932  	if err != nil {
   933  		return returnInfoError("could not get g", err, thread.ProcessMemory())
   934  	}
   935  	scope, err := GoroutineScope(t, thread)
   936  	if err != nil {
   937  		return returnInfoError("could not get scope", err, thread.ProcessMemory())
   938  	}
   939  	v, err := scope.evalAST(rbpi.retFrameCond)
   940  	if err != nil || v.Unreadable != nil || v.Kind != reflect.Bool {
   941  		// This condition was evaluated as part of the breakpoint condition
   942  		// evaluation, if the errors happen they will be reported as part of the
   943  		// condition errors.
   944  		return nil
   945  	}
   946  	if !constant.BoolVal(v.Value) {
   947  		// Breakpoint not hit as a return breakpoint.
   948  		return nil
   949  	}
   950  
   951  	oldFrameOffset := rbpi.frameOffset + int64(g.stack.hi)
   952  	oldSP := uint64(rbpi.spOffset + int64(g.stack.hi))
   953  	err = fakeFunctionEntryScope(scope, rbpi.fn, oldFrameOffset, oldSP)
   954  	if err != nil {
   955  		return returnInfoError("could not read function entry", err, thread.ProcessMemory())
   956  	}
   957  
   958  	vars, err := scope.Locals(0)
   959  	if err != nil {
   960  		return returnInfoError("could not evaluate return variables", err, thread.ProcessMemory())
   961  	}
   962  	vars = filterVariables(vars, func(v *Variable) bool {
   963  		return (v.Flags & VariableReturnArgument) != 0
   964  	})
   965  
   966  	return vars
   967  }
   968  
   969  func returnInfoError(descr string, err error, mem MemoryReadWriter) []*Variable {
   970  	v := newConstant(constant.MakeString(fmt.Sprintf("%s: %v", descr, err.Error())), mem)
   971  	v.Name = "return value read error"
   972  	return []*Variable{v}
   973  }
   974  
   975  // LogicalBreakpoint represents a breakpoint set by a user.
   976  // A logical breakpoint can be associated with zero or many physical
   977  // breakpoints.
   978  // Where a physical breakpoint is associated with a specific instruction
   979  // address a logical breakpoint is associated with a source code location.
   980  // Therefore a logical breakpoint can be associated with zero or many
   981  // physical breakpoints.
   982  // It will have one or more physical breakpoints when source code has been
   983  // inlined (or in the case of type parametric code).
   984  // It will have zero physical breakpoints when it represents a deferred
   985  // breakpoint for code that will be loaded in the future.
   986  type LogicalBreakpoint struct {
   987  	LogicalID    int
   988  	Name         string
   989  	FunctionName string
   990  	File         string
   991  	Line         int
   992  	Enabled      bool
   993  
   994  	Set SetBreakpoint
   995  
   996  	Tracepoint  bool // Tracepoint flag
   997  	TraceReturn bool
   998  	Goroutine   bool     // Retrieve goroutine information
   999  	Stacktrace  int      // Number of stack frames to retrieve
  1000  	Variables   []string // Variables to evaluate
  1001  	LoadArgs    *LoadConfig
  1002  	LoadLocals  *LoadConfig
  1003  
  1004  	HitCount      map[int64]uint64 // Number of times a breakpoint has been reached in a certain goroutine
  1005  	TotalHitCount uint64           // Number of times a breakpoint has been reached
  1006  	HitCondPerG   bool             // Use per goroutine hitcount as HitCond operand, instead of total hitcount
  1007  
  1008  	// HitCond: if not nil the breakpoint will be triggered only if the evaluated HitCond returns
  1009  	// true with the TotalHitCount.
  1010  	HitCond *struct {
  1011  		Op  token.Token
  1012  		Val int
  1013  	}
  1014  
  1015  	// Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true
  1016  	Cond ast.Expr
  1017  
  1018  	UserData interface{} // Any additional information about the breakpoint
  1019  }
  1020  
  1021  // SetBreakpoint describes how a breakpoint should be set.
  1022  type SetBreakpoint struct {
  1023  	FunctionName string
  1024  	File         string
  1025  	Line         int
  1026  	Expr         func(*Target) []uint64
  1027  	ExprString   string
  1028  	PidAddrs     []PidAddr
  1029  }
  1030  
  1031  type PidAddr struct {
  1032  	Pid  int
  1033  	Addr uint64
  1034  }