Improve 'next': return into deferred func
This commit is contained in:
parent
2cfbc2937f
commit
39945498a8
10
_fixtures/testnextdefer.go
Normal file
10
_fixtures/testnextdefer.go
Normal file
@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
fmt.Println("hi")
|
||||
}()
|
||||
fmt.Println("bye")
|
||||
}
|
@ -87,6 +87,9 @@ func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if entry == nil {
|
||||
return 0, fmt.Errorf("nil entry for member named %s", member)
|
||||
}
|
||||
name, ok := entry.Val(dwarf.AttrName).(string)
|
||||
if !ok || name != member {
|
||||
continue
|
||||
|
@ -249,6 +249,13 @@ func (dbp *DebuggedProcess) next() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if curg.DeferPC != 0 {
|
||||
_, err = dbp.TempBreak(curg.DeferPC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var goroutineExiting bool
|
||||
var waitCount int
|
||||
for _, th := range dbp.Threads {
|
||||
|
@ -226,8 +226,8 @@ type nextTest struct {
|
||||
begin, end int
|
||||
}
|
||||
|
||||
func testnext(testcases []nextTest, initialLocation string, t *testing.T) {
|
||||
withTestProcess("testnextprog", t, func(p *DebuggedProcess, fixture protest.Fixture) {
|
||||
func testnext(program string, testcases []nextTest, initialLocation string, t *testing.T) {
|
||||
withTestProcess(program, t, func(p *DebuggedProcess, fixture protest.Fixture) {
|
||||
bp, err := p.BreakByLocation(initialLocation)
|
||||
assertNoError(err, t, "Break()")
|
||||
assertNoError(p.Continue(), t, "Continue()")
|
||||
@ -277,7 +277,7 @@ func TestNextGeneral(t *testing.T) {
|
||||
{26, 27},
|
||||
{27, 34},
|
||||
}
|
||||
testnext(testcases, "main.testnext", t)
|
||||
testnext("testnextprog", testcases, "main.testnext", t)
|
||||
}
|
||||
|
||||
func TestNextGoroutine(t *testing.T) {
|
||||
@ -285,7 +285,7 @@ func TestNextGoroutine(t *testing.T) {
|
||||
{46, 47},
|
||||
{47, 42},
|
||||
}
|
||||
testnext(testcases, "main.testgoroutine", t)
|
||||
testnext("testnextprog", testcases, "main.testgoroutine", t)
|
||||
}
|
||||
|
||||
func TestNextFunctionReturn(t *testing.T) {
|
||||
@ -293,7 +293,15 @@ func TestNextFunctionReturn(t *testing.T) {
|
||||
{13, 14},
|
||||
{14, 35},
|
||||
}
|
||||
testnext(testcases, "main.helloworld", t)
|
||||
testnext("testnextprog", testcases, "main.helloworld", t)
|
||||
}
|
||||
|
||||
func TestNextFunctionReturnDefer(t *testing.T) {
|
||||
testcases := []nextTest{
|
||||
{5, 9},
|
||||
{9, 6},
|
||||
}
|
||||
testnext("testnextdefer", testcases, "main.main", t)
|
||||
}
|
||||
|
||||
func TestRuntimeBreakpoint(t *testing.T) {
|
||||
|
@ -50,6 +50,9 @@ type G struct {
|
||||
File string
|
||||
Line int
|
||||
Func *gosym.Func
|
||||
|
||||
// PC of entry to top-most deferred function.
|
||||
DeferPC uint64
|
||||
}
|
||||
|
||||
// Returns whether the goroutine is blocked on
|
||||
@ -89,7 +92,7 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) {
|
||||
|
||||
rdr := thread.Process.DwarfReader()
|
||||
rdr.Seek(0)
|
||||
_, err = rdr.SeekToTypeNamed("runtime.g")
|
||||
entry, err := rdr.SeekToTypeNamed("runtime.g")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -97,6 +100,37 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) {
|
||||
// Let's parse all of the members we care about in order so that
|
||||
// we don't have to spend any extra time seeking.
|
||||
|
||||
// Parse defer
|
||||
deferAddr, err := rdr.AddrForMember("_defer", initialInstructions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deferPC uint64
|
||||
// Dereference *defer pointer
|
||||
deferAddrBytes, err := thread.readMemory(uintptr(deferAddr), thread.Process.arch.PtrSize())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error derefing *G %s", err)
|
||||
}
|
||||
if binary.LittleEndian.Uint64(deferAddrBytes) != 0 {
|
||||
initialDeferInstructions := append([]byte{op.DW_OP_addr}, deferAddrBytes...)
|
||||
_, err = rdr.SeekToTypeNamed("runtime._defer")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deferPCAddr, err := rdr.AddrForMember("fn", initialDeferInstructions)
|
||||
deferPC, err = thread.readUintRaw(uintptr(deferPCAddr), 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deferPC, err = thread.readUintRaw(uintptr(deferPC), 8)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = rdr.SeekToEntry(entry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Parse sched
|
||||
schedAddr, err := rdr.AddrForMember("sched", initialInstructions)
|
||||
if err != nil {
|
||||
@ -149,6 +183,7 @@ func parseG(thread *ThreadContext, addr uint64) (*G, error) {
|
||||
Line: l,
|
||||
Func: fn,
|
||||
WaitReason: waitreason,
|
||||
DeferPC: deferPC,
|
||||
}
|
||||
return g, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user