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 }