github.com/neilgarb/delve@v1.9.2-nobreaks/service/test/integration2_test.go (about) 1 package service_test 2 3 import ( 4 "flag" 5 "fmt" 6 "io/ioutil" 7 "math/rand" 8 "net" 9 "net/rpc" 10 "net/rpc/jsonrpc" 11 "os" 12 "os/exec" 13 "path/filepath" 14 "reflect" 15 "runtime" 16 "strconv" 17 "strings" 18 "testing" 19 "time" 20 21 protest "github.com/go-delve/delve/pkg/proc/test" 22 "github.com/go-delve/delve/service/debugger" 23 24 "github.com/go-delve/delve/pkg/goversion" 25 "github.com/go-delve/delve/pkg/logflags" 26 "github.com/go-delve/delve/service" 27 "github.com/go-delve/delve/service/api" 28 "github.com/go-delve/delve/service/rpc2" 29 "github.com/go-delve/delve/service/rpccommon" 30 ) 31 32 var normalLoadConfig = api.LoadConfig{ 33 FollowPointers: true, 34 MaxVariableRecurse: 1, 35 MaxStringLen: 64, 36 MaxArrayValues: 64, 37 MaxStructFields: -1, 38 } 39 40 var testBackend, buildMode string 41 42 func TestMain(m *testing.M) { 43 flag.StringVar(&testBackend, "backend", "", "selects backend") 44 flag.StringVar(&buildMode, "test-buildmode", "", "selects build mode") 45 var logOutput string 46 flag.StringVar(&logOutput, "log-output", "", "configures log output") 47 flag.Parse() 48 protest.DefaultTestBackend(&testBackend) 49 if buildMode != "" && buildMode != "pie" { 50 fmt.Fprintf(os.Stderr, "unknown build mode %q", buildMode) 51 os.Exit(1) 52 } 53 logflags.Setup(logOutput != "", logOutput, "") 54 os.Exit(protest.RunTestsWithFixtures(m)) 55 } 56 57 func withTestClient2(name string, t *testing.T, fn func(c service.Client)) { 58 withTestClient2Extended(name, t, 0, [3]string{}, func(c service.Client, fixture protest.Fixture) { 59 fn(c) 60 }) 61 } 62 63 func startServer(name string, buildFlags protest.BuildFlags, t *testing.T, redirects [3]string) (clientConn net.Conn, fixture protest.Fixture) { 64 if testBackend == "rr" { 65 protest.MustHaveRecordingAllowed(t) 66 } 67 listener, clientConn := service.ListenerPipe() 68 defer listener.Close() 69 if buildMode == "pie" { 70 buildFlags |= protest.BuildModePIE 71 } 72 fixture = protest.BuildFixture(name, buildFlags) 73 for i := range redirects { 74 if redirects[i] != "" { 75 redirects[i] = filepath.Join(fixture.BuildDir, redirects[i]) 76 } 77 } 78 server := rpccommon.NewServer(&service.Config{ 79 Listener: listener, 80 ProcessArgs: []string{fixture.Path}, 81 Debugger: debugger.Config{ 82 Backend: testBackend, 83 CheckGoVersion: true, 84 Packages: []string{fixture.Source}, 85 BuildFlags: "", // build flags can be an empty string here because the only test that uses it, does not set special flags. 86 ExecuteKind: debugger.ExecutingGeneratedFile, 87 Redirects: redirects, 88 }, 89 }) 90 if err := server.Run(); err != nil { 91 t.Fatal(err) 92 } 93 return clientConn, fixture 94 } 95 96 func withTestClient2Extended(name string, t *testing.T, buildFlags protest.BuildFlags, redirects [3]string, fn func(c service.Client, fixture protest.Fixture)) { 97 clientConn, fixture := startServer(name, buildFlags, t, redirects) 98 client := rpc2.NewClientFromConn(clientConn) 99 defer func() { 100 client.Detach(true) 101 }() 102 103 fn(client, fixture) 104 } 105 106 func TestRunWithInvalidPath(t *testing.T) { 107 if testBackend == "rr" { 108 // This test won't work because rr returns an error, after recording, when 109 // the recording failed but also when the recording succeeded but the 110 // inferior returned an error. Therefore we have to ignore errors from rr. 111 return 112 } 113 listener, err := net.Listen("tcp", "127.0.0.1:0") 114 if err != nil { 115 t.Fatalf("couldn't start listener: %s\n", err) 116 } 117 defer listener.Close() 118 server := rpccommon.NewServer(&service.Config{ 119 Listener: listener, 120 ProcessArgs: []string{"invalid_path"}, 121 APIVersion: 2, 122 Debugger: debugger.Config{ 123 Backend: testBackend, 124 ExecuteKind: debugger.ExecutingGeneratedFile, 125 }, 126 }) 127 if err := server.Run(); err == nil { 128 t.Fatal("Expected Run to return error for invalid program path") 129 } 130 } 131 132 func TestRestart_afterExit(t *testing.T) { 133 withTestClient2("continuetestprog", t, func(c service.Client) { 134 origPid := c.ProcessPid() 135 state := <-c.Continue() 136 if !state.Exited { 137 t.Fatal("expected initial process to have exited") 138 } 139 if _, err := c.Restart(false); err != nil { 140 t.Fatal(err) 141 } 142 if c.ProcessPid() == origPid { 143 t.Fatal("did not spawn new process, has same PID") 144 } 145 state = <-c.Continue() 146 if !state.Exited { 147 t.Fatalf("expected restarted process to have exited %v", state) 148 } 149 }) 150 } 151 152 func TestRestart_breakpointPreservation(t *testing.T) { 153 protest.AllowRecording(t) 154 withTestClient2("continuetestprog", t, func(c service.Client) { 155 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint", Tracepoint: true}) 156 assertNoError(err, t, "CreateBreakpoint()") 157 stateCh := c.Continue() 158 159 state := <-stateCh 160 if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint { 161 t.Fatalf("Wrong breakpoint: %#v\n", state.CurrentThread.Breakpoint) 162 } 163 state = <-stateCh 164 if !state.Exited { 165 t.Fatal("Did not exit after first tracepoint") 166 } 167 168 t.Log("Restart") 169 c.Restart(false) 170 stateCh = c.Continue() 171 state = <-stateCh 172 if state.CurrentThread.Breakpoint.Name != "firstbreakpoint" || !state.CurrentThread.Breakpoint.Tracepoint { 173 t.Fatalf("Wrong breakpoint (after restart): %#v\n", state.CurrentThread.Breakpoint) 174 } 175 state = <-stateCh 176 if !state.Exited { 177 t.Fatal("Did not exit after first tracepoint (after restart)") 178 } 179 }) 180 } 181 182 func TestRestart_duringStop(t *testing.T) { 183 withTestClient2("continuetestprog", t, func(c service.Client) { 184 origPid := c.ProcessPid() 185 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1}) 186 if err != nil { 187 t.Fatal(err) 188 } 189 state := <-c.Continue() 190 if state.CurrentThread.Breakpoint == nil { 191 t.Fatal("did not hit breakpoint") 192 } 193 if _, err := c.Restart(false); err != nil { 194 t.Fatal(err) 195 } 196 if c.ProcessPid() == origPid { 197 t.Fatal("did not spawn new process, has same PID") 198 } 199 bps, err := c.ListBreakpoints(false) 200 if err != nil { 201 t.Fatal(err) 202 } 203 if len(bps) == 0 { 204 t.Fatal("breakpoints not preserved") 205 } 206 }) 207 } 208 209 // This source is a slightly modified version of 210 // _fixtures/testenv.go. The only difference is that 211 // the name of the environment variable we are trying to 212 // read is named differently, so we can assert the code 213 // was actually changed in the test. 214 const modifiedSource = `package main 215 216 import ( 217 "fmt" 218 "os" 219 "runtime" 220 ) 221 222 func main() { 223 x := os.Getenv("SOMEMODIFIEDVAR") 224 runtime.Breakpoint() 225 fmt.Printf("SOMEMODIFIEDVAR=%s\n", x) 226 } 227 ` 228 229 func TestRestart_rebuild(t *testing.T) { 230 // In the original fixture file the env var tested for is SOMEVAR. 231 os.Setenv("SOMEVAR", "bah") 232 233 withTestClient2Extended("testenv", t, 0, [3]string{}, func(c service.Client, f protest.Fixture) { 234 <-c.Continue() 235 236 var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "x", normalLoadConfig) 237 assertNoError(err, t, "EvalVariable") 238 239 if var1.Value != "bah" { 240 t.Fatalf("expected 'bah' got %q", var1.Value) 241 } 242 243 fi, err := os.Stat(f.Source) 244 assertNoError(err, t, "Stat fixture.Source") 245 246 originalSource, err := ioutil.ReadFile(f.Source) 247 assertNoError(err, t, "Reading original source") 248 249 // Ensure we write the original source code back after the test exits. 250 defer ioutil.WriteFile(f.Source, originalSource, fi.Mode()) 251 252 // Write modified source code to the fixture file. 253 err = ioutil.WriteFile(f.Source, []byte(modifiedSource), fi.Mode()) 254 assertNoError(err, t, "Writing modified source") 255 256 // First set our new env var and ensure later that the 257 // modified source code picks it up. 258 os.Setenv("SOMEMODIFIEDVAR", "foobar") 259 260 // Restart the program, rebuilding from source. 261 _, err = c.Restart(true) 262 assertNoError(err, t, "Restart(true)") 263 264 <-c.Continue() 265 266 var1, err = c.EvalVariable(api.EvalScope{GoroutineID: -1}, "x", normalLoadConfig) 267 assertNoError(err, t, "EvalVariable") 268 269 if var1.Value != "foobar" { 270 t.Fatalf("expected 'foobar' got %q", var1.Value) 271 } 272 }) 273 } 274 275 func TestClientServer_exit(t *testing.T) { 276 protest.AllowRecording(t) 277 withTestClient2("continuetestprog", t, func(c service.Client) { 278 state, err := c.GetState() 279 if err != nil { 280 t.Fatalf("Unexpected error: %v", err) 281 } 282 if e, a := false, state.Exited; e != a { 283 t.Fatalf("Expected exited %v, got %v", e, a) 284 } 285 state = <-c.Continue() 286 if state.Err == nil { 287 t.Fatalf("Error expected after continue") 288 } 289 if !state.Exited { 290 t.Fatalf("Expected exit after continue: %v", state) 291 } 292 _, err = c.GetState() 293 if err == nil { 294 t.Fatal("Expected error on querying state from exited process") 295 } 296 }) 297 } 298 299 func TestClientServer_step(t *testing.T) { 300 protest.AllowRecording(t) 301 withTestClient2("testprog", t, func(c service.Client) { 302 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.helloworld", Line: -1}) 303 if err != nil { 304 t.Fatalf("Unexpected error: %v", err) 305 } 306 307 stateBefore := <-c.Continue() 308 if stateBefore.Err != nil { 309 t.Fatalf("Unexpected error: %v", stateBefore.Err) 310 } 311 312 stateAfter, err := c.Step() 313 if err != nil { 314 t.Fatalf("Unexpected error: %v", err) 315 } 316 317 if before, after := stateBefore.CurrentThread.PC, stateAfter.CurrentThread.PC; before >= after { 318 t.Fatalf("Expected %#v to be greater than %#v", after, before) 319 } 320 }) 321 } 322 323 func TestClientServer_stepout(t *testing.T) { 324 protest.AllowRecording(t) 325 withTestClient2("testnextprog", t, func(c service.Client) { 326 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.helloworld", Line: -1}) 327 assertNoError(err, t, "CreateBreakpoint()") 328 stateBefore := <-c.Continue() 329 assertNoError(stateBefore.Err, t, "Continue()") 330 if stateBefore.CurrentThread.Line != 13 { 331 t.Fatalf("wrong line number %s:%d, expected %d", stateBefore.CurrentThread.File, stateBefore.CurrentThread.Line, 13) 332 } 333 stateAfter, err := c.StepOut() 334 assertNoError(err, t, "StepOut()") 335 if stateAfter.CurrentThread.Line != 35 { 336 t.Fatalf("wrong line number %s:%d, expected %d", stateAfter.CurrentThread.File, stateAfter.CurrentThread.Line, 13) 337 } 338 }) 339 } 340 341 func testnext2(testcases []nextTest, initialLocation string, t *testing.T) { 342 protest.AllowRecording(t) 343 withTestClient2("testnextprog", t, func(c service.Client) { 344 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: initialLocation, Line: -1}) 345 if err != nil { 346 t.Fatalf("Unexpected error: %v", err) 347 } 348 349 state := <-c.Continue() 350 if state.Err != nil { 351 t.Fatalf("Unexpected error: %v", state.Err) 352 } 353 354 _, err = c.ClearBreakpoint(bp.ID) 355 if err != nil { 356 t.Fatalf("Unexpected error: %v", err) 357 } 358 359 for _, tc := range testcases { 360 if state.CurrentThread.Line != tc.begin { 361 t.Fatalf("Program not stopped at correct spot expected %d was %d", tc.begin, state.CurrentThread.Line) 362 } 363 364 t.Logf("Next for scenario %#v", tc) 365 state, err = c.Next() 366 if err != nil { 367 t.Fatalf("Unexpected error: %v", err) 368 } 369 370 if state.CurrentThread.Line != tc.end { 371 t.Fatalf("Program did not continue to correct next location expected %d was %d", tc.end, state.CurrentThread.Line) 372 } 373 } 374 }) 375 } 376 377 func TestNextGeneral(t *testing.T) { 378 var testcases []nextTest 379 380 ver, _ := goversion.Parse(runtime.Version()) 381 382 if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) { 383 testcases = []nextTest{ 384 {17, 19}, 385 {19, 20}, 386 {20, 23}, 387 {23, 24}, 388 {24, 26}, 389 {26, 31}, 390 {31, 23}, 391 {23, 24}, 392 {24, 26}, 393 {26, 31}, 394 {31, 23}, 395 {23, 24}, 396 {24, 26}, 397 {26, 27}, 398 {27, 28}, 399 {28, 34}, 400 } 401 } else { 402 testcases = []nextTest{ 403 {17, 19}, 404 {19, 20}, 405 {20, 23}, 406 {23, 24}, 407 {24, 26}, 408 {26, 31}, 409 {31, 23}, 410 {23, 24}, 411 {24, 26}, 412 {26, 31}, 413 {31, 23}, 414 {23, 24}, 415 {24, 26}, 416 {26, 27}, 417 {27, 34}, 418 } 419 } 420 421 testnext2(testcases, "main.testnext", t) 422 } 423 424 func TestNextFunctionReturn(t *testing.T) { 425 testcases := []nextTest{ 426 {13, 14}, 427 {14, 15}, 428 {15, 35}, 429 } 430 testnext2(testcases, "main.helloworld", t) 431 } 432 433 func TestClientServer_breakpointInMainThread(t *testing.T) { 434 protest.AllowRecording(t) 435 withTestClient2("testprog", t, func(c service.Client) { 436 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.helloworld", Line: 1}) 437 if err != nil { 438 t.Fatalf("Unexpected error: %v", err) 439 } 440 441 state := <-c.Continue() 442 if state.Err != nil { 443 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 444 } 445 446 pc := state.CurrentThread.PC 447 448 if pc-1 != bp.Addr && pc != bp.Addr { 449 f, l := state.CurrentThread.File, state.CurrentThread.Line 450 t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, bp.Addr) 451 } 452 }) 453 } 454 455 func TestClientServer_breakpointInSeparateGoroutine(t *testing.T) { 456 protest.AllowRecording(t) 457 withTestClient2("testthreads", t, func(c service.Client) { 458 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.anotherthread", Line: 1}) 459 if err != nil { 460 t.Fatalf("Unexpected error: %v", err) 461 } 462 463 state := <-c.Continue() 464 if state.Err != nil { 465 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 466 } 467 468 f, l := state.CurrentThread.File, state.CurrentThread.Line 469 if f != "testthreads.go" && l != 9 { 470 t.Fatal("Program did not hit breakpoint") 471 } 472 }) 473 } 474 475 func TestClientServer_breakAtNonexistentPoint(t *testing.T) { 476 withTestClient2("testprog", t, func(c service.Client) { 477 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "nowhere", Line: 1}) 478 if err == nil { 479 t.Fatal("Should not be able to break at non existent function") 480 } 481 }) 482 } 483 484 func TestClientServer_clearBreakpoint(t *testing.T) { 485 withTestClient2("testprog", t, func(c service.Client) { 486 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sleepytime", Line: 1}) 487 if err != nil { 488 t.Fatalf("Unexpected error: %v", err) 489 } 490 491 if e, a := 1, countBreakpoints(t, c); e != a { 492 t.Fatalf("Expected breakpoint count %d, got %d", e, a) 493 } 494 495 deleted, err := c.ClearBreakpoint(bp.ID) 496 if err != nil { 497 t.Fatalf("Unexpected error: %v", err) 498 } 499 500 if deleted.ID != bp.ID { 501 t.Fatalf("Expected deleted breakpoint ID %v, got %v", bp.ID, deleted.ID) 502 } 503 504 if e, a := 0, countBreakpoints(t, c); e != a { 505 t.Fatalf("Expected breakpoint count %d, got %d", e, a) 506 } 507 }) 508 } 509 510 func TestClientServer_toggleBreakpoint(t *testing.T) { 511 withTestClient2("testtoggle", t, func(c service.Client) { 512 toggle := func(bp *api.Breakpoint) { 513 t.Helper() 514 dbp, err := c.ToggleBreakpoint(bp.ID) 515 if err != nil { 516 t.Fatalf("Unexpected error: %v", err) 517 } 518 if dbp.ID != bp.ID { 519 t.Fatalf("The IDs don't match") 520 } 521 } 522 523 // This one is toggled twice 524 bp1, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.lineOne", Tracepoint: true}) 525 if err != nil { 526 t.Fatalf("Unexpected error: %v\n", err) 527 } 528 529 toggle(bp1) 530 toggle(bp1) 531 532 // This one is toggled once 533 bp2, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.lineTwo", Tracepoint: true}) 534 if err != nil { 535 t.Fatalf("Unexpected error: %v\n", err) 536 } 537 538 toggle(bp2) 539 540 // This one is never toggled 541 bp3, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.lineThree", Tracepoint: true}) 542 if err != nil { 543 t.Fatalf("Unexpected error: %v\n", err) 544 } 545 546 if e, a := 3, countBreakpoints(t, c); e != a { 547 t.Fatalf("Expected breakpoint count %d, got %d", e, a) 548 } 549 550 enableCount := 0 551 disabledCount := 0 552 553 contChan := c.Continue() 554 for state := range contChan { 555 if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil { 556 switch state.CurrentThread.Breakpoint.ID { 557 case bp1.ID, bp3.ID: 558 enableCount++ 559 case bp2.ID: 560 disabledCount++ 561 } 562 563 t.Logf("%v", state) 564 } 565 if state.Exited { 566 continue 567 } 568 if state.Err != nil { 569 t.Fatalf("Unexpected error during continue: %v\n", state.Err) 570 } 571 } 572 573 if enableCount != 2 { 574 t.Fatalf("Wrong number of enabled hits: %d\n", enableCount) 575 } 576 577 if disabledCount != 0 { 578 t.Fatalf("A disabled breakpoint was hit: %d\n", disabledCount) 579 } 580 }) 581 } 582 583 func TestClientServer_toggleAmendedBreakpoint(t *testing.T) { 584 withTestClient2("testtoggle", t, func(c service.Client) { 585 toggle := func(bp *api.Breakpoint) { 586 dbp, err := c.ToggleBreakpoint(bp.ID) 587 if err != nil { 588 t.Fatalf("Unexpected error: %v", err) 589 } 590 if dbp.ID != bp.ID { 591 t.Fatalf("The IDs don't match") 592 } 593 } 594 595 // This one is toggled twice 596 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.lineOne", Tracepoint: true}) 597 if err != nil { 598 t.Fatalf("Unexpected error: %v\n", err) 599 } 600 bp.Cond = "n == 7" 601 assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 1") 602 603 // Toggle off. 604 toggle(bp) 605 // Toggle on. 606 toggle(bp) 607 608 amended, err := c.GetBreakpoint(bp.ID) 609 if err != nil { 610 t.Fatal(err) 611 } 612 if amended.Cond == "" { 613 t.Fatal("breakpoint amendedments not preserved after toggle") 614 } 615 }) 616 } 617 618 func TestClientServer_disableHitCondLSSBreakpoint(t *testing.T) { 619 withTestClient2("break", t, func(c service.Client) { 620 fp := testProgPath(t, "break") 621 hitCondBp, err := c.CreateBreakpoint(&api.Breakpoint{ 622 File: fp, 623 Line: 7, 624 HitCond: "< 3", 625 }) 626 if err != nil { 627 t.Fatalf("Unexpected error: %v", err) 628 } 629 630 state := <-c.Continue() 631 if state.Err != nil { 632 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 633 } 634 635 f, l := state.CurrentThread.File, state.CurrentThread.Line 636 if f != "break.go" && l != 7 { 637 t.Fatal("Program did not hit breakpoint") 638 } 639 640 ivar, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "i", normalLoadConfig) 641 assertNoError(err, t, "EvalVariable") 642 643 t.Logf("ivar: %s", ivar.SinglelineString()) 644 645 if ivar.Value != "1" { 646 t.Fatalf("Wrong variable value: %s", ivar.Value) 647 } 648 649 bp, err := c.GetBreakpoint(hitCondBp.ID) 650 assertNoError(err, t, "GetBreakpoint()") 651 652 if bp.Disabled { 653 t.Fatalf( 654 "Hit condition %s is still satisfiable but breakpoint has been disabled", 655 bp.HitCond, 656 ) 657 } 658 659 state = <-c.Continue() 660 if state.Err != nil { 661 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 662 } 663 664 f, l = state.CurrentThread.File, state.CurrentThread.Line 665 if f != "break.go" && l != 7 { 666 t.Fatal("Program did not hit breakpoint") 667 } 668 669 ivar, err = c.EvalVariable(api.EvalScope{GoroutineID: -1}, "i", normalLoadConfig) 670 assertNoError(err, t, "EvalVariable") 671 672 t.Logf("ivar: %s", ivar.SinglelineString()) 673 674 if ivar.Value != "2" { 675 t.Fatalf("Wrong variable value: %s", ivar.Value) 676 } 677 678 bp, err = c.GetBreakpoint(hitCondBp.ID) 679 assertNoError(err, t, "GetBreakpoint()") 680 681 if !bp.Disabled { 682 t.Fatalf( 683 "Hit condition %s is no more satisfiable but breakpoint has not been disabled", 684 bp.HitCond, 685 ) 686 } 687 }) 688 } 689 690 func TestClientServer_disableHitEQLCondBreakpoint(t *testing.T) { 691 withTestClient2("break", t, func(c service.Client) { 692 fp := testProgPath(t, "break") 693 hitCondBp, err := c.CreateBreakpoint(&api.Breakpoint{ 694 File: fp, 695 Line: 7, 696 HitCond: "== 3", 697 }) 698 if err != nil { 699 t.Fatalf("Unexpected error: %v", err) 700 } 701 702 state := <-c.Continue() 703 if state.Err != nil { 704 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 705 } 706 707 f, l := state.CurrentThread.File, state.CurrentThread.Line 708 if f != "break.go" && l != 7 { 709 t.Fatal("Program did not hit breakpoint") 710 } 711 712 ivar, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "i", normalLoadConfig) 713 assertNoError(err, t, "EvalVariable") 714 715 t.Logf("ivar: %s", ivar.SinglelineString()) 716 717 if ivar.Value != "3" { 718 t.Fatalf("Wrong variable value: %s", ivar.Value) 719 } 720 721 bp, err := c.GetBreakpoint(hitCondBp.ID) 722 assertNoError(err, t, "GetBreakpoint()") 723 724 if !bp.Disabled { 725 t.Fatalf( 726 "Hit condition %s is no more satisfiable but breakpoint has not been disabled", 727 bp.HitCond, 728 ) 729 } 730 }) 731 } 732 733 func TestClientServer_switchThread(t *testing.T) { 734 protest.AllowRecording(t) 735 withTestClient2("testnextprog", t, func(c service.Client) { 736 // With invalid thread id 737 _, err := c.SwitchThread(-1) 738 if err == nil { 739 t.Fatal("Expected error for invalid thread id") 740 } 741 742 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1}) 743 if err != nil { 744 t.Fatalf("Unexpected error: %v", err) 745 } 746 state := <-c.Continue() 747 if state.Err != nil { 748 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 749 } 750 751 var nt int 752 ct := state.CurrentThread.ID 753 threads, err := c.ListThreads() 754 if err != nil { 755 t.Fatalf("Unexpected error: %v", err) 756 } 757 for _, th := range threads { 758 if th.ID != ct { 759 nt = th.ID 760 break 761 } 762 } 763 if nt == 0 { 764 t.Fatal("could not find thread to switch to") 765 } 766 // With valid thread id 767 state, err = c.SwitchThread(nt) 768 if err != nil { 769 t.Fatal(err) 770 } 771 if state.CurrentThread.ID != nt { 772 t.Fatal("Did not switch threads") 773 } 774 }) 775 } 776 777 func TestClientServer_infoLocals(t *testing.T) { 778 protest.AllowRecording(t) 779 withTestClient2("testnextprog", t, func(c service.Client) { 780 fp := testProgPath(t, "testnextprog") 781 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 24}) 782 if err != nil { 783 t.Fatalf("Unexpected error: %v", err) 784 } 785 state := <-c.Continue() 786 if state.Err != nil { 787 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 788 } 789 locals, err := c.ListLocalVariables(api.EvalScope{GoroutineID: -1}, normalLoadConfig) 790 if err != nil { 791 t.Fatalf("Unexpected error: %v", err) 792 } 793 if len(locals) != 3 { 794 t.Fatalf("Expected 3 locals, got %d %#v", len(locals), locals) 795 } 796 }) 797 } 798 799 func TestClientServer_infoArgs(t *testing.T) { 800 protest.AllowRecording(t) 801 withTestClient2("testnextprog", t, func(c service.Client) { 802 fp := testProgPath(t, "testnextprog") 803 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 47}) 804 if err != nil { 805 t.Fatalf("Unexpected error: %v", err) 806 } 807 state := <-c.Continue() 808 if state.Err != nil { 809 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 810 } 811 regs, err := c.ListThreadRegisters(0, false) 812 if err != nil { 813 t.Fatalf("Unexpected error: %v", err) 814 } 815 if len(regs) == 0 { 816 t.Fatal("Expected string showing registers values, got empty string") 817 } 818 819 regs, err = c.ListScopeRegisters(api.EvalScope{GoroutineID: -1, Frame: 0}, false) 820 assertNoError(err, t, "ListScopeRegisters(-1, 0)") 821 if len(regs) == 0 { 822 t.Fatal("Expected string showing registers values, got empty string") 823 } 824 t.Logf("GoroutineID: -1, Frame: 0\n%s", regs.String()) 825 826 regs, err = c.ListScopeRegisters(api.EvalScope{GoroutineID: -1, Frame: 1}, false) 827 assertNoError(err, t, "ListScopeRegisters(-1, 1)") 828 if len(regs) == 0 { 829 t.Fatal("Expected string showing registers values, got empty string") 830 } 831 t.Logf("GoroutineID: -1, Frame: 1\n%s", regs.String()) 832 833 locals, err := c.ListFunctionArgs(api.EvalScope{GoroutineID: -1}, normalLoadConfig) 834 if err != nil { 835 t.Fatalf("Unexpected error: %v", err) 836 } 837 if len(locals) != 2 { 838 t.Fatalf("Expected 2 function args, got %d %#v", len(locals), locals) 839 } 840 }) 841 } 842 843 func TestClientServer_traceContinue(t *testing.T) { 844 protest.AllowRecording(t) 845 withTestClient2("integrationprog", t, func(c service.Client) { 846 fp := testProgPath(t, "integrationprog") 847 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 15, Tracepoint: true, Goroutine: true, Stacktrace: 5, Variables: []string{"i"}}) 848 if err != nil { 849 t.Fatalf("Unexpected error: %v\n", err) 850 } 851 count := 0 852 contChan := c.Continue() 853 for state := range contChan { 854 if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil { 855 count++ 856 857 t.Logf("%v", state) 858 859 bpi := state.CurrentThread.BreakpointInfo 860 861 if bpi.Goroutine == nil { 862 t.Fatalf("No goroutine information") 863 } 864 865 if len(bpi.Stacktrace) <= 0 { 866 t.Fatalf("No stacktrace\n") 867 } 868 869 if len(bpi.Variables) != 1 { 870 t.Fatalf("Wrong number of variables returned: %d", len(bpi.Variables)) 871 } 872 873 if bpi.Variables[0].Name != "i" { 874 t.Fatalf("Wrong variable returned %s", bpi.Variables[0].Name) 875 } 876 877 t.Logf("Variable i is %v", bpi.Variables[0]) 878 879 n, err := strconv.Atoi(bpi.Variables[0].Value) 880 881 if err != nil || n != count-1 { 882 t.Fatalf("Wrong variable value %q (%v %d)", bpi.Variables[0].Value, err, count) 883 } 884 } 885 if state.Exited { 886 continue 887 } 888 t.Logf("%v", state) 889 if state.Err != nil { 890 t.Fatalf("Unexpected error during continue: %v\n", state.Err) 891 } 892 893 } 894 895 if count != 3 { 896 t.Fatalf("Wrong number of continues hit: %d\n", count) 897 } 898 }) 899 } 900 901 func TestClientServer_traceContinue2(t *testing.T) { 902 protest.AllowRecording(t) 903 withTestClient2("integrationprog", t, func(c service.Client) { 904 bp1, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Tracepoint: true}) 905 if err != nil { 906 t.Fatalf("Unexpected error: %v\n", err) 907 } 908 bp2, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: 1, Tracepoint: true}) 909 if err != nil { 910 t.Fatalf("Unexpected error: %v\n", err) 911 } 912 countMain := 0 913 countSayhi := 0 914 contChan := c.Continue() 915 for state := range contChan { 916 if state.CurrentThread != nil && state.CurrentThread.Breakpoint != nil { 917 switch state.CurrentThread.Breakpoint.ID { 918 case bp1.ID: 919 countMain++ 920 case bp2.ID: 921 countSayhi++ 922 } 923 924 t.Logf("%v", state) 925 } 926 if state.Exited { 927 continue 928 } 929 if state.Err != nil { 930 t.Fatalf("Unexpected error during continue: %v\n", state.Err) 931 } 932 933 } 934 935 if countMain != 1 { 936 t.Fatalf("Wrong number of continues (main.main) hit: %d\n", countMain) 937 } 938 939 if countSayhi != 3 { 940 t.Fatalf("Wrong number of continues (main.sayhi) hit: %d\n", countSayhi) 941 } 942 }) 943 } 944 945 func TestClientServer_FindLocations(t *testing.T) { 946 withTestClient2("locationsprog", t, func(c service.Client) { 947 someFunctionCallAddr := findLocationHelper(t, c, "locationsprog.go:26", false, 1, 0)[0] 948 someFunctionLine1 := findLocationHelper(t, c, "locationsprog.go:27", false, 1, 0)[0] 949 findLocationHelper(t, c, "anotherFunction:1", false, 1, someFunctionLine1) 950 findLocationHelper(t, c, "main.anotherFunction:1", false, 1, someFunctionLine1) 951 findLocationHelper(t, c, "anotherFunction", false, 1, someFunctionCallAddr) 952 findLocationHelper(t, c, "main.anotherFunction", false, 1, someFunctionCallAddr) 953 findLocationHelper(t, c, fmt.Sprintf("*0x%x", someFunctionCallAddr), false, 1, someFunctionCallAddr) 954 findLocationHelper(t, c, "sprog.go:26", true, 0, 0) 955 956 findLocationHelper(t, c, "String", true, 0, 0) 957 findLocationHelper(t, c, "main.String", true, 0, 0) 958 959 someTypeStringFuncAddr := findLocationHelper(t, c, "locationsprog.go:14", false, 1, 0)[0] 960 otherTypeStringFuncAddr := findLocationHelper(t, c, "locationsprog.go:18", false, 1, 0)[0] 961 findLocationHelper(t, c, "SomeType.String", false, 1, someTypeStringFuncAddr) 962 findLocationHelper(t, c, "(*SomeType).String", false, 1, someTypeStringFuncAddr) 963 findLocationHelper(t, c, "main.SomeType.String", false, 1, someTypeStringFuncAddr) 964 findLocationHelper(t, c, "main.(*SomeType).String", false, 1, someTypeStringFuncAddr) 965 966 // Issue #275 967 readfile := findLocationHelper(t, c, "io/ioutil.ReadFile", false, 1, 0)[0] 968 969 // Issue #296 970 findLocationHelper(t, c, "/io/ioutil.ReadFile", false, 1, readfile) 971 findLocationHelper(t, c, "ioutil.ReadFile", false, 1, readfile) 972 973 stringAddrs := findLocationHelper(t, c, "/^main.*Type.*String$/", false, 2, 0) 974 975 if otherTypeStringFuncAddr != stringAddrs[0] && otherTypeStringFuncAddr != stringAddrs[1] { 976 t.Fatalf("Wrong locations returned for \"/.*Type.*String/\", got: %v expected: %v and %v\n", stringAddrs, someTypeStringFuncAddr, otherTypeStringFuncAddr) 977 } 978 979 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 4, Tracepoint: false}) 980 if err != nil { 981 t.Fatalf("CreateBreakpoint(): %v\n", err) 982 } 983 984 <-c.Continue() 985 986 locationsprog35Addr := findLocationHelper(t, c, "locationsprog.go:35", false, 1, 0)[0] 987 findLocationHelper(t, c, fmt.Sprintf("%s:35", testProgPath(t, "locationsprog")), false, 1, locationsprog35Addr) 988 findLocationHelper(t, c, "+1", false, 1, locationsprog35Addr) 989 findLocationHelper(t, c, "35", false, 1, locationsprog35Addr) 990 findLocationHelper(t, c, "-1", false, 1, findLocationHelper(t, c, "locationsprog.go:33", false, 1, 0)[0]) 991 992 findLocationHelper(t, c, `*amap["k"]`, false, 1, findLocationHelper(t, c, `amap["k"]`, false, 1, 0)[0]) 993 994 locsNoSubst, _ := c.FindLocation(api.EvalScope{GoroutineID: -1}, "_fixtures/locationsprog.go:35", false, nil) 995 sep := "/" 996 if strings.Contains(locsNoSubst[0].File, "\\") { 997 sep = "\\" 998 } 999 substRules := [][2]string{[2]string{strings.Replace(locsNoSubst[0].File, "locationsprog.go", "", 1), strings.Replace(locsNoSubst[0].File, "_fixtures"+sep+"locationsprog.go", "nonexistent", 1)}} 1000 t.Logf("substitute rules: %q -> %q", substRules[0][0], substRules[0][1]) 1001 locsSubst, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "nonexistent/locationsprog.go:35", false, substRules) 1002 if err != nil { 1003 t.Fatalf("FindLocation(locationsprog.go:35) with substitute rules: %v", err) 1004 } 1005 t.Logf("FindLocation(\"/nonexistent/path/locationsprog.go:35\") -> %#v", locsSubst) 1006 if locsNoSubst[0].PC != locsSubst[0].PC { 1007 t.Fatalf("FindLocation with substitute rules mismatch %#v %#v", locsNoSubst[0], locsSubst[0]) 1008 } 1009 1010 }) 1011 1012 withTestClient2("testnextdefer", t, func(c service.Client) { 1013 firstMainLine := findLocationHelper(t, c, "testnextdefer.go:5", false, 1, 0)[0] 1014 findLocationHelper(t, c, "main.main", false, 1, firstMainLine) 1015 }) 1016 1017 withTestClient2("stacktraceprog", t, func(c service.Client) { 1018 stacktracemeAddr := findLocationHelper(t, c, "stacktraceprog.go:4", false, 1, 0)[0] 1019 findLocationHelper(t, c, "main.stacktraceme", false, 1, stacktracemeAddr) 1020 }) 1021 1022 withTestClient2Extended("locationsUpperCase", t, 0, [3]string{}, func(c service.Client, fixture protest.Fixture) { 1023 // Upper case 1024 findLocationHelper(t, c, "locationsUpperCase.go:6", false, 1, 0) 1025 1026 // Fully qualified path 1027 findLocationHelper(t, c, fixture.Source+":6", false, 1, 0) 1028 bp, err := c.CreateBreakpoint(&api.Breakpoint{File: fixture.Source, Line: 6}) 1029 if err != nil { 1030 t.Fatalf("Could not set breakpoint in %s: %v\n", fixture.Source, err) 1031 } 1032 c.ClearBreakpoint(bp.ID) 1033 1034 // Allow `/` or `\` on Windows 1035 if runtime.GOOS == "windows" { 1036 findLocationHelper(t, c, filepath.FromSlash(fixture.Source)+":6", false, 1, 0) 1037 bp, err = c.CreateBreakpoint(&api.Breakpoint{File: filepath.FromSlash(fixture.Source), Line: 6}) 1038 if err != nil { 1039 t.Fatalf("Could not set breakpoint in %s: %v\n", filepath.FromSlash(fixture.Source), err) 1040 } 1041 c.ClearBreakpoint(bp.ID) 1042 } 1043 1044 // Case-insensitive on Windows, case-sensitive otherwise 1045 shouldWrongCaseBeError := true 1046 numExpectedMatches := 0 1047 if runtime.GOOS == "windows" { 1048 shouldWrongCaseBeError = false 1049 numExpectedMatches = 1 1050 } 1051 findLocationHelper(t, c, strings.ToLower(fixture.Source)+":6", shouldWrongCaseBeError, numExpectedMatches, 0) 1052 bp, err = c.CreateBreakpoint(&api.Breakpoint{File: strings.ToLower(fixture.Source), Line: 6}) 1053 if (err == nil) == shouldWrongCaseBeError { 1054 t.Fatalf("Could not set breakpoint in %s: %v\n", strings.ToLower(fixture.Source), err) 1055 } 1056 c.ClearBreakpoint(bp.ID) 1057 }) 1058 1059 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) { 1060 withTestClient2("pkgrenames", t, func(c service.Client) { 1061 someFuncLoc := findLocationHelper(t, c, "github.com/go-delve/delve/_fixtures/internal/dir%2eio.SomeFunction:0", false, 1, 0)[0] 1062 findLocationHelper(t, c, "dirio.SomeFunction:0", false, 1, someFuncLoc) 1063 }) 1064 } 1065 1066 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { 1067 withTestClient2("locationsprog_generic", t, func(c service.Client) { 1068 const ( 1069 methodLine = "locationsprog_generic.go:9" 1070 funcLine = "locationsprog_generic.go:13" 1071 funcLine2 = "locationsprog_generic.go:14" 1072 ) 1073 methodLoc := findLocationHelper2(t, c, methodLine, nil) 1074 if len(methodLoc.PCs) != 2 { 1075 // we didn't get both instantiations of the method 1076 t.Errorf("wrong number of PCs for %s: %#x", methodLine, methodLoc.PCs) 1077 } 1078 1079 funcLoc := findLocationHelper2(t, c, funcLine, nil) 1080 if len(funcLoc.PCs) != 2 { 1081 // we didn't get both instantiations of the function 1082 t.Errorf("wrong number of PCs for %s: %#x", funcLine, funcLoc.PCs) 1083 } 1084 1085 funcLoc2 := findLocationHelper2(t, c, funcLine2, nil) 1086 if len(funcLoc2.PCs) != 2 { 1087 t.Errorf("wrong number of PCs for %s: %#x", funcLine2, funcLoc2.PCs) 1088 } 1089 1090 findLocationHelper2(t, c, "main.ParamFunc", funcLoc) 1091 1092 findLocationHelper2(t, c, "ParamFunc", funcLoc) 1093 1094 findLocationHelper2(t, c, "main.ParamReceiver.Amethod", methodLoc) 1095 findLocationHelper2(t, c, "main.Amethod", methodLoc) 1096 findLocationHelper2(t, c, "ParamReceiver.Amethod", methodLoc) 1097 findLocationHelper2(t, c, "Amethod", methodLoc) 1098 1099 findLocationHelper2(t, c, "main.(*ParamReceiver).Amethod", methodLoc) 1100 findLocationHelper2(t, c, "(*ParamReceiver).Amethod", methodLoc) 1101 1102 findLocationHelper2(t, c, "main.(*ParamReceiver).Amethod", methodLoc) 1103 findLocationHelper2(t, c, "(*ParamReceiver).Amethod", methodLoc) 1104 1105 findLocationHelper2(t, c, "main.ParamFunc:1", funcLoc2) 1106 }) 1107 } 1108 } 1109 1110 func findLocationHelper2(t *testing.T, c service.Client, loc string, checkLoc *api.Location) *api.Location { 1111 locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, loc, false, nil) 1112 if err != nil { 1113 t.Fatalf("FindLocation(%q) -> error %v", loc, err) 1114 } 1115 t.Logf("FindLocation(%q) → %v\n", loc, locs) 1116 if len(locs) != 1 { 1117 t.Logf("Wrong number of locations returned for location %q (got %d expected 1)", loc, len(locs)) 1118 } 1119 1120 if checkLoc == nil { 1121 return &locs[0] 1122 } 1123 1124 if len(checkLoc.PCs) != len(locs[0].PCs) { 1125 t.Fatalf("Wrong number of PCs returned (got %#x expected %#x)", locs[0].PCs, checkLoc.PCs) 1126 } 1127 1128 for i := range checkLoc.PCs { 1129 if checkLoc.PCs[i] != locs[0].PCs[i] { 1130 t.Fatalf("Wrong PCs returned (got %#x expected %#x)", locs[0].PCs, checkLoc.PCs) 1131 } 1132 } 1133 1134 return &locs[0] 1135 } 1136 1137 func TestClientServer_FindLocationsAddr(t *testing.T) { 1138 withTestClient2("locationsprog2", t, func(c service.Client) { 1139 <-c.Continue() 1140 1141 afunction := findLocationHelper(t, c, "main.afunction", false, 1, 0)[0] 1142 anonfunc := findLocationHelper(t, c, "main.main.func1", false, 1, 0)[0] 1143 1144 findLocationHelper(t, c, "*fn1", false, 1, afunction) 1145 findLocationHelper(t, c, "*fn3", false, 1, anonfunc) 1146 }) 1147 } 1148 1149 func TestClientServer_FindLocationsExactMatch(t *testing.T) { 1150 // if an expression matches multiple functions but one of them is an exact 1151 // match it should be used anyway. 1152 // In this example "math/rand.Intn" would normally match "math/rand.Intn" 1153 // and "math/rand.(*Rand).Intn" but since the first match is exact it 1154 // should be prioritized. 1155 withTestClient2("locationsprog3", t, func(c service.Client) { 1156 <-c.Continue() 1157 findLocationHelper(t, c, "math/rand.Intn", false, 1, 0) 1158 }) 1159 } 1160 1161 func TestClientServer_EvalVariable(t *testing.T) { 1162 withTestClient2("testvariables", t, func(c service.Client) { 1163 state := <-c.Continue() 1164 1165 if state.Err != nil { 1166 t.Fatalf("Continue(): %v\n", state.Err) 1167 } 1168 1169 var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "a1", normalLoadConfig) 1170 assertNoError(err, t, "EvalVariable") 1171 1172 t.Logf("var1: %s", var1.SinglelineString()) 1173 1174 if var1.Value != "foofoofoofoofoofoo" { 1175 t.Fatalf("Wrong variable value: %s", var1.Value) 1176 } 1177 }) 1178 } 1179 1180 func TestClientServer_SetVariable(t *testing.T) { 1181 withTestClient2("testvariables", t, func(c service.Client) { 1182 state := <-c.Continue() 1183 1184 if state.Err != nil { 1185 t.Fatalf("Continue(): %v\n", state.Err) 1186 } 1187 1188 assertNoError(c.SetVariable(api.EvalScope{GoroutineID: -1}, "a2", "8"), t, "SetVariable()") 1189 1190 a2, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "a2", normalLoadConfig) 1191 if err != nil { 1192 t.Fatalf("Could not evaluate variable: %v", err) 1193 } 1194 1195 t.Logf("a2: %v", a2) 1196 1197 n, err := strconv.Atoi(a2.Value) 1198 1199 if err != nil && n != 8 { 1200 t.Fatalf("Wrong variable value: %v", a2) 1201 } 1202 }) 1203 } 1204 1205 func TestClientServer_FullStacktrace(t *testing.T) { 1206 protest.AllowRecording(t) 1207 if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { 1208 t.Skip("cgo doesn't work on darwin/arm64") 1209 } 1210 1211 lenient := false 1212 if runtime.GOOS == "windows" { 1213 lenient = true 1214 } 1215 1216 withTestClient2("goroutinestackprog", t, func(c service.Client) { 1217 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.stacktraceme", Line: -1}) 1218 assertNoError(err, t, "CreateBreakpoint()") 1219 state := <-c.Continue() 1220 if state.Err != nil { 1221 t.Fatalf("Continue(): %v\n", state.Err) 1222 } 1223 1224 gs, _, err := c.ListGoroutines(0, 0) 1225 assertNoError(err, t, "GoroutinesInfo()") 1226 found := make([]bool, 10) 1227 for _, g := range gs { 1228 frames, err := c.Stacktrace(g.ID, 40, 0, &normalLoadConfig) 1229 assertNoError(err, t, fmt.Sprintf("Stacktrace(%d)", g.ID)) 1230 t.Logf("goroutine %d", g.ID) 1231 for i, frame := range frames { 1232 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()) 1233 if frame.Function == nil { 1234 continue 1235 } 1236 if frame.Function.Name() != "main.agoroutine" { 1237 continue 1238 } 1239 for _, arg := range frame.Arguments { 1240 if arg.Name != "i" { 1241 continue 1242 } 1243 t.Logf("\tvariable i is %+v\n", arg) 1244 argn, err := strconv.Atoi(arg.Value) 1245 if err == nil { 1246 found[argn] = true 1247 } 1248 } 1249 } 1250 } 1251 1252 for i := range found { 1253 if !found[i] { 1254 if lenient { 1255 lenient = false 1256 } else { 1257 t.Fatalf("Goroutine %d not found", i) 1258 } 1259 } 1260 } 1261 1262 t.Logf("continue") 1263 1264 state = <-c.Continue() 1265 if state.Err != nil { 1266 t.Fatalf("Continue(): %v\n", state.Err) 1267 } 1268 1269 frames, err := c.Stacktrace(-1, 10, 0, &normalLoadConfig) 1270 assertNoError(err, t, "Stacktrace") 1271 1272 cur := 3 1273 for i, frame := range frames { 1274 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()) 1275 if i == 0 { 1276 continue 1277 } 1278 v := frame.Var("n") 1279 if v == nil { 1280 t.Fatalf("Could not find value of variable n in frame %d", i) 1281 } 1282 vn, err := strconv.Atoi(v.Value) 1283 if err != nil || vn != cur { 1284 t.Fatalf("Expected value %d got %d (error: %v)", cur, vn, err) 1285 } 1286 cur-- 1287 if cur < 0 { 1288 break 1289 } 1290 } 1291 }) 1292 } 1293 1294 func assertErrorOrExited(s *api.DebuggerState, err error, t *testing.T, reason string) { 1295 if err != nil { 1296 return 1297 } 1298 if s != nil && s.Exited { 1299 return 1300 } 1301 t.Fatalf("%s (no error and no exited status)", reason) 1302 } 1303 1304 func TestIssue355(t *testing.T) { 1305 // After the target process has terminated should return an error but not crash 1306 protest.AllowRecording(t) 1307 withTestClient2("continuetestprog", t, func(c service.Client) { 1308 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1}) 1309 assertNoError(err, t, "CreateBreakpoint()") 1310 ch := c.Continue() 1311 state := <-ch 1312 tid := state.CurrentThread.ID 1313 gid := state.SelectedGoroutine.ID 1314 assertNoError(state.Err, t, "First Continue()") 1315 ch = c.Continue() 1316 state = <-ch 1317 if !state.Exited { 1318 t.Fatalf("Target did not terminate after second continue") 1319 } 1320 1321 ch = c.Continue() 1322 state = <-ch 1323 assertError(state.Err, t, "Continue()") 1324 1325 s, err := c.Next() 1326 assertErrorOrExited(s, err, t, "Next()") 1327 s, err = c.Step() 1328 assertErrorOrExited(s, err, t, "Step()") 1329 s, err = c.StepInstruction() 1330 assertErrorOrExited(s, err, t, "StepInstruction()") 1331 s, err = c.SwitchThread(tid) 1332 assertErrorOrExited(s, err, t, "SwitchThread()") 1333 s, err = c.SwitchGoroutine(gid) 1334 assertErrorOrExited(s, err, t, "SwitchGoroutine()") 1335 s, err = c.Halt() 1336 assertErrorOrExited(s, err, t, "Halt()") 1337 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: -1}) 1338 if testBackend != "rr" { 1339 assertError(err, t, "CreateBreakpoint()") 1340 } 1341 _, err = c.ClearBreakpoint(bp.ID) 1342 if testBackend != "rr" { 1343 assertError(err, t, "ClearBreakpoint()") 1344 } 1345 _, err = c.ListThreads() 1346 assertError(err, t, "ListThreads()") 1347 _, err = c.GetThread(tid) 1348 assertError(err, t, "GetThread()") 1349 assertError(c.SetVariable(api.EvalScope{GoroutineID: gid}, "a", "10"), t, "SetVariable()") 1350 _, err = c.ListLocalVariables(api.EvalScope{GoroutineID: gid}, normalLoadConfig) 1351 assertError(err, t, "ListLocalVariables()") 1352 _, err = c.ListFunctionArgs(api.EvalScope{GoroutineID: gid}, normalLoadConfig) 1353 assertError(err, t, "ListFunctionArgs()") 1354 _, err = c.ListThreadRegisters(0, false) 1355 assertError(err, t, "ListThreadRegisters()") 1356 _, err = c.ListScopeRegisters(api.EvalScope{GoroutineID: gid}, false) 1357 assertError(err, t, "ListScopeRegisters()") 1358 _, _, err = c.ListGoroutines(0, 0) 1359 assertError(err, t, "ListGoroutines()") 1360 _, err = c.Stacktrace(gid, 10, 0, &normalLoadConfig) 1361 assertError(err, t, "Stacktrace()") 1362 _, err = c.FindLocation(api.EvalScope{GoroutineID: gid}, "+1", false, nil) 1363 assertError(err, t, "FindLocation()") 1364 _, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, 0x40100, api.IntelFlavour) 1365 assertError(err, t, "DisassemblePC()") 1366 }) 1367 } 1368 1369 func TestDisasm(t *testing.T) { 1370 // Tests that disassembling by PC, range, and current PC all yeld similar results 1371 // Tests that disassembly by current PC will return a disassembly containing the instruction at PC 1372 // Tests that stepping on a calculated CALL instruction will yield a disassembly that contains the 1373 // effective destination of the CALL instruction 1374 withTestClient2("locationsprog2", t, func(c service.Client) { 1375 ch := c.Continue() 1376 state := <-ch 1377 assertNoError(state.Err, t, "Continue()") 1378 1379 locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main", false, nil) 1380 assertNoError(err, t, "FindLocation()") 1381 if len(locs) != 1 { 1382 t.Fatalf("wrong number of locations for main.main: %d", len(locs)) 1383 } 1384 d1, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour) 1385 assertNoError(err, t, "DisassemblePC()") 1386 if len(d1) < 2 { 1387 t.Fatalf("wrong size of disassembly: %d", len(d1)) 1388 } 1389 1390 pcstart := d1[0].Loc.PC 1391 pcend := d1[len(d1)-1].Loc.PC + uint64(len(d1[len(d1)-1].Bytes)) 1392 1393 // start address should be less than end address 1394 _, err = c.DisassembleRange(api.EvalScope{GoroutineID: -1}, pcend, pcstart, api.IntelFlavour) 1395 assertError(err, t, "DisassembleRange()") 1396 1397 d2, err := c.DisassembleRange(api.EvalScope{GoroutineID: -1}, pcstart, pcend, api.IntelFlavour) 1398 assertNoError(err, t, "DisassembleRange()") 1399 1400 if len(d1) != len(d2) { 1401 t.Logf("d1: %v", d1) 1402 t.Logf("d2: %v", d2) 1403 t.Fatal("mismatched length between disassemble pc and disassemble range") 1404 } 1405 1406 d3, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, state.CurrentThread.PC, api.IntelFlavour) 1407 assertNoError(err, t, "DisassemblePC() - second call") 1408 1409 if len(d1) != len(d3) { 1410 t.Logf("d1: %v", d1) 1411 t.Logf("d3: %v", d3) 1412 t.Fatal("mismatched length between the two calls of disassemble pc") 1413 } 1414 1415 // look for static call to afunction() on line 29 1416 found := false 1417 for i := range d3 { 1418 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" { 1419 found = true 1420 break 1421 } 1422 } 1423 if !found { 1424 t.Fatal("Could not find call to main.afunction on line 29") 1425 } 1426 1427 haspc := false 1428 for i := range d3 { 1429 if d3[i].AtPC { 1430 haspc = true 1431 break 1432 } 1433 } 1434 1435 if !haspc { 1436 t.Logf("d3: %v", d3) 1437 t.Fatal("PC instruction not found") 1438 } 1439 1440 if runtime.GOARCH == "386" && buildMode == "pie" { 1441 // Skip the rest of the test because on intel 386 with PIE build mode 1442 // the compiler will insert calls to __x86.get_pc_thunk which do not have DIEs and we can't resolve. 1443 return 1444 } 1445 1446 startinstr := getCurinstr(d3) 1447 count := 0 1448 for { 1449 if count > 20 { 1450 t.Fatal("too many step instructions executed without finding a call instruction") 1451 } 1452 state, err := c.StepInstruction() 1453 assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) 1454 1455 d3, err = c.DisassemblePC(api.EvalScope{GoroutineID: -1}, state.CurrentThread.PC, api.IntelFlavour) 1456 assertNoError(err, t, fmt.Sprintf("StepInstruction() %d", count)) 1457 1458 curinstr := getCurinstr(d3) 1459 1460 if curinstr == nil { 1461 t.Fatalf("Could not find current instruction %d", count) 1462 } 1463 1464 if curinstr.Loc.Line != startinstr.Loc.Line { 1465 t.Fatal("Calling StepInstruction() repeatedly did not find the call instruction") 1466 } 1467 1468 if strings.HasPrefix(curinstr.Text, "call") || strings.HasPrefix(curinstr.Text, "CALL") { 1469 t.Logf("call: %v", curinstr) 1470 if curinstr.DestLoc == nil || curinstr.DestLoc.Function == nil { 1471 t.Fatalf("Call instruction does not have destination: %v", curinstr) 1472 } 1473 if curinstr.DestLoc.Function.Name() != "main.afunction" { 1474 t.Fatalf("Call instruction destination not main.afunction: %v", curinstr) 1475 } 1476 break 1477 } 1478 1479 count++ 1480 } 1481 }) 1482 } 1483 1484 func TestNegativeStackDepthBug(t *testing.T) { 1485 // After the target process has terminated should return an error but not crash 1486 protest.AllowRecording(t) 1487 withTestClient2("continuetestprog", t, func(c service.Client) { 1488 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1}) 1489 assertNoError(err, t, "CreateBreakpoint()") 1490 ch := c.Continue() 1491 state := <-ch 1492 assertNoError(state.Err, t, "Continue()") 1493 _, err = c.Stacktrace(-1, -2, 0, &normalLoadConfig) 1494 assertError(err, t, "Stacktrace()") 1495 }) 1496 } 1497 1498 func TestClientServer_CondBreakpoint(t *testing.T) { 1499 if runtime.GOOS == "freebsd" { 1500 t.Skip("test is not valid on FreeBSD") 1501 } 1502 protest.AllowRecording(t) 1503 withTestClient2("parallel_next", t, func(c service.Client) { 1504 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: 1}) 1505 assertNoError(err, t, "CreateBreakpoint()") 1506 bp.Cond = "n == 7" 1507 assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 1") 1508 bp, err = c.GetBreakpoint(bp.ID) 1509 assertNoError(err, t, "GetBreakpoint() 1") 1510 bp.Variables = append(bp.Variables, "n") 1511 assertNoError(c.AmendBreakpoint(bp), t, "AmendBreakpoint() 2") 1512 bp, err = c.GetBreakpoint(bp.ID) 1513 assertNoError(err, t, "GetBreakpoint() 2") 1514 if bp.Cond == "" { 1515 t.Fatalf("No condition set on breakpoint %#v", bp) 1516 } 1517 if len(bp.Variables) != 1 { 1518 t.Fatalf("Wrong number of expressions to evaluate on breakpoint %#v", bp) 1519 } 1520 state := <-c.Continue() 1521 assertNoError(state.Err, t, "Continue()") 1522 1523 nvar, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "n", normalLoadConfig) 1524 assertNoError(err, t, "EvalVariable()") 1525 1526 if nvar.SinglelineString() != "7" { 1527 t.Fatalf("Stopped on wrong goroutine %s\n", nvar.Value) 1528 } 1529 }) 1530 } 1531 1532 func clientEvalVariable(t *testing.T, c service.Client, expr string) *api.Variable { 1533 v, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, expr, normalLoadConfig) 1534 assertNoError(err, t, fmt.Sprintf("EvalVariable(%s)", expr)) 1535 return v 1536 } 1537 1538 func TestSkipPrologue(t *testing.T) { 1539 withTestClient2("locationsprog2", t, func(c service.Client) { 1540 <-c.Continue() 1541 1542 afunction := findLocationHelper(t, c, "main.afunction", false, 1, 0)[0] 1543 findLocationHelper(t, c, "*fn1", false, 1, afunction) 1544 findLocationHelper(t, c, "locationsprog2.go:8", false, 1, afunction) 1545 1546 afunction0 := uint64(clientEvalVariable(t, c, "main.afunction").Addr) 1547 1548 if afunction == afunction0 { 1549 t.Fatal("Skip prologue failed") 1550 } 1551 }) 1552 } 1553 1554 func TestSkipPrologue2(t *testing.T) { 1555 withTestClient2("callme", t, func(c service.Client) { 1556 callme := findLocationHelper(t, c, "main.callme", false, 1, 0)[0] 1557 callmeZ := uint64(clientEvalVariable(t, c, "main.callme").Addr) 1558 findLocationHelper(t, c, "callme.go:5", false, 1, callme) 1559 if callme == callmeZ { 1560 t.Fatal("Skip prologue failed") 1561 } 1562 1563 callme2 := findLocationHelper(t, c, "main.callme2", false, 1, 0)[0] 1564 callme2Z := uint64(clientEvalVariable(t, c, "main.callme2").Addr) 1565 findLocationHelper(t, c, "callme.go:12", false, 1, callme2) 1566 if callme2 == callme2Z { 1567 t.Fatal("Skip prologue failed") 1568 } 1569 1570 callme3 := findLocationHelper(t, c, "main.callme3", false, 1, 0)[0] 1571 callme3Z := uint64(clientEvalVariable(t, c, "main.callme3").Addr) 1572 ver, _ := goversion.Parse(runtime.Version()) 1573 1574 if (ver.Major < 0 || ver.AfterOrEqual(goversion.GoVer18Beta)) && runtime.GOARCH != "386" { 1575 findLocationHelper(t, c, "callme.go:19", false, 1, callme3) 1576 } else { 1577 // callme3 does not have local variables therefore the first line of the 1578 // function is immediately after the prologue 1579 // This is only true before go1.8 or on Intel386 where frame pointer chaining 1580 // introduced a bit of prologue even for functions without local variables 1581 findLocationHelper(t, c, "callme.go:19", false, 1, callme3Z) 1582 } 1583 if callme3 == callme3Z { 1584 t.Fatal("Skip prologue failed") 1585 } 1586 }) 1587 } 1588 1589 func TestIssue419(t *testing.T) { 1590 // Calling service/rpc.(*Client).Halt could cause a crash because both Halt and Continue simultaneously 1591 // try to read 'runtime.g' and debug/dwarf.Data.Type is not thread safe 1592 finish := make(chan struct{}) 1593 withTestClient2("issue419", t, func(c service.Client) { 1594 go func() { 1595 defer close(finish) 1596 rand.Seed(time.Now().Unix()) 1597 d := time.Duration(rand.Intn(4) + 1) 1598 time.Sleep(d * time.Second) 1599 t.Logf("halt") 1600 _, err := c.Halt() 1601 assertNoError(err, t, "RequestManualStop()") 1602 }() 1603 statech := c.Continue() 1604 state := <-statech 1605 assertNoError(state.Err, t, "Continue()") 1606 t.Logf("done") 1607 <-finish 1608 }) 1609 } 1610 1611 func TestTypesCommand(t *testing.T) { 1612 protest.AllowRecording(t) 1613 withTestClient2("testvariables2", t, func(c service.Client) { 1614 state := <-c.Continue() 1615 assertNoError(state.Err, t, "Continue()") 1616 types, err := c.ListTypes("") 1617 assertNoError(err, t, "ListTypes()") 1618 1619 found := false 1620 for i := range types { 1621 if types[i] == "main.astruct" { 1622 found = true 1623 break 1624 } 1625 } 1626 if !found { 1627 t.Fatal("Type astruct not found in ListTypes output") 1628 } 1629 1630 types, err = c.ListTypes("^main.astruct$") 1631 assertNoError(err, t, "ListTypes(\"main.astruct\")") 1632 if len(types) != 1 { 1633 t.Fatalf("ListTypes(\"^main.astruct$\") did not filter properly, expected 1 got %d: %v", len(types), types) 1634 } 1635 }) 1636 } 1637 1638 func TestIssue406(t *testing.T) { 1639 protest.AllowRecording(t) 1640 withTestClient2("issue406", t, func(c service.Client) { 1641 locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "issue406.go:146", false, nil) 1642 assertNoError(err, t, "FindLocation()") 1643 _, err = c.CreateBreakpoint(&api.Breakpoint{Addr: locs[0].PC}) 1644 assertNoError(err, t, "CreateBreakpoint()") 1645 ch := c.Continue() 1646 state := <-ch 1647 assertNoError(state.Err, t, "Continue()") 1648 v, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "cfgtree", normalLoadConfig) 1649 assertNoError(err, t, "EvalVariable()") 1650 vs := v.MultilineString("", "") 1651 t.Logf("cfgtree formats to: %s\n", vs) 1652 }) 1653 } 1654 1655 func TestEvalExprName(t *testing.T) { 1656 withTestClient2("testvariables2", t, func(c service.Client) { 1657 state := <-c.Continue() 1658 assertNoError(state.Err, t, "Continue()") 1659 1660 var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "i1+1", normalLoadConfig) 1661 assertNoError(err, t, "EvalVariable") 1662 1663 const name = "i1+1" 1664 1665 t.Logf("i1+1 → %#v", var1) 1666 1667 if var1.Name != name { 1668 t.Fatalf("Wrong variable name %q, expected %q", var1.Name, name) 1669 } 1670 }) 1671 } 1672 1673 func TestClientServer_Issue528(t *testing.T) { 1674 // FindLocation with Receiver.MethodName syntax does not work 1675 // on remote package names due to a bug in debug/gosym that 1676 // Was fixed in go 1.7 // Commit that fixes the issue in go: 1677 // f744717d1924340b8f5e5a385e99078693ad9097 1678 1679 ver, _ := goversion.Parse(runtime.Version()) 1680 if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) { 1681 t.Log("Test skipped") 1682 return 1683 } 1684 1685 withTestClient2("issue528", t, func(c service.Client) { 1686 findLocationHelper(t, c, "State.Close", false, 1, 0) 1687 }) 1688 } 1689 1690 func TestClientServer_FpRegisters(t *testing.T) { 1691 if runtime.GOARCH != "amd64" { 1692 t.Skip("test is valid only on AMD64") 1693 } 1694 regtests := []struct{ name, value string }{ 1695 // x87 1696 {"ST(0)", "0x3fffe666660000000000"}, 1697 {"ST(1)", "0x3fffd9999a0000000000"}, 1698 {"ST(2)", "0x3fffcccccd0000000000"}, 1699 {"ST(3)", "0x3fffc000000000000000"}, 1700 {"ST(4)", "0x3fffb333333333333000"}, 1701 {"ST(5)", "0x3fffa666666666666800"}, 1702 {"ST(6)", "0x3fff9999999999999800"}, 1703 {"ST(7)", "0x3fff8cccccccccccd000"}, 1704 1705 // SSE 1706 {"XMM0", "0x3ff33333333333333ff199999999999a v2_int={ 3ff199999999999a 3ff3333333333333 } v4_int={ 9999999a 3ff19999 33333333 3ff33333 } v8_int={ 999a 9999 9999 3ff1 3333 3333 3333 3ff3 } v16_int={ 9a 99 99 99 99 99 f1 3f 33 33 33 33 33 33 f3 3f }"}, 1707 {"XMM1", "0x3ff66666666666663ff4cccccccccccd"}, 1708 {"XMM2", "0x3fe666663fd9999a3fcccccd3fc00000"}, 1709 {"XMM3", "0x3ff199999999999a3ff3333333333333"}, 1710 {"XMM4", "0x3ff4cccccccccccd3ff6666666666666"}, 1711 {"XMM5", "0x3fcccccd3fc000003fe666663fd9999a"}, 1712 {"XMM6", "0x4004cccccccccccc4003333333333334"}, 1713 {"XMM7", "0x40026666666666664002666666666666"}, 1714 {"XMM8", "0x4059999a404ccccd4059999a404ccccd"}, 1715 1716 // AVX 2 1717 {"XMM11", "0x3ff66666666666663ff4cccccccccccd"}, 1718 {"XMM11", "…[YMM11h] 0x3ff66666666666663ff4cccccccccccd"}, 1719 1720 // AVX 512 1721 {"XMM12", "0x3ff66666666666663ff4cccccccccccd"}, 1722 {"XMM12", "…[YMM12h] 0x3ff66666666666663ff4cccccccccccd"}, 1723 {"XMM12", "…[ZMM12hl] 0x3ff66666666666663ff4cccccccccccd"}, 1724 {"XMM12", "…[ZMM12hh] 0x3ff66666666666663ff4cccccccccccd"}, 1725 } 1726 protest.AllowRecording(t) 1727 withTestClient2Extended("fputest/", t, 0, [3]string{}, func(c service.Client, fixture protest.Fixture) { 1728 _, err := c.CreateBreakpoint(&api.Breakpoint{File: filepath.Join(fixture.BuildDir, "fputest.go"), Line: 25}) 1729 assertNoError(err, t, "CreateBreakpoint") 1730 1731 state := <-c.Continue() 1732 t.Logf("state after continue: %#v", state) 1733 1734 scope := api.EvalScope{GoroutineID: -1} 1735 1736 boolvar := func(name string) bool { 1737 v, err := c.EvalVariable(scope, name, normalLoadConfig) 1738 if err != nil { 1739 t.Fatalf("could not read %s variable", name) 1740 } 1741 t.Logf("%s variable: %#v", name, v) 1742 return v.Value != "false" 1743 } 1744 1745 avx2 := boolvar("avx2") 1746 avx512 := boolvar("avx512") 1747 1748 if runtime.GOOS == "windows" { 1749 // not supported 1750 avx2 = false 1751 avx512 = false 1752 } 1753 1754 state = <-c.Continue() 1755 t.Logf("state after continue: %#v", state) 1756 1757 regs, err := c.ListThreadRegisters(0, true) 1758 assertNoError(err, t, "ListThreadRegisters()") 1759 1760 for _, regtest := range regtests { 1761 if regtest.name == "XMM11" && !avx2 { 1762 continue 1763 } 1764 if regtest.name == "XMM12" && (!avx512 || testBackend == "rr") { 1765 continue 1766 } 1767 found := false 1768 for _, reg := range regs { 1769 if reg.Name == regtest.name { 1770 found = true 1771 if strings.HasPrefix(regtest.value, "…") { 1772 if !strings.Contains(reg.Value, regtest.value[len("…"):]) { 1773 t.Fatalf("register %s expected to contain %q got %q", reg.Name, regtest.value, reg.Value) 1774 } 1775 } else { 1776 if !strings.HasPrefix(reg.Value, regtest.value) { 1777 t.Fatalf("register %s expected %q got %q", reg.Name, regtest.value, reg.Value) 1778 } 1779 } 1780 } 1781 } 1782 if !found { 1783 t.Fatalf("register %s not found: %v", regtest.name, regs) 1784 } 1785 } 1786 1787 // Test register expressions 1788 1789 for _, tc := range []struct{ expr, tgt string }{ 1790 {"XMM1[:32]", `"cdccccccccccf43f666666666666f63f"`}, 1791 {"_XMM1[:32]", `"cdccccccccccf43f666666666666f63f"`}, 1792 {"__XMM1[:32]", `"cdccccccccccf43f666666666666f63f"`}, 1793 {"XMM1.int8[0]", `-51`}, 1794 {"XMM1.uint16[0]", `52429`}, 1795 {"XMM1.float32[0]", `-107374184`}, 1796 {"XMM1.float64[0]", `1.3`}, 1797 {"RAX.uint8[0]", "42"}, 1798 } { 1799 v, err := c.EvalVariable(scope, tc.expr, normalLoadConfig) 1800 if err != nil { 1801 t.Fatalf("could not evalue expression %s: %v", tc.expr, err) 1802 } 1803 out := v.SinglelineString() 1804 1805 if out != tc.tgt { 1806 t.Fatalf("for %q expected %q got %q\n", tc.expr, tc.tgt, out) 1807 } 1808 } 1809 }) 1810 } 1811 1812 func TestClientServer_RestartBreakpointPosition(t *testing.T) { 1813 protest.AllowRecording(t) 1814 if buildMode == "pie" || (runtime.GOOS == "darwin" && runtime.GOARCH == "arm64") { 1815 t.Skip("not meaningful in PIE mode") 1816 } 1817 withTestClient2("locationsprog2", t, func(c service.Client) { 1818 bpBefore, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.afunction", Line: -1, Tracepoint: true, Name: "this"}) 1819 addrBefore := bpBefore.Addr 1820 t.Logf("%x\n", bpBefore.Addr) 1821 assertNoError(err, t, "CreateBreakpoint") 1822 stateCh := c.Continue() 1823 for range stateCh { 1824 } 1825 _, err = c.Halt() 1826 assertNoError(err, t, "Halt") 1827 _, err = c.Restart(false) 1828 assertNoError(err, t, "Restart") 1829 bps, err := c.ListBreakpoints(false) 1830 assertNoError(err, t, "ListBreakpoints") 1831 for _, bp := range bps { 1832 if bp.Name == bpBefore.Name { 1833 if bp.Addr != addrBefore { 1834 t.Fatalf("Address changed after restart: %x %x", bp.Addr, addrBefore) 1835 } 1836 t.Logf("%x %x\n", bp.Addr, addrBefore) 1837 } 1838 } 1839 }) 1840 } 1841 1842 func TestClientServer_SelectedGoroutineLoc(t *testing.T) { 1843 // CurrentLocation of SelectedGoroutine should reflect what's happening on 1844 // the thread running the goroutine, not the position the goroutine was in 1845 // the last time it was parked. 1846 protest.AllowRecording(t) 1847 withTestClient2("testprog", t, func(c service.Client) { 1848 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: -11}) 1849 assertNoError(err, t, "CreateBreakpoint") 1850 1851 s := <-c.Continue() 1852 assertNoError(s.Err, t, "Continue") 1853 1854 gloc := s.SelectedGoroutine.CurrentLoc 1855 1856 if gloc.PC != s.CurrentThread.PC { 1857 t.Errorf("mismatched PC %#x %#x", gloc.PC, s.CurrentThread.PC) 1858 } 1859 1860 if gloc.File != s.CurrentThread.File || gloc.Line != s.CurrentThread.Line { 1861 t.Errorf("mismatched file:lineno: %s:%d %s:%d", gloc.File, gloc.Line, s.CurrentThread.File, s.CurrentThread.Line) 1862 } 1863 }) 1864 } 1865 1866 func TestClientServer_ReverseContinue(t *testing.T) { 1867 protest.AllowRecording(t) 1868 if testBackend != "rr" { 1869 t.Skip("backend is not rr") 1870 } 1871 withTestClient2("continuetestprog", t, func(c service.Client) { 1872 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: -1}) 1873 assertNoError(err, t, "CreateBreakpoint(main.main)") 1874 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.sayhi", Line: -1}) 1875 assertNoError(err, t, "CreateBreakpoint(main.sayhi)") 1876 1877 state := <-c.Continue() 1878 assertNoError(state.Err, t, "first continue") 1879 mainPC := state.CurrentThread.PC 1880 t.Logf("after first continue %#x", mainPC) 1881 1882 state = <-c.Continue() 1883 assertNoError(state.Err, t, "second continue") 1884 sayhiPC := state.CurrentThread.PC 1885 t.Logf("after second continue %#x", sayhiPC) 1886 1887 if mainPC == sayhiPC { 1888 t.Fatalf("expected different PC after second PC (%#x)", mainPC) 1889 } 1890 1891 state = <-c.Rewind() 1892 assertNoError(state.Err, t, "rewind") 1893 1894 if mainPC != state.CurrentThread.PC { 1895 t.Fatalf("Expected rewind to go back to the first breakpoint: %#x", state.CurrentThread.PC) 1896 } 1897 }) 1898 } 1899 1900 func TestClientServer_collectBreakpointInfoOnNext(t *testing.T) { 1901 protest.AllowRecording(t) 1902 withTestClient2("testnextprog", t, func(c service.Client) { 1903 _, err := c.CreateBreakpoint(&api.Breakpoint{ 1904 Addr: findLocationHelper(t, c, "testnextprog.go:23", false, 1, 0)[0], 1905 Variables: []string{"j"}, 1906 LoadLocals: &normalLoadConfig}) 1907 assertNoError(err, t, "CreateBreakpoint()") 1908 _, err = c.CreateBreakpoint(&api.Breakpoint{ 1909 Addr: findLocationHelper(t, c, "testnextprog.go:24", false, 1, 0)[0], 1910 Variables: []string{"j"}, 1911 LoadLocals: &normalLoadConfig}) 1912 assertNoError(err, t, "CreateBreakpoint()") 1913 1914 stateBefore := <-c.Continue() 1915 assertNoError(stateBefore.Err, t, "Continue()") 1916 if stateBefore.CurrentThread.Line != 23 { 1917 t.Fatalf("wrong line number %s:%d, expected %d", stateBefore.CurrentThread.File, stateBefore.CurrentThread.Line, 23) 1918 } 1919 if bi := stateBefore.CurrentThread.BreakpointInfo; bi == nil || len(bi.Variables) != 1 { 1920 t.Fatalf("bad breakpoint info %v", bi) 1921 } 1922 1923 stateAfter, err := c.Next() 1924 assertNoError(err, t, "Next()") 1925 if stateAfter.CurrentThread.Line != 24 { 1926 t.Fatalf("wrong line number %s:%d, expected %d", stateAfter.CurrentThread.File, stateAfter.CurrentThread.Line, 24) 1927 } 1928 if bi := stateAfter.CurrentThread.BreakpointInfo; bi == nil || len(bi.Variables) != 1 { 1929 t.Fatalf("bad breakpoint info %v", bi) 1930 } 1931 }) 1932 } 1933 1934 func TestClientServer_collectBreakpointInfoError(t *testing.T) { 1935 protest.AllowRecording(t) 1936 withTestClient2("testnextprog", t, func(c service.Client) { 1937 _, err := c.CreateBreakpoint(&api.Breakpoint{ 1938 Addr: findLocationHelper(t, c, "testnextprog.go:23", false, 1, 0)[0], 1939 Variables: []string{"nonexistentvariable", "j"}, 1940 LoadLocals: &normalLoadConfig}) 1941 assertNoError(err, t, "CreateBreakpoint()") 1942 state := <-c.Continue() 1943 assertNoError(state.Err, t, "Continue()") 1944 }) 1945 } 1946 1947 func TestClientServerConsistentExit(t *testing.T) { 1948 // This test is useful because it ensures that Next and Continue operations both 1949 // exit with the same exit status and details when the target application terminates. 1950 // Other program execution API calls should also behave in the same way. 1951 // An error should be present in state.Err. 1952 withTestClient2("pr1055", t, func(c service.Client) { 1953 fp := testProgPath(t, "pr1055") 1954 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 12}) 1955 if err != nil { 1956 t.Fatalf("Unexpected error: %v", err) 1957 } 1958 state := <-c.Continue() 1959 if state.Err != nil { 1960 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 1961 } 1962 state, err = c.Next() 1963 if err != nil { 1964 t.Fatalf("Unexpected error: %v", err) 1965 } 1966 if !state.Exited { 1967 t.Fatal("Process state is not exited") 1968 } 1969 if state.ExitStatus != 2 { 1970 t.Fatalf("Process exit status is not 2, got: %v", state.ExitStatus) 1971 } 1972 1973 // Ensure future commands also return the correct exit status. 1974 // Previously there was a bug where the command which prompted the 1975 // process to exit (continue, next, etc...) would return the corrent 1976 // exit status but subsequent commands would return an incorrect exit 1977 // status of 0. To test this we simply repeat the 'next' command and 1978 // ensure we get the correct response again. 1979 state, err = c.Next() 1980 if err != nil { 1981 t.Fatalf("Unexpected error: %v", err) 1982 } 1983 if !state.Exited { 1984 t.Fatal("Second process state is not exited") 1985 } 1986 if state.ExitStatus != 2 { 1987 t.Fatalf("Second process exit status is not 2, got: %v", state.ExitStatus) 1988 } 1989 }) 1990 } 1991 1992 func TestClientServer_StepOutReturn(t *testing.T) { 1993 ver, _ := goversion.Parse(runtime.Version()) 1994 if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 1995 t.Skip("return variables aren't marked on 1.9 or earlier") 1996 } 1997 withTestClient2("stepoutret", t, func(c service.Client) { 1998 c.SetReturnValuesLoadConfig(&normalLoadConfig) 1999 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.stepout", Line: -1}) 2000 assertNoError(err, t, "CreateBreakpoint()") 2001 stateBefore := <-c.Continue() 2002 assertNoError(stateBefore.Err, t, "Continue()") 2003 stateAfter, err := c.StepOut() 2004 assertNoError(err, t, "StepOut") 2005 ret := stateAfter.CurrentThread.ReturnValues 2006 2007 if len(ret) != 2 { 2008 t.Fatalf("wrong number of return values %v", ret) 2009 } 2010 2011 stridx := 0 2012 numidx := 1 2013 2014 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 12) { 2015 // in 1.11 and earlier the order of return values in DWARF is 2016 // unspecified, in 1.11 and later it follows the order of definition 2017 // specified by the user 2018 for i := range ret { 2019 if ret[i].Name == "str" { 2020 stridx = i 2021 numidx = 1 - i 2022 break 2023 } 2024 } 2025 } 2026 2027 if ret[stridx].Name != "str" { 2028 t.Fatalf("(str) bad return value name %s", ret[stridx].Name) 2029 } 2030 if ret[stridx].Kind != reflect.String { 2031 t.Fatalf("(str) bad return value kind %v", ret[stridx].Kind) 2032 } 2033 if ret[stridx].Value != "return 47" { 2034 t.Fatalf("(str) bad return value %q", ret[stridx].Value) 2035 } 2036 2037 if ret[numidx].Name != "num" { 2038 t.Fatalf("(num) bad return value name %s", ret[numidx].Name) 2039 } 2040 if ret[numidx].Kind != reflect.Int { 2041 t.Fatalf("(num) bad return value kind %v", ret[numidx].Kind) 2042 } 2043 if ret[numidx].Value != "48" { 2044 t.Fatalf("(num) bad return value %s", ret[numidx].Value) 2045 } 2046 }) 2047 } 2048 2049 func TestAcceptMulticlient(t *testing.T) { 2050 if testBackend == "rr" { 2051 t.Skip("recording not allowed for TestAcceptMulticlient") 2052 } 2053 listener, err := net.Listen("tcp", "127.0.0.1:0") 2054 if err != nil { 2055 t.Fatalf("couldn't start listener: %s\n", err) 2056 } 2057 serverDone := make(chan struct{}) 2058 go func() { 2059 defer close(serverDone) 2060 defer listener.Close() 2061 disconnectChan := make(chan struct{}) 2062 server := rpccommon.NewServer(&service.Config{ 2063 Listener: listener, 2064 ProcessArgs: []string{protest.BuildFixture("testvariables2", 0).Path}, 2065 AcceptMulti: true, 2066 DisconnectChan: disconnectChan, 2067 Debugger: debugger.Config{ 2068 Backend: testBackend, 2069 ExecuteKind: debugger.ExecutingGeneratedTest, 2070 }, 2071 }) 2072 if err := server.Run(); err != nil { 2073 panic(err) 2074 } 2075 <-disconnectChan 2076 server.Stop() 2077 }() 2078 client1 := rpc2.NewClient(listener.Addr().String()) 2079 client1.Disconnect(false) 2080 2081 client2 := rpc2.NewClient(listener.Addr().String()) 2082 state := <-client2.Continue() 2083 if state.CurrentThread.Function.Name() != "main.main" { 2084 t.Fatalf("bad state after continue: %v\n", state) 2085 } 2086 client2.Detach(true) 2087 <-serverDone 2088 } 2089 2090 func TestForceStopWhileContinue(t *testing.T) { 2091 listener, err := net.Listen("tcp", "127.0.0.1:0") 2092 if err != nil { 2093 t.Fatalf("couldn't start listener: %s\n", err) 2094 } 2095 serverStopped := make(chan struct{}) 2096 disconnectChan := make(chan struct{}) 2097 go func() { 2098 defer close(serverStopped) 2099 defer listener.Close() 2100 server := rpccommon.NewServer(&service.Config{ 2101 Listener: listener, 2102 ProcessArgs: []string{protest.BuildFixture("http_server", protest.AllNonOptimized).Path}, 2103 AcceptMulti: true, 2104 DisconnectChan: disconnectChan, 2105 Debugger: debugger.Config{ 2106 Backend: "default", 2107 }, 2108 }) 2109 if err := server.Run(); err != nil { 2110 panic(err) 2111 } 2112 <-disconnectChan 2113 server.Stop() 2114 }() 2115 2116 client := rpc2.NewClient(listener.Addr().String()) 2117 client.Disconnect(true /*continue*/) 2118 time.Sleep(10 * time.Millisecond) // give server time to start running 2119 close(disconnectChan) // stop the server 2120 <-serverStopped // Stop() didn't block on detach because we halted first 2121 } 2122 2123 func TestClientServerFunctionCall(t *testing.T) { 2124 protest.MustSupportFunctionCalls(t, testBackend) 2125 withTestClient2("fncall", t, func(c service.Client) { 2126 c.SetReturnValuesLoadConfig(&normalLoadConfig) 2127 state := <-c.Continue() 2128 assertNoError(state.Err, t, "Continue()") 2129 beforeCallFn := state.CurrentThread.Function.Name() 2130 state, err := c.Call(-1, "call1(one, two)", false) 2131 assertNoError(err, t, "Call()") 2132 t.Logf("returned to %q", state.CurrentThread.Function.Name()) 2133 if state.CurrentThread.Function.Name() != beforeCallFn { 2134 t.Fatalf("did not return to the calling function %q %q", beforeCallFn, state.CurrentThread.Function.Name()) 2135 } 2136 if state.CurrentThread.ReturnValues == nil { 2137 t.Fatal("no return values on return from call") 2138 } 2139 t.Logf("Return values %v", state.CurrentThread.ReturnValues) 2140 if len(state.CurrentThread.ReturnValues) != 1 { 2141 t.Fatal("not enough return values") 2142 } 2143 if state.CurrentThread.ReturnValues[0].Value != "3" { 2144 t.Fatalf("wrong return value %s", state.CurrentThread.ReturnValues[0].Value) 2145 } 2146 state = <-c.Continue() 2147 if !state.Exited { 2148 t.Fatalf("expected process to exit after call %v", state.CurrentThread) 2149 } 2150 }) 2151 } 2152 2153 func TestClientServerFunctionCallBadPos(t *testing.T) { 2154 protest.MustSupportFunctionCalls(t, testBackend) 2155 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 12) { 2156 t.Skip("this is a safe point for Go 1.12") 2157 } 2158 withTestClient2("fncall", t, func(c service.Client) { 2159 loc, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "fmt/print.go:649", false, nil) 2160 assertNoError(err, t, "could not find location") 2161 2162 _, err = c.CreateBreakpoint(&api.Breakpoint{File: loc[0].File, Line: loc[0].Line}) 2163 assertNoError(err, t, "CreateBreakpoin") 2164 2165 state := <-c.Continue() 2166 assertNoError(state.Err, t, "Continue()") 2167 2168 state = <-c.Continue() 2169 assertNoError(state.Err, t, "Continue()") 2170 2171 c.SetReturnValuesLoadConfig(&normalLoadConfig) 2172 state, err = c.Call(-1, "main.call1(main.zero, main.zero)", false) 2173 if err == nil || err.Error() != "call not at safe point" { 2174 t.Fatalf("wrong error or no error: %v", err) 2175 } 2176 }) 2177 } 2178 2179 func TestClientServerFunctionCallPanic(t *testing.T) { 2180 protest.MustSupportFunctionCalls(t, testBackend) 2181 withTestClient2("fncall", t, func(c service.Client) { 2182 c.SetReturnValuesLoadConfig(&normalLoadConfig) 2183 state := <-c.Continue() 2184 assertNoError(state.Err, t, "Continue()") 2185 state, err := c.Call(-1, "callpanic()", false) 2186 assertNoError(err, t, "Call()") 2187 t.Logf("at: %s:%d", state.CurrentThread.File, state.CurrentThread.Line) 2188 if state.CurrentThread.ReturnValues == nil { 2189 t.Fatal("no return values on return from call") 2190 } 2191 t.Logf("Return values %v", state.CurrentThread.ReturnValues) 2192 if len(state.CurrentThread.ReturnValues) != 1 { 2193 t.Fatal("not enough return values") 2194 } 2195 if state.CurrentThread.ReturnValues[0].Name != "~panic" { 2196 t.Fatal("not a panic") 2197 } 2198 if state.CurrentThread.ReturnValues[0].Children[0].Value != "callpanic panicked" { 2199 t.Fatalf("wrong panic value %s", state.CurrentThread.ReturnValues[0].Children[0].Value) 2200 } 2201 }) 2202 } 2203 2204 func TestClientServerFunctionCallStacktrace(t *testing.T) { 2205 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) { 2206 t.Skip("Go 1.15 executes function calls in a different goroutine so the stack trace will not contain main.main or runtime.main") 2207 } 2208 protest.MustSupportFunctionCalls(t, testBackend) 2209 withTestClient2("fncall", t, func(c service.Client) { 2210 c.SetReturnValuesLoadConfig(&api.LoadConfig{FollowPointers: false, MaxStringLen: 2048}) 2211 state := <-c.Continue() 2212 assertNoError(state.Err, t, "Continue()") 2213 state, err := c.Call(-1, "callstacktrace()", false) 2214 assertNoError(err, t, "Call()") 2215 t.Logf("at: %s:%d", state.CurrentThread.File, state.CurrentThread.Line) 2216 if state.CurrentThread.ReturnValues == nil { 2217 t.Fatal("no return values on return from call") 2218 } 2219 if len(state.CurrentThread.ReturnValues) != 1 || state.CurrentThread.ReturnValues[0].Kind != reflect.String { 2220 t.Fatal("not enough return values") 2221 } 2222 st := state.CurrentThread.ReturnValues[0].Value 2223 t.Logf("Returned stacktrace:\n%s", st) 2224 2225 if !strings.Contains(st, "main.callstacktrace") || !strings.Contains(st, "main.main") || !strings.Contains(st, "runtime.main") { 2226 t.Fatal("bad stacktrace returned") 2227 } 2228 }) 2229 } 2230 2231 func TestAncestors(t *testing.T) { 2232 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 2233 t.Skip("not supported on Go <= 1.10") 2234 } 2235 savedGodebug := os.Getenv("GODEBUG") 2236 os.Setenv("GODEBUG", "tracebackancestors=100") 2237 defer os.Setenv("GODEBUG", savedGodebug) 2238 withTestClient2("testnextprog", t, func(c service.Client) { 2239 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.testgoroutine", Line: -1}) 2240 assertNoError(err, t, "CreateBreakpoin") 2241 state := <-c.Continue() 2242 assertNoError(state.Err, t, "Continue()") 2243 ancestors, err := c.Ancestors(-1, 1000, 1000) 2244 assertNoError(err, t, "Ancestors") 2245 t.Logf("ancestors: %#v\n", ancestors) 2246 if len(ancestors) != 1 { 2247 t.Fatalf("expected only one ancestor got %d", len(ancestors)) 2248 } 2249 2250 mainFound := false 2251 for _, ancestor := range ancestors { 2252 for _, frame := range ancestor.Stack { 2253 if frame.Function.Name() == "main.main" { 2254 mainFound = true 2255 } 2256 } 2257 } 2258 if !mainFound { 2259 t.Fatal("function main.main not found in any ancestor") 2260 } 2261 }) 2262 } 2263 2264 type brokenRPCClient struct { 2265 client *rpc.Client 2266 } 2267 2268 func (c *brokenRPCClient) Detach(kill bool) error { 2269 defer c.client.Close() 2270 out := new(rpc2.DetachOut) 2271 return c.call("Detach", rpc2.DetachIn{Kill: kill}, out) 2272 } 2273 2274 func (c *brokenRPCClient) call(method string, args, reply interface{}) error { 2275 return c.client.Call("RPCServer."+method, args, reply) 2276 } 2277 2278 func TestUnknownMethodCall(t *testing.T) { 2279 clientConn, _ := startServer("continuetestprog", 0, t, [3]string{}) 2280 client := &brokenRPCClient{jsonrpc.NewClient(clientConn)} 2281 client.call("SetApiVersion", api.SetAPIVersionIn{APIVersion: 2}, &api.SetAPIVersionOut{}) 2282 defer client.Detach(true) 2283 var out int 2284 err := client.call("NonexistentRPCCall", nil, &out) 2285 assertError(err, t, "call()") 2286 if !strings.HasPrefix(err.Error(), "unknown method: ") { 2287 t.Errorf("wrong error message: %v", err) 2288 } 2289 } 2290 2291 func TestIssue1703(t *testing.T) { 2292 // Calling Disassemble when there is no current goroutine should work. 2293 withTestClient2("testnextprog", t, func(c service.Client) { 2294 locs, err := c.FindLocation(api.EvalScope{GoroutineID: -1}, "main.main", true, nil) 2295 assertNoError(err, t, "FindLocation") 2296 t.Logf("FindLocation: %#v", locs) 2297 text, err := c.DisassemblePC(api.EvalScope{GoroutineID: -1}, locs[0].PC, api.IntelFlavour) 2298 assertNoError(err, t, "DisassemblePC") 2299 t.Logf("text: %#v\n", text) 2300 }) 2301 } 2302 2303 func TestRerecord(t *testing.T) { 2304 protest.AllowRecording(t) 2305 if testBackend != "rr" { 2306 t.Skip("only valid for recorded targets") 2307 } 2308 withTestClient2("testrerecord", t, func(c service.Client) { 2309 fp := testProgPath(t, "testrerecord") 2310 _, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 10}) 2311 assertNoError(err, t, "CreateBreakpoin") 2312 2313 gett := func() int { 2314 state := <-c.Continue() 2315 if state.Err != nil { 2316 t.Fatalf("Unexpected error: %v, state: %#v", state.Err, state) 2317 } 2318 2319 vart, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "t", normalLoadConfig) 2320 assertNoError(err, t, "EvalVariable") 2321 if vart.Unreadable != "" { 2322 t.Fatalf("Could not read variable 't': %s\n", vart.Unreadable) 2323 } 2324 2325 t.Logf("Value of t is %s\n", vart.Value) 2326 2327 vartval, err := strconv.Atoi(vart.Value) 2328 assertNoError(err, t, "Parsing value of variable t") 2329 return vartval 2330 } 2331 2332 t0 := gett() 2333 2334 _, err = c.RestartFrom(false, "", false, nil, [3]string{}, false) 2335 assertNoError(err, t, "First restart") 2336 t1 := gett() 2337 2338 if t0 != t1 { 2339 t.Fatalf("Expected same value for t after restarting (without rerecording) %d %d", t0, t1) 2340 } 2341 2342 time.Sleep(2 * time.Second) // make sure that we're not running inside the same second 2343 2344 _, err = c.RestartFrom(true, "", false, nil, [3]string{}, false) 2345 assertNoError(err, t, "Second restart") 2346 t2 := gett() 2347 2348 if t0 == t2 { 2349 t.Fatalf("Expected new value for t after restarting (with rerecording) %d %d", t0, t2) 2350 } 2351 }) 2352 } 2353 2354 func TestIssue1787(t *testing.T) { 2355 // Calling FunctionReturnLocations without a selected goroutine should 2356 // work. 2357 withTestClient2("testnextprog", t, func(c service.Client) { 2358 if c, _ := c.(*rpc2.RPCClient); c != nil { 2359 c.FunctionReturnLocations("main.main") 2360 } 2361 }) 2362 } 2363 2364 func TestDoubleCreateBreakpoint(t *testing.T) { 2365 withTestClient2("testnextprog", t, func(c service.Client) { 2366 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint", Tracepoint: true}) 2367 assertNoError(err, t, "CreateBreakpoint 1") 2368 2369 bps, err := c.ListBreakpoints(false) 2370 assertNoError(err, t, "ListBreakpoints 1") 2371 2372 t.Logf("breakpoints before second call:") 2373 for _, bp := range bps { 2374 t.Logf("\t%v", bp) 2375 } 2376 2377 numBreakpoints := len(bps) 2378 2379 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "secondbreakpoint", Tracepoint: true}) 2380 assertError(err, t, "CreateBreakpoint 2") // breakpoint exists 2381 2382 bps, err = c.ListBreakpoints(false) 2383 assertNoError(err, t, "ListBreakpoints 2") 2384 2385 t.Logf("breakpoints after second call:") 2386 for _, bp := range bps { 2387 t.Logf("\t%v", bp) 2388 } 2389 2390 if len(bps) != numBreakpoints { 2391 t.Errorf("wrong number of breakpoints, got %d expected %d", len(bps), numBreakpoints) 2392 } 2393 }) 2394 } 2395 2396 func TestStopRecording(t *testing.T) { 2397 protest.AllowRecording(t) 2398 if testBackend != "rr" { 2399 t.Skip("only for rr backend") 2400 } 2401 withTestClient2("sleep", t, func(c service.Client) { 2402 time.Sleep(time.Second) 2403 c.StopRecording() 2404 _, err := c.GetState() 2405 assertNoError(err, t, "GetState()") 2406 2407 // try rerecording 2408 go func() { 2409 c.RestartFrom(true, "", false, nil, [3]string{}, false) 2410 }() 2411 2412 time.Sleep(time.Second) // hopefully the re-recording started... 2413 c.StopRecording() 2414 _, err = c.GetState() 2415 assertNoError(err, t, "GetState()") 2416 }) 2417 } 2418 2419 func TestClearLogicalBreakpoint(t *testing.T) { 2420 // Clearing a logical breakpoint should clear all associated physical 2421 // breakpoints. 2422 // Issue #1955. 2423 withTestClient2Extended("testinline", t, protest.EnableInlining, [3]string{}, func(c service.Client, fixture protest.Fixture) { 2424 bp, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.inlineThis"}) 2425 assertNoError(err, t, "CreateBreakpoint()") 2426 t.Logf("breakpoint set at %#v", bp.Addrs) 2427 if len(bp.Addrs) < 2 { 2428 t.Fatal("Wrong number of addresses for main.inlineThis breakpoint") 2429 } 2430 _, err = c.ClearBreakpoint(bp.ID) 2431 assertNoError(err, t, "ClearBreakpoint()") 2432 bps, err := c.ListBreakpoints(false) 2433 assertNoError(err, t, "ListBreakpoints()") 2434 for _, curbp := range bps { 2435 if curbp.ID == bp.ID { 2436 t.Errorf("logical breakpoint still exists: %#v", curbp) 2437 break 2438 } 2439 } 2440 }) 2441 } 2442 2443 func TestRedirects(t *testing.T) { 2444 const ( 2445 infile = "redirect-input.txt" 2446 outfile = "redirect-output.txt" 2447 ) 2448 protest.AllowRecording(t) 2449 withTestClient2Extended("redirect", t, 0, [3]string{infile, outfile, ""}, func(c service.Client, fixture protest.Fixture) { 2450 outpath := filepath.Join(fixture.BuildDir, outfile) 2451 <-c.Continue() 2452 buf, err := ioutil.ReadFile(outpath) 2453 assertNoError(err, t, "Reading output file") 2454 t.Logf("output %q", buf) 2455 if !strings.HasPrefix(string(buf), "Redirect test") { 2456 t.Fatalf("Wrong output %q", string(buf)) 2457 } 2458 os.Remove(outpath) 2459 if testBackend != "rr" { 2460 _, err = c.Restart(false) 2461 assertNoError(err, t, "Restart") 2462 <-c.Continue() 2463 buf2, err := ioutil.ReadFile(outpath) 2464 t.Logf("output %q", buf2) 2465 assertNoError(err, t, "Reading output file (second time)") 2466 if !strings.HasPrefix(string(buf2), "Redirect test") { 2467 t.Fatalf("Wrong output %q", string(buf2)) 2468 } 2469 if string(buf2) == string(buf) { 2470 t.Fatalf("Expected output change got %q and %q", string(buf), string(buf2)) 2471 } 2472 os.Remove(outpath) 2473 } 2474 }) 2475 } 2476 2477 func TestIssue2162(t *testing.T) { 2478 if buildMode == "pie" || runtime.GOOS == "windows" { 2479 t.Skip("skip it for stepping into one place where no source for pc when on pie mode or windows") 2480 } 2481 withTestClient2("issue2162", t, func(c service.Client) { 2482 state, err := c.GetState() 2483 assertNoError(err, t, "GetState()") 2484 if state.CurrentThread.Function == nil { 2485 // Can't call Step if we don't have the source code of the current function 2486 return 2487 } 2488 2489 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main"}) 2490 if err != nil { 2491 t.Fatalf("Unexpected error: %v", err) 2492 } 2493 2494 _, err = c.Step() 2495 assertNoError(err, t, "Step()") 2496 }) 2497 } 2498 2499 func TestDetachLeaveRunning(t *testing.T) { 2500 // See https://github.com/go-delve/delve/issues/2259 2501 if testBackend == "rr" { 2502 return 2503 } 2504 2505 listener, clientConn := service.ListenerPipe() 2506 defer listener.Close() 2507 var buildFlags protest.BuildFlags 2508 if buildMode == "pie" { 2509 buildFlags |= protest.BuildModePIE 2510 } 2511 fixture := protest.BuildFixture("testnextnethttp", buildFlags) 2512 2513 cmd := exec.Command(fixture.Path) 2514 cmd.Stdout = os.Stdout 2515 cmd.Stderr = os.Stderr 2516 assertNoError(cmd.Start(), t, "starting fixture") 2517 defer cmd.Process.Kill() 2518 2519 // wait for testnextnethttp to start listening 2520 t0 := time.Now() 2521 for { 2522 conn, err := net.Dial("tcp", "127.0.0.1:9191") 2523 if err == nil { 2524 conn.Close() 2525 break 2526 } 2527 time.Sleep(50 * time.Millisecond) 2528 if time.Since(t0) > 10*time.Second { 2529 t.Fatal("fixture did not start") 2530 } 2531 } 2532 2533 server := rpccommon.NewServer(&service.Config{ 2534 Listener: listener, 2535 APIVersion: 2, 2536 Debugger: debugger.Config{ 2537 AttachPid: cmd.Process.Pid, 2538 WorkingDir: ".", 2539 Backend: testBackend, 2540 }, 2541 }) 2542 if err := server.Run(); err != nil { 2543 t.Fatal(err) 2544 } 2545 2546 client := rpc2.NewClientFromConn(clientConn) 2547 defer server.Stop() 2548 assertNoError(client.Detach(false), t, "Detach") 2549 } 2550 2551 func assertNoDuplicateBreakpoints(t *testing.T, c service.Client) { 2552 t.Helper() 2553 bps, _ := c.ListBreakpoints(false) 2554 seen := make(map[int]bool) 2555 for _, bp := range bps { 2556 t.Logf("%#v\n", bp) 2557 if seen[bp.ID] { 2558 t.Fatalf("duplicate breakpoint ID %d", bp.ID) 2559 } 2560 seen[bp.ID] = true 2561 } 2562 } 2563 2564 func TestToggleBreakpointRestart(t *testing.T) { 2565 // Checks that breakpoints IDs do not overlap after Restart if there are disabled breakpoints. 2566 withTestClient2("testtoggle", t, func(c service.Client) { 2567 bp1, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 1, Name: "firstbreakpoint"}) 2568 assertNoError(err, t, "CreateBreakpoint 1") 2569 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 2, Name: "secondbreakpoint"}) 2570 assertNoError(err, t, "CreateBreakpoint 2") 2571 _, err = c.ToggleBreakpoint(bp1.ID) 2572 assertNoError(err, t, "ToggleBreakpoint") 2573 _, err = c.Restart(false) 2574 assertNoError(err, t, "Restart") 2575 assertNoDuplicateBreakpoints(t, c) 2576 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 3, Name: "thirdbreakpoint"}) 2577 assertNoError(err, t, "CreateBreakpoint 3") 2578 assertNoDuplicateBreakpoints(t, c) 2579 }) 2580 } 2581 2582 func TestStopServerWithClosedListener(t *testing.T) { 2583 // Checks that the error erturned by listener.Accept() is ignored when we 2584 // are trying to shutdown. See issue #1633. 2585 if testBackend == "rr" || buildMode == "pie" { 2586 t.Skip("N/A") 2587 } 2588 listener, err := net.Listen("tcp", "localhost:0") 2589 assertNoError(err, t, "listener") 2590 fixture := protest.BuildFixture("math", 0) 2591 server := rpccommon.NewServer(&service.Config{ 2592 Listener: listener, 2593 AcceptMulti: false, 2594 APIVersion: 2, 2595 CheckLocalConnUser: true, 2596 DisconnectChan: make(chan struct{}), 2597 ProcessArgs: []string{fixture.Path}, 2598 Debugger: debugger.Config{ 2599 WorkingDir: ".", 2600 Backend: "default", 2601 Foreground: false, 2602 BuildFlags: "", 2603 ExecuteKind: debugger.ExecutingGeneratedFile, 2604 }, 2605 }) 2606 assertNoError(server.Run(), t, "blah") 2607 time.Sleep(1 * time.Second) // let server start 2608 server.Stop() 2609 listener.Close() 2610 time.Sleep(1 * time.Second) // give time to server to panic 2611 } 2612 2613 func TestGoroutinesGrouping(t *testing.T) { 2614 // Tests the goroutine grouping and filtering feature 2615 withTestClient2("goroutinegroup", t, func(c service.Client) { 2616 state := <-c.Continue() 2617 assertNoError(state.Err, t, "Continue") 2618 _, ggrp, _, _, err := c.ListGoroutinesWithFilter(0, 0, nil, &api.GoroutineGroupingOptions{GroupBy: api.GoroutineLabel, GroupByKey: "name", MaxGroupMembers: 5, MaxGroups: 10}) 2619 assertNoError(err, t, "ListGoroutinesWithFilter (group by label)") 2620 t.Logf("%#v\n", ggrp) 2621 if len(ggrp) < 5 { 2622 t.Errorf("not enough groups %d\n", len(ggrp)) 2623 } 2624 var unnamedCount int 2625 for i := range ggrp { 2626 if ggrp[i].Name == "name=" { 2627 unnamedCount = ggrp[i].Total 2628 break 2629 } 2630 } 2631 gs, _, _, _, err := c.ListGoroutinesWithFilter(0, 0, []api.ListGoroutinesFilter{{Kind: api.GoroutineLabel, Arg: "name="}}, nil) 2632 assertNoError(err, t, "ListGoroutinesWithFilter (filter unnamed)") 2633 if len(gs) != unnamedCount { 2634 t.Errorf("wrong number of goroutines returned by filter: %d (expected %d)\n", len(gs), unnamedCount) 2635 } 2636 }) 2637 } 2638 2639 func TestLongStringArg(t *testing.T) { 2640 // Test the ability to load more elements of a string argument, this could 2641 // be broken if registerized variables are not handled correctly. 2642 withTestClient2("morestringarg", t, func(c service.Client) { 2643 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.f"}) 2644 assertNoError(err, t, "CreateBreakpoint") 2645 state := <-c.Continue() 2646 assertNoError(state.Err, t, "Continue") 2647 2648 test := func(name, val1, val2 string) uint64 { 2649 var1, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, name, normalLoadConfig) 2650 assertNoError(err, t, "EvalVariable") 2651 t.Logf("%#v\n", var1) 2652 if var1.Value != val1 { 2653 t.Fatalf("wrong value for variable: %q", var1.Value) 2654 } 2655 var2, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, fmt.Sprintf("(*(*%q)(%#x))[64:]", var1.Type, var1.Addr), normalLoadConfig) 2656 assertNoError(err, t, "EvalVariable") 2657 t.Logf("%#v\n", var2) 2658 if var2.Value != val2 { 2659 t.Fatalf("wrong value for variable: %q", var2.Value) 2660 2661 } 2662 return var1.Addr 2663 } 2664 2665 saddr := test("s", "very long string 01234567890123456789012345678901234567890123456", "7890123456789012345678901234567890123456789X") 2666 test("q", "very long string B 012345678901234567890123456789012345678901234", "567890123456789012345678901234567890123456789X2") 2667 saddr2 := test("s", "very long string 01234567890123456789012345678901234567890123456", "7890123456789012345678901234567890123456789X") 2668 if saddr != saddr2 { 2669 t.Fatalf("address of s changed (%#x %#x)", saddr, saddr2) 2670 } 2671 }) 2672 } 2673 2674 func TestGenericsBreakpoint(t *testing.T) { 2675 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { 2676 t.Skip("generics") 2677 } 2678 // Tests that setting breakpoints inside a generic function with multiple 2679 // instantiations results in a single logical breakpoint with N physical 2680 // breakpoints (N = number of instantiations). 2681 withTestClient2("genericbp", t, func(c service.Client) { 2682 fp := testProgPath(t, "genericbp") 2683 bp, err := c.CreateBreakpoint(&api.Breakpoint{File: fp, Line: 6}) 2684 assertNoError(err, t, "CreateBreakpoint") 2685 if len(bp.Addrs) != 2 { 2686 t.Fatalf("wrong number of physical breakpoints: %d", len(bp.Addrs)) 2687 } 2688 2689 frame1Line := func() int { 2690 frames, err := c.Stacktrace(-1, 10, 0, nil) 2691 assertNoError(err, t, "Stacktrace") 2692 return frames[1].Line 2693 } 2694 2695 state := <-c.Continue() 2696 assertNoError(state.Err, t, "Continue") 2697 if line := frame1Line(); line != 10 { 2698 t.Errorf("wrong line after first continue, expected 10, got %d", line) 2699 } 2700 2701 state = <-c.Continue() 2702 assertNoError(state.Err, t, "Continue") 2703 if line := frame1Line(); line != 11 { 2704 t.Errorf("wrong line after first continue, expected 11, got %d", line) 2705 } 2706 2707 if bp.FunctionName != "main.testfn" { 2708 t.Errorf("wrong name for breakpoint (CreateBreakpoint): %q", bp.FunctionName) 2709 } 2710 2711 bps, err := c.ListBreakpoints(false) 2712 assertNoError(err, t, "ListBreakpoints") 2713 2714 for _, bp := range bps { 2715 if bp.ID > 0 { 2716 if bp.FunctionName != "main.testfn" { 2717 t.Errorf("wrong name for breakpoint (ListBreakpoints): %q", bp.FunctionName) 2718 } 2719 break 2720 } 2721 } 2722 2723 rmbp, err := c.ClearBreakpoint(bp.ID) 2724 assertNoError(err, t, "ClearBreakpoint") 2725 if rmbp.FunctionName != "main.testfn" { 2726 t.Errorf("wrong name for breakpoint (ClearBreakpoint): %q", rmbp.FunctionName) 2727 } 2728 }) 2729 } 2730 2731 func TestRestartRewindAfterEnd(t *testing.T) { 2732 if testBackend != "rr" { 2733 t.Skip("not relevant") 2734 } 2735 // Check that Restart works after the program has terminated, even if a 2736 // Continue is requested just before it. 2737 // Also check that Rewind can be used after the program has terminated. 2738 protest.AllowRecording(t) 2739 withTestClient2("math", t, func(c service.Client) { 2740 state := <-c.Continue() 2741 if !state.Exited { 2742 t.Fatalf("program did not exit") 2743 } 2744 state = <-c.Continue() 2745 if !state.Exited { 2746 t.Errorf("bad Continue return state: %v", state) 2747 } 2748 time.Sleep(1 * time.Second) // bug only happens if there is some time for the server to close the notify channel 2749 _, err := c.Restart(false) 2750 if err != nil { 2751 t.Fatalf("Restart: %v", err) 2752 } 2753 state = <-c.Continue() 2754 if !state.Exited { 2755 t.Fatalf("program did not exit exited") 2756 } 2757 _, err = c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.main", Line: 0}) 2758 if err != nil { 2759 t.Fatalf("CreateBreakpoint: %v", err) 2760 } 2761 state = <-c.Rewind() 2762 if state.Exited || state.Err != nil { 2763 t.Errorf("bad Rewind return state: %v", state) 2764 } 2765 if state.CurrentThread.Line != 7 { 2766 t.Errorf("wrong stop location %s:%d", state.CurrentThread.File, state.CurrentThread.Line) 2767 } 2768 }) 2769 } 2770 2771 func TestClientServer_SinglelineStringFormattedWithBigInts(t *testing.T) { 2772 // Check that variables that represent large numbers are represented correctly when using a formatting string 2773 2774 if runtime.GOARCH != "amd64" { 2775 t.Skip("N/A") 2776 } 2777 withTestClient2Extended("xmm0print/", t, 0, [3]string{}, func(c service.Client, fixture protest.Fixture) { 2778 _, err := c.CreateBreakpoint(&api.Breakpoint{FunctionName: "main.VPSLLQ36", Line: 4}) 2779 assertNoError(err, t, "CreateBreakpoint") 2780 state := <-c.Continue() 2781 if state.CurrentThread.Line != 8 { 2782 t.Fatalf("wrong location after continue %s:%d", state.CurrentThread.File, state.CurrentThread.Line) 2783 } 2784 2785 constvar, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "9331634762088972288", normalLoadConfig) 2786 assertNoError(err, t, "ErrVariable(9331634762088972288)") 2787 out := constvar.SinglelineStringFormatted("%X") 2788 t.Logf("constant: %q\n", out) 2789 if out != "8180A06000000000" { 2790 t.Errorf("expected \"8180A06000000000\" got %q when printing constant", out) 2791 } 2792 2793 xmm0var, err := c.EvalVariable(api.EvalScope{GoroutineID: -1}, "XMM0.uint64", normalLoadConfig) 2794 assertNoError(err, t, "EvalVariable(XMM0.uint64)") 2795 2796 expected := []string{ 2797 "9331634762088972288", "8180A06000000000", 2798 "9331634762088972288", "8180A06000000000", 2799 "9259436018245828608", "8080200000000000", 2800 "9259436018245828608", "8080200000000000", 2801 } 2802 2803 for i := range xmm0var.Children { 2804 child := &xmm0var.Children[i] 2805 if child.Kind != reflect.Uint64 { 2806 t.Errorf("wrong kind for variable %s\n", child.Kind) 2807 } 2808 out1 := child.SinglelineString() 2809 out2 := child.SinglelineStringFormatted("%X") 2810 t.Logf("%q %q\n", out1, out2) 2811 if out1 != expected[i*2] { 2812 t.Errorf("for child %d expected %s got %s (decimal)", i, expected[i*2], out1) 2813 } 2814 if out2 != expected[i*2+1] { 2815 t.Errorf("for child %d expected %s got %s (hexadecimal)", i, expected[i*2+1], out2) 2816 } 2817 } 2818 }) 2819 }