github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/proc/native/threads.go (about)

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