github.com/neilgarb/delve@v1.9.2-nobreaks/service/test/integration1_test.go (about) 1 package service_test 2 3 import ( 4 "fmt" 5 "math/rand" 6 "net" 7 "path/filepath" 8 "runtime" 9 "strconv" 10 "strings" 11 "testing" 12 "time" 13 14 protest "github.com/go-delve/delve/pkg/proc/test" 15 "github.com/go-delve/delve/service/debugger" 16 17 "github.com/go-delve/delve/pkg/goversion" 18 "github.com/go-delve/delve/service" 19 "github.com/go-delve/delve/service/api" 20 "github.com/go-delve/delve/service/rpc1" 21 "github.com/go-delve/delve/service/rpccommon" 22 ) 23 24 func withTestClient1(name string, t *testing.T, fn func(c *rpc1.RPCClient)) { 25 withTestClient1Extended(name, t, func(c *rpc1.RPCClient, fixture protest.Fixture) { 26 fn(c) 27 }) 28 } 29 30 func withTestClient1Extended(name string, t *testing.T, fn func(c *rpc1.RPCClient, fixture protest.Fixture)) { 31 if testBackend == "rr" { 32 protest.MustHaveRecordingAllowed(t) 33 } 34 listener, err := net.Listen("tcp", "127.0.0.1:0") 35 if err != nil { 36 t.Fatalf("couldn't start listener: %s\n", err) 37 } 38 defer listener.Close() 39 var buildFlags protest.BuildFlags 40 if buildMode == "pie" { 41 buildFlags = protest.BuildModePIE 42 } 43 fixture := protest.BuildFixture(name, buildFlags) 44 server := rpccommon.NewServer(&service.Config{ 45 Listener: listener, 46 ProcessArgs: []string{fixture.Path}, 47 Debugger: debugger.Config{ 48 Backend: testBackend, 49 }, 50 }) 51 if err := server.Run(); err != nil { 52 t.Fatal(err) 53 } 54 client := rpc1.NewClient(listener.Addr().String()) 55 defer func() { 56 client.Detach(true) 57 }() 58 59 fn(client, fixture) 60 } 61 62 func Test1RunWithInvalidPath(t *testing.T) { 63 if testBackend == "rr" { 64 // This test won't work because rr returns an error, after recording, when 65 // the recording failed but also when the recording succeeded but the 66 // inferior returned an error. Therefore we have to ignore errors from rr. 67 return 68 } 69 listener, err := net.Listen("tcp", "127.0.0.1:0") 70 if err != nil { 71 t.Fatalf("couldn't start listener: %s\n", err) 72 } 73 defer listener.Close() 74 server := rpccommon.NewServer(&service.Config{ 75 Listener: listener, 76 ProcessArgs: []string{"invalid_path"}, 77 Debugger: debugger.Config{ 78 Backend: testBackend, 79 }, 80 }) 81 if err := server.Run(); err == nil { 82 t.Fatal("Expected Run to return error for invalid program path") 83 } 84 } 85 86 func Test1Restart_afterExit(t *testing.T) { 87 withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) { 88 origPid := c.ProcessPid() 89 state := <-c.Continue() 90 if !state.Exited { 91 t.Fatal("expected initial process to have exited") 92 } 93 if err := c.Restart(); err != nil { 94 t.Fatal(err) 95 } 96 if c.ProcessPid() == origPid { 97 t.Fatal("did not spawn new process, has same PID") 98 } 99 state = <-c.Continue() 100 if !state.Exited { 101 t.Fatalf("expected restarted process to have exited %v", state) 102 } 103 }) 104 } 105 106 func Test1Restart_breakpointPreservation(t *testing.T) { 107 withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) { 108 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint", Tracepoint: true}) 109 assertNoError(err, t, "CreateBreakpoint()") 110 stateCh := c.Continue() 111 112 state := <-stateCh 113 if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint { 114 t.Fatalf("Wrong breakpoint: %#v\n", state.CurrentThread.Breakpoint) 115 } 116 state = <-stateCh 117 if !state.Exited { 118 t.Fatal("Did not exit after first tracepoint") 119 } 120 121 t.Log("Restart") 122 c.Restart() 123 stateCh = c.Continue() 124 state = <-stateCh 125 if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint { 126 t.Fatalf("Wrong breakpoint (after restart): %#v\n", state.CurrentThread.Breakpoint) 127 } 128 state = <-stateCh 129 if !state.Exited { 130 t.Fatal("Did not exit after first tracepoint (after restart)") 131 } 132 }) 133 } 134 135 func Test1Restart_duringStop(t *testing.T) { 136 withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) { 137 origPid := c.ProcessPid() 138 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1}) 139 if err != nil { 140 t.Fatal(err) 141 } 142 state := <-c.Continue() 143 if state.CurrentThread.Breakpoint == nil { 144 t.Fatal("did not hit breakpoint") 145 } 146 if err := c.Restart(); err != nil { 147 t.Fatal(err) 148 } 149 if c.ProcessPid() == origPid { 150 t.Fatal("did not spawn new process, has same PID") 151 } 152 bps, err := c.ListBreakpoints() 153 if err != nil { 154 t.Fatal(err) 155 } 156 if len(bps) == 0 { 157 t.Fatal("breakpoints not preserved") 158 } 159 }) 160 } 161 162 func Test1ClientServer_exit(t *testing.T) { 163 withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) { 164 state, err := c.GetState() 165 if err != nil { 166 t.Fatalf("Unexpected error: %v", err) 167 } 168 if e, a := false, state.Exited; e != a { 169 t.Fatalf("Expected exited %v, got %v", e, a) 170 } 171 state = <-c.Continue() 172 if state.Err == nil { 173 t.Fatalf("Error expected after continue") 174 } 175 if !state.Exited { 176 t.Fatalf("Expected exit after continue: %v", state) 177 } 178 _, err = c.GetState() 179 if err == nil { 180 t.Fatal("Expected error on querying state from exited process") 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}) 188 if err != nil { 189 t.Fatalf("Unexpected error: %v", err) 190 } 191 192 stateBefore := <-c.Continue() 193 if stateBefore.Err != nil { 194 t.Fatalf("Unexpected error: %v", stateBefore.Err) 195 } 196 197 stateAfter, err := c.Step() 198 if err != nil { 199 t.Fatalf("Unexpected error: %v", err) 200 } 201 202 if before, after := stateBefore.CurrentThread.PC, stateAfter.CurrentThread.PC; before >= after { 203 t.Fatalf("Expected %#v to be greater than %#v", after, before) 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}) 211 if err != nil { 212 t.Fatalf("Unexpected error: %v", err) 213 } 214 215 state := <-c.Continue() 216 if state.Err != nil { 217 t.Fatalf("Unexpected error: %v", state.Err) 218 } 219 220 _, err = c.ClearBreakpoint(bp.ID) 221 if err != nil { 222 t.Fatalf("Unexpected error: %v", err) 223 } 224 225 for _, tc := range testcases { 226 if state.CurrentThread.Line != tc.begin { 227 t.Fatalf("Program not stopped at correct spot expected %d was %d", tc.begin, state.CurrentThread.Line) 228 } 229 230 t.Logf("Next for scenario %#v", tc) 231 state, err = c.Next() 232 if err != nil { 233 t.Fatalf("Unexpected error: %v", err) 234 } 235 236 if state.CurrentThread.Line != tc.end { 237 t.Fatalf("Program did not continue to correct next location expected %d was %d", tc.end, state.CurrentThread.Line) 238 } 239 } 240 }) 241 } 242 243 func Test1NextGeneral(t *testing.T) { 244 var testcases []nextTest 245 246 ver, _ := goversion.Parse(runtime.Version()) 247 248 if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) { 249 testcases = []nextTest{ 250 {17, 19}, 251 {19, 20}, 252 {20, 23}, 253 {23, 24}, 254 {24, 26}, 255 {26, 31}, 256 {31, 23}, 257 {23, 24}, 258 {24, 26}, 259 {26, 31}, 260 {31, 23}, 261 {23, 24}, 262 {24, 26}, 263 {26, 27}, 264 {27, 28}, 265 {28, 34}, 266 } 267 } else { 268 testcases = []nextTest{ 269 {17, 19}, 270 {19, 20}, 271 {20, 23}, 272 {23, 24}, 273 {24, 26}, 274 {26, 31}, 275 {31, 23}, 276 {23, 24}, 277 {24, 26}, 278 {26, 31}, 279 {31, 23}, 280 {23, 24}, 281 {24, 26}, 282 {26, 27}, 283 {27, 34}, 284 } 285 } 286 287 testnext(testcases, "main.testnext", t) 288 } 289 290 func Test1NextFunctionReturn(t *testing.T) { 291 testcases := []nextTest{ 292 {13, 14}, 293 {14, 15}, 294 {15, 35}, 295 } 296 testnext(testcases, "main.helloworld", t) 297 } 298 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}) 302 if err != nil { 303 t.Fatalf("Unexpected error: %v", err) 304 } 305 306 state := <-c.Continue() 307 if err != nil { 308 t.Fatalf("Unexpected error: %v, state: %#v", err, state) 309 } 310 311 pc := state.CurrentThread.PC 312 313 if pc-1 != bp.Addr && pc != bp.Addr { 314 f, l := state.CurrentThread.File, state.CurrentThread.Line 315 t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, bp.Addr) 316 } 317 }) 318 } 319 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}) 323 if err != nil { 324 t.Fatalf("Unexpected error: %v", err) 325 } 326 327 state := <-c.Continue() 328 if state.Err != nil { 329 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 330 } 331 332 f, l := state.CurrentThread.File, state.CurrentThread.Line 333 if f != "testthreads.go" && l != 9 { 334 t.Fatal("Program did not hit breakpoint") 335 } 336 }) 337 } 338 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}) 342 if err == nil { 343 t.Fatal("Should not be able to break at non existent function") 344 } 345 }) 346 } 347 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}) 351 if err != nil { 352 t.Fatalf("Unexpected error: %v", err) 353 } 354 355 if e, a := 1, countBreakpoints(t, c); e != a { 356 t.Fatalf("Expected breakpoint count %d, got %d", e, a) 357 } 358 359 deleted, err := c.ClearBreakpoint(bp.ID) 360 if err != nil { 361 t.Fatalf("Unexpected error: %v", err) 362 } 363 364 if deleted.ID != bp.ID { 365 t.Fatalf("Expected deleted breakpoint ID %v, got %v", bp.ID, deleted.ID) 366 } 367 368 if e, a := 0, countBreakpoints(t, c); e != a { 369 t.Fatalf("Expected breakpoint count %d, got %d", e, a) 370 } 371 }) 372 } 373 374 func Test1ClientServer_switchThread(t *testing.T) { 375 withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) { 376 // With invalid thread id 377 _, err := c.SwitchThread(-1) 378 if err == nil { 379 t.Fatal("Expected error for invalid thread id") 380 } 381 382 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1}) 383 if err != nil { 384 t.Fatalf("Unexpected error: %v", err) 385 } 386 state := <-c.Continue() 387 if state.Err != nil { 388 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 389 } 390 391 var nt int 392 ct := state.CurrentThread.ID 393 threads, err := c.ListThreads() 394 if err != nil { 395 t.Fatalf("Unexpected error: %v", err) 396 } 397 for _, th := range threads { 398 if th.ID != ct { 399 nt = th.ID 400 break 401 } 402 } 403 if nt == 0 { 404 t.Fatal("could not find thread to switch to") 405 } 406 // With valid thread id 407 state, err = c.SwitchThread(nt) 408 if err != nil { 409 t.Fatal(err) 410 } 411 if state.CurrentThread.ID != nt { 412 t.Fatal("Did not switch threads") 413 } 414 }) 415 } 416 417 func Test1ClientServer_infoLocals(t *testing.T) { 418 withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) { 419 fp := testProgPath(t, "testnextprog") 420 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 24}) 421 if err != nil { 422 t.Fatalf("Unexpected error: %v", err) 423 } 424 state := <-c.Continue() 425 if state.Err != nil { 426 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 427 } 428 locals, err := c.ListLocalVariables(api.EvalScope{GoroutineID: -1}) 429 if err != nil { 430 t.Fatalf("Unexpected error: %v", err) 431 } 432 if len(locals) != 3 { 433 t.Fatalf("Expected 3 locals, got %d %#v", len(locals), locals) 434 } 435 }) 436 } 437 438 func Test1ClientServer_infoArgs(t *testing.T) { 439 withTestClient1("testnextprog", t, func(c *rpc1.RPCClient) { 440 fp := testProgPath(t, "testnextprog") 441 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 47}) 442 if err != nil { 443 t.Fatalf("Unexpected error: %v", err) 444 } 445 state := <-c.Continue() 446 if state.Err != nil { 447 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 448 } 449 regs, err := c.ListRegisters() 450 if err != nil { 451 t.Fatalf("Unexpected error: %v", err) 452 } 453 if regs == "" { 454 t.Fatal("Expected string showing registers values, got empty string") 455 } 456 locals, err := c.ListFunctionArgs(api.EvalScope{GoroutineID: -1}) 457 if err != nil { 458 t.Fatalf("Unexpected error: %v", err) 459 } 460 if len(locals) != 2 { 461 t.Fatalf("Expected 2 function args, got %d %#v", len(locals), locals) 462 } 463 }) 464 } 465 466 func Test1ClientServer_traceContinue(t *testing.T) { 467 withTestClient1("integrationprog", t, func(c *rpc1.RPCClient) { 468 fp := testProgPath(t, "integrationprog") 469 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 15, Tracepoint: true, Goroutine: true, Stacktrace: 5, Variables: []string{"i"}}) 470 if err != nil { 471 t.Fatalf("Unexpected error: %v\n", err) 472 } 473 count := 0 474 contChan := c.Continue() 475 for state := range contChan { 476 if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil { 477 count++ 478 479 t.Logf("%v", state) 480 481 bpi := state.CurrentThread.BreakpointInfo 482 483 if bpi.Goroutine == nil { 484 t.Fatalf("No goroutine information") 485 } 486 487 if len(bpi.Stacktrace) <= 0 { 488 t.Fatalf("No stacktrace\n") 489 } 490 491 if len(bpi.Variables) != 1 { 492 t.Fatalf("Wrong number of variables returned: %d", len(bpi.Variables)) 493 } 494 495 if bpi.Variables[0].Name != "i" { 496 t.Fatalf("Wrong variable returned %s", bpi.Variables[0].Name) 497 } 498 499 t.Logf("Variable i is %v", bpi.Variables[0]) 500 501 n, err := strconv.Atoi(bpi.Variables[0].Value) 502 503 if err != nil || n != count-1 { 504 t.Fatalf("Wrong variable value %q (%v %d)", bpi.Variables[0].Value, err, count) 505 } 506 } 507 if state.Exited { 508 continue 509 } 510 t.Logf("%v", state) 511 if state.Err != nil { 512 t.Fatalf("Unexpected error during continue: %v\n", state.Err) 513 } 514 515 } 516 517 if count != 3 { 518 t.Fatalf("Wrong number of continues hit: %d\n", count) 519 } 520 }) 521 } 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 if err != nil { 527 t.Fatalf("Unexpected error: %v\n", err) 528 } 529 bp2, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: 1, Tracepoint: true}) 530 if err != nil { 531 t.Fatalf("Unexpected error: %v\n", err) 532 } 533 countMain := 0 534 countSayhi := 0 535 contChan := c.Continue() 536 for state := range contChan { 537 if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil { 538 switch state.CurrentThread.Breakpoint.ID { 539 case bp1.ID: 540 countMain++ 541 case bp2.ID: 542 countSayhi++ 543 } 544 545 t.Logf("%v", state) 546 } 547 if state.Exited { 548 continue 549 } 550 if state.Err != nil { 551 t.Fatalf("Unexpected error during continue: %v\n", state.Err) 552 } 553 554 } 555 556 if countMain != 1 { 557 t.Fatalf("Wrong number of continues (main.main) hit: %d\n", countMain) 558 } 559 560 if countSayhi != 3 { 561 t.Fatalf("Wrong number of continues (main.sayhi) hit: %d\n", countSayhi) 562 } 563 }) 564 } 565 566 func Test1ClientServer_FindLocations(t *testing.T) { 567 withTestClient1("locationsprog", t, func(c *rpc1.RPCClient) { 568 someFunctionCallAddr := findLocationHelper(t, c, "locationsprog.go:26", false, 1, 0)[0] 569 someFunctionLine1 := findLocationHelper(t, c, "locationsprog.go:27", false, 1, 0)[0] 570 findLocationHelper(t, c, "anotherFunction:1", false, 1, someFunctionLine1) 571 findLocationHelper(t, c, "main.anotherFunction:1", false, 1, someFunctionLine1) 572 findLocationHelper(t, c, "anotherFunction", false, 1, someFunctionCallAddr) 573 findLocationHelper(t, c, "main.anotherFunction", false, 1, someFunctionCallAddr) 574 findLocationHelper(t, c, fmt.Sprintf("*0x%x", someFunctionCallAddr), false, 1, someFunctionCallAddr) 575 findLocationHelper(t, c, "sprog.go:26", true, 0, 0) 576 577 findLocationHelper(t, c, "String", true, 0, 0) 578 findLocationHelper(t, c, "main.String", true, 0, 0) 579 580 someTypeStringFuncAddr := findLocationHelper(t, c, "locationsprog.go:14", false, 1, 0)[0] 581 otherTypeStringFuncAddr := findLocationHelper(t, c, "locationsprog.go:18", false, 1, 0)[0] 582 findLocationHelper(t, c, "SomeType.String", false, 1, someTypeStringFuncAddr) 583 findLocationHelper(t, c, "(*SomeType).String", false, 1, someTypeStringFuncAddr) 584 findLocationHelper(t, c, "main.SomeType.String", false, 1, someTypeStringFuncAddr) 585 findLocationHelper(t, c, "main.(*SomeType).String", false, 1, someTypeStringFuncAddr) 586 587 // Issue #275 588 readfile := findLocationHelper(t, c, "io/ioutil.ReadFile", false, 1, 0)[0] 589 590 // Issue #296 591 findLocationHelper(t, c, "/io/ioutil.ReadFile", false, 1, readfile) 592 findLocationHelper(t, c, "ioutil.ReadFile", false, 1, readfile) 593 594 stringAddrs := findLocationHelper(t, c, "/^main.*Type.*String$/", false, 2, 0) 595 596 if otherTypeStringFuncAddr != stringAddrs[0] && otherTypeStringFuncAddr != stringAddrs[1] { 597 t.Fatalf("Wrong locations returned for \"/.*Type.*String/\", got: %v expected: %v and %v\n", stringAddrs, someTypeStringFuncAddr, otherTypeStringFuncAddr) 598 } 599 600 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 4, Tracepoint: false}) 601 if err != nil { 602 t.Fatalf("CreateBreakpoint(): %v\n", err) 603 } 604 605 <-c.Continue() 606 607 locationsprog35Addr := findLocationHelper(t, c, "locationsprog.go:35", false, 1, 0)[0] 608 findLocationHelper(t, c, fmt.Sprintf("%s:35", testProgPath(t, "locationsprog")), false, 1, locationsprog35Addr) 609 findLocationHelper(t, c, "+1", false, 1, locationsprog35Addr) 610 findLocationHelper(t, c, "35", false, 1, locationsprog35Addr) 611 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 findLocationHelper(t, c, "main.main", false, 1, firstMainLine) 617 }) 618 619 withTestClient1("stacktraceprog", t, func(c *rpc1.RPCClient) { 620 stacktracemeAddr := findLocationHelper(t, c, "stacktraceprog.go:4", false, 1, 0)[0] 621 findLocationHelper(t, c, "main.stacktraceme", false, 1, stacktracemeAddr) 622 }) 623 624 withTestClient1Extended("locationsUpperCase", t, func(c *rpc1.RPCClient, fixture protest.Fixture) { 625 // Upper case 626 findLocationHelper(t, c, "locationsUpperCase.go:6", false, 1, 0) 627 628 // Fully qualified path 629 findLocationHelper(t, c, fixture.Source+":6", false, 1, 0) 630 bp, err := c.CreateBreakpoint(&api.Breakpoint{File: fixture.Source, Line: 6}) 631 if err != nil { 632 t.Fatalf("Could not set breakpoint in %s: %v\n", fixture.Source, err) 633 } 634 c.ClearBreakpoint(bp.ID) 635 636 // Allow `/` or `\` on Windows 637 if runtime.GOOS == "windows" { 638 findLocationHelper(t, c, filepath.FromSlash(fixture.Source)+":6", false, 1, 0) 639 bp, err = c.CreateBreakpoint(&api.Breakpoint{File: filepath.FromSlash(fixture.Source), Line: 6}) 640 if err != nil { 641 t.Fatalf("Could not set breakpoint in %s: %v\n", filepath.FromSlash(fixture.Source), err) 642 } 643 c.ClearBreakpoint(bp.ID) 644 } 645 646 // Case-insensitive on Windows, case-sensitive otherwise 647 shouldWrongCaseBeError := true 648 numExpectedMatches := 0 649 if runtime.GOOS == "windows" { 650 shouldWrongCaseBeError = false 651 numExpectedMatches = 1 652 } 653 findLocationHelper(t, c, strings.ToLower(fixture.Source)+":6", shouldWrongCaseBeError, numExpectedMatches, 0) 654 bp, err = c.CreateBreakpoint(&api.Breakpoint{File: strings.ToLower(fixture.Source), Line: 6}) 655 if (err == nil) == shouldWrongCaseBeError { 656 t.Fatalf("Could not set breakpoint in %s: %v\n", strings.ToLower(fixture.Source), err) 657 } 658 c.ClearBreakpoint(bp.ID) 659 }) 660 } 661 662 func Test1ClientServer_FindLocationsAddr(t *testing.T) { 663 withTestClient1("locationsprog2", t, func(c *rpc1.RPCClient) { 664 <-c.Continue() 665 666 afunction := findLocationHelper(t, c, "main.afunction", false, 1, 0)[0] 667 anonfunc := findLocationHelper(t, c, "main.main.func1", false, 1, 0)[0] 668 669 findLocationHelper(t, c, "*fn1", false, 1, afunction) 670 findLocationHelper(t, c, "*fn3", false, 1, anonfunc) 671 }) 672 } 673 674 func Test1ClientServer_EvalVariable(t *testing.T) { 675 withTestClient1("testvariables", t, func(c *rpc1.RPCClient) { 676 state := <-c.Continue() 677 678 if state.Err != nil { 679 t.Fatalf("Continue(): %v\n", state.Err) 680 } 681 682 var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "a1") 683 assertNoError(err, t, "EvalVariable") 684 685 t.Logf("var1: %s", var1.SinglelineString()) 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 state := <-c.Continue() 696 697 if state.Err != nil { 698 t.Fatalf("Continue(): %v\n", state.Err) 699 } 700 701 assertNoError(c.SetVariable(api.EvalScope{GoroutineID: -1}, "a2", "8"), t, "SetVariable()") 702 703 a2, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "a2") 704 if err != nil { 705 t.Fatalf("Could not evaluate variable: %v", err) 706 } 707 708 t.Logf("a2: %v", a2) 709 710 n, err := strconv.Atoi(a2.Value) 711 712 if err != nil && n != 8 { 713 t.Fatalf("Wrong variable value: %v", a2) 714 } 715 }) 716 } 717 718 func Test1ClientServer_FullStacktrace(t *testing.T) { 719 if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { 720 t.Skip("cgo doesn't work on darwin/arm64") 721 } 722 723 lenient := false 724 if runtime.GOOS == "windows" { 725 lenient = true 726 } 727 728 withTestClient1("goroutinestackprog", t, func(c *rpc1.RPCClient) { 729 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.stacktraceme", Line: -1}) 730 assertNoError(err, t, "CreateBreakpoint()") 731 state := <-c.Continue() 732 if state.Err != nil { 733 t.Fatalf("Continue(): %v\n", state.Err) 734 } 735 736 gs, err := c.ListGoroutines() 737 assertNoError(err, t, "GoroutinesInfo()") 738 found := make([]bool, 10) 739 for _, g := range gs { 740 frames, err := c.Stacktrace(g.ID, 40, true) 741 assertNoError(err, t, fmt.Sprintf("Stacktrace(%d)", g.ID)) 742 t.Logf("goroutine %d", g.ID) 743 for i, frame := range frames { 744 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()) 745 if frame.Function == nil { 746 continue 747 } 748 if frame.Function.Name() != "main.agoroutine" { 749 continue 750 } 751 for _, arg := range frame.Arguments { 752 if arg.Name != "i" { 753 continue 754 } 755 t.Logf("\tvariable i is %+v\n", arg) 756 argn, err := strconv.Atoi(arg.Value) 757 if err == nil { 758 found[argn] = true 759 } 760 } 761 } 762 } 763 764 for i := range found { 765 if !found[i] { 766 if lenient { 767 lenient = false 768 } else { 769 t.Fatalf("Goroutine %d not found", i) 770 } 771 } 772 } 773 774 t.Logf("continue") 775 776 state = <-c.Continue() 777 if state.Err != nil { 778 t.Fatalf("Continue(): %v\n", state.Err) 779 } 780 781 frames, err := c.Stacktrace(-1, 10, true) 782 assertNoError(err, t, "Stacktrace") 783 784 cur := 3 785 for i, frame := range frames { 786 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()) 787 if i == 0 { 788 continue 789 } 790 v := frame.Var("n") 791 if v == nil { 792 t.Fatalf("Could not find value of variable n in frame %d", i) 793 } 794 vn, err := strconv.Atoi(v.Value) 795 if err != nil || vn != cur { 796 t.Fatalf("Expected value %d got %d (error: %v)", cur, vn, err) 797 } 798 cur-- 799 if cur < 0 { 800 break 801 } 802 } 803 }) 804 } 805 806 func Test1Issue355(t *testing.T) { 807 // After the target process has terminated should return an error but not crash 808 withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) { 809 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1}) 810 assertNoError(err, t, "CreateBreakpoint()") 811 ch := c.Continue() 812 state := <-ch 813 tid := state.CurrentThread.ID 814 gid := state.SelectedGoroutine.ID 815 assertNoError(state.Err, t, "First Continue()") 816 ch = c.Continue() 817 state = <-ch 818 if !state.Exited { 819 t.Fatalf("Target did not terminate after second continue") 820 } 821 822 ch = c.Continue() 823 state = <-ch 824 assertError(state.Err, t, "Continue()") 825 826 s, err := c.Next() 827 assertErrorOrExited(s, err, t, "Next()") 828 s, err = c.Step() 829 assertErrorOrExited(s, err, t, "Step()") 830 s, err = c.StepInstruction() 831 assertErrorOrExited(s, err, t, "StepInstruction()") 832 s, err = c.SwitchThread(tid) 833 assertErrorOrExited(s, err, t, "SwitchThread()") 834 s, err = c.SwitchGoroutine(gid) 835 assertErrorOrExited(s, err, t, "SwitchGoroutine()") 836 s, err = c.Halt() 837 assertErrorOrExited(s, err, t, "Halt()") 838 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: -1}) 839 assertError(err, t, "CreateBreakpoint()") 840 _, err = c.ClearBreakpoint(bp.ID) 841 assertError(err, t, "ClearBreakpoint()") 842 _, err = c.ListThreads() 843 assertError(err, t, "ListThreads()") 844 _, err = c.GetThread(tid) 845 assertError(err, t, "GetThread()") 846 assertError(c.SetVariable(api.EvalScope{GoroutineID: gid}, "a", "10"), t, "SetVariable()") 847 _, err = c.ListLocalVariables(api.EvalScope{GoroutineID: gid}) 848 assertError(err, t, "ListLocalVariables()") 849 _, err = c.ListFunctionArgs(api.EvalScope{GoroutineID: gid}) 850 assertError(err, t, "ListFunctionArgs()") 851 _, err = c.ListRegisters() 852 assertError(err, t, "ListRegisters()") 853 _, err = c.ListGoroutines() 854 assertError(err, t, "ListGoroutines()") 855 _, err = c.Stacktrace(gid, 10, false) 856 assertError(err, t, "Stacktrace()") 857 _, err = c.FindLocation(api.EvalScope{GoroutineID: gid}, "+1") 858 assertError(err, t, "FindLocation()") 859 _, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, 0x40100, api.IntelFlavour) 860 assertError(err, t, "DisassemblePC()") 861 }) 862 } 863 864 func Test1Disasm(t *testing.T) { 865 // Tests that disassembling by PC, range, and current PC all yeld similar results 866 // Tests that disassembly by current PC will return a disassembly containing the instruction at PC 867 // Tests that stepping on a calculated CALL instruction will yield a disassembly that contains the 868 // effective destination of the CALL instruction 869 withTestClient1("locationsprog2", t, func(c *rpc1.RPCClient) { 870 ch := c.Continue() 871 state := <-ch 872 assertNoError(state.Err, t, "Continue()") 873 874 locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main") 875 assertNoError(err, t, "FindLocation()") 876 if len(locs) != 1 { 877 t.Fatalf("wrong number of locations for main.main: %d", len(locs)) 878 } 879 d1, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour) 880 assertNoError(err, t, "DisassemblePC()") 881 if len(d1) < 2 { 882 t.Fatalf("wrong size of disassembly: %d", len(d1)) 883 } 884 885 pcstart := d1[0].Loc.PC 886 pcend := d1[len(d1)-1].Loc.PC + uint64(len(d1[len(d1)-1].Bytes)) 887 d2, err := c.DisassembleRange(api.EvalScope{GoroutineID: -1}, pcstart, pcend, api.IntelFlavour) 888 assertNoError(err, t, "DisassembleRange()") 889 890 if len(d1) != len(d2) { 891 t.Logf("d1: %v", d1) 892 t.Logf("d2: %v", d2) 893 t.Fatal("mismatched length between disassemble pc and disassemble range") 894 } 895 896 d3, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, state.CurrentThread.PC, api.IntelFlavour) 897 assertNoError(err, t, "DisassemblePC() - second call") 898 899 if len(d1) != len(d3) { 900 t.Logf("d1: %v", d1) 901 t.Logf("d3: %v", d3) 902 t.Fatal("mismatched length between the two calls of disassemble pc") 903 } 904 905 // look for static call to afunction() on line 29 906 found := false 907 for i := range d3 { 908 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" { 909 found = true 910 break 911 } 912 } 913 if !found { 914 t.Fatal("Could not find call to main.afunction on line 29") 915 } 916 917 haspc := false 918 for i := range d3 { 919 if d3[i].AtPC { 920 haspc = true 921 break 922 } 923 } 924 925 if !haspc { 926 t.Logf("d3: %v", d3) 927 t.Fatal("PC instruction not found") 928 } 929 930 if runtime.GOARCH == "386" && buildMode == "pie" { 931 // Skip the rest of the test because on intel 386 with PIE build mode 932 // the compiler will insert calls to __x86.get_pc_thunk which do not have DIEs and we can't resolve. 933 return 934 } 935 936 startinstr := getCurinstr(d3) 937 count := 0 938 for { 939 if count > 20 { 940 t.Fatal("too many step instructions executed without finding a call instruction") 941 } 942 state, err := c.StepInstruction() 943 assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) 944 945 d3, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, state.CurrentThread.PC, api.IntelFlavour) 946 assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) 947 948 curinstr := getCurinstr(d3) 949 950 if curinstr == nil { 951 t.Fatalf("Could not find current instruction %d", count) 952 } 953 954 if curinstr.Loc.Line != startinstr.Loc.Line { 955 t.Fatal("Calling StepInstruction() repeatedly did not find the call instruction") 956 } 957 958 if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") { 959 t.Logf("call: %v", curinstr) 960 if curinstr.DestLoc == nil || curinstr.DestLoc.Function == nil { 961 t.Fatalf("Call instruction does not have destination: %v", curinstr) 962 } 963 if curinstr.DestLoc.Function.Name() != "main.afunction" { 964 t.Fatalf("Call instruction destination not main.afunction: %v", curinstr) 965 } 966 break 967 } 968 969 count++ 970 } 971 }) 972 } 973 974 func Test1NegativeStackDepthBug(t *testing.T) { 975 // After the target process has terminated should return an error but not crash 976 withTestClient1("continuetestprog", t, func(c *rpc1.RPCClient) { 977 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1}) 978 assertNoError(err, t, "CreateBreakpoint()") 979 ch := c.Continue() 980 state := <-ch 981 assertNoError(state.Err, t, "Continue()") 982 _, err = c.Stacktrace(-1, -2, true) 983 assertError(err, t, "Stacktrace()") 984 }) 985 } 986 987 func Test1ClientServer_CondBreakpoint(t *testing.T) { 988 if runtime.GOOS == "freebsd" { 989 t.Skip("test is not valid on FreeBSD") 990 } 991 withTestClient1("parallel_next", t, func(c *rpc1.RPCClient) { 992 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: 1}) 993 assertNoError(err, t, "CreateBreakpoint()") 994 bp.Cond = "n == 7" 995 assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 1") 996 bp, err = c.GetBreakpoint(bp.ID) 997 assertNoError(err, t, "GetBreakpoint() 1") 998 bp.Variables = append(bp.Variables, "n") 999 assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 2") 1000 bp, err = c.GetBreakpoint(bp.ID) 1001 assertNoError(err, t, "GetBreakpoint() 2") 1002 if bp.Cond == "" { 1003 t.Fatalf("No condition set on breakpoint %#v", bp) 1004 } 1005 if len(bp.Variables) != 1 { 1006 t.Fatalf("Wrong number of expressions to evaluate on breakpoint %#v", bp) 1007 } 1008 state := <-c.Continue() 1009 assertNoError(state.Err, t, "Continue()") 1010 1011 nvar, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "n") 1012 assertNoError(err, t, "EvalVariable()") 1013 1014 if nvar.SinglelineString() != "7" { 1015 t.Fatalf("Stopped on wrong goroutine %s\n", nvar.Value) 1016 } 1017 }) 1018 } 1019 1020 func Test1Issue419(t *testing.T) { 1021 // Calling service/rpc.(*Client).Halt could cause a crash because both Halt and Continue simultaneously 1022 // try to read 'runtime.g' and debug/dwarf.Data.Type is not thread safe 1023 withTestClient1("issue419", t, func(c *rpc1.RPCClient) { 1024 go func() { 1025 rand.Seed(time.Now().Unix()) 1026 d := time.Duration(rand.Intn(4) + 1) 1027 time.Sleep(d * time.Second) 1028 _, err := c.Halt() 1029 assertNoError(err, t, "RequestManualStop()") 1030 }() 1031 statech := c.Continue() 1032 state := <-statech 1033 assertNoError(state.Err, t, "Continue()") 1034 }) 1035 } 1036 1037 func Test1TypesCommand(t *testing.T) { 1038 withTestClient1("testvariables2", t, func(c *rpc1.RPCClient) { 1039 state := <-c.Continue() 1040 assertNoError(state.Err, t, "Continue()") 1041 types, err := c.ListTypes("") 1042 assertNoError(err, t, "ListTypes()") 1043 1044 found := false 1045 for i := range types { 1046 if types[i] == "main.astruct" { 1047 found = true 1048 break 1049 } 1050 } 1051 if !found { 1052 t.Fatal("Type astruct not found in ListTypes output") 1053 } 1054 1055 types, err = c.ListTypes("^main.astruct$") 1056 assertNoError(err, t, "ListTypes(\"main.astruct\")") 1057 if len(types) != 1 { 1058 t.Fatalf("ListTypes(\"^main.astruct$\") did not filter properly, expected 1 got %d: %v", len(types), types) 1059 } 1060 }) 1061 } 1062 1063 func Test1Issue406(t *testing.T) { 1064 withTestClient1("issue406", t, func(c *rpc1.RPCClient) { 1065 locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "issue406.go:146") 1066 assertNoError(err, t, "FindLocation()") 1067 _, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC}) 1068 assertNoError(err, t, "CreateBreakpoint()") 1069 ch := c.Continue() 1070 state := <-ch 1071 assertNoError(state.Err, t, "Continue()") 1072 v, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "cfgtree") 1073 assertNoError(err, t, "EvalVariable()") 1074 vs := v.MultilineString("", "") 1075 t.Logf("cfgtree formats to: %s\n", vs) 1076 }) 1077 }