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 }