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

     1  package native
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/undoio/delve/pkg/proc"
     7  )
     8  
     9  // Thread represents a single thread in the traced process
    10  // ID represents the thread id or port, Process holds a reference to the
    11  // Process struct that contains info on the process as
    12  // a whole, and Status represents the last result of a `wait` call
    13  // on this thread.
    14  type nativeThread struct {
    15  	ID                int                  // Thread ID or mach port
    16  	Status            *waitStatus          // Status returned from last wait call
    17  	CurrentBreakpoint proc.BreakpointState // Breakpoint thread is currently stopped at
    18  
    19  	dbp            *nativeProcess
    20  	singleStepping bool
    21  	os             *osSpecificDetails
    22  	common         proc.CommonThread
    23  }
    24  
    25  // Continue the execution of this thread.
    26  //
    27  // If we are currently at a breakpoint, we'll clear it
    28  // first and then resume execution. Thread will continue until
    29  // it hits a breakpoint or is signaled.
    30  func (t *nativeThread) Continue() error {
    31  	pc, err := t.PC()
    32  	if err != nil {
    33  		return err
    34  	}
    35  	// Check whether we are stopped at a breakpoint, and
    36  	// if so, single step over it before continuing.
    37  	if _, ok := t.dbp.FindBreakpoint(pc, false); ok {
    38  		if err := t.StepInstruction(); err != nil {
    39  			return err
    40  		}
    41  	}
    42  	return t.resume()
    43  }
    44  
    45  // StepInstruction steps a single instruction.
    46  //
    47  // Executes exactly one instruction and then returns.
    48  // If the thread is at a breakpoint, we first clear it,
    49  // execute the instruction, and then replace the breakpoint.
    50  // Otherwise we simply execute the next instruction.
    51  func (t *nativeThread) StepInstruction() (err error) {
    52  	t.singleStepping = true
    53  	defer func() {
    54  		t.singleStepping = false
    55  	}()
    56  
    57  	if bp := t.CurrentBreakpoint.Breakpoint; bp != nil && bp.WatchType != 0 && t.dbp.Breakpoints().M[bp.Addr] == bp {
    58  		err = t.clearHardwareBreakpoint(bp.Addr, bp.WatchType, bp.HWBreakIndex)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		defer func() {
    63  			err = t.writeHardwareBreakpoint(bp.Addr, bp.WatchType, bp.HWBreakIndex)
    64  		}()
    65  	}
    66  
    67  	pc, err := t.PC()
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	bp, ok := t.dbp.FindBreakpoint(pc, false)
    73  	if ok {
    74  		// Clear the breakpoint so that we can continue execution.
    75  		err = t.clearSoftwareBreakpoint(bp)
    76  		if err != nil {
    77  			return err
    78  		}
    79  
    80  		// Restore breakpoint now that we have passed it.
    81  		defer func() {
    82  			err = t.dbp.writeSoftwareBreakpoint(t, bp.Addr)
    83  		}()
    84  	}
    85  
    86  	err = t.singleStep()
    87  	if err != nil {
    88  		if _, exited := err.(proc.ErrProcessExited); exited {
    89  			return err
    90  		}
    91  		return fmt.Errorf("step failed: %s", err.Error())
    92  	}
    93  	return nil
    94  }
    95  
    96  // Location returns the threads location, including the file:line
    97  // of the corresponding source code, the function we're in
    98  // and the current instruction address.
    99  func (t *nativeThread) Location() (*proc.Location, error) {
   100  	pc, err := t.PC()
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	f, l, fn := t.dbp.bi.PCToLine(pc)
   105  	return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil
   106  }
   107  
   108  // BinInfo returns information on the binary.
   109  func (t *nativeThread) BinInfo() *proc.BinaryInfo {
   110  	return t.dbp.bi
   111  }
   112  
   113  // Common returns information common across Process
   114  // implementations.
   115  func (t *nativeThread) Common() *proc.CommonThread {
   116  	return &t.common
   117  }
   118  
   119  // SetCurrentBreakpoint sets the current breakpoint that this
   120  // thread is stopped at as CurrentBreakpoint on the thread struct.
   121  func (t *nativeThread) SetCurrentBreakpoint(adjustPC bool) error {
   122  	t.CurrentBreakpoint.Clear()
   123  
   124  	var bp *proc.Breakpoint
   125  
   126  	if t.dbp.Breakpoints().HasHWBreakpoints() {
   127  		var err error
   128  		bp, err = t.findHardwareBreakpoint()
   129  		if err != nil {
   130  			return err
   131  		}
   132  	}
   133  	if bp == nil {
   134  		pc, err := t.PC()
   135  		if err != nil {
   136  			return err
   137  		}
   138  
   139  		// If the breakpoint instruction does not change the value
   140  		// of PC after being executed we should look for breakpoints
   141  		// with bp.Addr == PC and there is no need to call SetPC
   142  		// after finding one.
   143  		adjustPC = adjustPC && t.BinInfo().Arch.BreakInstrMovesPC()
   144  
   145  		var ok bool
   146  		bp, ok = t.dbp.FindBreakpoint(pc, adjustPC)
   147  		if ok {
   148  			if adjustPC {
   149  				if err = t.setPC(bp.Addr); err != nil {
   150  					return err
   151  				}
   152  			}
   153  		}
   154  	}
   155  
   156  	t.CurrentBreakpoint.Breakpoint = bp
   157  	return nil
   158  }
   159  
   160  // Breakpoint returns the current breakpoint that is active
   161  // on this thread.
   162  func (t *nativeThread) Breakpoint() *proc.BreakpointState {
   163  	return &t.CurrentBreakpoint
   164  }
   165  
   166  // ThreadID returns the ID of this thread.
   167  func (t *nativeThread) ThreadID() int {
   168  	return t.ID
   169  }
   170  
   171  // clearSoftwareBreakpoint clears the specified breakpoint.
   172  func (t *nativeThread) clearSoftwareBreakpoint(bp *proc.Breakpoint) error {
   173  	if _, err := t.WriteMemory(bp.Addr, bp.OriginalData); err != nil {
   174  		return fmt.Errorf("could not clear breakpoint %s", err)
   175  	}
   176  	return nil
   177  }
   178  
   179  // Registers obtains register values from the debugged process.
   180  func (t *nativeThread) Registers() (proc.Registers, error) {
   181  	return registers(t)
   182  }
   183  
   184  // RestoreRegisters will set the value of the CPU registers to those
   185  // passed in via 'savedRegs'.
   186  func (t *nativeThread) RestoreRegisters(savedRegs proc.Registers) error {
   187  	return t.restoreRegisters(savedRegs)
   188  }
   189  
   190  // PC returns the current program counter value for this thread.
   191  func (t *nativeThread) PC() (uint64, error) {
   192  	regs, err := t.Registers()
   193  	if err != nil {
   194  		return 0, err
   195  	}
   196  	return regs.PC(), nil
   197  }
   198  
   199  // ProcessMemory returns this thread's process memory.
   200  func (t *nativeThread) ProcessMemory() proc.MemoryReadWriter {
   201  	return t.dbp.Memory()
   202  }