integration1_test.go 31.3 KB
Newer Older
1
package service_test
D
Dan Mace 已提交
2 3

import (
A
aarzilli 已提交
4
	"fmt"
5
	"math/rand"
D
Dan Mace 已提交
6
	"net"
7
	"path/filepath"
8
	"runtime"
A
aarzilli 已提交
9
	"strconv"
L
Luke Hoban 已提交
10
	"strings"
D
Dan Mace 已提交
11
	"testing"
12
	"time"
D
Dan Mace 已提交
13

14
	protest "github.com/go-delve/delve/pkg/proc/test"
15
	"github.com/go-delve/delve/service/debugger"
D
Derek Parker 已提交
16

17 18 19 20 21
	"github.com/go-delve/delve/pkg/goversion"
	"github.com/go-delve/delve/service"
	"github.com/go-delve/delve/service/api"
	"github.com/go-delve/delve/service/rpc1"
	"github.com/go-delve/delve/service/rpccommon"
D
Dan Mace 已提交
22 23
)

24
func withTestClient1(name string, t *testing.T, fn func(c *rpc1.RPCClient)) {
25 26 27 28 29 30
	withTestClient1Extended(name, t, func(c *rpc1.RPCClient, fixture protest.Fixture) {
		fn(c)
	})
}

func withTestClient1Extended(name string, t *testing.T, fn func(c *rpc1.RPCClient, fixture protest.Fixture)) {
31 32 33
	if testBackend == "rr" {
		protest.MustHaveRecordingAllowed(t)
	}
34
	listener, err := net.Listen("tcp", "127.0.0.1:0")
D
Dan Mace 已提交
35 36 37
	if err != nil {
		t.Fatalf("couldn't start listener: %s\n", err)
	}
D
Derek Parker 已提交
38
	defer listener.Close()
39 40 41 42 43
	var buildFlags protest.BuildFlags
	if buildMode == "pie" {
		buildFlags = protest.BuildModePIE
	}
	fixture := protest.BuildFixture(name, buildFlags)
A
aarzilli 已提交
44
	server := rpccommon.NewServer(&service.Config{
45
		Listener:    listener,
46
		ProcessArgs: []string{fixture.Path},
47 48 49
		Debugger: debugger.Config{
			Backend: testBackend,
		},
D
Derek Parker 已提交
50
	})
51 52 53
	if err := server.Run(); err != nil {
		t.Fatal(err)
	}
54
	client := rpc1.NewClient(listener.Addr().String())
55 56 57 58
	defer func() {
		client.Detach(true)
	}()

59
	fn(client, fixture)
D
Dan Mace 已提交
60 61
}

62
func Test1RunWithInvalidPath(t *testing.T) {
63 64 65 66 67 68
	if testBackend == "rr" {
		// This test won't work because rr returns an error, after recording, when
		// the recording failed but also when the recording succeeded but the
		// inferior returned an error. Therefore we have to ignore errors from rr.
		return
	}
69
	listener, err := net.Listen("tcp", "127.0.0.1:0")
70 71 72 73
	if err != nil {
		t.Fatalf("couldn't start listener: %s\n", err)
	}
	defer listener.Close()
A
aarzilli 已提交
74
	server := rpccommon.NewServer(&service.Config{
75 76
		Listener:    listener,
		ProcessArgs: []string{"invalid_path"},
77 78 79
		Debugger: debugger.Config{
			Backend: testBackend,
		},
D
Derek Parker 已提交
80
	})
81 82 83 84 85
	if err := server.Run(); err == nil {
		t.Fatal("Expected Run to return error for invalid program path")
	}
}

86
func Test1Restart_afterExit(t *testing.T) {
87
	withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) {
D
Derek Parker 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100
		origPid := c.ProcessPid()
		state := <-c.Continue()
		if !state.Exited {
			t.Fatal("expected initial process to have exited")
		}
		if err := c.Restart(); err != nil {
			t.Fatal(err)
		}
		if c.ProcessPid() == origPid {
			t.Fatal("did not spawn new process, has same PID")
		}
		state = <-c.Continue()
		if !state.Exited {
101
			t.Fatalf("expected restarted process to have exited %v", state)
D
Derek Parker 已提交
102 103 104 105
		}
	})
}

106
func Test1Restart_breakpointPreservation(t *testing.T) {
107
	withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) {
108 109 110
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint", Tracepoint: true})
		assertNoError(err, t, "CreateBreakpoint()")
		stateCh := c.Continue()
A
aarzilli 已提交
111 112

		state := <-stateCh
113 114 115
		if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint {
			t.Fatalf("Wrong breakpoint: %#v\n", state.CurrentThread.Breakpoint)
		}
A
aarzilli 已提交
116
		state = <-stateCh
117 118 119
		if !state.Exited {
			t.Fatal("Did not exit after first tracepoint")
		}
A
aarzilli 已提交
120

121 122 123
		t.Log("Restart")
		c.Restart()
		stateCh = c.Continue()
A
aarzilli 已提交
124
		state = <-stateCh
125 126 127
		if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint {
			t.Fatalf("Wrong breakpoint (after restart): %#v\n", state.CurrentThread.Breakpoint)
		}
A
aarzilli 已提交
128
		state = <-stateCh
129 130 131 132 133 134
		if !state.Exited {
			t.Fatal("Did not exit after first tracepoint (after restart)")
		}
	})
}

135
func Test1Restart_duringStop(t *testing.T) {
136
	withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) {
D
Derek Parker 已提交
137
		origPid := c.ProcessPid()
138
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1})
D
Derek Parker 已提交
139 140 141 142
		if err != nil {
			t.Fatal(err)
		}
		state := <-c.Continue()
143
		if state.CurrentThread.Breakpoint == nil {
D
Derek Parker 已提交
144 145 146 147 148 149 150 151 152 153 154 155
			t.Fatal("did not hit breakpoint")
		}
		if err := c.Restart(); err != nil {
			t.Fatal(err)
		}
		if c.ProcessPid() == origPid {
			t.Fatal("did not spawn new process, has same PID")
		}
		bps, err := c.ListBreakpoints()
		if err != nil {
			t.Fatal(err)
		}
156 157
		if len(bps) == 0 {
			t.Fatal("breakpoints not preserved")
D
Derek Parker 已提交
158 159 160 161
		}
	})
}

162
func Test1ClientServer_exit(t *testing.T) {
163
	withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) {
D
Dan Mace 已提交
164 165 166 167 168 169 170
		state, err := c.GetState()
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if e, a := false, state.Exited; e != a {
			t.Fatalf("Expected exited %v, got %v", e, a)
		}
A
aarzilli 已提交
171
		state = <-c.Continue()
172 173
		if state.Err == nil {
			t.Fatalf("Error expected after continue")
D
Derek Parker 已提交
174
		}
A
aarzilli 已提交
175 176
		if !state.Exited {
			t.Fatalf("Expected exit after continue: %v", state)
D
Derek Parker 已提交
177
		}
178
		_, err = c.GetState()
179 180
		if err == nil {
			t.Fatal("Expected error on querying state from exited process")
D
Dan Mace 已提交
181 182 183 184
		}
	})
}

185
func Test1ClientServer_step(t *testing.T) {
186
	withTestClient1("testprog", t, func(c *rpc1.RPCClient) {
187
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.helloworld", Line: -1})
D
Dan Mace 已提交
188 189 190 191
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

D
Derek Parker 已提交
192
		stateBefore := <-c.Continue()
A
aarzilli 已提交
193 194
		if stateBefore.Err != nil {
			t.Fatalf("Unexpected error: %v", stateBefore.Err)
D
Dan Mace 已提交
195 196 197 198 199 200 201 202
		}

		stateAfter, err := c.Step()
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if before, after := stateBefore.CurrentThread.PC, stateAfter.CurrentThread.PC; before >= after {
C
chainhelen 已提交
203
			t.Fatalf("Expected %#v to be greater than %#v", after, before)
D
Dan Mace 已提交
204 205 206 207 208
		}
	})
}

func testnext(testcases []nextTest, initialLocation string, t *testing.T) {
209
	withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) {
210
		bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: initialLocation, Line: -1})
D
Dan Mace 已提交
211 212 213 214
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

A
aarzilli 已提交
215 216 217
		state := <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Unexpected error: %v", state.Err)
D
Dan Mace 已提交
218 219
		}

D
Derek Parker 已提交
220
		_, err = c.ClearBreakpoint(bp.ID)
D
Dan Mace 已提交
221 222 223 224 225 226
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		for _, tc := range testcases {
			if state.CurrentThread.Line != tc.begin {
D
Dan Mace 已提交
227
				t.Fatalf("Program not stopped at correct spot expected %d was %d", tc.begin, state.CurrentThread.Line)
D
Dan Mace 已提交
228 229 230 231 232 233 234 235 236
			}

			t.Logf("Next for scenario %#v", tc)
			state, err = c.Next()
			if err != nil {
				t.Fatalf("Unexpected error: %v", err)
			}

			if state.CurrentThread.Line != tc.end {
D
Dan Mace 已提交
237
				t.Fatalf("Program did not continue to correct next location expected %d was %d", tc.end, state.CurrentThread.Line)
D
Dan Mace 已提交
238 239 240 241 242
			}
		}
	})
}

243
func Test1NextGeneral(t *testing.T) {
244 245
	var testcases []nextTest

246
	ver, _ := goversion.Parse(runtime.Version())
247

D
Derek Parker 已提交
248
	if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) {
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
		testcases = []nextTest{
			{17, 19},
			{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, 28},
			{28, 34},
		}
	} else {
		testcases = []nextTest{
			{17, 19},
			{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},
		}
D
Dan Mace 已提交
285
	}
286

D
Dan Mace 已提交
287 288 289
	testnext(testcases, "main.testnext", t)
}

290
func Test1NextFunctionReturn(t *testing.T) {
D
Dan Mace 已提交
291
	testcases := []nextTest{
292
		{13, 14},
D
Derek Parker 已提交
293 294
		{14, 15},
		{15, 35},
D
Dan Mace 已提交
295 296 297 298
	}
	testnext(testcases, "main.helloworld", t)
}

299
func Test1ClientServer_breakpointInMainThread(t *testing.T) {
300
	withTestClient1("testprog", t, func(c *rpc1.RPCClient) {
301
		bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.helloworld", Line: 1})
D
Dan Mace 已提交
302 303 304 305
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

A
aarzilli 已提交
306
		state := <-c.Continue()
D
Dan Mace 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319
		if err != nil {
			t.Fatalf("Unexpected error: %v, state: %#v", err, state)
		}

		pc := state.CurrentThread.PC

		if pc-1 != bp.Addr && pc != bp.Addr {
			f, l := state.CurrentThread.File, state.CurrentThread.Line
			t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, bp.Addr)
		}
	})
}

320
func Test1ClientServer_breakpointInSeparateGoroutine(t *testing.T) {
321
	withTestClient1("testthreads", t, func(c *rpc1.RPCClient) {
322
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.anotherthread", Line: 1})
D
Dan Mace 已提交
323 324 325 326
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

A
aarzilli 已提交
327 328 329
		state := <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state)
D
Dan Mace 已提交
330 331 332
		}

		f, l := state.CurrentThread.File, state.CurrentThread.Line
333
		if f != "testthreads.go" && l != 9 {
D
Dan Mace 已提交
334 335 336 337 338
			t.Fatal("Program did not hit breakpoint")
		}
	})
}

339
func Test1ClientServer_breakAtNonexistentPoint(t *testing.T) {
340
	withTestClient1("testprog", t, func(c *rpc1.RPCClient) {
341
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "nowhere", Line: 1})
D
Dan Mace 已提交
342 343 344 345 346 347
		if err == nil {
			t.Fatal("Should not be able to break at non existent function")
		}
	})
}

348
func Test1ClientServer_clearBreakpoint(t *testing.T) {
349
	withTestClient1("testprog", t, func(c *rpc1.RPCClient) {
350
		bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sleepytime", Line: 1})
D
Dan Mace 已提交
351 352 353 354
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

355
		if e, a := 1, countBreakpoints(t, c); e != a {
D
Dan Mace 已提交
356 357 358
			t.Fatalf("Expected breakpoint count %d, got %d", e, a)
		}

D
Derek Parker 已提交
359
		deleted, err := c.ClearBreakpoint(bp.ID)
D
Dan Mace 已提交
360 361 362 363 364 365 366 367
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}

		if deleted.ID != bp.ID {
			t.Fatalf("Expected deleted breakpoint ID %v, got %v", bp.ID, deleted.ID)
		}

368
		if e, a := 0, countBreakpoints(t, c); e != a {
D
Dan Mace 已提交
369 370 371 372 373
			t.Fatalf("Expected breakpoint count %d, got %d", e, a)
		}
	})
}

374
func Test1ClientServer_switchThread(t *testing.T) {
375
	withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) {
D
Dan Mace 已提交
376 377 378 379 380 381
		// With invalid thread id
		_, err := c.SwitchThread(-1)
		if err == nil {
			t.Fatal("Expected error for invalid thread id")
		}

382
		_, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1})
D
Dan Mace 已提交
383 384 385
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
A
aarzilli 已提交
386 387 388
		state := <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state)
D
Dan Mace 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415
		}

		var nt int
		ct := state.CurrentThread.ID
		threads, err := c.ListThreads()
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		for _, th := range threads {
			if th.ID != ct {
				nt = th.ID
				break
			}
		}
		if nt == 0 {
			t.Fatal("could not find thread to switch to")
		}
		// With valid thread id
		state, err = c.SwitchThread(nt)
		if err != nil {
			t.Fatal(err)
		}
		if state.CurrentThread.ID != nt {
			t.Fatal("Did not switch threads")
		}
	})
}
416

417
func Test1ClientServer_infoLocals(t *testing.T) {
418
	withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) {
A
aarzilli 已提交
419
		fp := testProgPath(t, "testnextprog")
A
Alessandro Arzilli 已提交
420
		_, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 24})
421 422 423
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
A
aarzilli 已提交
424 425 426
		state := <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state)
427
		}
D
Derek Parker 已提交
428
		locals, err := c.ListLocalVariables(api.EvalScope{GoroutineID: -1})
429 430 431 432 433 434 435 436 437
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if len(locals) != 3 {
			t.Fatalf("Expected 3 locals, got %d %#v", len(locals), locals)
		}
	})
}

438
func Test1ClientServer_infoArgs(t *testing.T) {
439
	withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) {
A
aarzilli 已提交
440 441
		fp := testProgPath(t, "testnextprog")
		_, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 47})
442 443 444
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
A
aarzilli 已提交
445 446 447
		state := <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state)
448
		}
449 450 451 452 453 454 455
		regs, err := c.ListRegisters()
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if regs == "" {
			t.Fatal("Expected string showing registers values, got empty string")
		}
D
Derek Parker 已提交
456
		locals, err := c.ListFunctionArgs(api.EvalScope{GoroutineID: -1})
457 458 459 460 461 462 463 464
		if err != nil {
			t.Fatalf("Unexpected error: %v", err)
		}
		if len(locals) != 2 {
			t.Fatalf("Expected 2 function args, got %d %#v", len(locals), locals)
		}
	})
}
A
aarzilli 已提交
465

466
func Test1ClientServer_traceContinue(t *testing.T) {
467
	withTestClient1("integrationprog", t, func(c *rpc1.RPCClient) {
A
aarzilli 已提交
468
		fp := testProgPath(t, "integrationprog")
D
Derek Parker 已提交
469
		_, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 15, Tracepoint: true, Goroutine: true, Stacktrace: 5, Variables: []string{"i"}})
A
aarzilli 已提交
470 471 472 473
		if err != nil {
			t.Fatalf("Unexpected error: %v\n", err)
		}
		count := 0
D
Derek Parker 已提交
474 475
		contChan := c.Continue()
		for state := range contChan {
476
			if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil {
A
aarzilli 已提交
477 478 479 480
				count++

				t.Logf("%v", state)

481
				bpi := state.CurrentThread.BreakpointInfo
A
aarzilli 已提交
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498

				if bpi.Goroutine == nil {
					t.Fatalf("No goroutine information")
				}

				if len(bpi.Stacktrace) <= 0 {
					t.Fatalf("No stacktrace\n")
				}

				if len(bpi.Variables) != 1 {
					t.Fatalf("Wrong number of variables returned: %d", len(bpi.Variables))
				}

				if bpi.Variables[0].Name != "i" {
					t.Fatalf("Wrong variable returned %s", bpi.Variables[0].Name)
				}

499 500 501 502 503 504
				t.Logf("Variable i is %v", bpi.Variables[0])

				n, err := strconv.Atoi(bpi.Variables[0].Value)

				if err != nil || n != count-1 {
					t.Fatalf("Wrong variable value %q (%v %d)", bpi.Variables[0].Value, err, count)
A
aarzilli 已提交
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
				}
			}
			if state.Exited {
				continue
			}
			t.Logf("%v", state)
			if state.Err != nil {
				t.Fatalf("Unexpected error during continue: %v\n", state.Err)
			}

		}

		if count != 3 {
			t.Fatalf("Wrong number of continues hit: %d\n", count)
		}
	})
}
522

523
func Test1ClientServer_traceContinue2(t *testing.T) {
524
	withTestClient1("integrationprog", t, func(c *rpc1.RPCClient) {
525
		bp1, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Tracepoint: true})
526 527 528
		if err != nil {
			t.Fatalf("Unexpected error: %v\n", err)
		}
529
		bp2, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: 1, Tracepoint: true})
530 531 532 533 534 535 536
		if err != nil {
			t.Fatalf("Unexpected error: %v\n", err)
		}
		countMain := 0
		countSayhi := 0
		contChan := c.Continue()
		for state := range contChan {
537 538
			if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil {
				switch state.CurrentThread.Breakpoint.ID {
539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
				case bp1.ID:
					countMain++
				case bp2.ID:
					countSayhi++
				}

				t.Logf("%v", state)
			}
			if state.Exited {
				continue
			}
			if state.Err != nil {
				t.Fatalf("Unexpected error during continue: %v\n", state.Err)
			}

		}

		if countMain != 1 {
			t.Fatalf("Wrong number of continues (main.main) hit: %d\n", countMain)
		}

		if countSayhi != 3 {
			t.Fatalf("Wrong number of continues (main.sayhi) hit: %d\n", countSayhi)
		}
	})
}
565

566
func Test1ClientServer_FindLocations(t *testing.T) {
567
	withTestClient1("locationsprog", t, func(c *rpc1.RPCClient) {
568 569 570 571
		someFunctionCallAddr := findLocationHelper(t, c, "locationsprog.go:26", false, 1, 0)[0]
		someFunctionLine1 := findLocationHelper(t, c, "locationsprog.go:27", false, 1, 0)[0]
		findLocationHelper(t, c, "anotherFunction:1", false, 1, someFunctionLine1)
		findLocationHelper(t, c, "main.anotherFunction:1", false, 1, someFunctionLine1)
572 573 574 575 576 577 578 579
		findLocationHelper(t, c, "anotherFunction", false, 1, someFunctionCallAddr)
		findLocationHelper(t, c, "main.anotherFunction", false, 1, someFunctionCallAddr)
		findLocationHelper(t, c, fmt.Sprintf("*0x%x", someFunctionCallAddr), false, 1, someFunctionCallAddr)
		findLocationHelper(t, c, "sprog.go:26", true, 0, 0)

		findLocationHelper(t, c, "String", true, 0, 0)
		findLocationHelper(t, c, "main.String", true, 0, 0)

580 581
		someTypeStringFuncAddr := findLocationHelper(t, c, "locationsprog.go:14", false, 1, 0)[0]
		otherTypeStringFuncAddr := findLocationHelper(t, c, "locationsprog.go:18", false, 1, 0)[0]
582 583 584 585 586
		findLocationHelper(t, c, "SomeType.String", false, 1, someTypeStringFuncAddr)
		findLocationHelper(t, c, "(*SomeType).String", false, 1, someTypeStringFuncAddr)
		findLocationHelper(t, c, "main.SomeType.String", false, 1, someTypeStringFuncAddr)
		findLocationHelper(t, c, "main.(*SomeType).String", false, 1, someTypeStringFuncAddr)

587
		// Issue #275
588 589 590 591 592
		readfile := findLocationHelper(t, c, "io/ioutil.ReadFile", false, 1, 0)[0]

		// Issue #296
		findLocationHelper(t, c, "/io/ioutil.ReadFile", false, 1, readfile)
		findLocationHelper(t, c, "ioutil.ReadFile", false, 1, readfile)
593

594 595 596 597 598 599
		stringAddrs := findLocationHelper(t, c, "/^main.*Type.*String$/", false, 2, 0)

		if otherTypeStringFuncAddr != stringAddrs[0] && otherTypeStringFuncAddr != stringAddrs[1] {
			t.Fatalf("Wrong locations returned for \"/.*Type.*String/\", got: %v expected: %v and %v\n", stringAddrs, someTypeStringFuncAddr, otherTypeStringFuncAddr)
		}

A
Alessandro Arzilli 已提交
600
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 4, Tracepoint: false})
601 602 603 604 605 606
		if err != nil {
			t.Fatalf("CreateBreakpoint(): %v\n", err)
		}

		<-c.Continue()

A
Alessandro Arzilli 已提交
607 608 609 610 611
		locationsprog35Addr := findLocationHelper(t, c, "locationsprog.go:35", false, 1, 0)[0]
		findLocationHelper(t, c, fmt.Sprintf("%s:35", testProgPath(t, "locationsprog")), false, 1, locationsprog35Addr)
		findLocationHelper(t, c, "+1", false, 1, locationsprog35Addr)
		findLocationHelper(t, c, "35", false, 1, locationsprog35Addr)
		findLocationHelper(t, c, "-1", false, 1, findLocationHelper(t, c, "locationsprog.go:33", false, 1, 0)[0])
612 613
	})

614
	withTestClient1("testnextdefer", t, func(c *rpc1.RPCClient) {
615
		firstMainLine := findLocationHelper(t, c, "testnextdefer.go:5", false, 1, 0)[0]
616 617 618
		findLocationHelper(t, c, "main.main", false, 1, firstMainLine)
	})

619
	withTestClient1("stacktraceprog", t, func(c *rpc1.RPCClient) {
620 621 622
		stacktracemeAddr := findLocationHelper(t, c, "stacktraceprog.go:4", false, 1, 0)[0]
		findLocationHelper(t, c, "main.stacktraceme", false, 1, stacktracemeAddr)
	})
L
Luke Hoban 已提交
623

624
	withTestClient1Extended("locationsUpperCase", t, func(c *rpc1.RPCClient, fixture protest.Fixture) {
L
Luke Hoban 已提交
625 626 627 628
		// Upper case
		findLocationHelper(t, c, "locationsUpperCase.go:6", false, 1, 0)

		// Fully qualified path
629 630
		findLocationHelper(t, c, fixture.Source+":6", false, 1, 0)
		bp, err := c.CreateBreakpoint(&api.Breakpoint{File: fixture.Source, Line: 6})
L
Luke Hoban 已提交
631
		if err != nil {
632
			t.Fatalf("Could not set breakpoint in %s: %v\n", fixture.Source, err)
L
Luke Hoban 已提交
633 634 635 636 637
		}
		c.ClearBreakpoint(bp.ID)

		//  Allow `/` or `\` on Windows
		if runtime.GOOS == "windows" {
638 639
			findLocationHelper(t, c, filepath.FromSlash(fixture.Source)+":6", false, 1, 0)
			bp, err = c.CreateBreakpoint(&api.Breakpoint{File: filepath.FromSlash(fixture.Source), Line: 6})
L
Luke Hoban 已提交
640
			if err != nil {
641
				t.Fatalf("Could not set breakpoint in %s: %v\n", filepath.FromSlash(fixture.Source), err)
L
Luke Hoban 已提交
642 643 644 645 646 647 648 649 650 651 652
			}
			c.ClearBreakpoint(bp.ID)
		}

		// Case-insensitive on Windows, case-sensitive otherwise
		shouldWrongCaseBeError := true
		numExpectedMatches := 0
		if runtime.GOOS == "windows" {
			shouldWrongCaseBeError = false
			numExpectedMatches = 1
		}
653 654
		findLocationHelper(t, c, strings.ToLower(fixture.Source)+":6", shouldWrongCaseBeError, numExpectedMatches, 0)
		bp, err = c.CreateBreakpoint(&api.Breakpoint{File: strings.ToLower(fixture.Source), Line: 6})
L
Luke Hoban 已提交
655
		if (err == nil) == shouldWrongCaseBeError {
656
			t.Fatalf("Could not set breakpoint in %s: %v\n", strings.ToLower(fixture.Source), err)
L
Luke Hoban 已提交
657 658 659
		}
		c.ClearBreakpoint(bp.ID)
	})
660
}
A
aarzilli 已提交
661

662
func Test1ClientServer_FindLocationsAddr(t *testing.T) {
663
	withTestClient1("locationsprog2", t, func(c *rpc1.RPCClient) {
664 665 666
		<-c.Continue()

		afunction := findLocationHelper(t, c, "main.afunction", false, 1, 0)[0]
667
		anonfunc := findLocationHelper(t, c, "main.main.func1", false, 1, 0)[0]
668 669 670 671 672 673

		findLocationHelper(t, c, "*fn1", false, 1, afunction)
		findLocationHelper(t, c, "*fn3", false, 1, anonfunc)
	})
}

674
func Test1ClientServer_EvalVariable(t *testing.T) {
675
	withTestClient1("testvariables", t, func(c *rpc1.RPCClient) {
A
aarzilli 已提交
676 677 678 679 680 681
		state := <-c.Continue()

		if state.Err != nil {
			t.Fatalf("Continue(): %v\n", state.Err)
		}

D
Derek Parker 已提交
682
		var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "a1")
683
		assertNoError(err, t, "EvalVariable")
A
aarzilli 已提交
684

685
		t.Logf("var1: %s", var1.SinglelineString())
A
aarzilli 已提交
686 687

		if var1.Value != "foofoofoofoofoofoo" {
688
			t.Fatalf("Wrong variable value: %s", var1.Value)
689 690 691 692
		}
	})
}

693
func Test1ClientServer_SetVariable(t *testing.T) {
694
	withTestClient1("testvariables", t, func(c *rpc1.RPCClient) {
695 696 697 698 699 700
		state := <-c.Continue()

		if state.Err != nil {
			t.Fatalf("Continue(): %v\n", state.Err)
		}

D
Derek Parker 已提交
701
		assertNoError(c.SetVariable(api.EvalScope{GoroutineID: -1}, "a2", "8"), t, "SetVariable()")
702

D
Derek Parker 已提交
703
		a2, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "a2")
704 705 706
		if err != nil {
			t.Fatalf("Could not evaluate variable: %v", err)
		}
707

708
		t.Logf("a2: %v", a2)
709

710 711 712 713
		n, err := strconv.Atoi(a2.Value)

		if err != nil && n != 8 {
			t.Fatalf("Wrong variable value: %v", a2)
A
aarzilli 已提交
714 715 716
		}
	})
}
717

718
func Test1ClientServer_FullStacktrace(t *testing.T) {
719
	withTestClient1("goroutinestackprog", t, func(c *rpc1.RPCClient) {
720 721 722 723 724 725 726 727 728 729 730 731 732
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.stacktraceme", Line: -1})
		assertNoError(err, t, "CreateBreakpoint()")
		state := <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Continue(): %v\n", state.Err)
		}

		gs, err := c.ListGoroutines()
		assertNoError(err, t, "GoroutinesInfo()")
		found := make([]bool, 10)
		for _, g := range gs {
			frames, err := c.Stacktrace(g.ID, 10, true)
			assertNoError(err, t, fmt.Sprintf("Stacktrace(%d)", g.ID))
733
			t.Logf("goroutine %d", g.ID)
734
			for i, frame := range frames {
735
				t.Logf("\tframe %d off=%#x bpoff=%#x pc=%#x %s:%d %s", i, frame.FrameOffset, frame.FramePointerOffset, frame.PC, frame.File, frame.Line, frame.Function.Name())
736 737 738
				if frame.Function == nil {
					continue
				}
739
				if frame.Function.Name() != "main.agoroutine" {
740 741 742 743 744 745
					continue
				}
				for _, arg := range frame.Arguments {
					if arg.Name != "i" {
						continue
					}
746
					t.Logf("\tvariable i is %+v\n", arg)
747 748 749 750
					argn, err := strconv.Atoi(arg.Value)
					if err == nil {
						found[argn] = true
					}
751 752 753 754 755 756
				}
			}
		}

		for i := range found {
			if !found[i] {
757
				t.Fatalf("Goroutine %d not found", i)
758 759 760
			}
		}

761 762
		t.Logf("continue")

763 764 765 766 767 768 769 770 771 772
		state = <-c.Continue()
		if state.Err != nil {
			t.Fatalf("Continue(): %v\n", state.Err)
		}

		frames, err := c.Stacktrace(-1, 10, true)
		assertNoError(err, t, "Stacktrace")

		cur := 3
		for i, frame := range frames {
773
			t.Logf("\tframe %d off=%#x bpoff=%#x pc=%#x %s:%d %s", i, frame.FrameOffset, frame.FramePointerOffset, frame.PC, frame.File, frame.Line, frame.Function.Name())
774 775 776 777 778 779 780
			if i == 0 {
				continue
			}
			v := frame.Var("n")
			if v == nil {
				t.Fatalf("Could not find value of variable n in frame %d", i)
			}
781 782 783
			vn, err := strconv.Atoi(v.Value)
			if err != nil || vn != cur {
				t.Fatalf("Expected value %d got %d (error: %v)", cur, vn, err)
784 785 786 787 788 789 790 791
			}
			cur--
			if cur < 0 {
				break
			}
		}
	})
}
792

793
func Test1Issue355(t *testing.T) {
794
	// After the target process has terminated should return an error but not crash
795
	withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) {
796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
		bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1})
		assertNoError(err, t, "CreateBreakpoint()")
		ch := c.Continue()
		state := <-ch
		tid := state.CurrentThread.ID
		gid := state.SelectedGoroutine.ID
		assertNoError(state.Err, t, "First Continue()")
		ch = c.Continue()
		state = <-ch
		if !state.Exited {
			t.Fatalf("Target did not terminate after second continue")
		}

		ch = c.Continue()
		state = <-ch
		assertError(state.Err, t, "Continue()")

		_, err = c.Next()
		assertError(err, t, "Next()")
		_, err = c.Step()
		assertError(err, t, "Step()")
		_, err = c.StepInstruction()
		assertError(err, t, "StepInstruction()")
		_, err = c.SwitchThread(tid)
		assertError(err, t, "SwitchThread()")
		_, err = c.SwitchGoroutine(gid)
		assertError(err, t, "SwitchGoroutine()")
		_, err = c.Halt()
		assertError(err, t, "Halt()")
		_, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: -1})
		assertError(err, t, "CreateBreakpoint()")
		_, err = c.ClearBreakpoint(bp.ID)
		assertError(err, t, "ClearBreakpoint()")
		_, err = c.ListThreads()
		assertError(err, t, "ListThreads()")
		_, err = c.GetThread(tid)
		assertError(err, t, "GetThread()")
D
Derek Parker 已提交
833 834
		assertError(c.SetVariable(api.EvalScope{GoroutineID: gid}, "a", "10"), t, "SetVariable()")
		_, err = c.ListLocalVariables(api.EvalScope{GoroutineID: gid})
835
		assertError(err, t, "ListLocalVariables()")
D
Derek Parker 已提交
836
		_, err = c.ListFunctionArgs(api.EvalScope{GoroutineID: gid})
837 838 839 840 841 842 843
		assertError(err, t, "ListFunctionArgs()")
		_, err = c.ListRegisters()
		assertError(err, t, "ListRegisters()")
		_, err = c.ListGoroutines()
		assertError(err, t, "ListGoroutines()")
		_, err = c.Stacktrace(gid, 10, false)
		assertError(err, t, "Stacktrace()")
D
Derek Parker 已提交
844
		_, err = c.FindLocation(api.EvalScope{GoroutineID: gid}, "+1")
845
		assertError(err, t, "FindLocation()")
D
Derek Parker 已提交
846
		_, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, 0x40100, api.IntelFlavour)
A
aarzilli 已提交
847 848 849 850
		assertError(err, t, "DisassemblePC()")
	})
}

851
func Test1Disasm(t *testing.T) {
A
aarzilli 已提交
852 853 854 855
	// Tests that disassembling by PC, range, and current PC all yeld similar results
	// Tests that disassembly by current PC will return a disassembly containing the instruction at PC
	// Tests that stepping on a calculated CALL instruction will yield a disassembly that contains the
	// effective destination of the CALL instruction
856
	withTestClient1("locationsprog2", t, func(c *rpc1.RPCClient) {
A
aarzilli 已提交
857 858 859 860
		ch := c.Continue()
		state := <-ch
		assertNoError(state.Err, t, "Continue()")

D
Derek Parker 已提交
861
		locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main")
A
aarzilli 已提交
862 863 864 865
		assertNoError(err, t, "FindLocation()")
		if len(locs) != 1 {
			t.Fatalf("wrong number of locations for main.main: %d", len(locs))
		}
D
Derek Parker 已提交
866
		d1, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour)
A
aarzilli 已提交
867 868 869 870 871 872 873
		assertNoError(err, t, "DisassemblePC()")
		if len(d1) < 2 {
			t.Fatalf("wrong size of disassembly: %d", len(d1))
		}

		pcstart := d1[0].Loc.PC
		pcend := d1[len(d1)-1].Loc.PC + uint64(len(d1[len(d1)-1].Bytes))
D
Derek Parker 已提交
874
		d2, err := c.DisassembleRange(api.EvalScope{GoroutineID: -1}, pcstart, pcend, api.IntelFlavour)
A
aarzilli 已提交
875 876 877 878 879 880 881 882
		assertNoError(err, t, "DisassembleRange()")

		if len(d1) != len(d2) {
			t.Logf("d1: %v", d1)
			t.Logf("d2: %v", d2)
			t.Fatal("mismatched length between disassemble pc and disassemble range")
		}

D
Derek Parker 已提交
883
		d3, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, state.CurrentThread.PC, api.IntelFlavour)
A
aarzilli 已提交
884 885 886 887 888 889 890 891 892 893 894
		assertNoError(err, t, "DisassemblePC() - second call")

		if len(d1) != len(d3) {
			t.Logf("d1: %v", d1)
			t.Logf("d3: %v", d3)
			t.Fatal("mismatched length between the two calls of disassemble pc")
		}

		// look for static call to afunction() on line 29
		found := false
		for i := range d3 {
H
hengwu0 已提交
895
			if d3[i].Loc.Line == 29 && (strings.HasPrefix(d3[i].Text, "call") || strings.HasPrefix(d3[i].Text, "CALL")) && d3[i].DestLoc != nil && d3[i].DestLoc.Function != nil && d3[i].DestLoc.Function.Name() == "main.afunction" {
A
aarzilli 已提交
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
				found = true
				break
			}
		}
		if !found {
			t.Fatal("Could not find call to main.afunction on line 29")
		}

		haspc := false
		for i := range d3 {
			if d3[i].AtPC {
				haspc = true
				break
			}
		}

		if !haspc {
			t.Logf("d3: %v", d3)
			t.Fatal("PC instruction not found")
		}

917 918 919 920 921
		if runtime.GOARCH == "386" && buildMode == "pie" {
			// Skip the rest of the test because on intel 386 with PIE build mode
			// the compiler will insert calls to __x86.get_pc_thunk which do not have DIEs and we can't resolve.
			return
		}
A
aarzilli 已提交
922

923
		startinstr := getCurinstr(d3)
A
aarzilli 已提交
924 925 926 927 928 929 930 931
		count := 0
		for {
			if count > 20 {
				t.Fatal("too many step instructions executed without finding a call instruction")
			}
			state, err := c.StepInstruction()
			assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count))

D
Derek Parker 已提交
932
			d3, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, state.CurrentThread.PC, api.IntelFlavour)
A
aarzilli 已提交
933 934 935 936 937 938 939 940 941 942 943 944
			assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count))

			curinstr := getCurinstr(d3)

			if curinstr == nil {
				t.Fatalf("Could not find current instruction %d", count)
			}

			if curinstr.Loc.Line != startinstr.Loc.Line {
				t.Fatal("Calling StepInstruction() repeatedly did not find the call instruction")
			}

H
hengwu0 已提交
945
			if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") {
A
aarzilli 已提交
946 947 948 949
				t.Logf("call: %v", curinstr)
				if curinstr.DestLoc == nil || curinstr.DestLoc.Function == nil {
					t.Fatalf("Call instruction does not have destination: %v", curinstr)
				}
950
				if curinstr.DestLoc.Function.Name() != "main.afunction" {
A
aarzilli 已提交
951 952 953 954 955 956 957
					t.Fatalf("Call instruction destination not main.afunction: %v", curinstr)
				}
				break
			}

			count++
		}
958 959
	})
}
960

961
func Test1NegativeStackDepthBug(t *testing.T) {
962
	// After the target process has terminated should return an error but not crash
963
	withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) {
964 965 966 967 968 969 970 971 972
		_, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1})
		assertNoError(err, t, "CreateBreakpoint()")
		ch := c.Continue()
		state := <-ch
		assertNoError(state.Err, t, "Continue()")
		_, err = c.Stacktrace(-1, -2, true)
		assertError(err, t, "Stacktrace()")
	})
}
973

974
func Test1ClientServer_CondBreakpoint(t *testing.T) {
975 976 977
	if runtime.GOOS == "freebsd" {
		t.Skip("test is not valid on FreeBSD")
	}
978
	withTestClient1("parallel_next", t, func(c *rpc1.RPCClient) {
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997
		bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: 1})
		assertNoError(err, t, "CreateBreakpoint()")
		bp.Cond = "n == 7"
		assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 1")
		bp, err = c.GetBreakpoint(bp.ID)
		assertNoError(err, t, "GetBreakpoint() 1")
		bp.Variables = append(bp.Variables, "n")
		assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 2")
		bp, err = c.GetBreakpoint(bp.ID)
		assertNoError(err, t, "GetBreakpoint() 2")
		if bp.Cond == "" {
			t.Fatalf("No condition set on breakpoint %#v", bp)
		}
		if len(bp.Variables) != 1 {
			t.Fatalf("Wrong number of expressions to evaluate on breakpoint %#v", bp)
		}
		state := <-c.Continue()
		assertNoError(state.Err, t, "Continue()")

D
Derek Parker 已提交
998
		nvar, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "n")
999 1000 1001 1002 1003 1004 1005
		assertNoError(err, t, "EvalVariable()")

		if nvar.SinglelineString() != "7" {
			t.Fatalf("Stopped on wrong goroutine %s\n", nvar.Value)
		}
	})
}
1006

1007
func Test1Issue419(t *testing.T) {
1008 1009
	// Calling service/rpc.(*Client).Halt could cause a crash because both Halt and Continue simultaneously
	// try to read 'runtime.g' and debug/dwarf.Data.Type is not thread safe
1010
	withTestClient1("issue419", t, func(c *rpc1.RPCClient) {
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
		go func() {
			rand.Seed(time.Now().Unix())
			d := time.Duration(rand.Intn(4) + 1)
			time.Sleep(d * time.Second)
			_, err := c.Halt()
			assertNoError(err, t, "RequestManualStop()")
		}()
		statech := c.Continue()
		state := <-statech
		assertNoError(state.Err, t, "Continue()")
	})
}
A
aarzilli 已提交
1023

1024
func Test1TypesCommand(t *testing.T) {
1025
	withTestClient1("testvariables2", t, func(c *rpc1.RPCClient) {
A
aarzilli 已提交
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
		state := <-c.Continue()
		assertNoError(state.Err, t, "Continue()")
		types, err := c.ListTypes("")
		assertNoError(err, t, "ListTypes()")

		found := false
		for i := range types {
			if types[i] == "main.astruct" {
				found = true
				break
			}
		}
		if !found {
			t.Fatal("Type astruct not found in ListTypes output")
		}

1042
		types, err = c.ListTypes("^main.astruct$")
A
aarzilli 已提交
1043
		assertNoError(err, t, "ListTypes(\"main.astruct\")")
1044 1045
		if len(types) != 1 {
			t.Fatalf("ListTypes(\"^main.astruct$\") did not filter properly, expected 1 got %d: %v", len(types), types)
A
aarzilli 已提交
1046 1047 1048
		}
	})
}
1049 1050

func Test1Issue406(t *testing.T) {
1051
	withTestClient1("issue406", t, func(c *rpc1.RPCClient) {
D
Derek Parker 已提交
1052
		locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "issue406.go:146")
1053 1054 1055 1056 1057 1058
		assertNoError(err, t, "FindLocation()")
		_, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC})
		assertNoError(err, t, "CreateBreakpoint()")
		ch := c.Continue()
		state := <-ch
		assertNoError(state.Err, t, "Continue()")
D
Derek Parker 已提交
1059
		v, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "cfgtree")
1060 1061 1062 1063 1064
		assertNoError(err, t, "EvalVariable()")
		vs := v.MultilineString("")
		t.Logf("cfgtree formats to: %s\n", vs)
	})
}