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

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

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

12 13 14 15 16 17 18 19 20
func getRegisters(p *proctl.DebuggedProcess, t *testing.T) proctl.Registers {
	regs, err := p.Registers()
	if err != nil {
		t.Fatal("Registers():", err)
	}

	return regs
}

21 22
func dataAtAddr(pid int, addr uint64) ([]byte, error) {
	data := make([]byte, 1)
D
Derek Parker 已提交
23
	_, err := proctl.ReadMemory(pid, uintptr(addr), data)
24 25 26 27 28 29 30
	if err != nil {
		return nil, err
	}

	return data, nil
}

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
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 已提交
46
func currentLineNumber(p *proctl.DebuggedProcess, t *testing.T) (string, int) {
47
	pc := currentPC(p, t)
D
Derek Parker 已提交
48
	f, l, _ := p.GoSymTable.PCToLine(pc)
49

D
Derek Parker 已提交
50
	return f, l
51 52
}

53
func TestStep(t *testing.T) {
54
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
55 56 57 58 59 60 61
		helloworldfunc := p.GoSymTable.LookupFunc("main.helloworld")
		helloworldaddr := helloworldfunc.Entry

		_, err := p.Break(uintptr(helloworldaddr))
		assertNoError(err, t, "Break()")
		assertNoError(p.Continue(), t, "Continue()")

62
		regs := getRegisters(p, t)
63
		rip := regs.PC()
64

65
		err = p.Step()
D
Derek Parker 已提交
66
		assertNoError(err, t, "Step()")
67

68
		regs = getRegisters(p, t)
69 70 71 72 73
		if rip >= regs.PC() {
			t.Errorf("Expected %#v to be greater than %#v", regs.PC(), rip)
		}
	})
}
74

75
func TestContinue(t *testing.T) {
76
	helper.WithTestProcess("../_fixtures/continuetestprog", t, func(p *proctl.DebuggedProcess) {
77
		err := p.Continue()
78 79 80 81 82
		if err != nil {
			if _, ok := err.(proctl.ProcessExitedError); !ok {
				t.Fatal(err)
			}
		}
83

84 85
		if p.Status().ExitStatus() != 0 {
			t.Fatal("Process did not exit successfully", p.Status().ExitStatus())
86 87
		}
	})
88
}
89 90

func TestBreakPoint(t *testing.T) {
91
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
92
		sleepytimefunc := p.GoSymTable.LookupFunc("main.helloworld")
93 94 95
		sleepyaddr := sleepytimefunc.Entry

		bp, err := p.Break(uintptr(sleepyaddr))
D
Derek Parker 已提交
96
		assertNoError(err, t, "Break()")
97 98 99

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

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

		if pc != breakpc {
108 109
			f, l, _ := p.GoSymTable.PCToLine(pc)
			t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, breakpc)
110 111 112
		}

		err = p.Step()
113
		assertNoError(err, t, "Step()")
114

115 116 117 118
		pc, err = p.CurrentPC()
		if err != nil {
			t.Fatal(err)
		}
119 120 121 122 123

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

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
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")
		}
	})
}

155
func TestBreakPointWithNonExistantFunction(t *testing.T) {
156
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
157 158 159 160 161
		_, err := p.Break(uintptr(0))
		if err == nil {
			t.Fatal("Should not be able to break at non existant function")
		}
	})
162
}
163 164

func TestClearBreakPoint(t *testing.T) {
165
	helper.WithTestProcess("../_fixtures/testprog", t, func(p *proctl.DebuggedProcess) {
166 167
		fn := p.GoSymTable.LookupFunc("main.sleepytime")
		bp, err := p.Break(uintptr(fn.Entry))
D
Derek Parker 已提交
168
		assertNoError(err, t, "Break()")
169 170 171 172 173 174 175

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

		bp, err = p.Clear(fn.Entry)
D
Derek Parker 已提交
176
		assertNoError(err, t, "Clear()")
177 178 179 180 181 182 183 184 185 186

		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)
		}

187
		if len(p.BreakPoints) != 0 {
188 189 190
			t.Fatal("Breakpoint not removed internally")
		}
	})
191
}
192 193 194

func TestNext(t *testing.T) {
	var (
195 196
		err            error
		executablePath = "../_fixtures/testnextprog"
197 198 199 200 201
	)

	testcases := []struct {
		begin, end int
	}{
D
Derek Parker 已提交
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
		{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 已提交
217
		{35, 41},
218
		{41, 40},
D
Derek Parker 已提交
219
		{40, 41},
220 221 222 223 224 225 226
	}

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

227
	helper.WithTestProcess(executablePath, t, func(p *proctl.DebuggedProcess) {
228
		pc, _, _ := p.GoSymTable.LineToPC(fp, testcases[0].begin)
D
Derek Parker 已提交
229
		_, err := p.Break(uintptr(pc))
230 231
		assertNoError(err, t, "Break()")
		assertNoError(p.Continue(), t, "Continue()")
232 233

		for _, tc := range testcases {
D
Derek Parker 已提交
234
			f, ln := currentLineNumber(p, t)
235
			if ln != tc.begin {
D
Derek Parker 已提交
236
				t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, f, ln)
237 238 239 240
			}

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

D
Derek Parker 已提交
241
			f, ln = currentLineNumber(p, t)
242
			if ln != tc.end {
D
Derek Parker 已提交
243
				t.Fatalf("Program did not continue to correct next location expected %d was %s:%d", tc.end, f, ln)
244 245
			}
		}
246

247
		if len(p.BreakPoints) != 1 {
D
Derek Parker 已提交
248
			t.Fatal("Not all breakpoints were cleaned up", len(p.BreakPoints))
249
		}
250 251
	})
}