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

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