forked from go-delve/delve
-
Notifications
You must be signed in to change notification settings - Fork 0
/
breakpoints.go
132 lines (122 loc) · 3.45 KB
/
breakpoints.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package proctl
import (
"fmt"
"runtime"
)
// Represents a single breakpoint. Stores information on the break
// point including the byte of data that originally was stored at that
// address.
type BreakPoint struct {
FunctionName string
File string
Line int
Addr uint64
OriginalData []byte
ID int
temp bool
}
// Returned when trying to set a breakpoint at
// an address that already has a breakpoint set for it.
type BreakPointExistsError struct {
file string
line int
addr uint64
}
func (bpe BreakPointExistsError) Error() string {
return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr)
}
// InvalidAddressError represents the result of
// attempting to set a breakpoint at an invalid address.
type InvalidAddressError struct {
address uint64
}
func (iae InvalidAddressError) Error() string {
return fmt.Sprintf("Invalid address %#v\n", iae.address)
}
// Returns whether or not a breakpoint has been set for the given address.
func (dbp *DebuggedProcess) BreakpointExists(addr uint64) bool {
for _, bp := range dbp.HWBreakPoints {
// TODO(darwin)
if runtime.GOOS == "darwin" {
break
}
if bp != nil && bp.Addr == addr {
return true
}
}
if _, ok := dbp.BreakPoints[addr]; ok {
return true
}
return false
}
func (dbp *DebuggedProcess) newBreakpoint(fn, f string, l int, addr uint64, data []byte) *BreakPoint {
dbp.breakpointIDCounter++
return &BreakPoint{
FunctionName: fn,
File: f,
Line: l,
Addr: addr,
OriginalData: data,
ID: dbp.breakpointIDCounter,
}
}
func (dbp *DebuggedProcess) setBreakpoint(tid int, addr uint64) (*BreakPoint, error) {
var f, l, fn = dbp.GoSymTable.PCToLine(uint64(addr))
if fn == nil {
return nil, InvalidAddressError{address: addr}
}
if dbp.BreakpointExists(addr) {
return nil, BreakPointExistsError{f, l, addr}
}
// Try and set a hardware breakpoint.
for i, v := range dbp.HWBreakPoints {
// TODO(darwin)
if runtime.GOOS == "darwin" {
break
}
if v == nil {
if err := setHardwareBreakpoint(i, tid, addr); err != nil {
return nil, fmt.Errorf("could not set hardware breakpoint: %v", err)
}
dbp.HWBreakPoints[i] = dbp.newBreakpoint(fn.Name, f, l, addr, nil)
return dbp.HWBreakPoints[i], nil
}
}
// Fall back to software breakpoint. 0xCC is INT 3, software
// breakpoint trap interrupt.
thread := dbp.Threads[tid]
originalData := make([]byte, 1)
if _, err := readMemory(thread, uintptr(addr), originalData); err != nil {
return nil, err
}
if _, err := writeMemory(thread, uintptr(addr), []byte{0xCC}); err != nil {
return nil, err
}
dbp.BreakPoints[addr] = dbp.newBreakpoint(fn.Name, f, l, addr, originalData)
return dbp.BreakPoints[addr], nil
}
func (dbp *DebuggedProcess) clearBreakpoint(tid int, addr uint64) (*BreakPoint, error) {
// Check for hardware breakpoint
for i, bp := range dbp.HWBreakPoints {
if bp == nil {
continue
}
if bp.Addr == addr {
dbp.HWBreakPoints[i] = nil
if err := clearHardwareBreakpoint(i, tid); err != nil {
return nil, err
}
return bp, nil
}
}
// Check for software breakpoint
if bp, ok := dbp.BreakPoints[addr]; ok {
thread := dbp.Threads[tid]
if _, err := writeMemory(thread, uintptr(bp.Addr), bp.OriginalData); err != nil {
return nil, fmt.Errorf("could not clear breakpoint %s", err)
}
delete(dbp.BreakPoints, addr)
return bp, nil
}
return nil, fmt.Errorf("No breakpoint currently set for %#v", addr)
}