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

import (
4
	"bytes"
5 6 7
	"encoding/binary"
	"os"
	"os/exec"
8
	"path/filepath"
9
	"runtime"
D
Derek Parker 已提交
10
	"testing"
D
Derek Parker 已提交
11
)
12

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
func withTestProcess(name string, t *testing.T, fn func(p *DebuggedProcess)) {
	runtime.LockOSThread()
	base := filepath.Base(name)
	if err := exec.Command("go", "build", "-gcflags=-N -l", "-o", base, name+".go").Run(); err != nil {
		t.Fatalf("Could not compile %s due to %s", name, err)
	}
	defer os.Remove("./" + base)

	p, err := Launch([]string{"./" + base})
	if err != nil {
		t.Fatal("Launch():", err)
	}

	defer p.Process.Kill()

	fn(p)
}

func getRegisters(p *DebuggedProcess, t *testing.T) Registers {
32 33 34 35 36 37 38 39
	regs, err := p.Registers()
	if err != nil {
		t.Fatal("Registers():", err)
	}

	return regs
}

D
Derek Parker 已提交
40
func dataAtAddr(thread *ThreadContext, addr uint64) ([]byte, error) {
41
	data := make([]byte, 1)
D
Derek Parker 已提交
42
	_, err := readMemory(thread, uintptr(addr), data)
43 44 45 46 47 48 49
	if err != nil {
		return nil, err
	}

	return data, nil
}

50 51
func assertNoError(err error, t *testing.T, s string) {
	if err != nil {
52 53 54
		_, file, line, _ := runtime.Caller(1)
		fname := filepath.Base(file)
		t.Fatalf("failed assertion at %s:%d: %s : %s\n", fname, line, s, err)
55 56 57
	}
}

58
func currentPC(p *DebuggedProcess, t *testing.T) uint64 {
59 60 61 62 63 64 65 66
	pc, err := p.CurrentPC()
	if err != nil {
		t.Fatal(err)
	}

	return pc
}

67
func currentLineNumber(p *DebuggedProcess, t *testing.T) (string, int) {
68
	pc := currentPC(p, t)
D
Derek Parker 已提交
69
	f, l, _ := p.GoSymTable.PCToLine(pc)
70

D
Derek Parker 已提交
71
	return f, l
72 73
}

74
func TestStep(t *testing.T) {
75
	withTestProcess("../_fixtures/testprog", t, func(p *DebuggedProcess) {
76 77 78
		helloworldfunc := p.GoSymTable.LookupFunc("main.helloworld")
		helloworldaddr := helloworldfunc.Entry

79
		_, err := p.Break(helloworldaddr)
80 81 82
		assertNoError(err, t, "Break()")
		assertNoError(p.Continue(), t, "Continue()")

83
		regs := getRegisters(p, t)
84
		rip := regs.PC()
85

86
		err = p.Step()
D
Derek Parker 已提交
87
		assertNoError(err, t, "Step()")
88

89
		regs = getRegisters(p, t)
90 91 92 93 94
		if rip >= regs.PC() {
			t.Errorf("Expected %#v to be greater than %#v", regs.PC(), rip)
		}
	})
}
95

96
func TestBreakPoint(t *testing.T) {
97
	withTestProcess("../_fixtures/testprog", t, func(p *DebuggedProcess) {
D
Derek Parker 已提交
98 99
		helloworldfunc := p.GoSymTable.LookupFunc("main.helloworld")
		helloworldaddr := helloworldfunc.Entry
100

D
Derek Parker 已提交
101
		bp, err := p.Break(helloworldaddr)
D
Derek Parker 已提交
102
		assertNoError(err, t, "Break()")
D
Derek Parker 已提交
103
		assertNoError(p.Continue(), t, "Continue()")
104

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

D
Derek Parker 已提交
110
		if pc-1 != bp.Addr {
111
			f, l, _ := p.GoSymTable.PCToLine(pc)
D
Derek Parker 已提交
112
			t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, bp.Addr)
113 114
		}
	})
115
}
116

117
func TestBreakPointInSeperateGoRoutine(t *testing.T) {
118
	withTestProcess("../_fixtures/testthreads", t, func(p *DebuggedProcess) {
119 120 121 122 123
		fn := p.GoSymTable.LookupFunc("main.anotherthread")
		if fn == nil {
			t.Fatal("No fn exists")
		}

124
		_, err := p.Break(fn.Entry)
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
		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")
		}
	})
}

146
func TestBreakPointWithNonExistantFunction(t *testing.T) {
147
	withTestProcess("../_fixtures/testprog", t, func(p *DebuggedProcess) {
148
		_, err := p.Break(0)
149 150 151 152
		if err == nil {
			t.Fatal("Should not be able to break at non existant function")
		}
	})
153
}
154 155

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

		bp, err = p.Clear(fn.Entry)
D
Derek Parker 已提交
162
		assertNoError(err, t, "Clear()")
163

D
Derek Parker 已提交
164
		data, err := dataAtAddr(p.CurrentThread, bp.Addr)
165 166 167 168
		if err != nil {
			t.Fatal(err)
		}

169
		int3 := []byte{0xcc}
170 171 172 173
		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
	withTestProcess(executablePath, t, func(p *DebuggedProcess) {
215
		pc, _, _ := p.GoSymTable.LineToPC(fp, testcases[0].begin)
216
		_, err := p.Break(pc)
217 218
		assertNoError(err, t, "Break()")
		assertNoError(p.Continue(), t, "Continue()")
219

D
Derek Parker 已提交
220
		f, ln := currentLineNumber(p, t)
221 222
		for _, tc := range testcases {
			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 235 236 237 238 239 240 241
		p.Clear(pc)
		if len(p.BreakPoints) != 0 {
			t.Fatal("Not all breakpoints were cleaned up", len(p.HWBreakPoints))
		}
		for _, bp := range p.HWBreakPoints {
			if bp != nil {
				t.Fatal("Not all breakpoints were cleaned up", bp.Addr)
			}
242
		}
243 244
	})
}
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260

func TestFindReturnAddress(t *testing.T) {
	var testfile, _ = filepath.Abs("../_fixtures/testnextprog")

	withTestProcess(testfile, t, func(p *DebuggedProcess) {
		var (
			fdes = p.FrameEntries
			gsd  = p.GoSymTable
		)

		testsourcefile := testfile + ".go"
		start, _, err := gsd.LineToPC(testsourcefile, 24)
		if err != nil {
			t.Fatal(err)
		}

261
		_, err = p.Break(start)
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
		if err != nil {
			t.Fatal(err)
		}

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

		regs, err := p.Registers()
		if err != nil {
			t.Fatal(err)
		}

		fde, err := fdes.FDEForPC(start)
		if err != nil {
			t.Fatal(err)
		}

		ret := fde.ReturnAddressOffset(start)
		if err != nil {
			t.Fatal(err)
		}

		addr := uint64(int64(regs.SP()) + ret)
		data := make([]byte, 8)

D
Derek Parker 已提交
289
		readMemory(p.CurrentThread, uintptr(addr), data)
290 291
		addr = binary.LittleEndian.Uint64(data)

D
Derek Parker 已提交
292 293 294 295
		linuxExpected := uint64(0x400fbc)
		darwinExpected := uint64(0x23bc)
		if addr != linuxExpected && addr != darwinExpected {
			t.Fatalf("return address not found correctly, expected (linux) %#v or (darwin) %#v got %#v", linuxExpected, darwinExpected, addr)
296 297 298
		}
	})
}