From 17d8aa2bd17c2a0e9d8070a1f223c71c4922851e Mon Sep 17 00:00:00 2001 From: aarzilli Date: Thu, 19 Nov 2015 16:19:42 +0100 Subject: [PATCH] proc: bugfix: wrong final count in TestBreakpointCounts (linux) Sometimes after PtraceSingleStep the thread does not advance of a single instruction but is, instead, blocked immediately by a SIGSTOP Made singleStep repeat the process until a SIGTRAP is observed. Unsure where the SIGSTOP comes from. --- proc/proc_test.go | 64 +++++++++++++++++++++++++++++++++++++++++++ proc/threads_linux.go | 17 ++++++++---- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/proc/proc_test.go b/proc/proc_test.go index 56f72c51..824eb4d4 100644 --- a/proc/proc_test.go +++ b/proc/proc_test.go @@ -1181,6 +1181,70 @@ func TestBreakpointCounts(t *testing.T) { }) } +const doTestBreakpointCountsWithDetection = false + +func TestBreakpointCountsWithDetection(t *testing.T) { + if !doTestBreakpointCountsWithDetection { + return + } + m := map[int64]int64{} + withTestProcess("bpcountstest", t, func(p *Process, fixture protest.Fixture) { + addr, _, err := p.goSymTable.LineToPC(fixture.Source, 12) + assertNoError(err, t, "LineToPC") + bp, err := p.SetBreakpoint(addr) + assertNoError(err, t, "SetBreakpoint()") + + for { + if err := p.Continue(); err != nil { + if _, exited := err.(ProcessExitedError); exited { + break + } + assertNoError(err, t, "Continue()") + } + fmt.Printf("Continue returned %d\n", bp.TotalHitCount) + for _, th := range p.Threads { + if th.CurrentBreakpoint == nil { + continue + } + scope, err := th.Scope() + assertNoError(err, t, "Scope()") + v, err := scope.EvalVariable("i") + assertNoError(err, t, "evalVariable") + i, _ := constant.Int64Val(v.Value) + v, err = scope.EvalVariable("id") + assertNoError(err, t, "evalVariable") + id, _ := constant.Int64Val(v.Value) + m[id] = i + fmt.Printf("\tgoroutine (%d) %d: %d\n", th.Id, id, i) + } + + total := int64(0) + for i := range m { + total += m[i] + 1 + } + + if uint64(total) != bp.TotalHitCount { + t.Fatalf("Mismatched total count %d %d\n", total, bp.TotalHitCount) + } + } + + t.Logf("TotalHitCount: %d", bp.TotalHitCount) + if bp.TotalHitCount != 200 { + t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.TotalHitCount) + } + + if len(bp.HitCount) != 2 { + t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.HitCount)) + } + + for _, v := range bp.HitCount { + if v != 100 { + t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.HitCount) + } + } + }) +} + func TestIssue262(t *testing.T) { // Continue does not work when the current breakpoint is set on a NOP instruction withTestProcess("issue262", t, func(p *Process, fixture protest.Fixture) { diff --git a/proc/threads_linux.go b/proc/threads_linux.go index 800601da..4bca4485 100644 --- a/proc/threads_linux.go +++ b/proc/threads_linux.go @@ -38,12 +38,19 @@ func (t *Thread) resume() (err error) { } func (t *Thread) singleStep() (err error) { - t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.Id) }) - if err != nil { - return err + for { + t.dbp.execPtraceFunc(func() { err = sys.PtraceSingleStep(t.Id) }) + if err != nil { + return err + } + wpid, status, err := t.dbp.wait(t.Id, 0) + if err != nil { + return err + } + if wpid == t.Id && status.StopSignal() == sys.SIGTRAP { + return nil + } } - _, _, err = t.dbp.wait(t.Id, 0) - return err } func (t *Thread) blocked() bool {