proc: breakpoints refactoring
Move some duplicate code, related to breakpoints, that was in both backends into a single place. This is in preparation to solve issue #844 (conditional breakpoints make step and next fail) which will make this common breakpoint code more complicated.
This commit is contained in:
parent
8d34bb5bb4
commit
178589a4e7
@ -152,3 +152,104 @@ type NoBreakpointError struct {
|
||||
func (nbp NoBreakpointError) Error() string {
|
||||
return fmt.Sprintf("no breakpoint at %#v", nbp.Addr)
|
||||
}
|
||||
|
||||
type BreakpointMap struct {
|
||||
M map[uint64]*Breakpoint
|
||||
|
||||
breakpointIDCounter int
|
||||
internalBreakpointIDCounter int
|
||||
}
|
||||
|
||||
func NewBreakpointMap() BreakpointMap {
|
||||
return BreakpointMap{
|
||||
M: make(map[uint64]*Breakpoint),
|
||||
}
|
||||
}
|
||||
|
||||
func (bpmap *BreakpointMap) ResetBreakpointIDCounter() {
|
||||
bpmap.breakpointIDCounter = 0
|
||||
}
|
||||
|
||||
type writeBreakpointFn func(addr uint64) (file string, line int, fn *Function, originalData []byte, err error)
|
||||
type clearBreakpointFn func(*Breakpoint) error
|
||||
|
||||
// Set creates a breakpoint at addr calling writeBreakpoint. Do not call this
|
||||
// function, call proc.Process.SetBreakpoint instead, this function exists
|
||||
// to implement proc.Process.SetBreakpoint.
|
||||
func (bpmap *BreakpointMap) Set(addr uint64, kind BreakpointKind, cond ast.Expr, writeBreakpoint writeBreakpointFn) (*Breakpoint, error) {
|
||||
if bp, ok := bpmap.M[addr]; ok {
|
||||
return bp, BreakpointExistsError{bp.File, bp.Line, bp.Addr}
|
||||
}
|
||||
|
||||
f, l, fn, originalData, err := writeBreakpoint(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newBreakpoint := &Breakpoint{
|
||||
FunctionName: fn.Name,
|
||||
File: f,
|
||||
Line: l,
|
||||
Addr: addr,
|
||||
Kind: kind,
|
||||
Cond: cond,
|
||||
OriginalData: originalData,
|
||||
HitCount: map[int]uint64{},
|
||||
}
|
||||
|
||||
if kind != UserBreakpoint {
|
||||
bpmap.internalBreakpointIDCounter++
|
||||
newBreakpoint.ID = bpmap.internalBreakpointIDCounter
|
||||
} else {
|
||||
bpmap.breakpointIDCounter++
|
||||
newBreakpoint.ID = bpmap.breakpointIDCounter
|
||||
}
|
||||
|
||||
bpmap.M[addr] = newBreakpoint
|
||||
|
||||
return newBreakpoint, nil
|
||||
}
|
||||
|
||||
// SetWithID creates a breakpoint at addr, with the specified ID.
|
||||
func (bpmap *BreakpointMap) SetWithID(id int, addr uint64, writeBreakpoint writeBreakpointFn) (*Breakpoint, error) {
|
||||
bp, err := bpmap.Set(addr, UserBreakpoint, nil, writeBreakpoint)
|
||||
if err == nil {
|
||||
bp.ID = id
|
||||
bpmap.breakpointIDCounter--
|
||||
}
|
||||
return bp, err
|
||||
}
|
||||
|
||||
// Clear clears the breakpoint at addr.
|
||||
// Do not call this function call proc.Process.ClearBreakpoint instead.
|
||||
func (bpmap *BreakpointMap) Clear(addr uint64, clearBreakpoint clearBreakpointFn) (*Breakpoint, error) {
|
||||
bp, ok := bpmap.M[addr]
|
||||
if !ok {
|
||||
return nil, NoBreakpointError{Addr: addr}
|
||||
}
|
||||
|
||||
if err := clearBreakpoint(bp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delete(bpmap.M, addr)
|
||||
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
// ClearInternalBreakpoints removes all internal breakpoints from the map,
|
||||
// calling clearBreakpoint on each one.
|
||||
// Do not call this function, call proc.Process.ClearInternalBreakpoints
|
||||
// instead, this function is used to implement that.
|
||||
func (bpmap *BreakpointMap) ClearInternalBreakpoints(clearBreakpoint clearBreakpointFn) error {
|
||||
for addr, bp := range bpmap.M {
|
||||
if !bp.Internal() {
|
||||
continue
|
||||
}
|
||||
if err := clearBreakpoint(bp); err != nil {
|
||||
return err
|
||||
}
|
||||
delete(bpmap.M, addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ func (r *OffsetReaderAt) ReadMemory(buf []byte, addr uintptr) (n int, err error)
|
||||
type Process struct {
|
||||
bi proc.BinaryInfo
|
||||
core *Core
|
||||
breakpoints map[uint64]*proc.Breakpoint
|
||||
breakpoints proc.BreakpointMap
|
||||
currentThread *Thread
|
||||
selectedGoroutine *proc.G
|
||||
allGCache []*proc.G
|
||||
@ -167,7 +167,7 @@ func OpenCore(corePath, exePath string) (*Process, error) {
|
||||
}
|
||||
p := &Process{
|
||||
core: core,
|
||||
breakpoints: make(map[uint64]*proc.Breakpoint),
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
bi: proc.NewBinaryInfo("linux", "amd64"),
|
||||
}
|
||||
for _, thread := range core.Threads {
|
||||
@ -258,8 +258,8 @@ func (t *Thread) SetCurrentBreakpoint() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Process) Breakpoints() map[uint64]*proc.Breakpoint {
|
||||
return p.breakpoints
|
||||
func (p *Process) Breakpoints() *proc.BreakpointMap {
|
||||
return &p.breakpoints
|
||||
}
|
||||
|
||||
func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
|
@ -40,7 +40,7 @@ func Disassemble(dbp Process, g *G, startPC, endPC uint64) ([]AsmInstruction, er
|
||||
return disassemble(mem, regs, dbp.Breakpoints(), dbp.BinInfo(), startPC, endPC)
|
||||
}
|
||||
|
||||
func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints map[uint64]*Breakpoint, bi *BinaryInfo, startPC, endPC uint64) ([]AsmInstruction, error) {
|
||||
func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startPC, endPC uint64) ([]AsmInstruction, error) {
|
||||
mem := make([]byte, int(endPC-startPC))
|
||||
_, err := memrw.ReadMemory(mem, uintptr(startPC))
|
||||
if err != nil {
|
||||
@ -56,7 +56,7 @@ func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints map[uint64]
|
||||
}
|
||||
|
||||
for len(mem) > 0 {
|
||||
bp, atbp := breakpoints[pc]
|
||||
bp, atbp := breakpoints.M[pc]
|
||||
if atbp {
|
||||
for i := range bp.OriginalData {
|
||||
mem[i] = bp.OriginalData[i]
|
||||
|
@ -111,9 +111,7 @@ type Process struct {
|
||||
|
||||
manualStopRequested bool
|
||||
|
||||
breakpoints map[uint64]*proc.Breakpoint
|
||||
breakpointIDCounter int
|
||||
internalBreakpointIDCounter int
|
||||
breakpoints proc.BreakpointMap
|
||||
|
||||
gcmdok bool // true if the stub supports g and G commands
|
||||
threadStopInfo bool // true if the stub supports qThreadStopInfo
|
||||
@ -170,7 +168,7 @@ func New(process *os.Process) *Process {
|
||||
},
|
||||
threads: make(map[int]*Thread),
|
||||
bi: proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH),
|
||||
breakpoints: make(map[uint64]*proc.Breakpoint),
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
gcmdok: true,
|
||||
threadStopInfo: true,
|
||||
process: process,
|
||||
@ -319,12 +317,10 @@ func (p *Process) Connect(conn net.Conn, path string, pid int) error {
|
||||
|
||||
panicpc, err := proc.FindFunctionLocation(p, "runtime.startpanic", true, 0)
|
||||
if err == nil {
|
||||
bp, err := p.SetBreakpoint(panicpc, proc.UserBreakpoint, nil)
|
||||
bp, err := p.breakpoints.SetWithID(-1, panicpc, p.writeBreakpoint)
|
||||
if err == nil {
|
||||
bp.Name = proc.UnrecoveredPanic
|
||||
bp.Variables = []string{"runtime.curg._panic.arg"}
|
||||
bp.ID = -1
|
||||
p.breakpointIDCounter--
|
||||
}
|
||||
}
|
||||
|
||||
@ -816,7 +812,7 @@ func (p *Process) Restart(pos string) error {
|
||||
}
|
||||
p.selectedGoroutine, _ = proc.GetG(p.CurrentThread())
|
||||
|
||||
for addr := range p.breakpoints {
|
||||
for addr := range p.breakpoints.M {
|
||||
p.conn.setBreakpoint(addr)
|
||||
}
|
||||
|
||||
@ -918,7 +914,7 @@ func (p *Process) Direction(dir proc.Direction) error {
|
||||
if p.conn.direction == dir {
|
||||
return nil
|
||||
}
|
||||
for _, bp := range p.Breakpoints() {
|
||||
for _, bp := range p.Breakpoints().M {
|
||||
if bp.Internal() {
|
||||
return ErrDirChange
|
||||
}
|
||||
@ -927,89 +923,60 @@ func (p *Process) Direction(dir proc.Direction) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Process) Breakpoints() map[uint64]*proc.Breakpoint {
|
||||
return p.breakpoints
|
||||
func (p *Process) Breakpoints() *proc.BreakpointMap {
|
||||
return &p.breakpoints
|
||||
}
|
||||
|
||||
func (p *Process) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
|
||||
// Check to see if address is past the breakpoint, (i.e. breakpoint was hit).
|
||||
if bp, ok := p.breakpoints[pc-uint64(p.bi.Arch.BreakpointSize())]; ok {
|
||||
if bp, ok := p.breakpoints.M[pc-uint64(p.bi.Arch.BreakpointSize())]; ok {
|
||||
return bp, true
|
||||
}
|
||||
// Directly use addr to lookup breakpoint.
|
||||
if bp, ok := p.breakpoints[pc]; ok {
|
||||
if bp, ok := p.breakpoints.M[pc]; ok {
|
||||
return bp, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (p *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
|
||||
if bp, ok := p.breakpoints[addr]; ok {
|
||||
return bp, proc.BreakpointExistsError{bp.File, bp.Line, bp.Addr}
|
||||
}
|
||||
func (p *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
|
||||
f, l, fn := p.bi.PCToLine(uint64(addr))
|
||||
if fn == nil {
|
||||
return nil, proc.InvalidAddressError{Address: addr}
|
||||
}
|
||||
|
||||
newBreakpoint := &proc.Breakpoint{
|
||||
FunctionName: fn.Name,
|
||||
File: f,
|
||||
Line: l,
|
||||
Addr: addr,
|
||||
Kind: kind,
|
||||
Cond: cond,
|
||||
HitCount: map[int]uint64{},
|
||||
}
|
||||
|
||||
if kind != proc.UserBreakpoint {
|
||||
p.internalBreakpointIDCounter++
|
||||
newBreakpoint.ID = p.internalBreakpointIDCounter
|
||||
} else {
|
||||
p.breakpointIDCounter++
|
||||
newBreakpoint.ID = p.breakpointIDCounter
|
||||
return "", 0, nil, nil, proc.InvalidAddressError{Address: addr}
|
||||
}
|
||||
|
||||
if err := p.conn.setBreakpoint(addr); err != nil {
|
||||
return nil, err
|
||||
return "", 0, nil, nil, err
|
||||
}
|
||||
p.breakpoints[addr] = newBreakpoint
|
||||
return newBreakpoint, nil
|
||||
|
||||
return f, l, fn, nil, nil
|
||||
}
|
||||
|
||||
func (p *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
|
||||
return p.breakpoints.Set(addr, kind, cond, p.writeBreakpoint)
|
||||
}
|
||||
|
||||
func (p *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
if p.exited {
|
||||
return nil, &proc.ProcessExitedError{Pid: p.conn.pid}
|
||||
}
|
||||
bp := p.breakpoints[addr]
|
||||
if bp == nil {
|
||||
return nil, proc.NoBreakpointError{Addr: addr}
|
||||
}
|
||||
|
||||
if err := p.conn.clearBreakpoint(addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delete(p.breakpoints, addr)
|
||||
|
||||
return bp, nil
|
||||
return p.breakpoints.Clear(addr, func(bp *proc.Breakpoint) error {
|
||||
return p.conn.clearBreakpoint(bp.Addr)
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Process) ClearInternalBreakpoints() error {
|
||||
for _, bp := range p.breakpoints {
|
||||
if !bp.Internal() {
|
||||
continue
|
||||
}
|
||||
if _, err := p.ClearBreakpoint(bp.Addr); err != nil {
|
||||
return p.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
|
||||
if err := p.conn.clearBreakpoint(bp.Addr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i := range p.threads {
|
||||
if p.threads[i].CurrentBreakpoint != nil && p.threads[i].CurrentBreakpoint.Internal() {
|
||||
p.threads[i].CurrentBreakpoint = nil
|
||||
for _, thread := range p.threads {
|
||||
if thread.CurrentBreakpoint == bp {
|
||||
thread.CurrentBreakpoint = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
type threadUpdater struct {
|
||||
@ -1186,7 +1153,7 @@ func (t *Thread) BinInfo() *proc.BinaryInfo {
|
||||
|
||||
func (t *Thread) stepInstruction(tu *threadUpdater) error {
|
||||
pc := t.regs.PC()
|
||||
if _, atbp := t.p.breakpoints[pc]; atbp {
|
||||
if _, atbp := t.p.breakpoints.M[pc]; atbp {
|
||||
err := t.p.conn.clearBreakpoint(pc)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1354,7 +1321,7 @@ func (t *Thread) reloadGAtPC() error {
|
||||
// around by clearing and re-setting the breakpoint in a specific sequence
|
||||
// with the memory writes.
|
||||
// Additionally all breakpoints in [pc, pc+len(movinstr)] need to be removed
|
||||
for addr := range t.p.breakpoints {
|
||||
for addr := range t.p.breakpoints.M {
|
||||
if addr >= pc && addr <= pc+uint64(len(movinstr)) {
|
||||
err := t.p.conn.clearBreakpoint(addr)
|
||||
if err != nil {
|
||||
|
@ -97,7 +97,7 @@ type ProcessManipulation interface {
|
||||
|
||||
// BreakpointManipulation is an interface for managing breakpoints.
|
||||
type BreakpointManipulation interface {
|
||||
Breakpoints() map[uint64]*Breakpoint
|
||||
Breakpoints() *BreakpointMap
|
||||
SetBreakpoint(addr uint64, kind BreakpointKind, cond ast.Expr) (*Breakpoint, error)
|
||||
ClearBreakpoint(addr uint64) (*Breakpoint, error)
|
||||
ClearInternalBreakpoints() error
|
||||
|
@ -17,7 +17,7 @@ type Process struct {
|
||||
|
||||
// Breakpoint table, holds information on breakpoints.
|
||||
// Maps instruction address to Breakpoint struct.
|
||||
breakpoints map[uint64]*proc.Breakpoint
|
||||
breakpoints proc.BreakpointMap
|
||||
|
||||
// List of threads mapped as such: pid -> *Thread
|
||||
threads map[int]*Thread
|
||||
@ -29,19 +29,17 @@ type Process struct {
|
||||
// Normally selectedGoroutine is currentThread.GetG, it will not be only if SwitchGoroutine is called with a goroutine that isn't attached to a thread
|
||||
selectedGoroutine *proc.G
|
||||
|
||||
allGCache []*proc.G
|
||||
os *OSProcessDetails
|
||||
breakpointIDCounter int
|
||||
internalBreakpointIDCounter int
|
||||
firstStart bool
|
||||
haltMu sync.Mutex
|
||||
halt bool
|
||||
resumeChan chan<- struct{}
|
||||
exited bool
|
||||
ptraceChan chan func()
|
||||
ptraceDoneChan chan interface{}
|
||||
childProcess bool // this process was launched, not attached to
|
||||
manualStopRequested bool
|
||||
allGCache []*proc.G
|
||||
os *OSProcessDetails
|
||||
firstStart bool
|
||||
haltMu sync.Mutex
|
||||
halt bool
|
||||
resumeChan chan<- struct{}
|
||||
exited bool
|
||||
ptraceChan chan func()
|
||||
ptraceDoneChan chan interface{}
|
||||
childProcess bool // this process was launched, not attached to
|
||||
manualStopRequested bool
|
||||
}
|
||||
|
||||
// New returns an initialized Process struct. Before returning,
|
||||
@ -52,7 +50,7 @@ func New(pid int) *Process {
|
||||
dbp := &Process{
|
||||
pid: pid,
|
||||
threads: make(map[int]*Thread),
|
||||
breakpoints: make(map[uint64]*proc.Breakpoint),
|
||||
breakpoints: proc.NewBreakpointMap(),
|
||||
firstStart: true,
|
||||
os: new(OSProcessDetails),
|
||||
ptraceChan: make(chan func()),
|
||||
@ -90,7 +88,7 @@ func (dbp *Process) Detach(kill bool) (err error) {
|
||||
}
|
||||
if !kill {
|
||||
// Clean up any breakpoints we've set.
|
||||
for _, bp := range dbp.breakpoints {
|
||||
for _, bp := range dbp.breakpoints.M {
|
||||
if bp != nil {
|
||||
_, err := dbp.ClearBreakpoint(bp.Addr)
|
||||
if err != nil {
|
||||
@ -147,8 +145,8 @@ func (dbp *Process) CurrentThread() proc.Thread {
|
||||
return dbp.currentThread
|
||||
}
|
||||
|
||||
func (dbp *Process) Breakpoints() map[uint64]*proc.Breakpoint {
|
||||
return dbp.breakpoints
|
||||
func (dbp *Process) Breakpoints() *proc.BreakpointMap {
|
||||
return &dbp.breakpoints
|
||||
}
|
||||
|
||||
// LoadInformation finds the executable and then uses it
|
||||
@ -193,52 +191,29 @@ func (dbp *Process) ManualStopRequested() bool {
|
||||
return msr
|
||||
}
|
||||
|
||||
func (dbp *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) {
|
||||
f, l, fn := dbp.bi.PCToLine(uint64(addr))
|
||||
if fn == nil {
|
||||
return "", 0, nil, nil, proc.InvalidAddressError{Address: addr}
|
||||
}
|
||||
|
||||
originalData := make([]byte, dbp.bi.Arch.BreakpointSize())
|
||||
_, err := dbp.currentThread.ReadMemory(originalData, uintptr(addr))
|
||||
if err != nil {
|
||||
return "", 0, nil, nil, err
|
||||
}
|
||||
if err := dbp.writeSoftwareBreakpoint(dbp.currentThread, addr); err != nil {
|
||||
return "", 0, nil, nil, err
|
||||
}
|
||||
|
||||
return f, l, fn, originalData, nil
|
||||
}
|
||||
|
||||
// SetBreakpoint sets a breakpoint at addr, and stores it in the process wide
|
||||
// break point table. Setting a break point must be thread specific due to
|
||||
// ptrace actions needing the thread to be in a signal-delivery-stop.
|
||||
func (dbp *Process) SetBreakpoint(addr uint64, kind proc.BreakpointKind, cond ast.Expr) (*proc.Breakpoint, error) {
|
||||
tid := dbp.currentThread.ID
|
||||
|
||||
if bp, ok := dbp.FindBreakpoint(addr); ok {
|
||||
return bp, proc.BreakpointExistsError{bp.File, bp.Line, bp.Addr}
|
||||
}
|
||||
|
||||
f, l, fn := dbp.bi.PCToLine(uint64(addr))
|
||||
if fn == nil {
|
||||
return nil, proc.InvalidAddressError{Address: addr}
|
||||
}
|
||||
|
||||
newBreakpoint := &proc.Breakpoint{
|
||||
FunctionName: fn.Name,
|
||||
File: f,
|
||||
Line: l,
|
||||
Addr: addr,
|
||||
Kind: kind,
|
||||
Cond: cond,
|
||||
HitCount: map[int]uint64{},
|
||||
}
|
||||
|
||||
if kind != proc.UserBreakpoint {
|
||||
dbp.internalBreakpointIDCounter++
|
||||
newBreakpoint.ID = dbp.internalBreakpointIDCounter
|
||||
} else {
|
||||
dbp.breakpointIDCounter++
|
||||
newBreakpoint.ID = dbp.breakpointIDCounter
|
||||
}
|
||||
|
||||
thread := dbp.threads[tid]
|
||||
originalData := make([]byte, dbp.bi.Arch.BreakpointSize())
|
||||
_, err := thread.ReadMemory(originalData, uintptr(addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := dbp.writeSoftwareBreakpoint(thread, addr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newBreakpoint.OriginalData = originalData
|
||||
dbp.breakpoints[addr] = newBreakpoint
|
||||
|
||||
return newBreakpoint, nil
|
||||
return dbp.breakpoints.Set(addr, kind, cond, dbp.writeBreakpoint)
|
||||
}
|
||||
|
||||
// ClearBreakpoint clears the breakpoint at addr.
|
||||
@ -246,18 +221,7 @@ func (dbp *Process) ClearBreakpoint(addr uint64) (*proc.Breakpoint, error) {
|
||||
if dbp.exited {
|
||||
return nil, &proc.ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
bp, ok := dbp.FindBreakpoint(addr)
|
||||
if !ok {
|
||||
return nil, proc.NoBreakpointError{Addr: addr}
|
||||
}
|
||||
|
||||
if _, err := dbp.currentThread.ClearBreakpoint(bp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delete(dbp.breakpoints, addr)
|
||||
|
||||
return bp, nil
|
||||
return dbp.breakpoints.Clear(addr, dbp.currentThread.ClearBreakpoint)
|
||||
}
|
||||
|
||||
func (dbp *Process) ContinueOnce() (proc.Thread, error) {
|
||||
@ -377,11 +341,11 @@ func (dbp *Process) Halt() (err error) {
|
||||
// FindBreakpoint finds the breakpoint for the given pc.
|
||||
func (dbp *Process) FindBreakpoint(pc uint64) (*proc.Breakpoint, bool) {
|
||||
// Check to see if address is past the breakpoint, (i.e. breakpoint was hit).
|
||||
if bp, ok := dbp.breakpoints[pc-uint64(dbp.bi.Arch.BreakpointSize())]; ok {
|
||||
if bp, ok := dbp.breakpoints.M[pc-uint64(dbp.bi.Arch.BreakpointSize())]; ok {
|
||||
return bp, true
|
||||
}
|
||||
// Directly use addr to lookup breakpoint.
|
||||
if bp, ok := dbp.breakpoints[pc]; ok {
|
||||
if bp, ok := dbp.breakpoints.M[pc]; ok {
|
||||
return bp, true
|
||||
}
|
||||
return nil, false
|
||||
@ -406,12 +370,10 @@ func initializeDebugProcess(dbp *Process, path string) (*Process, error) {
|
||||
|
||||
panicpc, err := proc.FindFunctionLocation(dbp, "runtime.startpanic", true, 0)
|
||||
if err == nil {
|
||||
bp, err := dbp.SetBreakpoint(panicpc, proc.UserBreakpoint, nil)
|
||||
bp, err := dbp.breakpoints.SetWithID(-1, panicpc, dbp.writeBreakpoint)
|
||||
if err == nil {
|
||||
bp.Name = proc.UnrecoveredPanic
|
||||
bp.Variables = []string{"runtime.curg._panic.arg"}
|
||||
bp.ID = -1
|
||||
dbp.breakpointIDCounter--
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,20 +381,17 @@ func initializeDebugProcess(dbp *Process, path string) (*Process, error) {
|
||||
}
|
||||
|
||||
func (dbp *Process) ClearInternalBreakpoints() error {
|
||||
for _, bp := range dbp.breakpoints {
|
||||
if !bp.Internal() {
|
||||
continue
|
||||
}
|
||||
if _, err := dbp.ClearBreakpoint(bp.Addr); err != nil {
|
||||
return dbp.breakpoints.ClearInternalBreakpoints(func(bp *proc.Breakpoint) error {
|
||||
if err := dbp.currentThread.ClearBreakpoint(bp); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for i := range dbp.threads {
|
||||
if dbp.threads[i].CurrentBreakpoint != nil && dbp.threads[i].CurrentBreakpoint.Internal() {
|
||||
dbp.threads[i].CurrentBreakpoint = nil
|
||||
for _, thread := range dbp.threads {
|
||||
if thread.CurrentBreakpoint == bp {
|
||||
thread.CurrentBreakpoint = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (dbp *Process) handlePtraceFuncs() {
|
||||
|
@ -65,7 +65,7 @@ func (thread *Thread) StepInstruction() (err error) {
|
||||
bp, ok := thread.dbp.FindBreakpoint(pc)
|
||||
if ok {
|
||||
// Clear the breakpoint so that we can continue execution.
|
||||
_, err = thread.ClearBreakpoint(bp)
|
||||
err = thread.ClearBreakpoint(bp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -177,11 +177,11 @@ func (th *Thread) ThreadID() int {
|
||||
}
|
||||
|
||||
// ClearBreakpoint clears the specified breakpoint.
|
||||
func (thread *Thread) ClearBreakpoint(bp *proc.Breakpoint) (*proc.Breakpoint, error) {
|
||||
func (thread *Thread) ClearBreakpoint(bp *proc.Breakpoint) error {
|
||||
if _, err := thread.WriteMemory(uintptr(bp.Addr), bp.OriginalData); err != nil {
|
||||
return nil, fmt.Errorf("could not clear breakpoint %s", err)
|
||||
return fmt.Errorf("could not clear breakpoint %s", err)
|
||||
}
|
||||
return bp, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Registers obtains register values from the debugged process.
|
||||
|
@ -68,7 +68,7 @@ func Next(dbp Process) (err error) {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
for _, bp := range dbp.Breakpoints() {
|
||||
for _, bp := range dbp.Breakpoints().M {
|
||||
if bp.Internal() {
|
||||
return fmt.Errorf("next while nexting")
|
||||
}
|
||||
@ -216,7 +216,7 @@ func Step(dbp Process) (err error) {
|
||||
if dbp.Exited() {
|
||||
return &ProcessExitedError{Pid: dbp.Pid()}
|
||||
}
|
||||
for _, bp := range dbp.Breakpoints() {
|
||||
for _, bp := range dbp.Breakpoints().M {
|
||||
if bp.Internal() {
|
||||
return fmt.Errorf("next while nexting")
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ type nextTest struct {
|
||||
|
||||
func countBreakpoints(p proc.Process) int {
|
||||
bpcount := 0
|
||||
for _, bp := range p.Breakpoints() {
|
||||
for _, bp := range p.Breakpoints().M {
|
||||
if bp.ID >= 0 {
|
||||
bpcount++
|
||||
}
|
||||
@ -422,7 +422,7 @@ func testseq(program string, contFunc contFunc, testcases []nextTest, initialLoc
|
||||
}
|
||||
|
||||
if countBreakpoints(p) != 0 {
|
||||
t.Fatal("Not all breakpoints were cleaned up", len(p.Breakpoints()))
|
||||
t.Fatal("Not all breakpoints were cleaned up", len(p.Breakpoints().M))
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -2272,7 +2272,7 @@ func TestStepConcurrentDirect(t *testing.T) {
|
||||
_, err = p.ClearBreakpoint(bp.Addr)
|
||||
assertNoError(err, t, "ClearBreakpoint()")
|
||||
|
||||
for _, b := range p.Breakpoints() {
|
||||
for _, b := range p.Breakpoints().M {
|
||||
if b.Name == proc.UnrecoveredPanic {
|
||||
_, err := p.ClearBreakpoint(b.Addr)
|
||||
assertNoError(err, t, "ClearBreakpoint(unrecovered-panic)")
|
||||
@ -2327,7 +2327,7 @@ func TestStepConcurrentDirect(t *testing.T) {
|
||||
}
|
||||
|
||||
func nextInProgress(p proc.Process) bool {
|
||||
for _, bp := range p.Breakpoints() {
|
||||
for _, bp := range p.Breakpoints().M {
|
||||
if bp.Internal() {
|
||||
return true
|
||||
}
|
||||
@ -2343,7 +2343,7 @@ func TestStepConcurrentPtr(t *testing.T) {
|
||||
_, err = p.SetBreakpoint(pc, proc.UserBreakpoint, nil)
|
||||
assertNoError(err, t, "SetBreakpoint()")
|
||||
|
||||
for _, b := range p.Breakpoints() {
|
||||
for _, b := range p.Breakpoints().M {
|
||||
if b.Name == proc.UnrecoveredPanic {
|
||||
_, err := p.ClearBreakpoint(b.Addr)
|
||||
assertNoError(err, t, "ClearBreakpoint(unrecovered-panic)")
|
||||
|
@ -411,11 +411,11 @@ func onRuntimeBreakpoint(thread Thread) bool {
|
||||
}
|
||||
|
||||
// onNextGorutine returns true if this thread is on the goroutine requested by the current 'next' command
|
||||
func onNextGoroutine(thread Thread, breakpoints map[uint64]*Breakpoint) (bool, error) {
|
||||
func onNextGoroutine(thread Thread, breakpoints *BreakpointMap) (bool, error) {
|
||||
var bp *Breakpoint
|
||||
for i := range breakpoints {
|
||||
if breakpoints[i].Internal() && breakpoints[i].Cond != nil {
|
||||
bp = breakpoints[i]
|
||||
for i := range breakpoints.M {
|
||||
if breakpoints.M[i].Internal() && breakpoints.M[i].Cond != nil {
|
||||
bp = breakpoints.M[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ func (d *Debugger) state() (*api.DebuggerState, error) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, bp := range d.target.Breakpoints() {
|
||||
for _, bp := range d.target.Breakpoints().M {
|
||||
if bp.Internal() {
|
||||
state.NextInProgress = true
|
||||
break
|
||||
@ -398,7 +398,7 @@ func (d *Debugger) Breakpoints() []*api.Breakpoint {
|
||||
|
||||
func (d *Debugger) breakpoints() []*api.Breakpoint {
|
||||
bps := []*api.Breakpoint{}
|
||||
for _, bp := range d.target.Breakpoints() {
|
||||
for _, bp := range d.target.Breakpoints().M {
|
||||
if bp.Internal() {
|
||||
continue
|
||||
}
|
||||
@ -420,7 +420,7 @@ func (d *Debugger) FindBreakpoint(id int) *api.Breakpoint {
|
||||
}
|
||||
|
||||
func (d *Debugger) findBreakpoint(id int) *proc.Breakpoint {
|
||||
for _, bp := range d.target.Breakpoints() {
|
||||
for _, bp := range d.target.Breakpoints().M {
|
||||
if bp.ID == id {
|
||||
return bp
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user