diff --git a/pkg/proc/breakpoints.go b/pkg/proc/breakpoints.go index 1e9055991c2e8169a2e942095268e6b625ef5f05..202f1e53d114351a3a3469cf685b57116fbde69e 100644 --- a/pkg/proc/breakpoints.go +++ b/pkg/proc/breakpoints.go @@ -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 +} diff --git a/pkg/proc/core/core.go b/pkg/proc/core/core.go index e1b496df05d3bd5a59fcf597807d38943c719ef3..0c92dcb907393bec423cca68d855e6e5ed37590e 100644 --- a/pkg/proc/core/core.go +++ b/pkg/proc/core/core.go @@ -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) { diff --git a/pkg/proc/disasm.go b/pkg/proc/disasm.go index 07b25866bdee61ee248db9597b140ffb292a5584..acabe8d23cfaca7797a6db48e5a86526342ac1ba 100644 --- a/pkg/proc/disasm.go +++ b/pkg/proc/disasm.go @@ -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] diff --git a/pkg/proc/gdbserial/gdbserver.go b/pkg/proc/gdbserial/gdbserver.go index 182aaf8b0d59ee3909aa89d11585e4b626a73271..0eddd4dd18a253ff05b9fab201ddb575c6c6ba52 100644 --- a/pkg/proc/gdbserial/gdbserver.go +++ b/pkg/proc/gdbserial/gdbserver.go @@ -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} + return "", 0, nil, 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 err := p.conn.setBreakpoint(addr); err != nil { + return "", 0, nil, nil, err } - if kind != proc.UserBreakpoint { - p.internalBreakpointIDCounter++ - newBreakpoint.ID = p.internalBreakpointIDCounter - } else { - p.breakpointIDCounter++ - newBreakpoint.ID = p.breakpointIDCounter - } + return f, l, fn, nil, nil +} - if err := p.conn.setBreakpoint(addr); err != nil { - return nil, err - } - p.breakpoints[addr] = newBreakpoint - return newBreakpoint, 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 { diff --git a/pkg/proc/interface.go b/pkg/proc/interface.go index f3b5562416b4e3ed1a9f394f95fc6ab4a5420e03..1cb6f684fe1158a21cd1e2b2fe897a041b890af9 100644 --- a/pkg/proc/interface.go +++ b/pkg/proc/interface.go @@ -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 diff --git a/pkg/proc/native/proc.go b/pkg/proc/native/proc.go index a7850fd747e59fb76f89de6e164d4cd8f5d70007..3118aa7973e8143ca18921ef8851a20c2fb4846f 100644 --- a/pkg/proc/native/proc.go +++ b/pkg/proc/native/proc.go @@ -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 } -// 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} - } - +func (dbp *Process) writeBreakpoint(addr uint64) (string, int, *proc.Function, []byte, error) { 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 + return "", 0, nil, nil, proc.InvalidAddressError{Address: addr} } - thread := dbp.threads[tid] originalData := make([]byte, dbp.bi.Arch.BreakpointSize()) - _, err := thread.ReadMemory(originalData, uintptr(addr)) + _, err := dbp.currentThread.ReadMemory(originalData, uintptr(addr)) if err != nil { - return nil, err + return "", 0, nil, nil, err } - if err := dbp.writeSoftwareBreakpoint(thread, addr); err != nil { - return nil, err + if err := dbp.writeSoftwareBreakpoint(dbp.currentThread, addr); err != nil { + return "", 0, nil, nil, err } - newBreakpoint.OriginalData = originalData - dbp.breakpoints[addr] = newBreakpoint - return newBreakpoint, nil + 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) { + 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() { diff --git a/pkg/proc/native/threads.go b/pkg/proc/native/threads.go index c16947242b07e966123973ffaf0829f32f163248..d520f7f7a6a07cc55eb4ce9a136451163cdd9778 100644 --- a/pkg/proc/native/threads.go +++ b/pkg/proc/native/threads.go @@ -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. diff --git a/pkg/proc/proc.go b/pkg/proc/proc.go index 7d9246353ac66ae0da775a9842cfa43f76ccea0e..b6ac15868bd18a259f6dda57e0ac8e5dc035e33b 100644 --- a/pkg/proc/proc.go +++ b/pkg/proc/proc.go @@ -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") } diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 8cb5d8d0ac34efb4011f042e8abeeb34f3e8e91f..10c6a2f6fc463d8abaf6efdf41f37e02700ac610 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -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)") diff --git a/pkg/proc/threads.go b/pkg/proc/threads.go index c9f9ab3ae2658fa2b8bb708f8b840f00d10a25a0..b6d55d3de65ceba5fe112932fc061aa0693025f5 100644 --- a/pkg/proc/threads.go +++ b/pkg/proc/threads.go @@ -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 } } diff --git a/service/debugger/debugger.go b/service/debugger/debugger.go index b5c431b7ae99d281a791872e4f5c42afd7538af6..1e4981648c4ef9919316c5a1d9520f4519288775 100644 --- a/service/debugger/debugger.go +++ b/service/debugger/debugger.go @@ -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 }