From 07c716818e3bb54956d0f09f7b15d37ff6256ec0 Mon Sep 17 00:00:00 2001 From: aarzilli Date: Fri, 13 Oct 2017 22:13:43 +0200 Subject: [PATCH] proc/test: miscellaneous test changes for go1.10 --- pkg/dwarf/line/line_parser_test.go | 85 ++++++++++++++++-------------- pkg/proc/core/core_test.go | 9 +++- pkg/proc/dwarf_expr_test.go | 2 +- pkg/proc/proc_test.go | 17 ++++-- pkg/proc/stack.go | 21 +++++--- service/test/variables_test.go | 2 +- 6 files changed, 81 insertions(+), 55 deletions(-) diff --git a/pkg/dwarf/line/line_parser_test.go b/pkg/dwarf/line/line_parser_test.go index 4ee83bd3..a5ffdcc1 100644 --- a/pkg/dwarf/line/line_parser_test.go +++ b/pkg/dwarf/line/line_parser_test.go @@ -64,56 +64,59 @@ const ( func testDebugLinePrologueParser(p string, t *testing.T) { data := grabDebugLineSection(p, t) debugLines := ParseAll(data) - dbl := debugLines[0] - prologue := dbl.Prologue - if prologue.Version != uint16(2) { - t.Fatal("Version not parsed correctly", prologue.Version) - } + mainFileFound := false - if prologue.MinInstrLength != uint8(1) { - t.Fatal("Minimun Instruction Length not parsed correctly", prologue.MinInstrLength) - } + for _, dbl := range debugLines { + prologue := dbl.Prologue - if prologue.InitialIsStmt != uint8(1) { - t.Fatal("Initial value of 'is_stmt' not parsed correctly", prologue.InitialIsStmt) - } + if prologue.Version != uint16(2) { + t.Fatal("Version not parsed correctly", prologue.Version) + } - if prologue.LineBase != lineBaseGo14 && prologue.LineBase != lineBaseGo18 { - // go < 1.8 uses -1 - // go >= 1.8 uses -4 - t.Fatal("Line base not parsed correctly", prologue.LineBase) - } + if prologue.MinInstrLength != uint8(1) { + t.Fatal("Minimun Instruction Length not parsed correctly", prologue.MinInstrLength) + } - if prologue.LineRange != lineRangeGo14 && prologue.LineRange != lineRangeGo18 { - // go < 1.8 uses 4 - // go >= 1.8 uses 10 - t.Fatal("Line Range not parsed correctly", prologue.LineRange) - } + if prologue.InitialIsStmt != uint8(1) { + t.Fatal("Initial value of 'is_stmt' not parsed correctly", prologue.InitialIsStmt) + } - if prologue.OpcodeBase != uint8(10) { - t.Fatal("Opcode Base not parsed correctly", prologue.OpcodeBase) - } + if prologue.LineBase != lineBaseGo14 && prologue.LineBase != lineBaseGo18 { + // go < 1.8 uses -1 + // go >= 1.8 uses -4 + t.Fatal("Line base not parsed correctly", prologue.LineBase) + } - lengths := []uint8{0, 1, 1, 1, 1, 0, 0, 0, 1} - for i, l := range prologue.StdOpLengths { - if l != lengths[i] { - t.Fatal("Length not parsed correctly", l) + if prologue.LineRange != lineRangeGo14 && prologue.LineRange != lineRangeGo18 { + // go < 1.8 uses 4 + // go >= 1.8 uses 10 + t.Fatal("Line Range not parsed correctly", prologue.LineRange) + } + + if prologue.OpcodeBase != uint8(10) { + t.Fatal("Opcode Base not parsed correctly", prologue.OpcodeBase) + } + + lengths := []uint8{0, 1, 1, 1, 1, 0, 0, 0, 1} + for i, l := range prologue.StdOpLengths { + if l != lengths[i] { + t.Fatal("Length not parsed correctly", l) + } + } + + if len(dbl.IncludeDirs) != 0 { + t.Fatal("Include dirs not parsed correctly") + } + + for _, n := range dbl.FileNames { + if strings.Contains(n.Path, "/delve/_fixtures/testnextprog.go") { + mainFileFound = true + break + } } } - - if len(dbl.IncludeDirs) != 0 { - t.Fatal("Include dirs not parsed correctly") - } - - ok := false - for _, n := range dbl.FileNames { - if strings.Contains(n.Path, "/delve/_fixtures/testnextprog.go") { - ok = true - break - } - } - if !ok { + if !mainFileFound { t.Fatal("File names table not parsed correctly") } } diff --git a/pkg/proc/core/core_test.go b/pkg/proc/core/core_test.go index 58c7a362..d9b3a51b 100644 --- a/pkg/proc/core/core_test.go +++ b/pkg/proc/core/core_test.go @@ -13,6 +13,7 @@ import ( "strings" "testing" + "github.com/derekparker/delve/pkg/goversion" "github.com/derekparker/delve/pkg/proc" "github.com/derekparker/delve/pkg/proc/test" ) @@ -175,7 +176,7 @@ func TestCore(t *testing.T) { t.Errorf("Stacktrace() on goroutine %v = %v", g, err) } for _, frame := range stack { - if strings.Contains(frame.Current.Fn.Name, "panic") { + if frame.Current.Fn != nil && strings.Contains(frame.Current.Fn.Name, "panic") { panicking = g panickingStack = stack } @@ -218,6 +219,12 @@ func TestCoreFpRegisters(t *testing.T) { if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { return } + // in go1.10 the crash is executed on a different thread and registers are + // no longer available in the core dump. + if ver, _ := goversion.Parse(runtime.Version()); ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { + t.Skip("not supported in go1.10 and later") + } + p := withCoreFile(t, "fputest/", "panic") gs, err := proc.GoroutinesInfo(p) diff --git a/pkg/proc/dwarf_expr_test.go b/pkg/proc/dwarf_expr_test.go index a04cf4c6..8d7568ce 100644 --- a/pkg/proc/dwarf_expr_test.go +++ b/pkg/proc/dwarf_expr_test.go @@ -177,7 +177,7 @@ func TestDwarfExprComposite(t *testing.T) { scope := dwarfExprCheck(t, mem, dwarfRegisters(®s), bi, testCases) thevar, err := scope.EvalExpression("s", normalLoadConfig) - assertNoError(err, t, fmt.Sprintf("EvalExpression(s)", "s")) + assertNoError(err, t, fmt.Sprintf("EvalExpression(%s)", "s")) if thevar.Unreadable != nil { t.Errorf("variable \"s\" unreadable: %v", thevar.Unreadable) } else { diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index 63dcee57..163acd79 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -1686,7 +1686,7 @@ func TestIssue384(t *testing.T) { if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { // go 1.10 emits DW_AT_decl_line and we won't be able to evaluate 'st' // which is declared after line 13. - return + t.Skip("can not evaluate not-yet-declared variables with go 1.10") } protest.AllowRecording(t) @@ -2140,7 +2140,7 @@ func TestStepReturnAndPanic(t *testing.T) { // Tests that Step works correctly when returning from functions // and when a deferred function is called when panic'ing. ver, _ := goversion.Parse(runtime.Version()) - if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) { + if ver.Major > 0 && ver.AfterOrEqual(goversion.GoVersion{1, 9, -1, 0, 0, ""}) && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { testseq("defercall", contStep, []nextTest{ {17, 5}, {5, 6}, @@ -2184,7 +2184,7 @@ func TestStepIgnorePrivateRuntime(t *testing.T) { // (such as runtime.convT2E in this case) ver, _ := goversion.Parse(runtime.Version()) - if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 7, -1, 0, 0, ""}) { + if ver.Major > 0 && ver.AfterOrEqual(goversion.GoVersion{1, 7, -1, 0, 0, ""}) && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { testseq("teststepprog", contStep, []nextTest{ {21, 13}, {13, 14}, @@ -2192,6 +2192,12 @@ func TestStepIgnorePrivateRuntime(t *testing.T) { {15, 14}, {14, 17}, {17, 22}}, "", t) + } else if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { + testseq("teststepprog", contStep, []nextTest{ + {21, 13}, + {13, 14}, + {14, 15}, + {15, 22}}, "", t) } else { testseq("teststepprog", contStep, []nextTest{ {21, 13}, @@ -2933,7 +2939,7 @@ func TestIssue877(t *testing.T) { func TestIssue893(t *testing.T) { // Test what happens when next is called immediately after launching the // executable, acceptable behaviors are: (a) no error, (b) no source at PC - // error. + // error, (c) program runs to completion protest.AllowRecording(t) withTestProcess("increment", t, func(p proc.Process, fixture protest.Fixture) { err := proc.Next(p) @@ -2949,6 +2955,9 @@ func TestIssue893(t *testing.T) { if _, ok := err.(*proc.NoSourceForPCError); ok { return } + if _, ok := err.(proc.ProcessExitedError); ok { + return + } assertNoError(err, t, "Next") }) } diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go index 249ca2b8..55ccd30a 100644 --- a/pkg/proc/stack.go +++ b/pkg/proc/stack.go @@ -182,11 +182,6 @@ func (it *stackIterator) Next() bool { callFrameRegs, ret, retaddr := it.advanceRegs() it.frame = it.newStackframe(ret, retaddr) - if it.frame.Ret <= 0 { - it.atend = true - return true - } - if it.stkbar != nil && it.frame.Ret == it.stackBarrierPC && it.frame.addrret == it.stkbar[0].ptr { // Skip stack barrier frames it.frame.Ret = it.stkbar[0].val @@ -197,6 +192,11 @@ func (it *stackIterator) Next() bool { return true } + if it.frame.Ret <= 0 { + it.atend = true + return true + } + it.top = false it.pc = it.frame.Ret it.regs = callFrameRegs @@ -221,7 +221,10 @@ func (it *stackIterator) switchStack() bool { return false } - // switch from system stack to goroutine stack + // This function is called by a goroutine to execute a C function and + // switches from the goroutine stack to the system stack. + // Since we are unwinding the stack from callee to caller we have switch + // from the system stack to the goroutine stack. off, _ := readIntRaw(it.mem, uintptr(it.regs.SP()+asmcgocallSPOffsetSaveSlot), int64(it.bi.Arch.PtrSize())) // reads "offset of SP from StackHi" from where runtime.asmcgocall saved it oldsp := it.regs.SP() @@ -242,7 +245,7 @@ func (it *stackIterator) switchStack() bool { it.top = false return true - case "runtime.mstart": + case "runtime.mstart", "runtime.sigtramp": if it.top || !it.systemstack || it.g == nil { return false } @@ -255,6 +258,10 @@ func (it *stackIterator) switchStack() bool { // If we find a runtime.mstart frame on the system stack of a goroutine // parked on runtime.systemstack_switch we assume runtime.systemstack was // called and continue tracing from the parked position. + // + // OS Signals are processed on a special signal handling stack that works + // similarly to the system stack, runtime.sigtramp is at the bottom of + // this stack. if fn := it.bi.PCToFunc(it.g.PC); fn == nil || fn.Name != "runtime.systemstack_switch" { return false diff --git a/service/test/variables_test.go b/service/test/variables_test.go index ddb55d55..dff8d8b4 100644 --- a/service/test/variables_test.go +++ b/service/test/variables_test.go @@ -965,7 +965,7 @@ func TestConstants(t *testing.T) { ver, _ := goversion.Parse(runtime.Version()) if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{1, 10, -1, 0, 0, ""}) { // Not supported on 1.9 or earlier - return + t.Skip("constants added in go 1.10") } withTestProcess("consts", t, func(p proc.Process, fixture protest.Fixture) { assertNoError(proc.Continue(p), t, "Continue")