From f88899ea976007f37c793491903cccbab5d082d1 Mon Sep 17 00:00:00 2001 From: hengwu0 Date: Sat, 16 Nov 2019 20:25:13 +0800 Subject: [PATCH] proc/native: fix SetCurrentBreakpoint on arm64 arm64 use hardware breakpoint, and it will not set PC to the next instruction like amd64. Let adjustPC always fasle in arm64, in case of infinite loop. --- pkg/proc/amd64_arch.go | 7 +++++++ pkg/proc/arch.go | 1 + pkg/proc/arm64_arch.go | 7 +++++++ pkg/proc/native/threads.go | 13 +++++++++++-- pkg/proc/proc.go | 4 ++-- scripts/make.go | 2 +- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/pkg/proc/amd64_arch.go b/pkg/proc/amd64_arch.go index 223c120f..f7735b73 100644 --- a/pkg/proc/amd64_arch.go +++ b/pkg/proc/amd64_arch.go @@ -59,6 +59,13 @@ func (a *AMD64) BreakpointInstruction() []byte { return amd64BreakInstruction } +// BreakInstrMovesPC returns whether the +// breakpoint instruction will change the value +// of PC after being executed +func (a *AMD64) BreakInstrMovesPC() bool { + return true +} + // BreakpointSize returns the size of the // breakpoint instruction on this architecture. func (a *AMD64) BreakpointSize() int { diff --git a/pkg/proc/arch.go b/pkg/proc/arch.go index 7c14a641..30d80f27 100644 --- a/pkg/proc/arch.go +++ b/pkg/proc/arch.go @@ -11,6 +11,7 @@ type Arch interface { PtrSize() int MinInstructionLength() int BreakpointInstruction() []byte + BreakInstrMovesPC() bool BreakpointSize() int DerefTLS() bool FixFrameUnwindContext(*frame.FrameContext, uint64, *BinaryInfo) *frame.FrameContext diff --git a/pkg/proc/arm64_arch.go b/pkg/proc/arm64_arch.go index b9474bd8..c44a85d0 100644 --- a/pkg/proc/arm64_arch.go +++ b/pkg/proc/arm64_arch.go @@ -59,6 +59,13 @@ func (a *ARM64) BreakpointInstruction() []byte { return arm64BreakInstruction } +// BreakInstrMovesPC returns whether the +// breakpoint instruction will change the value +// of PC after being executed +func (a *ARM64) BreakInstrMovesPC() bool { + return false +} + // BreakpointSize returns the size of the // breakpoint instruction on this architecture. func (a *ARM64) BreakpointSize() int { diff --git a/pkg/proc/native/threads.go b/pkg/proc/native/threads.go index 5034d63b..a3c4f61a 100644 --- a/pkg/proc/native/threads.go +++ b/pkg/proc/native/threads.go @@ -119,9 +119,18 @@ func (t *Thread) SetCurrentBreakpoint(adjustPC bool) error { if err != nil { return err } + + // If the breakpoint instruction does not change the value + // of PC after being executed we should look for breakpoints + // with bp.Addr == PC and there is no need to call SetPC + // after finding one. + adjustPC = adjustPC && t.Arch().BreakInstrMovesPC() + if bp, ok := t.dbp.FindBreakpoint(pc, adjustPC); ok { - if err = t.SetPC(bp.Addr); err != nil { - return err + if adjustPC { + if err = t.SetPC(bp.Addr); err != nil { + return err + } } t.CurrentBreakpoint = bp.CheckCondition(t) if t.CurrentBreakpoint.Breakpoint != nil && t.CurrentBreakpoint.Active { diff --git a/pkg/proc/proc.go b/pkg/proc/proc.go index 3fdf9ad3..8ae3d72e 100644 --- a/pkg/proc/proc.go +++ b/pkg/proc/proc.go @@ -213,8 +213,8 @@ func Continue(dbp Process) error { case loc.Fn.Name == "runtime.breakpoint": // In linux-arm64, PtraceSingleStep seems cannot step over BRK instruction // (linux-arm64 feature or kernel bug maybe). - if arch, ok := curthread.Arch().(*ARM64); ok { - curthread.SetPC(loc.PC + uint64(arch.BreakpointSize())) + if !curthread.Arch().BreakInstrMovesPC() { + curthread.SetPC(loc.PC + uint64(curthread.Arch().BreakpointSize())) } // Single-step current thread until we exit runtime.breakpoint and // runtime.Breakpoint. diff --git a/scripts/make.go b/scripts/make.go index bdba288d..dbb29e55 100644 --- a/scripts/make.go +++ b/scripts/make.go @@ -79,7 +79,7 @@ Use the flags -s, -r and -b to specify which tests to run. Specifying nothing is `, Run: testCmd, } - test.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "Verbose tests") + test.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", true, "Verbose tests") test.PersistentFlags().StringVarP(&TestSet, "test-set", "s", "", `Select the set of tests to run, one of either: all tests all packages basic tests proc, integration and terminal