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