bugfix: Issue #170 (partial) set function breakpoints on the first instruction
the entry point of a function is the beginning of the prologue, which can be run multiple times for each invocation of a function if the stack needs to be expanded or the scheduler needs to be run.
This commit is contained in:
parent
a353735715
commit
a0115e3a15
25
proc/proc.go
25
proc/proc.go
@ -172,7 +172,30 @@ func (dbp *Process) FindLocation(str string) (uint64, error) {
|
||||
// Try to lookup by function name
|
||||
fn := dbp.goSymTable.LookupFunc(str)
|
||||
if fn != nil {
|
||||
return fn.Entry, nil
|
||||
// fn.Entry, the entry point of the function, is always a prologue, the prologue may call into the scheduler or grow the stack,
|
||||
// this will result in the breakpoint getting hit multiple times without any apparent program progress inbetween.
|
||||
// In order to avoid this confusing behaviour we try to find the first line of the function and set the breakpoint there.
|
||||
filename, lineno, _ := dbp.goSymTable.PCToLine(fn.Entry)
|
||||
var firstLinePC uint64
|
||||
var err error
|
||||
for {
|
||||
lineno++
|
||||
firstLinePC, _, err = dbp.goSymTable.LineToPC(filename, lineno)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if _, unk := err.(*gosym.UnknownLineError); !unk {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
var breakAddr uint64
|
||||
if firstLinePC < fn.End {
|
||||
breakAddr = firstLinePC
|
||||
} else {
|
||||
breakAddr = fn.Entry
|
||||
}
|
||||
return breakAddr, nil
|
||||
}
|
||||
|
||||
// Attempt to parse as number for breakpoint id or raw address
|
||||
|
@ -278,7 +278,6 @@ func testnext(program string, testcases []nextTest, initialLocation string, t *t
|
||||
|
||||
func TestNextGeneral(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{17, 19},
|
||||
{19, 20},
|
||||
{20, 23},
|
||||
{23, 24},
|
||||
@ -299,7 +298,6 @@ func TestNextGeneral(t *testing.T) {
|
||||
|
||||
func TestNextGoroutine(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{46, 47},
|
||||
{47, 42},
|
||||
}
|
||||
testnext("testnextprog", testcases, "main.testgoroutine", t)
|
||||
@ -307,7 +305,6 @@ func TestNextGoroutine(t *testing.T) {
|
||||
|
||||
func TestNextFunctionReturn(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{13, 14},
|
||||
{14, 35},
|
||||
}
|
||||
testnext("testnextprog", testcases, "main.helloworld", t)
|
||||
|
@ -216,7 +216,6 @@ func testnext(testcases []nextTest, initialLocation string, t *testing.T) {
|
||||
|
||||
func TestNextGeneral(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{17, 19},
|
||||
{19, 20},
|
||||
{20, 23},
|
||||
{23, 24},
|
||||
@ -237,7 +236,6 @@ func TestNextGeneral(t *testing.T) {
|
||||
|
||||
func TestNextGoroutine(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{46, 47},
|
||||
{47, 42},
|
||||
}
|
||||
testnext(testcases, "main.testgoroutine", t)
|
||||
@ -245,7 +243,6 @@ func TestNextGoroutine(t *testing.T) {
|
||||
|
||||
func TestNextFunctionReturn(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{13, 14},
|
||||
{14, 35},
|
||||
}
|
||||
testnext(testcases, "main.helloworld", t)
|
||||
@ -285,7 +282,7 @@ func TestClientServer_breakpointInSeparateGoroutine(t *testing.T) {
|
||||
}
|
||||
|
||||
f, l := state.CurrentThread.File, state.CurrentThread.Line
|
||||
if f != "testthreads.go" && l != 8 {
|
||||
if f != "testthreads.go" && l != 9 {
|
||||
t.Fatal("Program did not hit breakpoint")
|
||||
}
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user