proctl_test.go 5.0 KB
Newer Older
D
Derek Parker 已提交
1
package proctl_test
D
Derek Parker 已提交
2 3

import (
4
	"bytes"
5
	"path/filepath"
6
	"syscall"
D
Derek Parker 已提交
7 8
	"testing"

D
Derek Parker 已提交
9 10
	"github.com/derekparker/delve/helper"
	"github.com/derekparker/delve/proctl"
D
Derek Parker 已提交
11
)
12

13 14 15 16 17 18 19 20 21 22
func dataAtAddr(pid int, addr uint64) ([]byte, error) {
	data := make([]byte, 1)
	_, err := syscall.PtracePeekData(pid, uintptr(addr), data)
	if err != nil {
		return nil, err
	}

	return data, nil
}

23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
func assertNoError(err error, t *testing.T, s string) {
	if err != nil {
		t.Fatal(s, ":", err)
	}
}

func currentPC(p *proctl.DebuggedProcess, t *testing.T) uint64 {
	pc, err := p.CurrentPC()
	if err != nil {
		t.Fatal(err)
	}

	return pc
}

D
Derek Parker 已提交
38
func currentLineNumber(p *proctl.DebuggedProcess, t *testing.T) (string, int) {
39
	pc := currentPC(p, t)
D
Derek Parker 已提交
40
	f, l, _ := p.GoSymTable.PCToLine(pc)
41

D
Derek Parker 已提交
42
	return f, l
43 44
}

45
func TestStep(t *testing.T) {
46
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
D
Derek Parker 已提交
47
		regs := helper.GetRegisters(p, t)
48
		rip := regs.PC()
49

50
		err := p.Step()
D
Derek Parker 已提交
51
		assertNoError(err, t, "Step()")
52

D
Derek Parker 已提交
53
		regs = helper.GetRegisters(p, t)
54 55 56 57 58
		if rip >= regs.PC() {
			t.Errorf("Expected %#v to be greater than %#v", regs.PC(), rip)
		}
	})
}
59

60
func TestContinue(t *testing.T) {
61
	helper.WithTestProcess("../_fixtures/continuetestprog", t, func(p *proctl.DebuggedProcess) {
62
		err := p.Continue()
63 64 65 66 67
		if err != nil {
			if _, ok := err.(proctl.ProcessExitedError); !ok {
				t.Fatal(err)
			}
		}
68

69 70
		if p.Status().ExitStatus() != 0 {
			t.Fatal("Process did not exit successfully", p.Status().ExitStatus())
71 72
		}
	})
73
}
74 75

func TestBreakPoint(t *testing.T) {
76
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
77
		sleepytimefunc := p.GoSymTable.LookupFunc("main.helloworld")
78 79 80
		sleepyaddr := sleepytimefunc.Entry

		bp, err := p.Break(uintptr(sleepyaddr))
D
Derek Parker 已提交
81
		assertNoError(err, t, "Break()")
82 83 84

		breakpc := bp.Addr + 1
		err = p.Continue()
D
Derek Parker 已提交
85
		assertNoError(err, t, "Continue()")
86

87 88 89 90
		pc, err := p.CurrentPC()
		if err != nil {
			t.Fatal(err)
		}
91 92

		if pc != breakpc {
93 94
			f, l, _ := p.GoSymTable.PCToLine(pc)
			t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, breakpc)
95 96 97
		}

		err = p.Step()
D
Derek Parker 已提交
98 99 100
		if _, ok := err.(proctl.TimeoutError); !ok {
			assertNoError(err, t, "Step()")
		}
101

102 103 104 105
		pc, err = p.CurrentPC()
		if err != nil {
			t.Fatal(err)
		}
106 107 108 109 110

		if pc == breakpc {
			t.Fatalf("Step not respected:\nPC:%d\nFN:%d\n", pc, breakpc)
		}
	})
111
}
112

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
func TestBreakPointInSeperateGoRoutine(t *testing.T) {
	helper.WithTestProcess("../_fixtures/testthreads", t, func(p *proctl.DebuggedProcess) {
		fn := p.GoSymTable.LookupFunc("main.anotherthread")
		if fn == nil {
			t.Fatal("No fn exists")
		}

		_, err := p.Break(uintptr(fn.Entry))
		if err != nil {
			t.Fatal(err)
		}

		err = p.Continue()
		if err != nil {
			t.Fatal(err)
		}

		pc, err := p.CurrentPC()
		if err != nil {
			t.Fatal(err)
		}

		f, l, _ := p.GoSymTable.PCToLine(pc)
		if f != "testthreads.go" && l != 8 {
			t.Fatal("Program did not hit breakpoint")
		}
	})
}

142
func TestBreakPointWithNonExistantFunction(t *testing.T) {
143
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
144 145 146 147 148
		_, err := p.Break(uintptr(0))
		if err == nil {
			t.Fatal("Should not be able to break at non existant function")
		}
	})
149
}
150 151

func TestClearBreakPoint(t *testing.T) {
152
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
153 154
		fn := p.GoSymTable.LookupFunc("main.sleepytime")
		bp, err := p.Break(uintptr(fn.Entry))
D
Derek Parker 已提交
155
		assertNoError(err, t, "Break()")
156 157 158 159 160 161 162

		int3, err := dataAtAddr(p.Pid, bp.Addr)
		if err != nil {
			t.Fatal(err)
		}

		bp, err = p.Clear(fn.Entry)
D
Derek Parker 已提交
163
		assertNoError(err, t, "Clear()")
164 165 166 167 168 169 170 171 172 173

		data, err := dataAtAddr(p.Pid, bp.Addr)
		if err != nil {
			t.Fatal(err)
		}

		if bytes.Equal(data, int3) {
			t.Fatalf("Breakpoint was not cleared data: %#v, int3: %#v", data, int3)
		}

174
		if len(p.BreakPoints) != 0 {
175 176 177
			t.Fatal("Breakpoint not removed internally")
		}
	})
178
}
179 180 181

func TestNext(t *testing.T) {
	var (
182 183
		err            error
		executablePath = "../_fixtures/testnextprog"
184 185 186 187 188
	)

	testcases := []struct {
		begin, end int
	}{
D
Derek Parker 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
		{19, 20},
		{20, 23},
		{23, 24},
		{24, 26},
		{26, 31},
		{31, 23},
		{23, 24},
		{24, 26},
		{26, 31},
		{31, 23},
		{23, 24},
		{24, 26},
		{26, 27},
		{27, 34},
		{34, 35},
D
Derek Parker 已提交
204
		{35, 41},
205
		{41, 40},
D
Derek Parker 已提交
206
		{40, 41},
207 208 209 210 211 212 213
	}

	fp, err := filepath.Abs("../_fixtures/testnextprog.go")
	if err != nil {
		t.Fatal(err)
	}

214
	helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) {
215
		pc, _, _ := p.GoSymTable.LineToPC(fp, testcases[0].begin)
D
Derek Parker 已提交
216
		_, err := p.Break(uintptr(pc))
217 218
		assertNoError(err, t, "Break()")
		assertNoError(p.Continue(), t, "Continue()")
219 220

		for _, tc := range testcases {
D
Derek Parker 已提交
221
			f, ln := currentLineNumber(p, t)
222
			if ln != tc.begin {
D
Derek Parker 已提交
223
				t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, f, ln)
224 225 226 227
			}

			assertNoError(p.Next(), t, "Next() returned an error")

D
Derek Parker 已提交
228
			f, ln = currentLineNumber(p, t)
229
			if ln != tc.end {
D
Derek Parker 已提交
230
				t.Fatalf("Program did not continue to correct next location expected %d was %s:%d", tc.end, f, ln)
231 232
			}
		}
233

234
		if len(p.BreakPoints) != 1 {
D
Derek Parker 已提交
235
			t.Fatal("Not all breakpoints were cleaned up", len(p.BreakPoints))
236
		}
237 238
	})
}