github.com/undoio/delve@v1.9.0/pkg/proc/target_exec.go (about)

     1  package proc
     2  
     3  import (
     4  	"bytes"
     5  	"debug/dwarf"
     6  	"errors"
     7  	"fmt"
     8  	"go/ast"
     9  	"go/token"
    10  	"path/filepath"
    11  	"strings"
    12  
    13  	"github.com/undoio/delve/pkg/astutil"
    14  	"github.com/undoio/delve/pkg/dwarf/reader"
    15  )
    16  
    17  const maxSkipAutogeneratedWrappers = 5 // maximum recursion depth for skipAutogeneratedWrappers
    18  
    19  // ErrNoSourceForPC is returned when the given address
    20  // does not correspond with a source file location.
    21  type ErrNoSourceForPC struct {
    22  	pc uint64
    23  }
    24  
    25  func (err *ErrNoSourceForPC) Error() string {
    26  	return fmt.Sprintf("no source for PC %#x", err.pc)
    27  }
    28  
    29  // Next continues execution until the next source line.
    30  func (dbp *Target) Next() (err error) {
    31  	if _, err := dbp.Valid(); err != nil {
    32  		return err
    33  	}
    34  	if dbp.Breakpoints().HasSteppingBreakpoints() {
    35  		return fmt.Errorf("next while nexting")
    36  	}
    37  
    38  	if err = next(dbp, false, false); err != nil {
    39  		dbp.ClearSteppingBreakpoints()
    40  		return
    41  	}
    42  
    43  	return dbp.Continue()
    44  }
    45  
    46  // Continue continues execution of the debugged
    47  // process. It will continue until it hits a breakpoint
    48  // or is otherwise stopped.
    49  func (dbp *Target) Continue() error {
    50  	if _, err := dbp.Valid(); err != nil {
    51  		return err
    52  	}
    53  	for _, thread := range dbp.ThreadList() {
    54  		thread.Common().CallReturn = false
    55  		thread.Common().returnValues = nil
    56  	}
    57  	dbp.Breakpoints().WatchOutOfScope = nil
    58  	dbp.clearHardcodedBreakpoints()
    59  	dbp.cctx.CheckAndClearManualStopRequest()
    60  	defer func() {
    61  		// Make sure we clear internal breakpoints if we simultaneously receive a
    62  		// manual stop request and hit a breakpoint.
    63  		if dbp.cctx.CheckAndClearManualStopRequest() {
    64  			dbp.StopReason = StopManual
    65  			dbp.clearHardcodedBreakpoints()
    66  			if dbp.KeepSteppingBreakpoints&HaltKeepsSteppingBreakpoints == 0 {
    67  				dbp.ClearSteppingBreakpoints()
    68  			}
    69  		}
    70  	}()
    71  	for {
    72  		if dbp.cctx.CheckAndClearManualStopRequest() {
    73  			dbp.StopReason = StopManual
    74  			dbp.clearHardcodedBreakpoints()
    75  			if dbp.KeepSteppingBreakpoints&HaltKeepsSteppingBreakpoints == 0 {
    76  				dbp.ClearSteppingBreakpoints()
    77  			}
    78  			return nil
    79  		}
    80  		dbp.ClearCaches()
    81  		trapthread, stopReason, contOnceErr := dbp.proc.ContinueOnce(dbp.cctx)
    82  		dbp.StopReason = stopReason
    83  
    84  		threads := dbp.ThreadList()
    85  		for _, thread := range threads {
    86  			if thread.Breakpoint().Breakpoint != nil {
    87  				thread.Breakpoint().Breakpoint.checkCondition(dbp, thread, thread.Breakpoint())
    88  			}
    89  		}
    90  
    91  		if contOnceErr != nil {
    92  			// Attempt to refresh status of current thread/current goroutine, see
    93  			// Issue #2078.
    94  			// Errors are ignored because depending on why ContinueOnce failed this
    95  			// might very well not work.
    96  			if valid, _ := dbp.Valid(); valid {
    97  				if trapthread != nil {
    98  					_ = dbp.SwitchThread(trapthread.ThreadID())
    99  				} else if curth := dbp.CurrentThread(); curth != nil {
   100  					dbp.selectedGoroutine, _ = GetG(curth)
   101  				}
   102  			}
   103  			if pe, ok := contOnceErr.(ErrProcessExited); ok {
   104  				dbp.exitStatus = pe.Status
   105  			}
   106  			return contOnceErr
   107  		}
   108  		if dbp.StopReason == StopLaunched {
   109  			dbp.ClearSteppingBreakpoints()
   110  		}
   111  
   112  		callInjectionDone, callErr := callInjectionProtocol(dbp, threads)
   113  		hcbpErr := dbp.handleHardcodedBreakpoints(trapthread, threads)
   114  		// callErr and hcbpErr check delayed until after pickCurrentThread, which
   115  		// must always happen, otherwise the debugger could be left in an
   116  		// inconsistent state.
   117  
   118  		if err := pickCurrentThread(dbp, trapthread, threads); err != nil {
   119  			return err
   120  		}
   121  
   122  		if callErr != nil {
   123  			return callErr
   124  		}
   125  		if hcbpErr != nil {
   126  			return hcbpErr
   127  		}
   128  
   129  		curthread := dbp.CurrentThread()
   130  		curbp := curthread.Breakpoint()
   131  
   132  		switch {
   133  		case curbp.Active && curbp.Stepping:
   134  			if curbp.SteppingInto {
   135  				// See description of proc.(*Process).next for the meaning of StepBreakpoints
   136  				if err := conditionErrors(threads); err != nil {
   137  					return err
   138  				}
   139  				if dbp.GetDirection() == Forward {
   140  					text, err := disassembleCurrentInstruction(dbp, curthread, 0)
   141  					if err != nil {
   142  						return err
   143  					}
   144  					var fn *Function
   145  					if loc, _ := curthread.Location(); loc != nil {
   146  						fn = loc.Fn
   147  					}
   148  					// here we either set a breakpoint into the destination of the CALL
   149  					// instruction or we determined that the called function is hidden,
   150  					// either way we need to resume execution
   151  					if err = setStepIntoBreakpoint(dbp, fn, text, sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil {
   152  						return err
   153  					}
   154  				} else {
   155  					if err := dbp.ClearSteppingBreakpoints(); err != nil {
   156  						return err
   157  					}
   158  					return dbp.StepInstruction()
   159  				}
   160  			} else {
   161  				curthread.Common().returnValues = curbp.Breakpoint.returnInfo.Collect(dbp, curthread)
   162  				if err := dbp.ClearSteppingBreakpoints(); err != nil {
   163  					return err
   164  				}
   165  				dbp.StopReason = StopNextFinished
   166  				return conditionErrors(threads)
   167  			}
   168  		case curbp.Active:
   169  			onNextGoroutine, err := onNextGoroutine(dbp, curthread, dbp.Breakpoints())
   170  			if err != nil {
   171  				return err
   172  			}
   173  			if onNextGoroutine &&
   174  				(!isTraceOrTraceReturn(curbp.Breakpoint) || dbp.KeepSteppingBreakpoints&TracepointKeepsSteppingBreakpoints == 0) {
   175  				err := dbp.ClearSteppingBreakpoints()
   176  				if err != nil {
   177  					return err
   178  				}
   179  			}
   180  			if curbp.LogicalID() == unrecoveredPanicID {
   181  				dbp.ClearSteppingBreakpoints()
   182  			}
   183  			if curbp.LogicalID() != hardcodedBreakpointID {
   184  				dbp.StopReason = StopBreakpoint
   185  			}
   186  			if curbp.Breakpoint.WatchType != 0 {
   187  				dbp.StopReason = StopWatchpoint
   188  			}
   189  			return conditionErrors(threads)
   190  		default:
   191  			// not a manual stop, not on runtime.Breakpoint, not on a breakpoint, just repeat
   192  		}
   193  		if callInjectionDone {
   194  			// a call injection was finished, don't let a breakpoint with a failed
   195  			// condition or a step breakpoint shadow this.
   196  			dbp.StopReason = StopCallReturned
   197  			return conditionErrors(threads)
   198  		}
   199  	}
   200  }
   201  
   202  func isTraceOrTraceReturn(bp *Breakpoint) bool {
   203  	if bp.Logical == nil {
   204  		return false
   205  	}
   206  	return bp.Logical.Tracepoint || bp.Logical.TraceReturn
   207  }
   208  
   209  func conditionErrors(threads []Thread) error {
   210  	var condErr error
   211  	for _, th := range threads {
   212  		if bp := th.Breakpoint(); bp.Breakpoint != nil && bp.CondError != nil {
   213  			if condErr == nil {
   214  				condErr = bp.CondError
   215  			} else {
   216  				return fmt.Errorf("multiple errors evaluating conditions")
   217  			}
   218  		}
   219  	}
   220  	return condErr
   221  }
   222  
   223  // pick a new dbp.currentThread, with the following priority:
   224  //   - a thread with an active stepping breakpoint
   225  //   - a thread with an active breakpoint, prioritizing trapthread
   226  //   - trapthread
   227  func pickCurrentThread(dbp *Target, trapthread Thread, threads []Thread) error {
   228  	for _, th := range threads {
   229  		if bp := th.Breakpoint(); bp.Active && bp.Stepping {
   230  			return dbp.SwitchThread(th.ThreadID())
   231  		}
   232  	}
   233  	if bp := trapthread.Breakpoint(); bp.Active {
   234  		return dbp.SwitchThread(trapthread.ThreadID())
   235  	}
   236  	for _, th := range threads {
   237  		if bp := th.Breakpoint(); bp.Active {
   238  			return dbp.SwitchThread(th.ThreadID())
   239  		}
   240  	}
   241  	return dbp.SwitchThread(trapthread.ThreadID())
   242  }
   243  
   244  func disassembleCurrentInstruction(p Process, thread Thread, off int64) ([]AsmInstruction, error) {
   245  	regs, err := thread.Registers()
   246  	if err != nil {
   247  		return nil, err
   248  	}
   249  	pc := regs.PC() + uint64(off)
   250  	return disassemble(p.Memory(), regs, p.Breakpoints(), p.BinInfo(), pc, pc+uint64(p.BinInfo().Arch.MaxInstructionLength()), true)
   251  }
   252  
   253  // stepInstructionOut repeatedly calls StepInstruction until the current
   254  // function is neither fnname1 or fnname2.
   255  // This function is used to step out of runtime.Breakpoint as well as
   256  // runtime.debugCallV1.
   257  func stepInstructionOut(dbp *Target, curthread Thread, fnname1, fnname2 string) error {
   258  	defer dbp.ClearCaches()
   259  	for {
   260  		if err := curthread.StepInstruction(); err != nil {
   261  			return err
   262  		}
   263  		loc, err := curthread.Location()
   264  		var locFnName string
   265  		if loc.Fn != nil {
   266  			locFnName = loc.Fn.Name
   267  			// Calls to runtime.Breakpoint are inlined in some versions of Go when
   268  			// inlining is enabled. Here we attempt to resolve any inlining.
   269  			dwarfTree, _ := loc.Fn.cu.image.getDwarfTree(loc.Fn.offset)
   270  			if dwarfTree != nil {
   271  				inlstack := reader.InlineStack(dwarfTree, loc.PC)
   272  				if len(inlstack) > 0 {
   273  					if locFnName2, ok := inlstack[0].Val(dwarf.AttrName).(string); ok {
   274  						locFnName = locFnName2
   275  					}
   276  				}
   277  			}
   278  		}
   279  		if err != nil || loc.Fn == nil || (locFnName != fnname1 && locFnName != fnname2) {
   280  			g, _ := GetG(curthread)
   281  			selg := dbp.SelectedGoroutine()
   282  			if g != nil && selg != nil && g.ID == selg.ID {
   283  				selg.CurrentLoc = *loc
   284  			}
   285  			return curthread.SetCurrentBreakpoint(true)
   286  		}
   287  	}
   288  }
   289  
   290  // Step will continue until another source line is reached.
   291  // Will step into functions.
   292  func (dbp *Target) Step() (err error) {
   293  	if _, err := dbp.Valid(); err != nil {
   294  		return err
   295  	}
   296  	if dbp.Breakpoints().HasSteppingBreakpoints() {
   297  		return fmt.Errorf("next while nexting")
   298  	}
   299  
   300  	if err = next(dbp, true, false); err != nil {
   301  		_ = dbp.ClearSteppingBreakpoints()
   302  		return err
   303  	}
   304  
   305  	if bpstate := dbp.CurrentThread().Breakpoint(); bpstate.Breakpoint != nil && bpstate.Active && bpstate.SteppingInto && dbp.GetDirection() == Backward {
   306  		dbp.ClearSteppingBreakpoints()
   307  		return dbp.StepInstruction()
   308  	}
   309  
   310  	return dbp.Continue()
   311  }
   312  
   313  // sameGoroutineCondition returns an expression that evaluates to true when
   314  // the current goroutine is g.
   315  func sameGoroutineCondition(g *G) ast.Expr {
   316  	if g == nil {
   317  		return nil
   318  	}
   319  	return astutil.Eql(astutil.Sel(astutil.PkgVar("runtime", "curg"), "goid"), astutil.Int(int64(g.ID)))
   320  }
   321  
   322  func frameoffCondition(frame *Stackframe) ast.Expr {
   323  	return astutil.Eql(astutil.PkgVar("runtime", "frameoff"), astutil.Int(frame.FrameOffset()))
   324  }
   325  
   326  // StepOut will continue until the current goroutine exits the
   327  // function currently being executed or a deferred function is executed
   328  func (dbp *Target) StepOut() error {
   329  	backward := dbp.GetDirection() == Backward
   330  	if _, err := dbp.Valid(); err != nil {
   331  		return err
   332  	}
   333  	if dbp.Breakpoints().HasSteppingBreakpoints() {
   334  		return fmt.Errorf("next while nexting")
   335  	}
   336  
   337  	selg := dbp.SelectedGoroutine()
   338  	curthread := dbp.CurrentThread()
   339  
   340  	topframe, retframe, err := topframe(selg, curthread)
   341  	if err != nil {
   342  		return err
   343  	}
   344  
   345  	success := false
   346  	defer func() {
   347  		if !success {
   348  			dbp.ClearSteppingBreakpoints()
   349  		}
   350  	}()
   351  
   352  	if topframe.Inlined {
   353  		if err := next(dbp, false, true); err != nil {
   354  			return err
   355  		}
   356  
   357  		success = true
   358  		return dbp.Continue()
   359  	}
   360  
   361  	sameGCond := sameGoroutineCondition(selg)
   362  
   363  	if backward {
   364  		if err := stepOutReverse(dbp, topframe, retframe, sameGCond); err != nil {
   365  			return err
   366  		}
   367  
   368  		success = true
   369  		return dbp.Continue()
   370  	}
   371  
   372  	deferpc, err := setDeferBreakpoint(dbp, nil, topframe, sameGCond, false)
   373  	if err != nil {
   374  		return err
   375  	}
   376  
   377  	if topframe.Ret == 0 && deferpc == 0 {
   378  		return errors.New("nothing to stepout to")
   379  	}
   380  
   381  	if topframe.Ret != 0 {
   382  		topframe, retframe := skipAutogeneratedWrappersOut(selg, curthread, &topframe, &retframe)
   383  		retFrameCond := astutil.And(sameGCond, frameoffCondition(retframe))
   384  		bp, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(0, retframe.Current.PC, NextBreakpoint, retFrameCond))
   385  		if err != nil {
   386  			return err
   387  		}
   388  		if bp != nil {
   389  			configureReturnBreakpoint(dbp.BinInfo(), bp, topframe, retFrameCond)
   390  		}
   391  	}
   392  
   393  	if bp := curthread.Breakpoint(); bp.Breakpoint == nil {
   394  		curthread.SetCurrentBreakpoint(false)
   395  	}
   396  
   397  	success = true
   398  	return dbp.Continue()
   399  }
   400  
   401  // StepInstruction will continue the current thread for exactly
   402  // one instruction. This method affects only the thread
   403  // associated with the selected goroutine. All other
   404  // threads will remain stopped.
   405  func (dbp *Target) StepInstruction() (err error) {
   406  	thread := dbp.CurrentThread()
   407  	g := dbp.SelectedGoroutine()
   408  	if g != nil {
   409  		if g.Thread == nil {
   410  			// Step called on parked goroutine
   411  			if _, err := dbp.SetBreakpoint(0, g.PC, NextBreakpoint,
   412  				sameGoroutineCondition(dbp.SelectedGoroutine())); err != nil {
   413  				return err
   414  			}
   415  			return dbp.Continue()
   416  		}
   417  		thread = g.Thread
   418  	}
   419  	dbp.ClearCaches()
   420  	if ok, err := dbp.Valid(); !ok {
   421  		return err
   422  	}
   423  	err = thread.StepInstruction()
   424  	if err != nil {
   425  		return err
   426  	}
   427  	thread.Breakpoint().Clear()
   428  	err = thread.SetCurrentBreakpoint(true)
   429  	if err != nil {
   430  		return err
   431  	}
   432  	if tg, _ := GetG(thread); tg != nil {
   433  		dbp.selectedGoroutine = tg
   434  	}
   435  	dbp.StopReason = StopNextFinished
   436  	return nil
   437  }
   438  
   439  // Set breakpoints at every line, and the return address. Also look for
   440  // a deferred function and set a breakpoint there too.
   441  // If stepInto is true it will also set breakpoints inside all
   442  // functions called on the current source line, for non-absolute CALLs
   443  // a breakpoint of kind StepBreakpoint is set on the CALL instruction,
   444  // Continue will take care of setting a breakpoint to the destination
   445  // once the CALL is reached.
   446  //
   447  // Regardless of stepInto the following breakpoints will be set:
   448  //   - a breakpoint on the first deferred function with NextDeferBreakpoint
   449  //     kind, the list of all the addresses to deferreturn calls in this function
   450  //     and condition checking that we remain on the same goroutine
   451  //   - a breakpoint on each line of the function, with a condition checking
   452  //     that we stay on the same stack frame and goroutine.
   453  //   - a breakpoint on the return address of the function, with a condition
   454  //     checking that we move to the previous stack frame and stay on the same
   455  //     goroutine.
   456  //
   457  // The breakpoint on the return address is *not* set if the current frame is
   458  // an inlined call. For inlined calls topframe.Current.Fn is the function
   459  // where the inlining happened and the second set of breakpoints will also
   460  // cover the "return address".
   461  //
   462  // If inlinedStepOut is true this function implements the StepOut operation
   463  // for an inlined function call. Everything works the same as normal except
   464  // when removing instructions belonging to inlined calls we also remove all
   465  // instructions belonging to the current inlined call.
   466  func next(dbp *Target, stepInto, inlinedStepOut bool) error {
   467  	backward := dbp.GetDirection() == Backward
   468  	selg := dbp.SelectedGoroutine()
   469  	curthread := dbp.CurrentThread()
   470  	topframe, retframe, err := topframe(selg, curthread)
   471  	if err != nil {
   472  		return err
   473  	}
   474  
   475  	if topframe.Current.Fn == nil {
   476  		return &ErrNoSourceForPC{topframe.Current.PC}
   477  	}
   478  
   479  	if backward && retframe.Current.Fn == nil {
   480  		return &ErrNoSourceForPC{retframe.Current.PC}
   481  	}
   482  
   483  	// sanity check
   484  	if inlinedStepOut && !topframe.Inlined {
   485  		panic("next called with inlinedStepOut but topframe was not inlined")
   486  	}
   487  
   488  	success := false
   489  	defer func() {
   490  		if !success {
   491  			dbp.ClearSteppingBreakpoints()
   492  		}
   493  	}()
   494  
   495  	ext := filepath.Ext(topframe.Current.File)
   496  	csource := ext != ".go" && ext != ".s"
   497  	var regs Registers
   498  	if selg != nil && selg.Thread != nil {
   499  		regs, err = selg.Thread.Registers()
   500  		if err != nil {
   501  			return err
   502  		}
   503  	}
   504  
   505  	sameGCond := sameGoroutineCondition(selg)
   506  
   507  	var firstPCAfterPrologue uint64
   508  
   509  	if backward {
   510  		firstPCAfterPrologue, err = FirstPCAfterPrologue(dbp, topframe.Current.Fn, false)
   511  		if err != nil {
   512  			return err
   513  		}
   514  		if firstPCAfterPrologue == topframe.Current.PC {
   515  			// We don't want to step into the prologue so we just execute a reverse step out instead
   516  			if err := stepOutReverse(dbp, topframe, retframe, sameGCond); err != nil {
   517  				return err
   518  			}
   519  
   520  			success = true
   521  			return nil
   522  		}
   523  
   524  		topframe.Ret, err = findCallInstrForRet(dbp, dbp.Memory(), topframe.Ret, retframe.Current.Fn)
   525  		if err != nil {
   526  			return err
   527  		}
   528  	}
   529  
   530  	text, err := disassemble(dbp.Memory(), regs, dbp.Breakpoints(), dbp.BinInfo(), topframe.Current.Fn.Entry, topframe.Current.Fn.End, false)
   531  	if err != nil && stepInto {
   532  		return err
   533  	}
   534  
   535  	var sameFrameCond ast.Expr
   536  	if sameGCond != nil {
   537  		sameFrameCond = astutil.And(sameGCond, frameoffCondition(&topframe))
   538  	}
   539  
   540  	if stepInto && !backward {
   541  		err := setStepIntoBreakpoints(dbp, topframe.Current.Fn, text, topframe, sameGCond)
   542  		if err != nil {
   543  			return err
   544  		}
   545  	}
   546  
   547  	if !backward {
   548  		_, err = setDeferBreakpoint(dbp, text, topframe, sameGCond, stepInto)
   549  		if err != nil {
   550  			return err
   551  		}
   552  	}
   553  
   554  	// Add breakpoints on all the lines in the current function
   555  	pcs, err := topframe.Current.Fn.cu.lineInfo.AllPCsBetween(topframe.Current.Fn.Entry, topframe.Current.Fn.End-1, topframe.Current.File, topframe.Current.Line)
   556  	if err != nil {
   557  		return err
   558  	}
   559  
   560  	if backward {
   561  		// Ensure that pcs contains firstPCAfterPrologue when reverse stepping.
   562  		found := false
   563  		for _, pc := range pcs {
   564  			if pc == firstPCAfterPrologue {
   565  				found = true
   566  				break
   567  			}
   568  		}
   569  		if !found {
   570  			pcs = append(pcs, firstPCAfterPrologue)
   571  		}
   572  	}
   573  
   574  	if !stepInto {
   575  		// Removing any PC range belonging to an inlined call
   576  		frame := topframe
   577  		if inlinedStepOut {
   578  			frame = retframe
   579  		}
   580  		pcs, err = removeInlinedCalls(pcs, frame)
   581  		if err != nil {
   582  			return err
   583  		}
   584  	}
   585  
   586  	if !csource {
   587  		var covered bool
   588  		for i := range pcs {
   589  			if topframe.Current.Fn.Entry <= pcs[i] && pcs[i] < topframe.Current.Fn.End {
   590  				covered = true
   591  				break
   592  			}
   593  		}
   594  
   595  		if !covered {
   596  			fn := dbp.BinInfo().PCToFunc(topframe.Ret)
   597  			if selg != nil && fn != nil && fn.Name == "runtime.goexit" {
   598  				return nil
   599  			}
   600  		}
   601  	}
   602  
   603  	for _, pc := range pcs {
   604  		if _, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(0, pc, NextBreakpoint, sameFrameCond)); err != nil {
   605  			dbp.ClearSteppingBreakpoints()
   606  			return err
   607  		}
   608  	}
   609  
   610  	if stepInto && backward {
   611  		err := setStepIntoBreakpointsReverse(dbp, text, topframe, sameGCond)
   612  		if err != nil {
   613  			return err
   614  		}
   615  	}
   616  
   617  	if !topframe.Inlined {
   618  		topframe, retframe := skipAutogeneratedWrappersOut(selg, curthread, &topframe, &retframe)
   619  		retFrameCond := astutil.And(sameGCond, frameoffCondition(retframe))
   620  
   621  		// Add a breakpoint on the return address for the current frame.
   622  		// For inlined functions there is no need to do this, the set of PCs
   623  		// returned by the AllPCsBetween call above already cover all instructions
   624  		// of the containing function.
   625  		bp, _ := dbp.SetBreakpoint(0, retframe.Current.PC, NextBreakpoint, retFrameCond)
   626  		// Return address could be wrong, if we are unable to set a breakpoint
   627  		// there it's ok.
   628  		if bp != nil {
   629  			configureReturnBreakpoint(dbp.BinInfo(), bp, topframe, retFrameCond)
   630  		}
   631  	}
   632  
   633  	if bp := curthread.Breakpoint(); bp.Breakpoint == nil {
   634  		curthread.SetCurrentBreakpoint(false)
   635  	}
   636  	success = true
   637  	return nil
   638  }
   639  
   640  func setStepIntoBreakpoints(dbp *Target, curfn *Function, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
   641  	for _, instr := range text {
   642  		if instr.Loc.File != topframe.Current.File || instr.Loc.Line != topframe.Current.Line || !instr.IsCall() {
   643  			continue
   644  		}
   645  
   646  		if instr.DestLoc != nil {
   647  			if err := setStepIntoBreakpoint(dbp, curfn, []AsmInstruction{instr}, sameGCond); err != nil {
   648  				return err
   649  			}
   650  		} else {
   651  			// Non-absolute call instruction, set a StepBreakpoint here
   652  			if _, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(0, instr.Loc.PC, StepBreakpoint, sameGCond)); err != nil {
   653  				return err
   654  			}
   655  		}
   656  	}
   657  	return nil
   658  }
   659  
   660  func setStepIntoBreakpointsReverse(dbp *Target, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr) error {
   661  	bpmap := dbp.Breakpoints()
   662  	// Set a breakpoint after every CALL instruction
   663  	for i, instr := range text {
   664  		if instr.Loc.File != topframe.Current.File || !instr.IsCall() || instr.DestLoc == nil || instr.DestLoc.Fn == nil {
   665  			continue
   666  		}
   667  
   668  		if instr.DestLoc.Fn.privateRuntime() {
   669  			continue
   670  		}
   671  
   672  		if nextIdx := i + 1; nextIdx < len(text) {
   673  			_, ok := bpmap.M[text[nextIdx].Loc.PC]
   674  			if !ok {
   675  				if _, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(0, text[nextIdx].Loc.PC, StepBreakpoint, sameGCond)); err != nil {
   676  					return err
   677  				}
   678  			}
   679  		}
   680  	}
   681  	return nil
   682  }
   683  
   684  func FindDeferReturnCalls(text []AsmInstruction) []uint64 {
   685  	const deferreturn = "runtime.deferreturn"
   686  	deferreturns := []uint64{}
   687  
   688  	// Find all runtime.deferreturn locations in the function
   689  	// See documentation of Breakpoint.DeferCond for why this is necessary
   690  	for _, instr := range text {
   691  		if instr.IsCall() && instr.DestLoc != nil && instr.DestLoc.Fn != nil && instr.DestLoc.Fn.Name == deferreturn {
   692  			deferreturns = append(deferreturns, instr.Loc.PC)
   693  		}
   694  	}
   695  	return deferreturns
   696  }
   697  
   698  // Removes instructions belonging to inlined calls of topframe from pcs.
   699  // If includeCurrentFn is true it will also remove all instructions
   700  // belonging to the current function.
   701  func removeInlinedCalls(pcs []uint64, topframe Stackframe) ([]uint64, error) {
   702  	dwarfTree, err := topframe.Call.Fn.cu.image.getDwarfTree(topframe.Call.Fn.offset)
   703  	if err != nil {
   704  		return pcs, err
   705  	}
   706  	for _, e := range reader.InlineStack(dwarfTree, 0) {
   707  		if e.Offset == topframe.Call.Fn.offset {
   708  			continue
   709  		}
   710  		for _, rng := range e.Ranges {
   711  			pcs = removePCsBetween(pcs, rng[0], rng[1])
   712  		}
   713  	}
   714  	return pcs, nil
   715  }
   716  
   717  func removePCsBetween(pcs []uint64, start, end uint64) []uint64 {
   718  	out := pcs[:0]
   719  	for _, pc := range pcs {
   720  		if pc < start || pc >= end {
   721  			out = append(out, pc)
   722  		}
   723  	}
   724  	return out
   725  }
   726  
   727  func setStepIntoBreakpoint(dbp *Target, curfn *Function, text []AsmInstruction, cond ast.Expr) error {
   728  	if len(text) <= 0 {
   729  		return nil
   730  	}
   731  
   732  	// If the current function is already a runtime function then
   733  	// setStepIntoBreakpoint is allowed to step into unexported runtime
   734  	// functions.
   735  	stepIntoUnexportedRuntime := curfn != nil && strings.HasPrefix(curfn.Name, "runtime.")
   736  
   737  	instr := text[0]
   738  
   739  	if instr.DestLoc == nil {
   740  		// Call destination couldn't be resolved because this was not the
   741  		// current instruction, therefore the step-into breakpoint can not be set.
   742  		return nil
   743  	}
   744  
   745  	fn := instr.DestLoc.Fn
   746  
   747  	// Skip unexported runtime functions
   748  	if !stepIntoUnexportedRuntime && fn != nil && fn.privateRuntime() {
   749  		return nil
   750  	}
   751  
   752  	//TODO(aarzilli): if we want to let users hide functions
   753  	// or entire packages from being stepped into with 'step'
   754  	// those extra checks should be done here.
   755  
   756  	pc := instr.DestLoc.PC
   757  
   758  	// Skip InhibitStepInto functions for different arch.
   759  	if dbp.BinInfo().Arch.inhibitStepInto(dbp.BinInfo(), pc) {
   760  		return nil
   761  	}
   762  
   763  	fn, pc = skipAutogeneratedWrappersIn(dbp, fn, pc)
   764  
   765  	// We want to skip the function prologue but we should only do it if the
   766  	// destination address of the CALL instruction is the entry point of the
   767  	// function.
   768  	// Calls to runtime.duffzero and duffcopy inserted by the compiler can
   769  	// sometimes point inside the body of those functions, well after the
   770  	// prologue.
   771  	if fn != nil && fn.Entry == pc {
   772  		pc, _ = FirstPCAfterPrologue(dbp, fn, false)
   773  	}
   774  
   775  	// Set a breakpoint after the function's prologue
   776  	if _, err := allowDuplicateBreakpoint(dbp.SetBreakpoint(0, pc, NextBreakpoint, cond)); err != nil {
   777  		return err
   778  	}
   779  
   780  	return nil
   781  }
   782  
   783  func allowDuplicateBreakpoint(bp *Breakpoint, err error) (*Breakpoint, error) {
   784  	if err != nil {
   785  		//lint:ignore S1020 this is clearer
   786  		if _, isexists := err.(BreakpointExistsError); isexists {
   787  			return bp, nil
   788  		}
   789  	}
   790  	return bp, err
   791  }
   792  
   793  func isAutogenerated(loc Location) bool {
   794  	return loc.File == "<autogenerated>" && loc.Line == 1
   795  }
   796  
   797  func isAutogeneratedOrDeferReturn(loc Location) bool {
   798  	return isAutogenerated(loc) || (loc.Fn != nil && loc.Fn.Name == "runtime.deferreturn")
   799  }
   800  
   801  // skipAutogeneratedWrappers skips autogenerated wrappers when setting a
   802  // step-into breakpoint.
   803  // See genwrapper in: $GOROOT/src/cmd/compile/internal/gc/subr.go
   804  func skipAutogeneratedWrappersIn(p Process, startfn *Function, startpc uint64) (*Function, uint64) {
   805  	if startfn == nil {
   806  		return nil, startpc
   807  	}
   808  	fn := startfn
   809  	for count := 0; count < maxSkipAutogeneratedWrappers; count++ {
   810  		if !fn.cu.isgo {
   811  			// can't exit Go
   812  			return startfn, startpc
   813  		}
   814  		text, err := Disassemble(p.Memory(), nil, p.Breakpoints(), p.BinInfo(), fn.Entry, fn.End)
   815  		if err != nil {
   816  			break
   817  		}
   818  		if len(text) == 0 {
   819  			break
   820  		}
   821  		if !isAutogenerated(text[0].Loc) {
   822  			return fn, fn.Entry
   823  		}
   824  		tgtfns := []*Function{}
   825  		// collect all functions called by the current destination function
   826  		for _, instr := range text {
   827  			switch {
   828  			case instr.IsCall():
   829  				if instr.DestLoc == nil {
   830  					return startfn, startpc
   831  				}
   832  				if p.BinInfo().Arch.inhibitStepInto(p.BinInfo(), instr.DestLoc.PC) {
   833  					// ignored
   834  					continue
   835  				}
   836  				if instr.DestLoc.Fn == nil {
   837  					return startfn, startpc
   838  				}
   839  				// calls to non private runtime functions
   840  				if !instr.DestLoc.Fn.privateRuntime() {
   841  					tgtfns = append(tgtfns, instr.DestLoc.Fn)
   842  				}
   843  			case instr.IsJmp():
   844  				// unconditional jumps to a different function that isn't a private runtime function
   845  				if instr.DestLoc != nil && instr.DestLoc.Fn != fn && !instr.DestLoc.Fn.privateRuntime() {
   846  					tgtfns = append(tgtfns, instr.DestLoc.Fn)
   847  				}
   848  			}
   849  		}
   850  		if len(tgtfns) != 1 {
   851  			// too many or not enough function calls
   852  			break
   853  		}
   854  
   855  		tgtfn := tgtfns[0]
   856  		if strings.TrimSuffix(tgtfn.BaseName(), "-fm") != strings.TrimSuffix(fn.BaseName(), "-fm") {
   857  			return startfn, startpc
   858  		}
   859  		fn = tgtfn
   860  	}
   861  	return startfn, startpc
   862  }
   863  
   864  // skipAutogeneratedWrappersOut skip autogenerated wrappers when setting a
   865  // step out breakpoint.
   866  // See genwrapper in: $GOROOT/src/cmd/compile/internal/gc/subr.go
   867  // It also skips runtime.deferreturn frames (which are only ever on the stack on Go 1.18 or later)
   868  func skipAutogeneratedWrappersOut(g *G, thread Thread, startTopframe, startRetframe *Stackframe) (topframe, retframe *Stackframe) {
   869  	topframe, retframe = startTopframe, startRetframe
   870  	if startTopframe.Ret == 0 {
   871  		return
   872  	}
   873  	if !isAutogeneratedOrDeferReturn(startRetframe.Current) {
   874  		return
   875  	}
   876  	retfn := thread.BinInfo().PCToFunc(startTopframe.Ret)
   877  	if retfn == nil {
   878  		return
   879  	}
   880  	if !retfn.cu.isgo {
   881  		return
   882  	}
   883  	var err error
   884  	var frames []Stackframe
   885  	if g == nil {
   886  		frames, err = ThreadStacktrace(thread, maxSkipAutogeneratedWrappers)
   887  	} else {
   888  		frames, err = g.Stacktrace(maxSkipAutogeneratedWrappers, 0)
   889  	}
   890  	if err != nil {
   891  		return
   892  	}
   893  	for i := 1; i < len(frames); i++ {
   894  		frame := frames[i]
   895  		if frame.Current.Fn == nil {
   896  			return
   897  		}
   898  		file, line := frame.Current.Fn.cu.lineInfo.PCToLine(frame.Current.Fn.Entry, frame.Current.Fn.Entry)
   899  		if !isAutogeneratedOrDeferReturn(Location{File: file, Line: line, Fn: frame.Current.Fn}) {
   900  			return &frames[i-1], &frames[i]
   901  		}
   902  	}
   903  	return
   904  }
   905  
   906  // setDeferBreakpoint is a helper function used by next and StepOut to set a
   907  // breakpoint on the first deferred function.
   908  func setDeferBreakpoint(p *Target, text []AsmInstruction, topframe Stackframe, sameGCond ast.Expr, stepInto bool) (uint64, error) {
   909  	// Set breakpoint on the most recently deferred function (if any)
   910  	var deferpc uint64
   911  	if topframe.TopmostDefer != nil && topframe.TopmostDefer.DwrapPC != 0 {
   912  		_, _, deferfn := topframe.TopmostDefer.DeferredFunc(p)
   913  		if deferfn != nil {
   914  			var err error
   915  			deferpc, err = FirstPCAfterPrologue(p, deferfn, false)
   916  			if err != nil {
   917  				return 0, err
   918  			}
   919  		}
   920  	}
   921  	if deferpc != 0 && deferpc != topframe.Current.PC {
   922  		bp, err := allowDuplicateBreakpoint(p.SetBreakpoint(0, deferpc, NextDeferBreakpoint, sameGCond))
   923  		if err != nil {
   924  			return 0, err
   925  		}
   926  		if bp != nil && stepInto {
   927  			// If DeferReturns is set then the breakpoint will also be triggered when
   928  			// called from runtime.deferreturn. We only do this for the step command,
   929  			// not for next or stepout.
   930  			for _, breaklet := range bp.Breaklets {
   931  				if breaklet.Kind == NextDeferBreakpoint {
   932  					breaklet.DeferReturns = FindDeferReturnCalls(text)
   933  					break
   934  				}
   935  			}
   936  		}
   937  	}
   938  
   939  	return deferpc, nil
   940  }
   941  
   942  // findCallInstrForRet returns the PC address of the CALL instruction
   943  // immediately preceding the instruction at ret.
   944  func findCallInstrForRet(p Process, mem MemoryReadWriter, ret uint64, fn *Function) (uint64, error) {
   945  	text, err := disassemble(mem, nil, p.Breakpoints(), p.BinInfo(), fn.Entry, fn.End, false)
   946  	if err != nil {
   947  		return 0, err
   948  	}
   949  	var prevInstr AsmInstruction
   950  	for _, instr := range text {
   951  		if instr.Loc.PC == ret {
   952  			return prevInstr.Loc.PC, nil
   953  		}
   954  		prevInstr = instr
   955  	}
   956  	return 0, fmt.Errorf("could not find CALL instruction for address %#x in %s", ret, fn.Name)
   957  }
   958  
   959  // stepOutReverse sets a breakpoint on the CALL instruction that created the current frame, this is either:
   960  //   - the CALL instruction immediately preceding the return address of the
   961  //     current frame
   962  //   - the return address of the current frame if the current frame was
   963  //     created by a runtime.deferreturn run
   964  //   - the return address of the runtime.gopanic frame if the current frame
   965  //     was created by a panic
   966  //
   967  // This function is used to implement reversed StepOut
   968  func stepOutReverse(p *Target, topframe, retframe Stackframe, sameGCond ast.Expr) error {
   969  	curthread := p.CurrentThread()
   970  	selg := p.SelectedGoroutine()
   971  
   972  	if selg != nil && selg.Thread != nil {
   973  		curthread = selg.Thread
   974  	}
   975  
   976  	callerText, err := disassemble(p.Memory(), nil, p.Breakpoints(), p.BinInfo(), retframe.Current.Fn.Entry, retframe.Current.Fn.End, false)
   977  	if err != nil {
   978  		return err
   979  	}
   980  	deferReturns := FindDeferReturnCalls(callerText)
   981  
   982  	var frames []Stackframe
   983  	if selg == nil {
   984  		frames, err = ThreadStacktrace(curthread, 3)
   985  	} else {
   986  		frames, err = selg.Stacktrace(3, 0)
   987  	}
   988  	if err != nil {
   989  		return err
   990  	}
   991  
   992  	var callpc uint64
   993  
   994  	if ok, panicFrame := isPanicCall(frames); ok {
   995  		if len(frames) < panicFrame+2 || frames[panicFrame+1].Current.Fn == nil {
   996  			if panicFrame < len(frames) {
   997  				return &ErrNoSourceForPC{frames[panicFrame].Current.PC}
   998  			} else {
   999  				return &ErrNoSourceForPC{frames[0].Current.PC}
  1000  			}
  1001  		}
  1002  		callpc, err = findCallInstrForRet(p, p.Memory(), frames[panicFrame].Ret, frames[panicFrame+1].Current.Fn)
  1003  		if err != nil {
  1004  			return err
  1005  		}
  1006  	} else {
  1007  		callpc, err = findCallInstrForRet(p, p.Memory(), topframe.Ret, retframe.Current.Fn)
  1008  		if err != nil {
  1009  			return err
  1010  		}
  1011  
  1012  		// check if the call instruction to this frame is a call to runtime.deferreturn
  1013  		if len(frames) > 0 {
  1014  			frames[0].Ret = callpc
  1015  		}
  1016  		if ok, pc := isDeferReturnCall(frames, deferReturns); ok && pc != 0 {
  1017  			callpc = pc
  1018  		}
  1019  
  1020  	}
  1021  
  1022  	_, err = allowDuplicateBreakpoint(p.SetBreakpoint(0, callpc, NextBreakpoint, sameGCond))
  1023  
  1024  	return err
  1025  }
  1026  
  1027  // onNextGoroutine returns true if this thread is on the goroutine requested by the current 'next' command
  1028  func onNextGoroutine(tgt *Target, thread Thread, breakpoints *BreakpointMap) (bool, error) {
  1029  	var breaklet *Breaklet
  1030  breakletSearch:
  1031  	for i := range breakpoints.M {
  1032  		for _, blet := range breakpoints.M[i].Breaklets {
  1033  			if blet.Kind&steppingMask != 0 && blet.Cond != nil {
  1034  				breaklet = blet
  1035  				break breakletSearch
  1036  			}
  1037  		}
  1038  	}
  1039  	if breaklet == nil {
  1040  		return false, nil
  1041  	}
  1042  	// Internal breakpoint conditions can take multiple different forms:
  1043  	// Step into breakpoints:
  1044  	//   runtime.curg.goid == X
  1045  	// Next or StepOut breakpoints:
  1046  	//   runtime.curg.goid == X && runtime.frameoff == Y
  1047  	// Breakpoints that can be hit either by stepping on a line in the same
  1048  	// function or by returning from the function:
  1049  	//   runtime.curg.goid == X && (runtime.frameoff == Y || runtime.frameoff == Z)
  1050  	// Here we are only interested in testing the runtime.curg.goid clause.
  1051  	w := onNextGoroutineWalker{tgt: tgt, thread: thread}
  1052  	ast.Walk(&w, breaklet.Cond)
  1053  	return w.ret, w.err
  1054  }
  1055  
  1056  type onNextGoroutineWalker struct {
  1057  	tgt    *Target
  1058  	thread Thread
  1059  	ret    bool
  1060  	err    error
  1061  }
  1062  
  1063  func (w *onNextGoroutineWalker) Visit(n ast.Node) ast.Visitor {
  1064  	if binx, isbin := n.(*ast.BinaryExpr); isbin && binx.Op == token.EQL && exprToString(binx.X) == "runtime.curg.goid" {
  1065  		w.ret, w.err = evalBreakpointCondition(w.tgt, w.thread, n.(ast.Expr))
  1066  		return nil
  1067  	}
  1068  	return w
  1069  }
  1070  
  1071  func (tgt *Target) clearHardcodedBreakpoints() {
  1072  	threads := tgt.ThreadList()
  1073  	for _, thread := range threads {
  1074  		if thread.Breakpoint().Breakpoint != nil && thread.Breakpoint().LogicalID() == hardcodedBreakpointID {
  1075  			thread.Breakpoint().Active = false
  1076  			thread.Breakpoint().Breakpoint = nil
  1077  		}
  1078  	}
  1079  }
  1080  
  1081  // handleHardcodedBreakpoints looks for threads stopped at a hardcoded
  1082  // breakpoint (i.e. a breakpoint instruction, like INT 3, hardcoded in the
  1083  // program's text) and sets a fake breakpoint on them with logical id
  1084  // hardcodedBreakpointID.
  1085  // It checks trapthread and all threads that have SoftExc returning true.
  1086  func (tgt *Target) handleHardcodedBreakpoints(trapthread Thread, threads []Thread) error {
  1087  	mem := tgt.Memory()
  1088  	arch := tgt.BinInfo().Arch
  1089  	recorded, _ := tgt.Recorded()
  1090  
  1091  	isHardcodedBreakpoint := func(thread Thread, pc uint64) uint64 {
  1092  		for _, bpinstr := range [][]byte{arch.BreakpointInstruction(), arch.AltBreakpointInstruction()} {
  1093  			if bpinstr == nil {
  1094  				continue
  1095  			}
  1096  			buf := make([]byte, len(bpinstr))
  1097  			pc2 := pc
  1098  			if arch.BreakInstrMovesPC() {
  1099  				pc2 -= uint64(len(bpinstr))
  1100  			}
  1101  			_, _ = mem.ReadMemory(buf, pc2)
  1102  			if bytes.Equal(buf, bpinstr) {
  1103  				return uint64(len(bpinstr))
  1104  			}
  1105  		}
  1106  		return 0
  1107  	}
  1108  
  1109  	stepOverBreak := func(thread Thread, pc uint64) {
  1110  		if arch.BreakInstrMovesPC() {
  1111  			return
  1112  		}
  1113  		if recorded {
  1114  			return
  1115  		}
  1116  		if bpsize := isHardcodedBreakpoint(thread, pc); bpsize > 0 {
  1117  			setPC(thread, pc+uint64(bpsize))
  1118  		}
  1119  	}
  1120  
  1121  	setHardcodedBreakpoint := func(thread Thread, loc *Location) {
  1122  		bpstate := thread.Breakpoint()
  1123  		hcbp := &Breakpoint{}
  1124  		bpstate.Active = true
  1125  		bpstate.Breakpoint = hcbp
  1126  		hcbp.FunctionName = loc.Fn.Name
  1127  		hcbp.File = loc.File
  1128  		hcbp.Line = loc.Line
  1129  		hcbp.Addr = loc.PC
  1130  		hcbp.Logical = &LogicalBreakpoint{}
  1131  		hcbp.Logical.Name = HardcodedBreakpoint
  1132  		hcbp.Breaklets = []*Breaklet{&Breaklet{Kind: UserBreakpoint, LogicalID: hardcodedBreakpointID}}
  1133  		tgt.StopReason = StopHardcodedBreakpoint
  1134  	}
  1135  
  1136  	for _, thread := range threads {
  1137  		if thread.Breakpoint().Breakpoint != nil {
  1138  			continue
  1139  		}
  1140  		if (thread.ThreadID() != trapthread.ThreadID()) && !thread.SoftExc() {
  1141  			continue
  1142  		}
  1143  
  1144  		loc, err := thread.Location()
  1145  		if err != nil || loc.Fn == nil {
  1146  			continue
  1147  		}
  1148  
  1149  		g, _ := GetG(thread)
  1150  
  1151  		switch {
  1152  		case loc.Fn.Name == "runtime.breakpoint":
  1153  			if recorded, _ := tgt.Recorded(); recorded {
  1154  				setHardcodedBreakpoint(thread, loc)
  1155  				continue
  1156  			}
  1157  			stepOverBreak(thread, loc.PC)
  1158  			// In linux-arm64, PtraceSingleStep seems cannot step over BRK instruction
  1159  			// (linux-arm64 feature or kernel bug maybe).
  1160  			if !arch.BreakInstrMovesPC() {
  1161  				setPC(thread, loc.PC+uint64(arch.BreakpointSize()))
  1162  			}
  1163  			// Single-step current thread until we exit runtime.breakpoint and
  1164  			// runtime.Breakpoint.
  1165  			// On go < 1.8 it was sufficient to single-step twice on go1.8 a change
  1166  			// to the compiler requires 4 steps.
  1167  			if err := stepInstructionOut(tgt, thread, "runtime.breakpoint", "runtime.Breakpoint"); err != nil {
  1168  				return err
  1169  			}
  1170  			setHardcodedBreakpoint(thread, loc)
  1171  		case g == nil || tgt.fncallForG[g.ID] == nil:
  1172  			if isHardcodedBreakpoint(thread, loc.PC) > 0 {
  1173  				stepOverBreak(thread, loc.PC)
  1174  				setHardcodedBreakpoint(thread, loc)
  1175  			}
  1176  		}
  1177  	}
  1178  	return nil
  1179  }