github.com/undoio/delve@v1.9.0/pkg/proc/proc_test.go (about) 1 package proc_test 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "flag" 7 "fmt" 8 "go/ast" 9 "go/constant" 10 "go/token" 11 "io/ioutil" 12 "math/rand" 13 "net" 14 "net/http" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "sort" 21 "strconv" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/undoio/delve/pkg/dwarf/frame" 27 "github.com/undoio/delve/pkg/dwarf/op" 28 "github.com/undoio/delve/pkg/dwarf/regnum" 29 "github.com/undoio/delve/pkg/goversion" 30 "github.com/undoio/delve/pkg/logflags" 31 "github.com/undoio/delve/pkg/proc" 32 "github.com/undoio/delve/pkg/proc/core" 33 "github.com/undoio/delve/pkg/proc/gdbserial" 34 "github.com/undoio/delve/pkg/proc/native" 35 protest "github.com/undoio/delve/pkg/proc/test" 36 "github.com/undoio/delve/service/api" 37 ) 38 39 var normalLoadConfig = proc.LoadConfig{true, 1, 64, 64, -1, 0} 40 var testBackend, buildMode string 41 42 func init() { 43 runtime.GOMAXPROCS(4) 44 os.Setenv("GOMAXPROCS", "4") 45 } 46 47 func TestMain(m *testing.M) { 48 flag.StringVar(&testBackend, "backend", "", "selects backend") 49 flag.StringVar(&buildMode, "test-buildmode", "", "selects build mode") 50 var logConf string 51 flag.StringVar(&logConf, "log", "", "configures logging") 52 flag.Parse() 53 protest.DefaultTestBackend(&testBackend) 54 if buildMode != "" && buildMode != "pie" { 55 fmt.Fprintf(os.Stderr, "unknown build mode %q", buildMode) 56 os.Exit(1) 57 } 58 logflags.Setup(logConf != "", logConf, "") 59 os.Exit(protest.RunTestsWithFixtures(m)) 60 } 61 62 func matchSkipConditions(conditions ...string) bool { 63 for _, cond := range conditions { 64 condfound := false 65 for _, s := range []string{runtime.GOOS, runtime.GOARCH, testBackend, buildMode} { 66 if s == cond { 67 condfound = true 68 break 69 } 70 } 71 if !condfound { 72 return false 73 } 74 } 75 return true 76 } 77 78 func skipOn(t testing.TB, reason string, conditions ...string) { 79 if matchSkipConditions(conditions...) { 80 t.Skipf("skipped on %s: %s", strings.Join(conditions, "/"), reason) 81 } 82 } 83 84 func skipUnlessOn(t testing.TB, reason string, conditions ...string) { 85 if !matchSkipConditions(conditions...) { 86 t.Skipf("skipped on %s: %s", strings.Join(conditions, "/"), reason) 87 } 88 } 89 90 func withTestProcess(name string, t testing.TB, fn func(p *proc.Target, fixture protest.Fixture)) { 91 withTestProcessArgs(name, t, ".", []string{}, 0, fn) 92 } 93 94 func withTestProcessArgs(name string, t testing.TB, wd string, args []string, buildFlags protest.BuildFlags, fn func(p *proc.Target, fixture protest.Fixture)) { 95 if buildMode == "pie" { 96 buildFlags |= protest.BuildModePIE 97 } 98 fixture := protest.BuildFixture(name, buildFlags) 99 var p *proc.Target 100 var err error 101 var tracedir string 102 var recording string 103 104 switch testBackend { 105 case "native": 106 p, err = native.Launch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{}) 107 case "lldb": 108 p, err = gdbserial.LLDBLaunch(append([]string{fixture.Path}, args...), wd, 0, []string{}, "", [3]string{}) 109 case "rr": 110 protest.MustHaveRecordingAllowed(t) 111 t.Log("recording") 112 p, tracedir, err = gdbserial.RecordAndReplay(append([]string{fixture.Path}, args...), wd, true, []string{}, [3]string{}) 113 t.Logf("replaying %q", tracedir) 114 case "undo": 115 protest.MustHaveRecordingAllowed(t) 116 t.Log("recording") 117 p, recording, err = gdbserial.UndoRecordAndReplay(append([]string{fixture.Path}, args...), wd, true, []string{}, [3]string{}) 118 t.Logf("replaying") 119 default: 120 t.Fatal("unknown backend") 121 } 122 if err != nil { 123 t.Fatal("Launch():", err) 124 } 125 126 defer func() { 127 p.Detach(true) 128 if recording != "" { 129 os.Remove(recording) 130 } 131 }() 132 133 fn(p, fixture) 134 } 135 136 func getRegisters(p *proc.Target, t *testing.T) proc.Registers { 137 regs, err := p.CurrentThread().Registers() 138 if err != nil { 139 t.Fatal("Registers():", err) 140 } 141 142 return regs 143 } 144 145 func dataAtAddr(thread proc.MemoryReadWriter, addr uint64) ([]byte, error) { 146 data := make([]byte, 1) 147 _, err := thread.ReadMemory(data, addr) 148 return data, err 149 } 150 151 func assertNoError(err error, t testing.TB, s string) { 152 if err != nil { 153 _, file, line, _ := runtime.Caller(1) 154 fname := filepath.Base(file) 155 t.Fatalf("failed assertion at %s:%d: %s - %s\n", fname, line, s, err) 156 } 157 } 158 159 func currentPC(p *proc.Target, t *testing.T) uint64 { 160 regs, err := p.CurrentThread().Registers() 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 return regs.PC() 166 } 167 168 func currentLineNumber(p *proc.Target, t *testing.T) (string, int) { 169 pc := currentPC(p, t) 170 f, l, _ := p.BinInfo().PCToLine(pc) 171 return f, l 172 } 173 174 func assertLineNumber(p *proc.Target, t *testing.T, lineno int, descr string) (string, int) { 175 f, l := currentLineNumber(p, t) 176 if l != lineno { 177 _, callerFile, callerLine, _ := runtime.Caller(1) 178 t.Fatalf("%s expected line :%d got %s:%d\n\tat %s:%d", descr, lineno, f, l, callerFile, callerLine) 179 } 180 return f, l 181 } 182 183 func TestExit(t *testing.T) { 184 protest.AllowRecording(t) 185 withTestProcess("continuetestprog", t, func(p *proc.Target, fixture protest.Fixture) { 186 err := p.Continue() 187 pe, ok := err.(proc.ErrProcessExited) 188 if !ok { 189 t.Fatalf("Continue() returned unexpected error type %s", err) 190 } 191 if pe.Status != 0 { 192 t.Errorf("Unexpected error status: %d", pe.Status) 193 } 194 if pe.Pid != p.Pid() { 195 t.Errorf("Unexpected process id: %d", pe.Pid) 196 } 197 }) 198 } 199 200 func TestExitAfterContinue(t *testing.T) { 201 protest.AllowRecording(t) 202 withTestProcess("continuetestprog", t, func(p *proc.Target, fixture protest.Fixture) { 203 setFunctionBreakpoint(p, t, "main.sayhi") 204 assertNoError(p.Continue(), t, "First Continue()") 205 err := p.Continue() 206 pe, ok := err.(proc.ErrProcessExited) 207 if !ok { 208 t.Fatalf("Continue() returned unexpected error type %s", pe) 209 } 210 if pe.Status != 0 { 211 t.Errorf("Unexpected error status: %d", pe.Status) 212 } 213 if pe.Pid != p.Pid() { 214 t.Errorf("Unexpected process id: %d", pe.Pid) 215 } 216 }) 217 } 218 219 func setFunctionBreakpoint(p *proc.Target, t testing.TB, fname string) *proc.Breakpoint { 220 _, f, l, _ := runtime.Caller(1) 221 f = filepath.Base(f) 222 223 addrs, err := proc.FindFunctionLocation(p, fname, 0) 224 if err != nil { 225 t.Fatalf("%s:%d: FindFunctionLocation(%s): %v", f, l, fname, err) 226 } 227 if len(addrs) != 1 { 228 t.Fatalf("%s:%d: setFunctionBreakpoint(%s): too many results %v", f, l, fname, addrs) 229 } 230 bp, err := p.SetBreakpoint(int(addrs[0]), addrs[0], proc.UserBreakpoint, nil) 231 if err != nil { 232 t.Fatalf("%s:%d: FindFunctionLocation(%s): %v", f, l, fname, err) 233 } 234 return bp 235 } 236 237 func setFileBreakpoint(p *proc.Target, t testing.TB, path string, lineno int) *proc.Breakpoint { 238 _, f, l, _ := runtime.Caller(1) 239 f = filepath.Base(f) 240 241 addrs, err := proc.FindFileLocation(p, path, lineno) 242 if err != nil { 243 t.Fatalf("%s:%d: FindFileLocation(%s, %d): %v", f, l, path, lineno, err) 244 } 245 if len(addrs) != 1 { 246 t.Fatalf("%s:%d: setFileLineBreakpoint(%s, %d): too many (or not enough) results %v", f, l, path, lineno, addrs) 247 } 248 bp, err := p.SetBreakpoint(int(addrs[0]), addrs[0], proc.UserBreakpoint, nil) 249 if err != nil { 250 t.Fatalf("%s:%d: SetBreakpoint: %v", f, l, err) 251 } 252 return bp 253 } 254 255 func findFunctionLocation(p *proc.Target, t *testing.T, fnname string) uint64 { 256 _, f, l, _ := runtime.Caller(1) 257 f = filepath.Base(f) 258 addrs, err := proc.FindFunctionLocation(p, fnname, 0) 259 if err != nil { 260 t.Fatalf("%s:%d: FindFunctionLocation(%s): %v", f, l, fnname, err) 261 } 262 if len(addrs) != 1 { 263 t.Fatalf("%s:%d: FindFunctionLocation(%s): too many results %v", f, l, fnname, addrs) 264 } 265 return addrs[0] 266 } 267 268 func findFileLocation(p *proc.Target, t *testing.T, file string, lineno int) uint64 { 269 _, f, l, _ := runtime.Caller(1) 270 f = filepath.Base(f) 271 addrs, err := proc.FindFileLocation(p, file, lineno) 272 if err != nil { 273 t.Fatalf("%s:%d: FindFileLocation(%s, %d): %v", f, l, file, lineno, err) 274 } 275 if len(addrs) != 1 { 276 t.Fatalf("%s:%d: FindFileLocation(%s, %d): too many results %v", f, l, file, lineno, addrs) 277 } 278 return addrs[0] 279 } 280 281 func TestHalt(t *testing.T) { 282 stopChan := make(chan interface{}, 1) 283 withTestProcess("loopprog", t, func(p *proc.Target, fixture protest.Fixture) { 284 setFunctionBreakpoint(p, t, "main.loop") 285 assertNoError(p.Continue(), t, "Continue") 286 resumeChan := make(chan struct{}, 1) 287 go func() { 288 <-resumeChan 289 time.Sleep(100 * time.Millisecond) 290 stopChan <- p.RequestManualStop() 291 }() 292 p.ResumeNotify(resumeChan) 293 assertNoError(p.Continue(), t, "Continue") 294 retVal := <-stopChan 295 296 if err, ok := retVal.(error); ok && err != nil { 297 t.Fatal() 298 } 299 }) 300 } 301 302 func TestStep(t *testing.T) { 303 protest.AllowRecording(t) 304 withTestProcess("testprog", t, func(p *proc.Target, fixture protest.Fixture) { 305 setFunctionBreakpoint(p, t, "main.helloworld") 306 assertNoError(p.Continue(), t, "Continue()") 307 308 regs := getRegisters(p, t) 309 rip := regs.PC() 310 311 err := p.CurrentThread().StepInstruction() 312 assertNoError(err, t, "Step()") 313 314 regs = getRegisters(p, t) 315 if rip >= regs.PC() { 316 t.Errorf("Expected %#v to be greater than %#v", regs.PC(), rip) 317 } 318 }) 319 } 320 321 func TestBreakpoint(t *testing.T) { 322 protest.AllowRecording(t) 323 withTestProcess("testprog", t, func(p *proc.Target, fixture protest.Fixture) { 324 bp := setFunctionBreakpoint(p, t, "main.helloworld") 325 assertNoError(p.Continue(), t, "Continue()") 326 327 regs, err := p.CurrentThread().Registers() 328 assertNoError(err, t, "Registers") 329 pc := regs.PC() 330 331 if bp.Logical.TotalHitCount != 1 { 332 t.Fatalf("Breakpoint should be hit once, got %d\n", bp.Logical.TotalHitCount) 333 } 334 335 if pc-1 != bp.Addr && pc != bp.Addr { 336 f, l, _ := p.BinInfo().PCToLine(pc) 337 t.Fatalf("Break not respected:\nPC:%#v %s:%d\nFN:%#v \n", pc, f, l, bp.Addr) 338 } 339 }) 340 } 341 342 func TestBreakpointInSeparateGoRoutine(t *testing.T) { 343 protest.AllowRecording(t) 344 withTestProcess("testthreads", t, func(p *proc.Target, fixture protest.Fixture) { 345 setFunctionBreakpoint(p, t, "main.anotherthread") 346 347 assertNoError(p.Continue(), t, "Continue") 348 349 regs, err := p.CurrentThread().Registers() 350 assertNoError(err, t, "Registers") 351 pc := regs.PC() 352 353 f, l, _ := p.BinInfo().PCToLine(pc) 354 if f != "testthreads.go" && l != 8 { 355 t.Fatal("Program did not hit breakpoint") 356 } 357 }) 358 } 359 360 func TestBreakpointWithNonExistantFunction(t *testing.T) { 361 withTestProcess("testprog", t, func(p *proc.Target, fixture protest.Fixture) { 362 _, err := p.SetBreakpoint(0, 0, proc.UserBreakpoint, nil) 363 if err == nil { 364 t.Fatal("Should not be able to break at non existent function") 365 } 366 }) 367 } 368 369 func TestClearBreakpointBreakpoint(t *testing.T) { 370 protest.AllowRecording(t) 371 withTestProcess("testprog", t, func(p *proc.Target, fixture protest.Fixture) { 372 bp := setFunctionBreakpoint(p, t, "main.sleepytime") 373 374 err := p.ClearBreakpoint(bp.Addr) 375 assertNoError(err, t, "ClearBreakpoint()") 376 377 data, err := dataAtAddr(p.Memory(), bp.Addr) 378 assertNoError(err, t, "dataAtAddr") 379 380 int3 := []byte{0xcc} 381 if bytes.Equal(data, int3) { 382 t.Fatalf("Breakpoint was not cleared data: %#v, int3: %#v", data, int3) 383 } 384 385 if countBreakpoints(p) != 0 { 386 t.Fatal("Breakpoint not removed internally") 387 } 388 }) 389 } 390 391 type nextTest struct { 392 begin, end int 393 } 394 395 func countBreakpoints(p *proc.Target) int { 396 bpcount := 0 397 for _, bp := range p.Breakpoints().M { 398 if bp.LogicalID() >= 0 { 399 bpcount++ 400 } 401 } 402 return bpcount 403 } 404 405 type contFunc int 406 407 const ( 408 contContinue contFunc = iota 409 contNext 410 contStep 411 contStepout 412 contReverseNext 413 contReverseStep 414 contReverseStepout 415 contContinueToBreakpoint 416 ) 417 418 type seqTest struct { 419 cf contFunc 420 pos interface{} 421 } 422 423 func testseq(program string, contFunc contFunc, testcases []nextTest, initialLocation string, t *testing.T) { 424 seqTestcases := make([]seqTest, len(testcases)+1) 425 seqTestcases[0] = seqTest{contContinue, testcases[0].begin} 426 for i := range testcases { 427 if i > 0 { 428 if testcases[i-1].end != testcases[i].begin { 429 panic(fmt.Errorf("begin/end mismatch at index %d", i)) 430 } 431 } 432 seqTestcases[i+1] = seqTest{contFunc, testcases[i].end} 433 } 434 testseq2(t, program, initialLocation, seqTestcases) 435 } 436 437 const traceTestseq2 = true 438 439 func testseq2(t *testing.T, program string, initialLocation string, testcases []seqTest) { 440 testseq2Args(".", []string{}, 0, t, program, initialLocation, testcases) 441 } 442 443 func testseq2Args(wd string, args []string, buildFlags protest.BuildFlags, t *testing.T, program string, initialLocation string, testcases []seqTest) { 444 protest.AllowRecording(t) 445 withTestProcessArgs(program, t, wd, args, buildFlags, func(p *proc.Target, fixture protest.Fixture) { 446 var bp *proc.Breakpoint 447 if initialLocation != "" { 448 bp = setFunctionBreakpoint(p, t, initialLocation) 449 } else if testcases[0].cf == contContinue { 450 bp = setFileBreakpoint(p, t, fixture.Source, testcases[0].pos.(int)) 451 } else { 452 panic("testseq2 can not set initial breakpoint") 453 } 454 if traceTestseq2 { 455 t.Logf("initial breakpoint %v", bp) 456 } 457 regs, err := p.CurrentThread().Registers() 458 assertNoError(err, t, "Registers") 459 460 f, ln := currentLineNumber(p, t) 461 for i, tc := range testcases { 462 switch tc.cf { 463 case contNext: 464 if traceTestseq2 { 465 t.Log("next") 466 } 467 assertNoError(p.Next(), t, "Next() returned an error") 468 case contStep: 469 if traceTestseq2 { 470 t.Log("step") 471 } 472 assertNoError(p.Step(), t, "Step() returned an error") 473 case contStepout: 474 if traceTestseq2 { 475 t.Log("stepout") 476 } 477 assertNoError(p.StepOut(), t, "StepOut() returned an error") 478 case contContinue: 479 if traceTestseq2 { 480 t.Log("continue") 481 } 482 assertNoError(p.Continue(), t, "Continue() returned an error") 483 if i == 0 { 484 if traceTestseq2 { 485 t.Log("clearing initial breakpoint") 486 } 487 err := p.ClearBreakpoint(bp.Addr) 488 assertNoError(err, t, "ClearBreakpoint() returned an error") 489 } 490 case contReverseNext: 491 if traceTestseq2 { 492 t.Log("reverse-next") 493 } 494 assertNoError(p.ChangeDirection(proc.Backward), t, "direction switch") 495 assertNoError(p.Next(), t, "reverse Next() returned an error") 496 assertNoError(p.ChangeDirection(proc.Forward), t, "direction switch") 497 case contReverseStep: 498 if traceTestseq2 { 499 t.Log("reverse-step") 500 } 501 assertNoError(p.ChangeDirection(proc.Backward), t, "direction switch") 502 assertNoError(p.Step(), t, "reverse Step() returned an error") 503 assertNoError(p.ChangeDirection(proc.Forward), t, "direction switch") 504 case contReverseStepout: 505 if traceTestseq2 { 506 t.Log("reverse-stepout") 507 } 508 assertNoError(p.ChangeDirection(proc.Backward), t, "direction switch") 509 assertNoError(p.StepOut(), t, "reverse StepOut() returned an error") 510 assertNoError(p.ChangeDirection(proc.Forward), t, "direction switch") 511 case contContinueToBreakpoint: 512 bp := setFileBreakpoint(p, t, fixture.Source, tc.pos.(int)) 513 if traceTestseq2 { 514 t.Log("continue") 515 } 516 assertNoError(p.Continue(), t, "Continue() returned an error") 517 err := p.ClearBreakpoint(bp.Addr) 518 assertNoError(err, t, "ClearBreakpoint() returned an error") 519 } 520 521 f, ln = currentLineNumber(p, t) 522 regs, _ = p.CurrentThread().Registers() 523 pc := regs.PC() 524 525 if traceTestseq2 { 526 t.Logf("at %#x %s:%d", pc, f, ln) 527 fmt.Printf("at %#x %s:%d\n", pc, f, ln) 528 } 529 switch pos := tc.pos.(type) { 530 case int: 531 if pos >= 0 && ln != pos { 532 t.Fatalf("Program did not continue to correct next location expected %d was %s:%d (%#x) (testcase %d)", pos, filepath.Base(f), ln, pc, i) 533 } 534 case string: 535 v := strings.Split(pos, ":") 536 tgtln, _ := strconv.Atoi(v[1]) 537 if !strings.HasSuffix(f, v[0]) || (ln != tgtln) { 538 t.Fatalf("Program did not continue to correct next location, expected %s was %s:%d (%#x) (testcase %d)", pos, filepath.Base(f), ln, pc, i) 539 } 540 } 541 } 542 543 if countBreakpoints(p) != 0 { 544 t.Fatal("Not all breakpoints were cleaned up", len(p.Breakpoints().M)) 545 } 546 }) 547 } 548 549 func TestNextGeneral(t *testing.T) { 550 var testcases []nextTest 551 552 ver, _ := goversion.Parse(runtime.Version()) 553 554 if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) { 555 testcases = []nextTest{ 556 {17, 19}, 557 {19, 20}, 558 {20, 23}, 559 {23, 24}, 560 {24, 26}, 561 {26, 31}, 562 {31, 23}, 563 {23, 24}, 564 {24, 26}, 565 {26, 31}, 566 {31, 23}, 567 {23, 24}, 568 {24, 26}, 569 {26, 27}, 570 {27, 28}, 571 {28, 34}, 572 } 573 } else { 574 testcases = []nextTest{ 575 {17, 19}, 576 {19, 20}, 577 {20, 23}, 578 {23, 24}, 579 {24, 26}, 580 {26, 31}, 581 {31, 23}, 582 {23, 24}, 583 {24, 26}, 584 {26, 31}, 585 {31, 23}, 586 {23, 24}, 587 {24, 26}, 588 {26, 27}, 589 {27, 34}, 590 } 591 } 592 593 testseq("testnextprog", contNext, testcases, "main.testnext", t) 594 } 595 596 func TestNextConcurrent(t *testing.T) { 597 skipOn(t, "broken", "freebsd") 598 testcases := []nextTest{ 599 {8, 9}, 600 {9, 10}, 601 {10, 11}, 602 } 603 protest.AllowRecording(t) 604 withTestProcess("parallel_next", t, func(p *proc.Target, fixture protest.Fixture) { 605 bp := setFunctionBreakpoint(p, t, "main.sayhi") 606 assertNoError(p.Continue(), t, "Continue") 607 f, ln := currentLineNumber(p, t) 608 initV := evalVariable(p, t, "n") 609 initVval, _ := constant.Int64Val(initV.Value) 610 err := p.ClearBreakpoint(bp.Addr) 611 assertNoError(err, t, "ClearBreakpoint()") 612 for _, tc := range testcases { 613 g, err := proc.GetG(p.CurrentThread()) 614 assertNoError(err, t, "GetG()") 615 if p.SelectedGoroutine().ID != g.ID { 616 t.Fatalf("SelectedGoroutine not CurrentThread's goroutine: %d %d", g.ID, p.SelectedGoroutine().ID) 617 } 618 if ln != tc.begin { 619 t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln) 620 } 621 assertNoError(p.Next(), t, "Next() returned an error") 622 f, ln = assertLineNumber(p, t, tc.end, "Program did not continue to the expected location") 623 v := evalVariable(p, t, "n") 624 vval, _ := constant.Int64Val(v.Value) 625 if vval != initVval { 626 t.Fatal("Did not end up on same goroutine") 627 } 628 } 629 }) 630 } 631 632 func TestNextConcurrentVariant2(t *testing.T) { 633 skipOn(t, "broken", "freebsd") 634 // Just like TestNextConcurrent but instead of removing the initial breakpoint we check that when it happens is for other goroutines 635 testcases := []nextTest{ 636 {8, 9}, 637 {9, 10}, 638 {10, 11}, 639 } 640 protest.AllowRecording(t) 641 withTestProcess("parallel_next", t, func(p *proc.Target, fixture protest.Fixture) { 642 setFunctionBreakpoint(p, t, "main.sayhi") 643 assertNoError(p.Continue(), t, "Continue") 644 f, ln := currentLineNumber(p, t) 645 initV := evalVariable(p, t, "n") 646 initVval, _ := constant.Int64Val(initV.Value) 647 for _, tc := range testcases { 648 t.Logf("test case %v", tc) 649 g, err := proc.GetG(p.CurrentThread()) 650 assertNoError(err, t, "GetG()") 651 if p.SelectedGoroutine().ID != g.ID { 652 t.Fatalf("SelectedGoroutine not CurrentThread's goroutine: %d %d", g.ID, p.SelectedGoroutine().ID) 653 } 654 if ln != tc.begin { 655 t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln) 656 } 657 assertNoError(p.Next(), t, "Next() returned an error") 658 var vval int64 659 for { 660 v := evalVariable(p, t, "n") 661 for _, thread := range p.ThreadList() { 662 proc.GetG(thread) 663 } 664 vval, _ = constant.Int64Val(v.Value) 665 if bpstate := p.CurrentThread().Breakpoint(); bpstate.Breakpoint == nil { 666 if vval != initVval { 667 t.Fatal("Did not end up on same goroutine") 668 } 669 break 670 } else { 671 if vval == initVval { 672 t.Fatal("Initial breakpoint triggered twice for the same goroutine") 673 } 674 assertNoError(p.Continue(), t, "Continue 2") 675 } 676 } 677 f, ln = assertLineNumber(p, t, tc.end, "Program did not continue to the expected location") 678 } 679 }) 680 } 681 682 func TestNextFunctionReturn(t *testing.T) { 683 testcases := []nextTest{ 684 {13, 14}, 685 {14, 15}, 686 {15, 35}, 687 } 688 protest.AllowRecording(t) 689 testseq("testnextprog", contNext, testcases, "main.helloworld", t) 690 } 691 692 func TestNextFunctionReturnDefer(t *testing.T) { 693 var testcases []nextTest 694 695 ver, _ := goversion.Parse(runtime.Version()) 696 697 if ver.Major < 0 || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) { 698 testcases = []nextTest{ 699 {5, 6}, 700 {6, 9}, 701 {9, 10}, 702 } 703 } else { 704 testcases = []nextTest{ 705 {5, 8}, 706 {8, 9}, 707 {9, 10}, 708 } 709 } 710 protest.AllowRecording(t) 711 testseq("testnextdefer", contNext, testcases, "main.main", t) 712 } 713 714 func TestNextNetHTTP(t *testing.T) { 715 testcases := []nextTest{ 716 {11, 12}, 717 {12, 13}, 718 } 719 withTestProcess("testnextnethttp", t, func(p *proc.Target, fixture protest.Fixture) { 720 go func() { 721 // Wait for program to start listening. 722 for { 723 conn, err := net.Dial("tcp", "127.0.0.1:9191") 724 if err == nil { 725 conn.Close() 726 break 727 } 728 time.Sleep(50 * time.Millisecond) 729 } 730 http.Get("http://127.0.0.1:9191") 731 }() 732 if err := p.Continue(); err != nil { 733 t.Fatal(err) 734 } 735 f, ln := currentLineNumber(p, t) 736 for _, tc := range testcases { 737 if ln != tc.begin { 738 t.Fatalf("Program not stopped at correct spot expected %d was %s:%d", tc.begin, filepath.Base(f), ln) 739 } 740 741 assertNoError(p.Next(), t, "Next() returned an error") 742 743 f, ln = assertLineNumber(p, t, tc.end, "Program did not continue to correct next location") 744 } 745 }) 746 } 747 748 func TestRuntimeBreakpoint(t *testing.T) { 749 withTestProcess("testruntimebreakpoint", t, func(p *proc.Target, fixture protest.Fixture) { 750 err := p.Continue() 751 if err != nil { 752 t.Fatal(err) 753 } 754 regs, err := p.CurrentThread().Registers() 755 assertNoError(err, t, "Registers") 756 pc := regs.PC() 757 f, l, _ := p.BinInfo().PCToLine(pc) 758 if l != 10 { 759 t.Fatalf("did not respect breakpoint %s:%d", f, l) 760 } 761 }) 762 } 763 764 func returnAddress(thread proc.Thread) (uint64, error) { 765 locations, err := proc.ThreadStacktrace(thread, 2) 766 if err != nil { 767 return 0, err 768 } 769 if len(locations) < 2 { 770 return 0, fmt.Errorf("no return address for function: %s", locations[0].Current.Fn.BaseName()) 771 } 772 return locations[1].Current.PC, nil 773 } 774 775 func TestFindReturnAddress(t *testing.T) { 776 protest.AllowRecording(t) 777 withTestProcess("testnextprog", t, func(p *proc.Target, fixture protest.Fixture) { 778 setFileBreakpoint(p, t, fixture.Source, 24) 779 err := p.Continue() 780 if err != nil { 781 t.Fatal(err) 782 } 783 addr, err := returnAddress(p.CurrentThread()) 784 if err != nil { 785 t.Fatal(err) 786 } 787 _, l, _ := p.BinInfo().PCToLine(addr) 788 if l != 40 { 789 t.Fatalf("return address not found correctly, expected line 40") 790 } 791 }) 792 } 793 794 func TestFindReturnAddressTopOfStackFn(t *testing.T) { 795 protest.AllowRecording(t) 796 withTestProcess("testreturnaddress", t, func(p *proc.Target, fixture protest.Fixture) { 797 fnName := "runtime.rt0_go" 798 setFunctionBreakpoint(p, t, fnName) 799 if err := p.Continue(); err != nil { 800 t.Fatal(err) 801 } 802 if _, err := returnAddress(p.CurrentThread()); err == nil { 803 t.Fatal("expected error to be returned") 804 } 805 }) 806 } 807 808 func TestSwitchThread(t *testing.T) { 809 protest.AllowRecording(t) 810 withTestProcess("testnextprog", t, func(p *proc.Target, fixture protest.Fixture) { 811 // With invalid thread id 812 err := p.SwitchThread(-1) 813 if err == nil { 814 t.Fatal("Expected error for invalid thread id") 815 } 816 setFunctionBreakpoint(p, t, "main.main") 817 err = p.Continue() 818 if err != nil { 819 t.Fatal(err) 820 } 821 var nt int 822 ct := p.CurrentThread().ThreadID() 823 for _, thread := range p.ThreadList() { 824 if thread.ThreadID() != ct { 825 nt = thread.ThreadID() 826 break 827 } 828 } 829 if nt == 0 { 830 t.Fatal("could not find thread to switch to") 831 } 832 // With valid thread id 833 err = p.SwitchThread(nt) 834 if err != nil { 835 t.Fatal(err) 836 } 837 if p.CurrentThread().ThreadID() != nt { 838 t.Fatal("Did not switch threads") 839 } 840 }) 841 } 842 843 func TestCGONext(t *testing.T) { 844 // Test if one can do 'next' in a cgo binary 845 // On OSX with Go < 1.5 CGO is not supported due to: https://github.com/golang/go/issues/8973 846 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 5) { 847 skipOn(t, "upstream issue", "darwin") 848 } 849 protest.MustHaveCgo(t) 850 851 skipOn(t, "broken - cgo stacktraces", "darwin", "arm64") 852 853 protest.AllowRecording(t) 854 withTestProcess("cgotest", t, func(p *proc.Target, fixture protest.Fixture) { 855 setFunctionBreakpoint(p, t, "main.main") 856 assertNoError(p.Continue(), t, "Continue()") 857 assertNoError(p.Next(), t, "Next()") 858 }) 859 } 860 861 type loc struct { 862 line int 863 fn string 864 } 865 866 func (l1 *loc) match(l2 proc.Stackframe) bool { 867 if l1.line >= 0 { 868 if l1.line != l2.Call.Line { 869 return false 870 } 871 } 872 return l1.fn == l2.Call.Fn.Name 873 } 874 875 func TestStacktrace(t *testing.T) { 876 stacks := [][]loc{ 877 {{4, "main.stacktraceme"}, {8, "main.func1"}, {16, "main.main"}}, 878 {{4, "main.stacktraceme"}, {8, "main.func1"}, {12, "main.func2"}, {17, "main.main"}}, 879 } 880 protest.AllowRecording(t) 881 withTestProcess("stacktraceprog", t, func(p *proc.Target, fixture protest.Fixture) { 882 bp := setFunctionBreakpoint(p, t, "main.stacktraceme") 883 884 for i := range stacks { 885 assertNoError(p.Continue(), t, "Continue()") 886 locations, err := proc.ThreadStacktrace(p.CurrentThread(), 40) 887 assertNoError(err, t, "Stacktrace()") 888 889 if len(locations) != len(stacks[i])+2 { 890 t.Fatalf("Wrong stack trace size %d %d\n", len(locations), len(stacks[i])+2) 891 } 892 893 t.Logf("Stacktrace %d:\n", i) 894 for i := range locations { 895 t.Logf("\t%s:%d\n", locations[i].Call.File, locations[i].Call.Line) 896 } 897 898 for j := range stacks[i] { 899 if !stacks[i][j].match(locations[j]) { 900 t.Fatalf("Wrong stack trace pos %d\n", j) 901 } 902 } 903 } 904 905 p.ClearBreakpoint(bp.Addr) 906 p.Continue() 907 }) 908 } 909 910 func TestStacktrace2(t *testing.T) { 911 withTestProcess("retstack", t, func(p *proc.Target, fixture protest.Fixture) { 912 assertNoError(p.Continue(), t, "Continue()") 913 914 locations, err := proc.ThreadStacktrace(p.CurrentThread(), 40) 915 assertNoError(err, t, "Stacktrace()") 916 if !stackMatch([]loc{{-1, "main.f"}, {16, "main.main"}}, locations, false) { 917 for i := range locations { 918 t.Logf("\t%s:%d [%s]\n", locations[i].Call.File, locations[i].Call.Line, locations[i].Call.Fn.Name) 919 } 920 t.Fatalf("Stack error at main.f()\n%v\n", locations) 921 } 922 923 assertNoError(p.Continue(), t, "Continue()") 924 locations, err = proc.ThreadStacktrace(p.CurrentThread(), 40) 925 assertNoError(err, t, "Stacktrace()") 926 if !stackMatch([]loc{{-1, "main.g"}, {17, "main.main"}}, locations, false) { 927 for i := range locations { 928 t.Logf("\t%s:%d [%s]\n", locations[i].Call.File, locations[i].Call.Line, locations[i].Call.Fn.Name) 929 } 930 t.Fatalf("Stack error at main.g()\n%v\n", locations) 931 } 932 }) 933 934 } 935 936 func stackMatch(stack []loc, locations []proc.Stackframe, skipRuntime bool) bool { 937 if len(stack) > len(locations) { 938 return false 939 } 940 i := 0 941 for j := range locations { 942 if i >= len(stack) { 943 break 944 } 945 if skipRuntime { 946 if locations[j].Call.Fn == nil || strings.HasPrefix(locations[j].Call.Fn.Name, "runtime.") { 947 continue 948 } 949 } 950 if !stack[i].match(locations[j]) { 951 return false 952 } 953 i++ 954 } 955 return i >= len(stack) 956 } 957 958 func TestStacktraceGoroutine(t *testing.T) { 959 skipOn(t, "broken - cgo stacktraces", "darwin", "arm64") 960 961 mainStack := []loc{{14, "main.stacktraceme"}, {29, "main.main"}} 962 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 963 mainStack[0].line = 15 964 } 965 agoroutineStacks := [][]loc{ 966 {{8, "main.agoroutine"}}, 967 {{9, "main.agoroutine"}}, 968 {{10, "main.agoroutine"}}, 969 } 970 971 lenient := 0 972 if runtime.GOOS == "windows" { 973 lenient = 1 974 } 975 976 protest.AllowRecording(t) 977 withTestProcess("goroutinestackprog", t, func(p *proc.Target, fixture protest.Fixture) { 978 bp := setFunctionBreakpoint(p, t, "main.stacktraceme") 979 980 assertNoError(p.Continue(), t, "Continue()") 981 982 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 983 assertNoError(err, t, "GoroutinesInfo") 984 985 agoroutineCount := 0 986 mainCount := 0 987 988 for i, g := range gs { 989 locations, err := g.Stacktrace(40, 0) 990 if err != nil { 991 // On windows we do not have frame information for goroutines doing system calls. 992 t.Logf("Could not retrieve goroutine stack for goid=%d: %v", g.ID, err) 993 continue 994 } 995 996 if stackMatch(mainStack, locations, false) { 997 mainCount++ 998 } 999 1000 found := false 1001 for _, agoroutineStack := range agoroutineStacks { 1002 if stackMatch(agoroutineStack, locations, true) { 1003 found = true 1004 } 1005 } 1006 1007 if found { 1008 agoroutineCount++ 1009 } else { 1010 t.Logf("Non-goroutine stack: %d (%d)", i, len(locations)) 1011 for i := range locations { 1012 name := "" 1013 if locations[i].Call.Fn != nil { 1014 name = locations[i].Call.Fn.Name 1015 } 1016 t.Logf("\t%s:%d %s (%#x) %x %v\n", locations[i].Call.File, locations[i].Call.Line, name, locations[i].Current.PC, locations[i].FrameOffset(), locations[i].SystemStack) 1017 } 1018 } 1019 } 1020 1021 if mainCount != 1 { 1022 t.Fatalf("Main goroutine stack not found %d", mainCount) 1023 } 1024 1025 if agoroutineCount < 10-lenient { 1026 t.Fatalf("Goroutine stacks not found (%d)", agoroutineCount) 1027 } 1028 1029 p.ClearBreakpoint(bp.Addr) 1030 p.Continue() 1031 }) 1032 } 1033 1034 func TestKill(t *testing.T) { 1035 skipOn(t, "N/A", "lldb") // k command presumably works but leaves the process around? 1036 withTestProcess("testprog", t, func(p *proc.Target, fixture protest.Fixture) { 1037 if err := p.Detach(true); err != nil { 1038 t.Fatal(err) 1039 } 1040 if valid, _ := p.Valid(); valid { 1041 t.Fatal("expected process to have exited") 1042 } 1043 if runtime.GOOS == "linux" { 1044 if runtime.GOARCH == "arm64" { 1045 //there is no any sync between signal sended(tracee handled) and open /proc/%d/. It may fail on arm64 1046 return 1047 } 1048 _, err := os.Open(fmt.Sprintf("/proc/%d/", p.Pid())) 1049 if err == nil { 1050 t.Fatal("process has not exited", p.Pid()) 1051 } 1052 } 1053 }) 1054 } 1055 1056 func testGSupportFunc(name string, t *testing.T, p *proc.Target, fixture protest.Fixture) { 1057 bp := setFunctionBreakpoint(p, t, "main.main") 1058 1059 assertNoError(p.Continue(), t, name+": Continue()") 1060 1061 g, err := proc.GetG(p.CurrentThread()) 1062 assertNoError(err, t, name+": GetG()") 1063 1064 if g == nil { 1065 t.Fatal(name + ": g was nil") 1066 } 1067 1068 t.Logf(name+": g is: %v", g) 1069 1070 p.ClearBreakpoint(bp.Addr) 1071 } 1072 1073 func TestGetG(t *testing.T) { 1074 protest.AllowRecording(t) 1075 withTestProcess("testprog", t, func(p *proc.Target, fixture protest.Fixture) { 1076 testGSupportFunc("nocgo", t, p, fixture) 1077 }) 1078 1079 // On OSX with Go < 1.5 CGO is not supported due to: https://github.com/golang/go/issues/8973 1080 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 5) { 1081 skipOn(t, "upstream issue", "darwin") 1082 } 1083 protest.MustHaveCgo(t) 1084 1085 protest.AllowRecording(t) 1086 withTestProcess("cgotest", t, func(p *proc.Target, fixture protest.Fixture) { 1087 testGSupportFunc("cgo", t, p, fixture) 1088 }) 1089 } 1090 1091 func TestContinueMulti(t *testing.T) { 1092 protest.AllowRecording(t) 1093 withTestProcess("integrationprog", t, func(p *proc.Target, fixture protest.Fixture) { 1094 bp1 := setFunctionBreakpoint(p, t, "main.main") 1095 bp2 := setFunctionBreakpoint(p, t, "main.sayhi") 1096 1097 mainCount := 0 1098 sayhiCount := 0 1099 for { 1100 err := p.Continue() 1101 if valid, _ := p.Valid(); !valid { 1102 break 1103 } 1104 assertNoError(err, t, "Continue()") 1105 1106 if bp := p.CurrentThread().Breakpoint(); bp.LogicalID() == bp1.LogicalID() { 1107 mainCount++ 1108 } 1109 1110 if bp := p.CurrentThread().Breakpoint(); bp.LogicalID() == bp2.LogicalID() { 1111 sayhiCount++ 1112 } 1113 } 1114 1115 if mainCount != 1 { 1116 t.Fatalf("Main breakpoint hit wrong number of times: %d\n", mainCount) 1117 } 1118 1119 if sayhiCount != 3 { 1120 t.Fatalf("Sayhi breakpoint hit wrong number of times: %d\n", sayhiCount) 1121 } 1122 }) 1123 } 1124 1125 func TestBreakpointOnFunctionEntry(t *testing.T) { 1126 testseq2(t, "testprog", "main.main", []seqTest{{contContinue, 17}}) 1127 } 1128 1129 func TestProcessReceivesSIGCHLD(t *testing.T) { 1130 protest.AllowRecording(t) 1131 withTestProcess("sigchldprog", t, func(p *proc.Target, fixture protest.Fixture) { 1132 err := p.Continue() 1133 _, ok := err.(proc.ErrProcessExited) 1134 if !ok { 1135 t.Fatalf("Continue() returned unexpected error type %v", err) 1136 } 1137 }) 1138 } 1139 1140 func TestIssue239(t *testing.T) { 1141 withTestProcess("is sue239", t, func(p *proc.Target, fixture protest.Fixture) { 1142 setFileBreakpoint(p, t, fixture.Source, 17) 1143 assertNoError(p.Continue(), t, "Continue()") 1144 }) 1145 } 1146 1147 func findFirstNonRuntimeFrame(p *proc.Target) (proc.Stackframe, error) { 1148 frames, err := proc.ThreadStacktrace(p.CurrentThread(), 10) 1149 if err != nil { 1150 return proc.Stackframe{}, err 1151 } 1152 1153 for _, frame := range frames { 1154 if frame.Current.Fn != nil && !strings.HasPrefix(frame.Current.Fn.Name, "runtime.") { 1155 return frame, nil 1156 } 1157 } 1158 return proc.Stackframe{}, fmt.Errorf("non-runtime frame not found") 1159 } 1160 1161 func evalVariableOrError(p *proc.Target, symbol string) (*proc.Variable, error) { 1162 var scope *proc.EvalScope 1163 var err error 1164 1165 if testBackend == "rr" || testBackend == "undo" { 1166 var frame proc.Stackframe 1167 frame, err = findFirstNonRuntimeFrame(p) 1168 if err == nil { 1169 scope = proc.FrameToScope(p, p.Memory(), nil, frame) 1170 } 1171 } else { 1172 scope, err = proc.GoroutineScope(p, p.CurrentThread()) 1173 } 1174 1175 if err != nil { 1176 return nil, err 1177 } 1178 return scope.EvalExpression(symbol, normalLoadConfig) 1179 } 1180 1181 func evalVariable(p *proc.Target, t testing.TB, symbol string) *proc.Variable { 1182 v, err := evalVariableOrError(p, symbol) 1183 if err != nil { 1184 _, file, line, _ := runtime.Caller(1) 1185 fname := filepath.Base(file) 1186 t.Fatalf("%s:%d: EvalVariable(%q): %v", fname, line, symbol, err) 1187 } 1188 return v 1189 } 1190 1191 func setVariable(p *proc.Target, symbol, value string) error { 1192 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 1193 if err != nil { 1194 return err 1195 } 1196 return scope.SetVariable(symbol, value) 1197 } 1198 1199 func TestVariableEvaluation(t *testing.T) { 1200 protest.AllowRecording(t) 1201 testcases := []struct { 1202 name string 1203 st reflect.Kind 1204 value interface{} 1205 length, cap int64 1206 childrenlen int 1207 }{ 1208 {"a1", reflect.String, "foofoofoofoofoofoo", 18, 0, 0}, 1209 {"a11", reflect.Array, nil, 3, -1, 3}, 1210 {"a12", reflect.Slice, nil, 2, 2, 2}, 1211 {"a13", reflect.Slice, nil, 3, 3, 3}, 1212 {"a2", reflect.Int, int64(6), 0, 0, 0}, 1213 {"a3", reflect.Float64, float64(7.23), 0, 0, 0}, 1214 {"a4", reflect.Array, nil, 2, -1, 2}, 1215 {"a5", reflect.Slice, nil, 5, 5, 5}, 1216 {"a6", reflect.Struct, nil, 2, 0, 2}, 1217 {"a7", reflect.Ptr, nil, 1, 0, 1}, 1218 {"a8", reflect.Struct, nil, 2, 0, 2}, 1219 {"a9", reflect.Ptr, nil, 1, 0, 1}, 1220 {"baz", reflect.String, "bazburzum", 9, 0, 0}, 1221 {"neg", reflect.Int, int64(-1), 0, 0, 0}, 1222 {"f32", reflect.Float32, float64(float32(1.2)), 0, 0, 0}, 1223 {"c64", reflect.Complex64, complex128(complex64(1 + 2i)), 0, 0, 0}, 1224 {"c128", reflect.Complex128, complex128(2 + 3i), 0, 0, 0}, 1225 {"a6.Baz", reflect.Int, int64(8), 0, 0, 0}, 1226 {"a7.Baz", reflect.Int, int64(5), 0, 0, 0}, 1227 {"a8.Baz", reflect.String, "feh", 3, 0, 0}, 1228 {"a8", reflect.Struct, nil, 2, 0, 2}, 1229 {"i32", reflect.Array, nil, 2, -1, 2}, 1230 {"b1", reflect.Bool, true, 0, 0, 0}, 1231 {"b2", reflect.Bool, false, 0, 0, 0}, 1232 {"f", reflect.Func, "main.barfoo", 0, 0, 0}, 1233 {"ba", reflect.Slice, nil, 200, 200, 64}, 1234 } 1235 1236 withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) { 1237 assertNoError(p.Continue(), t, "Continue() returned an error") 1238 1239 for _, tc := range testcases { 1240 v := evalVariable(p, t, tc.name) 1241 1242 if v.Kind != tc.st { 1243 t.Fatalf("%s simple type: expected: %s got: %s", tc.name, tc.st, v.Kind.String()) 1244 } 1245 if v.Value == nil && tc.value != nil { 1246 t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value) 1247 } else { 1248 switch v.Kind { 1249 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 1250 x, _ := constant.Int64Val(v.Value) 1251 if y, ok := tc.value.(int64); !ok || x != y { 1252 t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value) 1253 } 1254 case reflect.Float32, reflect.Float64: 1255 x, _ := constant.Float64Val(v.Value) 1256 if y, ok := tc.value.(float64); !ok || x != y { 1257 t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value) 1258 } 1259 case reflect.Complex64, reflect.Complex128: 1260 xr, _ := constant.Float64Val(constant.Real(v.Value)) 1261 xi, _ := constant.Float64Val(constant.Imag(v.Value)) 1262 if y, ok := tc.value.(complex128); !ok || complex(xr, xi) != y { 1263 t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value) 1264 } 1265 case reflect.String: 1266 if y, ok := tc.value.(string); !ok || constant.StringVal(v.Value) != y { 1267 t.Fatalf("%s value: expected: %v got: %v", tc.name, tc.value, v.Value) 1268 } 1269 } 1270 } 1271 if v.Len != tc.length { 1272 t.Fatalf("%s len: expected: %d got: %d", tc.name, tc.length, v.Len) 1273 } 1274 if v.Cap != tc.cap { 1275 t.Fatalf("%s cap: expected: %d got: %d", tc.name, tc.cap, v.Cap) 1276 } 1277 if len(v.Children) != tc.childrenlen { 1278 t.Fatalf("%s children len: expected %d got: %d", tc.name, tc.childrenlen, len(v.Children)) 1279 } 1280 } 1281 }) 1282 } 1283 1284 func TestFrameEvaluation(t *testing.T) { 1285 protest.AllowRecording(t) 1286 lenient := false 1287 if runtime.GOOS == "windows" { 1288 lenient = true 1289 } 1290 withTestProcess("goroutinestackprog", t, func(p *proc.Target, fixture protest.Fixture) { 1291 setFunctionBreakpoint(p, t, "main.stacktraceme") 1292 assertNoError(p.Continue(), t, "Continue()") 1293 1294 t.Logf("stopped on thread %d, goroutine: %#v", p.CurrentThread().ThreadID(), p.SelectedGoroutine()) 1295 1296 // Testing evaluation on goroutines 1297 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 1298 assertNoError(err, t, "GoroutinesInfo") 1299 found := make([]bool, 10) 1300 for _, g := range gs { 1301 frame := -1 1302 frames, err := g.Stacktrace(40, 0) 1303 if err != nil { 1304 t.Logf("could not stacktrace goroutine %d: %v\n", g.ID, err) 1305 continue 1306 } 1307 t.Logf("Goroutine %d %#v", g.ID, g.Thread) 1308 logStacktrace(t, p, frames) 1309 for i := range frames { 1310 if frames[i].Call.Fn != nil && frames[i].Call.Fn.Name == "main.agoroutine" { 1311 frame = i 1312 break 1313 } 1314 } 1315 1316 if frame < 0 { 1317 t.Logf("Goroutine %d: could not find correct frame", g.ID) 1318 continue 1319 } 1320 1321 scope, err := proc.ConvertEvalScope(p, g.ID, frame, 0) 1322 assertNoError(err, t, "ConvertEvalScope()") 1323 t.Logf("scope = %v", scope) 1324 v, err := scope.EvalExpression("i", normalLoadConfig) 1325 t.Logf("v = %v", v) 1326 if err != nil { 1327 t.Logf("Goroutine %d: %v\n", g.ID, err) 1328 continue 1329 } 1330 vval, _ := constant.Int64Val(v.Value) 1331 found[vval] = true 1332 } 1333 1334 for i := range found { 1335 if !found[i] { 1336 if lenient { 1337 lenient = false 1338 } else { 1339 t.Fatalf("Goroutine %d not found\n", i) 1340 } 1341 } 1342 } 1343 1344 // Testing evaluation on frames 1345 assertNoError(p.Continue(), t, "Continue() 2") 1346 g, err := proc.GetG(p.CurrentThread()) 1347 assertNoError(err, t, "GetG()") 1348 1349 frames, err := g.Stacktrace(40, 0) 1350 t.Logf("Goroutine %d %#v", g.ID, g.Thread) 1351 logStacktrace(t, p, frames) 1352 1353 for i := 0; i <= 3; i++ { 1354 scope, err := proc.ConvertEvalScope(p, g.ID, i+1, 0) 1355 assertNoError(err, t, fmt.Sprintf("ConvertEvalScope() on frame %d", i+1)) 1356 v, err := scope.EvalExpression("n", normalLoadConfig) 1357 assertNoError(err, t, fmt.Sprintf("EvalVariable() on frame %d", i+1)) 1358 n, _ := constant.Int64Val(v.Value) 1359 t.Logf("frame %d n %d\n", i+1, n) 1360 if n != int64(3-i) { 1361 t.Fatalf("On frame %d value of n is %d (not %d)", i+1, n, 3-i) 1362 } 1363 } 1364 }) 1365 } 1366 1367 func TestThreadFrameEvaluation(t *testing.T) { 1368 skipOn(t, "upstream issue - https://github.com/golang/go/issues/29322", "pie") 1369 deadlockBp := proc.FatalThrow 1370 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 1371 t.SkipNow() 1372 } 1373 protest.AllowRecording(t) 1374 withTestProcess("testdeadlock", t, func(p *proc.Target, fixture protest.Fixture) { 1375 assertNoError(p.Continue(), t, "Continue()") 1376 1377 bp := p.CurrentThread().Breakpoint() 1378 if bp.Breakpoint == nil || bp.Logical.Name != deadlockBp { 1379 t.Fatalf("did not stop at deadlock breakpoint %v", bp) 1380 } 1381 1382 // There is no selected goroutine during a deadlock, so the scope will 1383 // be a thread scope. 1384 scope, err := proc.ConvertEvalScope(p, 0, 0, 0) 1385 assertNoError(err, t, "ConvertEvalScope() on frame 0") 1386 _, err = scope.EvalExpression("s", normalLoadConfig) 1387 assertNoError(err, t, "EvalVariable(\"s\") on frame 0") 1388 }) 1389 } 1390 1391 func TestPointerSetting(t *testing.T) { 1392 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 1393 assertNoError(p.Continue(), t, "Continue() returned an error") 1394 1395 pval := func(n int64) { 1396 variable := evalVariable(p, t, "p1") 1397 c0val, _ := constant.Int64Val(variable.Children[0].Value) 1398 if c0val != n { 1399 t.Fatalf("Wrong value of p1, *%d expected *%d", c0val, n) 1400 } 1401 } 1402 1403 pval(1) 1404 1405 // change p1 to point to i2 1406 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 1407 assertNoError(err, t, "Scope()") 1408 i2addr, err := scope.EvalExpression("i2", normalLoadConfig) 1409 assertNoError(err, t, "EvalExpression()") 1410 assertNoError(setVariable(p, "p1", fmt.Sprintf("(*int)(0x%x)", i2addr.Addr)), t, "SetVariable()") 1411 pval(2) 1412 1413 // change the value of i2 check that p1 also changes 1414 assertNoError(setVariable(p, "i2", "5"), t, "SetVariable()") 1415 pval(5) 1416 }) 1417 } 1418 1419 func TestVariableFunctionScoping(t *testing.T) { 1420 withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) { 1421 err := p.Continue() 1422 assertNoError(err, t, "Continue() returned an error") 1423 1424 evalVariable(p, t, "a1") 1425 evalVariable(p, t, "a2") 1426 1427 // Move scopes, a1 exists here by a2 does not 1428 err = p.Continue() 1429 assertNoError(err, t, "Continue() returned an error") 1430 1431 evalVariable(p, t, "a1") 1432 1433 _, err = evalVariableOrError(p, "a2") 1434 if err == nil { 1435 t.Fatalf("Can eval out of scope variable a2") 1436 } 1437 }) 1438 } 1439 1440 func TestRecursiveStructure(t *testing.T) { 1441 protest.AllowRecording(t) 1442 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 1443 assertNoError(p.Continue(), t, "Continue()") 1444 v := evalVariable(p, t, "aas") 1445 t.Logf("v: %v\n", v) 1446 }) 1447 } 1448 1449 func TestIssue316(t *testing.T) { 1450 // A pointer loop that includes one interface should not send dlv into an infinite loop 1451 protest.AllowRecording(t) 1452 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 1453 assertNoError(p.Continue(), t, "Continue()") 1454 evalVariable(p, t, "iface5") 1455 }) 1456 } 1457 1458 func TestIssue325(t *testing.T) { 1459 // nil pointer dereference when evaluating interfaces to function pointers 1460 protest.AllowRecording(t) 1461 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 1462 assertNoError(p.Continue(), t, "Continue()") 1463 iface2fn1v := evalVariable(p, t, "iface2fn1") 1464 t.Logf("iface2fn1: %v\n", iface2fn1v) 1465 1466 iface2fn2v := evalVariable(p, t, "iface2fn2") 1467 t.Logf("iface2fn2: %v\n", iface2fn2v) 1468 }) 1469 } 1470 1471 func TestBreakpointCounts(t *testing.T) { 1472 skipOn(t, "broken", "freebsd") 1473 protest.AllowRecording(t) 1474 withTestProcess("bpcountstest", t, func(p *proc.Target, fixture protest.Fixture) { 1475 bp := setFileBreakpoint(p, t, fixture.Source, 12) 1476 1477 for { 1478 if err := p.Continue(); err != nil { 1479 if _, exited := err.(proc.ErrProcessExited); exited { 1480 break 1481 } 1482 assertNoError(err, t, "Continue()") 1483 } 1484 } 1485 1486 t.Logf("TotalHitCount: %d", bp.Logical.TotalHitCount) 1487 if bp.Logical.TotalHitCount != 200 { 1488 t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.Logical.TotalHitCount) 1489 } 1490 1491 if len(bp.Logical.HitCount) != 2 { 1492 t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.Logical.HitCount)) 1493 } 1494 1495 for _, v := range bp.Logical.HitCount { 1496 if v != 100 { 1497 t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.Logical.HitCount) 1498 } 1499 } 1500 }) 1501 } 1502 1503 func TestHardcodedBreakpointCounts(t *testing.T) { 1504 skipOn(t, "broken", "freebsd") 1505 withTestProcess("hcbpcountstest", t, func(p *proc.Target, fixture protest.Fixture) { 1506 counts := map[int]int{} 1507 for { 1508 if err := p.Continue(); err != nil { 1509 if _, exited := err.(proc.ErrProcessExited); exited { 1510 break 1511 } 1512 assertNoError(err, t, "Continue()") 1513 } 1514 1515 for _, th := range p.ThreadList() { 1516 bp := th.Breakpoint().Breakpoint 1517 if bp == nil { 1518 continue 1519 } 1520 if bp.Logical.Name != proc.HardcodedBreakpoint { 1521 t.Fatalf("wrong breakpoint name %s", bp.Logical.Name) 1522 } 1523 g, err := proc.GetG(th) 1524 assertNoError(err, t, "GetG") 1525 counts[g.ID]++ 1526 } 1527 } 1528 1529 if len(counts) != 2 { 1530 t.Fatalf("Wrong number of goroutines for hardcoded breakpoint (%d)", len(counts)) 1531 } 1532 1533 for goid, count := range counts { 1534 if count != 100 { 1535 t.Fatalf("Wrong hit count for hardcoded breakpoint (%d) on goroutine %d", count, goid) 1536 } 1537 } 1538 }) 1539 } 1540 1541 func BenchmarkArray(b *testing.B) { 1542 // each bencharr struct is 128 bytes, bencharr is 64 elements long 1543 b.SetBytes(int64(64 * 128)) 1544 withTestProcess("testvariables2", b, func(p *proc.Target, fixture protest.Fixture) { 1545 assertNoError(p.Continue(), b, "Continue()") 1546 b.ResetTimer() 1547 for i := 0; i < b.N; i++ { 1548 evalVariable(p, b, "bencharr") 1549 } 1550 }) 1551 } 1552 1553 const doTestBreakpointCountsWithDetection = false 1554 1555 func TestBreakpointCountsWithDetection(t *testing.T) { 1556 if !doTestBreakpointCountsWithDetection { 1557 return 1558 } 1559 m := map[int64]int64{} 1560 protest.AllowRecording(t) 1561 withTestProcess("bpcountstest", t, func(p *proc.Target, fixture protest.Fixture) { 1562 bp := setFileBreakpoint(p, t, fixture.Source, 12) 1563 1564 for { 1565 if err := p.Continue(); err != nil { 1566 if _, exited := err.(proc.ErrProcessExited); exited { 1567 break 1568 } 1569 assertNoError(err, t, "Continue()") 1570 } 1571 for _, th := range p.ThreadList() { 1572 if bp := th.Breakpoint(); bp.Breakpoint == nil { 1573 continue 1574 } 1575 scope, err := proc.GoroutineScope(p, th) 1576 assertNoError(err, t, "Scope()") 1577 v, err := scope.EvalExpression("i", normalLoadConfig) 1578 assertNoError(err, t, "evalVariable") 1579 i, _ := constant.Int64Val(v.Value) 1580 v, err = scope.EvalExpression("id", normalLoadConfig) 1581 assertNoError(err, t, "evalVariable") 1582 id, _ := constant.Int64Val(v.Value) 1583 m[id] = i 1584 } 1585 1586 total := int64(0) 1587 for i := range m { 1588 total += m[i] + 1 1589 } 1590 1591 if uint64(total) != bp.Logical.TotalHitCount { 1592 t.Fatalf("Mismatched total count %d %d\n", total, bp.Logical.TotalHitCount) 1593 } 1594 } 1595 1596 t.Logf("TotalHitCount: %d", bp.Logical.TotalHitCount) 1597 if bp.Logical.TotalHitCount != 200 { 1598 t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.Logical.TotalHitCount) 1599 } 1600 1601 if len(bp.Logical.HitCount) != 2 { 1602 t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.Logical.HitCount)) 1603 } 1604 1605 for _, v := range bp.Logical.HitCount { 1606 if v != 100 { 1607 t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.Logical.HitCount) 1608 } 1609 } 1610 }) 1611 } 1612 1613 func BenchmarkArrayPointer(b *testing.B) { 1614 // each bencharr struct is 128 bytes, benchparr is an array of 64 pointers to bencharr 1615 // each read will read 64 bencharr structs plus the 64 pointers of benchparr 1616 b.SetBytes(int64(64*128 + 64*8)) 1617 withTestProcess("testvariables2", b, func(p *proc.Target, fixture protest.Fixture) { 1618 assertNoError(p.Continue(), b, "Continue()") 1619 b.ResetTimer() 1620 for i := 0; i < b.N; i++ { 1621 evalVariable(p, b, "bencharr") 1622 } 1623 }) 1624 } 1625 1626 func BenchmarkMap(b *testing.B) { 1627 // m1 contains 41 entries, each one has a value that's 2 int values (2* 8 bytes) and a string key 1628 // each string key has an average of 9 character 1629 // reading strings and the map structure imposes a overhead that we ignore here 1630 b.SetBytes(int64(41 * (2*8 + 9))) 1631 withTestProcess("testvariables2", b, func(p *proc.Target, fixture protest.Fixture) { 1632 assertNoError(p.Continue(), b, "Continue()") 1633 b.ResetTimer() 1634 for i := 0; i < b.N; i++ { 1635 evalVariable(p, b, "m1") 1636 } 1637 }) 1638 } 1639 1640 func BenchmarkGoroutinesInfo(b *testing.B) { 1641 withTestProcess("testvariables2", b, func(p *proc.Target, fixture protest.Fixture) { 1642 assertNoError(p.Continue(), b, "Continue()") 1643 b.ResetTimer() 1644 for i := 0; i < b.N; i++ { 1645 p.ClearCaches() 1646 _, _, err := proc.GoroutinesInfo(p, 0, 0) 1647 assertNoError(err, b, "GoroutinesInfo") 1648 } 1649 }) 1650 } 1651 1652 func TestIssue262(t *testing.T) { 1653 // Continue does not work when the current breakpoint is set on a NOP instruction 1654 protest.AllowRecording(t) 1655 withTestProcess("issue262", t, func(p *proc.Target, fixture protest.Fixture) { 1656 setFileBreakpoint(p, t, fixture.Source, 11) 1657 1658 assertNoError(p.Continue(), t, "Continue()") 1659 err := p.Continue() 1660 if err == nil { 1661 t.Fatalf("No error on second continue") 1662 } 1663 _, exited := err.(proc.ErrProcessExited) 1664 if !exited { 1665 t.Fatalf("Process did not exit after second continue: %v", err) 1666 } 1667 }) 1668 } 1669 1670 func TestIssue305(t *testing.T) { 1671 // If 'next' hits a breakpoint on the goroutine it's stepping through 1672 // the internal breakpoints aren't cleared preventing further use of 1673 // 'next' command 1674 protest.AllowRecording(t) 1675 withTestProcess("issue305", t, func(p *proc.Target, fixture protest.Fixture) { 1676 setFileBreakpoint(p, t, fixture.Source, 5) 1677 1678 assertNoError(p.Continue(), t, "Continue()") 1679 1680 assertNoError(p.Next(), t, "Next() 1") 1681 assertNoError(p.Next(), t, "Next() 2") 1682 assertNoError(p.Next(), t, "Next() 3") 1683 assertNoError(p.Next(), t, "Next() 4") 1684 assertNoError(p.Next(), t, "Next() 5") 1685 }) 1686 } 1687 1688 func TestPointerLoops(t *testing.T) { 1689 // Pointer loops through map entries, pointers and slices 1690 // Regression test for issue #341 1691 protest.AllowRecording(t) 1692 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 1693 assertNoError(p.Continue(), t, "Continue()") 1694 for _, expr := range []string{"mapinf", "ptrinf", "sliceinf"} { 1695 t.Logf("requesting %s", expr) 1696 v := evalVariable(p, t, expr) 1697 t.Logf("%s: %v\n", expr, v) 1698 } 1699 }) 1700 } 1701 1702 func BenchmarkLocalVariables(b *testing.B) { 1703 withTestProcess("testvariables", b, func(p *proc.Target, fixture protest.Fixture) { 1704 assertNoError(p.Continue(), b, "Continue() returned an error") 1705 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 1706 assertNoError(err, b, "Scope()") 1707 b.ResetTimer() 1708 for i := 0; i < b.N; i++ { 1709 _, err := scope.LocalVariables(normalLoadConfig) 1710 assertNoError(err, b, "LocalVariables()") 1711 } 1712 }) 1713 } 1714 1715 func TestCondBreakpoint(t *testing.T) { 1716 skipOn(t, "broken", "freebsd") 1717 protest.AllowRecording(t) 1718 withTestProcess("parallel_next", t, func(p *proc.Target, fixture protest.Fixture) { 1719 bp := setFileBreakpoint(p, t, fixture.Source, 9) 1720 bp.UserBreaklet().Cond = &ast.BinaryExpr{ 1721 Op: token.EQL, 1722 X: &ast.Ident{Name: "n"}, 1723 Y: &ast.BasicLit{Kind: token.INT, Value: "7"}, 1724 } 1725 1726 assertNoError(p.Continue(), t, "Continue()") 1727 1728 nvar := evalVariable(p, t, "n") 1729 1730 n, _ := constant.Int64Val(nvar.Value) 1731 if n != 7 { 1732 t.Fatalf("Stopped on wrong goroutine %d\n", n) 1733 } 1734 }) 1735 } 1736 1737 func TestCondBreakpointError(t *testing.T) { 1738 skipOn(t, "broken", "freebsd") 1739 protest.AllowRecording(t) 1740 withTestProcess("parallel_next", t, func(p *proc.Target, fixture protest.Fixture) { 1741 bp := setFileBreakpoint(p, t, fixture.Source, 9) 1742 bp.UserBreaklet().Cond = &ast.BinaryExpr{ 1743 Op: token.EQL, 1744 X: &ast.Ident{Name: "nonexistentvariable"}, 1745 Y: &ast.BasicLit{Kind: token.INT, Value: "7"}, 1746 } 1747 1748 err := p.Continue() 1749 if err == nil { 1750 t.Fatalf("No error on first Continue()") 1751 } 1752 1753 if err.Error() != "error evaluating expression: could not find symbol value for nonexistentvariable" && err.Error() != "multiple errors evaluating conditions" { 1754 t.Fatalf("Unexpected error on first Continue(): %v", err) 1755 } 1756 1757 bp.UserBreaklet().Cond = &ast.BinaryExpr{ 1758 Op: token.EQL, 1759 X: &ast.Ident{Name: "n"}, 1760 Y: &ast.BasicLit{Kind: token.INT, Value: "7"}, 1761 } 1762 1763 err = p.Continue() 1764 if err != nil { 1765 if _, exited := err.(proc.ErrProcessExited); !exited { 1766 t.Fatalf("Unexpected error on second Continue(): %v", err) 1767 } 1768 } else { 1769 nvar := evalVariable(p, t, "n") 1770 1771 n, _ := constant.Int64Val(nvar.Value) 1772 if n != 7 { 1773 t.Fatalf("Stopped on wrong goroutine %d\n", n) 1774 } 1775 } 1776 }) 1777 } 1778 1779 func TestHitCondBreakpointEQ(t *testing.T) { 1780 protest.AllowRecording(t) 1781 withTestProcess("break", t, func(p *proc.Target, fixture protest.Fixture) { 1782 bp := setFileBreakpoint(p, t, fixture.Source, 7) 1783 bp.Logical.HitCond = &struct { 1784 Op token.Token 1785 Val int 1786 }{token.EQL, 3} 1787 1788 assertNoError(p.Continue(), t, "Continue()") 1789 ivar := evalVariable(p, t, "i") 1790 1791 i, _ := constant.Int64Val(ivar.Value) 1792 if i != 3 { 1793 t.Fatalf("Stopped on wrong hitcount %d\n", i) 1794 } 1795 1796 err := p.Continue() 1797 if _, exited := err.(proc.ErrProcessExited); !exited { 1798 t.Fatalf("Unexpected error on Continue(): %v", err) 1799 } 1800 }) 1801 } 1802 1803 func TestHitCondBreakpointGEQ(t *testing.T) { 1804 protest.AllowRecording(t) 1805 withTestProcess("break", t, func(p *proc.Target, fixture protest.Fixture) { 1806 bp := setFileBreakpoint(p, t, fixture.Source, 7) 1807 bp.Logical.HitCond = &struct { 1808 Op token.Token 1809 Val int 1810 }{token.GEQ, 3} 1811 1812 for it := 3; it <= 10; it++ { 1813 assertNoError(p.Continue(), t, "Continue()") 1814 ivar := evalVariable(p, t, "i") 1815 1816 i, _ := constant.Int64Val(ivar.Value) 1817 if int(i) != it { 1818 t.Fatalf("Stopped on wrong hitcount %d\n", i) 1819 } 1820 } 1821 1822 assertNoError(p.Continue(), t, "Continue()") 1823 }) 1824 } 1825 1826 func TestHitCondBreakpointREM(t *testing.T) { 1827 protest.AllowRecording(t) 1828 withTestProcess("break", t, func(p *proc.Target, fixture protest.Fixture) { 1829 bp := setFileBreakpoint(p, t, fixture.Source, 7) 1830 bp.Logical.HitCond = &struct { 1831 Op token.Token 1832 Val int 1833 }{token.REM, 2} 1834 1835 for it := 2; it <= 10; it += 2 { 1836 assertNoError(p.Continue(), t, "Continue()") 1837 ivar := evalVariable(p, t, "i") 1838 1839 i, _ := constant.Int64Val(ivar.Value) 1840 if int(i) != it { 1841 t.Fatalf("Stopped on wrong hitcount %d\n", i) 1842 } 1843 } 1844 1845 err := p.Continue() 1846 if _, exited := err.(proc.ErrProcessExited); !exited { 1847 t.Fatalf("Unexpected error on Continue(): %v", err) 1848 } 1849 }) 1850 } 1851 1852 func TestIssue356(t *testing.T) { 1853 // slice with a typedef does not get printed correctly 1854 protest.AllowRecording(t) 1855 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 1856 assertNoError(p.Continue(), t, "Continue() returned an error") 1857 mmvar := evalVariable(p, t, "mainMenu") 1858 if mmvar.Kind != reflect.Slice { 1859 t.Fatalf("Wrong kind for mainMenu: %v\n", mmvar.Kind) 1860 } 1861 }) 1862 } 1863 1864 func TestStepIntoFunction(t *testing.T) { 1865 withTestProcess("teststep", t, func(p *proc.Target, fixture protest.Fixture) { 1866 // Continue until breakpoint 1867 assertNoError(p.Continue(), t, "Continue() returned an error") 1868 // Step into function 1869 assertNoError(p.Step(), t, "Step() returned an error") 1870 // We should now be inside the function. 1871 loc, err := p.CurrentThread().Location() 1872 if err != nil { 1873 t.Fatal(err) 1874 } 1875 if loc.Fn.Name != "main.callme" { 1876 t.Fatalf("expected to be within the 'callme' function, was in %s instead", loc.Fn.Name) 1877 } 1878 if !strings.Contains(loc.File, "teststep") { 1879 t.Fatalf("debugger stopped at incorrect location: %s:%d", loc.File, loc.Line) 1880 } 1881 if loc.Line != 8 { 1882 t.Fatalf("debugger stopped at incorrect line: %d", loc.Line) 1883 } 1884 }) 1885 } 1886 1887 func TestIssue332_Part1(t *testing.T) { 1888 // Next shouldn't step inside a function call 1889 protest.AllowRecording(t) 1890 withTestProcess("issue332", t, func(p *proc.Target, fixture protest.Fixture) { 1891 setFileBreakpoint(p, t, fixture.Source, 8) 1892 assertNoError(p.Continue(), t, "Continue()") 1893 assertNoError(p.Next(), t, "first Next()") 1894 locations, err := proc.ThreadStacktrace(p.CurrentThread(), 2) 1895 assertNoError(err, t, "Stacktrace()") 1896 if locations[0].Call.Fn == nil { 1897 t.Fatalf("Not on a function") 1898 } 1899 if locations[0].Call.Fn.Name != "main.main" { 1900 t.Fatalf("Not on main.main after Next: %s (%s:%d)", locations[0].Call.Fn.Name, locations[0].Call.File, locations[0].Call.Line) 1901 } 1902 if locations[0].Call.Line != 9 { 1903 t.Fatalf("Not on line 9 after Next: %s (%s:%d)", locations[0].Call.Fn.Name, locations[0].Call.File, locations[0].Call.Line) 1904 } 1905 }) 1906 } 1907 1908 func TestIssue332_Part2(t *testing.T) { 1909 // Step should skip a function's prologue 1910 // In some parts of the prologue, for some functions, the FDE data is incorrect 1911 // which leads to 'next' and 'stack' failing with error "could not find FDE for PC: <garbage>" 1912 // because the incorrect FDE data leads to reading the wrong stack address as the return address 1913 protest.AllowRecording(t) 1914 withTestProcess("issue332", t, func(p *proc.Target, fixture protest.Fixture) { 1915 setFileBreakpoint(p, t, fixture.Source, 8) 1916 assertNoError(p.Continue(), t, "Continue()") 1917 1918 // step until we enter changeMe 1919 for { 1920 assertNoError(p.Step(), t, "Step()") 1921 locations, err := proc.ThreadStacktrace(p.CurrentThread(), 2) 1922 assertNoError(err, t, "Stacktrace()") 1923 if locations[0].Call.Fn == nil { 1924 t.Fatalf("Not on a function") 1925 } 1926 if locations[0].Call.Fn.Name == "main.changeMe" { 1927 break 1928 } 1929 } 1930 1931 regs, err := p.CurrentThread().Registers() 1932 assertNoError(err, t, "Registers()") 1933 pc := regs.PC() 1934 pcAfterPrologue := findFunctionLocation(p, t, "main.changeMe") 1935 if pcAfterPrologue == p.BinInfo().LookupFunc["main.changeMe"].Entry { 1936 t.Fatalf("main.changeMe and main.changeMe:0 are the same (%x)", pcAfterPrologue) 1937 } 1938 if pc != pcAfterPrologue { 1939 t.Fatalf("Step did not skip the prologue: current pc: %x, first instruction after prologue: %x", pc, pcAfterPrologue) 1940 } 1941 1942 assertNoError(p.Next(), t, "first Next()") 1943 assertNoError(p.Next(), t, "second Next()") 1944 assertNoError(p.Next(), t, "third Next()") 1945 err = p.Continue() 1946 if _, exited := err.(proc.ErrProcessExited); !exited { 1947 assertNoError(err, t, "final Continue()") 1948 } 1949 }) 1950 } 1951 1952 func TestIssue414(t *testing.T) { 1953 skipOn(t, "broken", "linux", "386", "pie") // test occasionally hangs on linux/386/pie 1954 // Stepping until the program exits 1955 protest.AllowRecording(t) 1956 withTestProcess("math", t, func(p *proc.Target, fixture protest.Fixture) { 1957 setFileBreakpoint(p, t, fixture.Source, 9) 1958 assertNoError(p.Continue(), t, "Continue()") 1959 for { 1960 pc := currentPC(p, t) 1961 f, ln := currentLineNumber(p, t) 1962 t.Logf("at %s:%d %#x\n", f, ln, pc) 1963 var err error 1964 // Stepping through the runtime is not generally safe so after we are out 1965 // of main.main just use Next. 1966 // See: https://github.com/go-delve/delve/pull/2082 1967 if f == fixture.Source { 1968 err = p.Step() 1969 } else { 1970 err = p.Next() 1971 } 1972 if err != nil { 1973 if _, exited := err.(proc.ErrProcessExited); exited { 1974 break 1975 } 1976 } 1977 assertNoError(err, t, "Step()") 1978 } 1979 }) 1980 } 1981 1982 func TestPackageVariables(t *testing.T) { 1983 var skippedVariable = map[string]bool{ 1984 "runtime.uint16Eface": true, 1985 "runtime.uint32Eface": true, 1986 "runtime.uint64Eface": true, 1987 "runtime.stringEface": true, 1988 "runtime.sliceEface": true, 1989 } 1990 1991 protest.AllowRecording(t) 1992 withTestProcess("testvariables", t, func(p *proc.Target, fixture protest.Fixture) { 1993 err := p.Continue() 1994 assertNoError(err, t, "Continue()") 1995 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 1996 assertNoError(err, t, "Scope()") 1997 vars, err := scope.PackageVariables(normalLoadConfig) 1998 assertNoError(err, t, "PackageVariables()") 1999 failed := false 2000 for _, v := range vars { 2001 if skippedVariable[v.Name] { 2002 continue 2003 } 2004 if v.Unreadable != nil && v.Unreadable.Error() != "no location attribute Location" { 2005 failed = true 2006 t.Logf("Unreadable variable %s: %v", v.Name, v.Unreadable) 2007 } 2008 } 2009 if failed { 2010 t.Fatalf("previous errors") 2011 } 2012 }) 2013 } 2014 2015 func TestIssue149(t *testing.T) { 2016 ver, _ := goversion.Parse(runtime.Version()) 2017 if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) { 2018 return 2019 } 2020 // setting breakpoint on break statement 2021 protest.AllowRecording(t) 2022 withTestProcess("break", t, func(p *proc.Target, fixture protest.Fixture) { 2023 findFileLocation(p, t, fixture.Source, 8) 2024 }) 2025 } 2026 2027 func TestPanicBreakpoint(t *testing.T) { 2028 protest.AllowRecording(t) 2029 withTestProcess("panic", t, func(p *proc.Target, fixture protest.Fixture) { 2030 assertNoError(p.Continue(), t, "Continue()") 2031 bp := p.CurrentThread().Breakpoint() 2032 if bp.Breakpoint == nil || bp.Logical.Name != proc.UnrecoveredPanic { 2033 t.Fatalf("not on unrecovered-panic breakpoint: %v", bp) 2034 } 2035 }) 2036 } 2037 2038 func TestCmdLineArgs(t *testing.T) { 2039 expectSuccess := func(p *proc.Target, fixture protest.Fixture) { 2040 err := p.Continue() 2041 bp := p.CurrentThread().Breakpoint() 2042 if bp.Breakpoint != nil && bp.Logical.Name == proc.UnrecoveredPanic { 2043 t.Fatalf("testing args failed on unrecovered-panic breakpoint: %v", bp) 2044 } 2045 exit, exited := err.(proc.ErrProcessExited) 2046 if !exited { 2047 t.Fatalf("Process did not exit: %v", err) 2048 } else { 2049 if exit.Status != 0 { 2050 t.Fatalf("process exited with invalid status %d", exit.Status) 2051 } 2052 } 2053 } 2054 2055 expectPanic := func(p *proc.Target, fixture protest.Fixture) { 2056 p.Continue() 2057 bp := p.CurrentThread().Breakpoint() 2058 if bp.Breakpoint == nil || bp.Logical.Name != proc.UnrecoveredPanic { 2059 t.Fatalf("not on unrecovered-panic breakpoint: %v", bp) 2060 } 2061 } 2062 2063 protest.AllowRecording(t) 2064 // make sure multiple arguments (including one with spaces) are passed to the binary correctly 2065 withTestProcessArgs("testargs", t, ".", []string{"test"}, 0, expectSuccess) 2066 withTestProcessArgs("testargs", t, ".", []string{"-test"}, 0, expectPanic) 2067 withTestProcessArgs("testargs", t, ".", []string{"test", "pass flag"}, 0, expectSuccess) 2068 // check that arguments with spaces are *only* passed correctly when correctly called 2069 withTestProcessArgs("testargs", t, ".", []string{"test pass", "flag"}, 0, expectPanic) 2070 withTestProcessArgs("testargs", t, ".", []string{"test", "pass", "flag"}, 0, expectPanic) 2071 withTestProcessArgs("testargs", t, ".", []string{"test pass flag"}, 0, expectPanic) 2072 // and that invalid cases (wrong arguments or no arguments) panic 2073 withTestProcess("testargs", t, expectPanic) 2074 withTestProcessArgs("testargs", t, ".", []string{"invalid"}, 0, expectPanic) 2075 withTestProcessArgs("testargs", t, ".", []string{"test", "invalid"}, 0, expectPanic) 2076 withTestProcessArgs("testargs", t, ".", []string{"invalid", "pass flag"}, 0, expectPanic) 2077 } 2078 2079 func TestIssue462(t *testing.T) { 2080 skipOn(t, "broken", "windows") // Stacktrace of Goroutine 0 fails with an error 2081 withTestProcess("testnextnethttp", t, func(p *proc.Target, fixture protest.Fixture) { 2082 go func() { 2083 // Wait for program to start listening. 2084 for { 2085 conn, err := net.Dial("tcp", "127.0.0.1:9191") 2086 if err == nil { 2087 conn.Close() 2088 break 2089 } 2090 time.Sleep(50 * time.Millisecond) 2091 } 2092 2093 p.RequestManualStop() 2094 }() 2095 2096 assertNoError(p.Continue(), t, "Continue()") 2097 _, err := proc.ThreadStacktrace(p.CurrentThread(), 40) 2098 assertNoError(err, t, "Stacktrace()") 2099 }) 2100 } 2101 2102 func TestNextParked(t *testing.T) { 2103 skipOn(t, "broken", "freebsd") 2104 protest.AllowRecording(t) 2105 withTestProcess("parallel_next", t, func(p *proc.Target, fixture protest.Fixture) { 2106 bp := setFunctionBreakpoint(p, t, "main.sayhi") 2107 2108 // continue until a parked goroutine exists 2109 var parkedg *proc.G 2110 for parkedg == nil { 2111 err := p.Continue() 2112 if _, exited := err.(proc.ErrProcessExited); exited { 2113 t.Log("could not find parked goroutine") 2114 return 2115 } 2116 assertNoError(err, t, "Continue()") 2117 2118 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 2119 assertNoError(err, t, "GoroutinesInfo()") 2120 2121 // Search for a parked goroutine that we know for sure will have to be 2122 // resumed before the program can exit. This is a parked goroutine that: 2123 // 1. is executing main.sayhi 2124 // 2. hasn't called wg.Done yet 2125 for _, g := range gs { 2126 if g.Thread != nil { 2127 continue 2128 } 2129 frames, _ := g.Stacktrace(5, 0) 2130 for _, frame := range frames { 2131 // line 11 is the line where wg.Done is called 2132 if frame.Current.Fn != nil && frame.Current.Fn.Name == "main.sayhi" && frame.Current.Line < 11 { 2133 parkedg = g 2134 break 2135 } 2136 } 2137 if parkedg != nil { 2138 break 2139 } 2140 } 2141 } 2142 2143 assertNoError(p.SwitchGoroutine(parkedg), t, "SwitchGoroutine()") 2144 p.ClearBreakpoint(bp.Addr) 2145 assertNoError(p.Next(), t, "Next()") 2146 2147 if p.SelectedGoroutine().ID != parkedg.ID { 2148 t.Fatalf("Next did not continue on the selected goroutine, expected %d got %d", parkedg.ID, p.SelectedGoroutine().ID) 2149 } 2150 }) 2151 } 2152 2153 func TestStepParked(t *testing.T) { 2154 skipOn(t, "broken", "freebsd") 2155 protest.AllowRecording(t) 2156 withTestProcess("parallel_next", t, func(p *proc.Target, fixture protest.Fixture) { 2157 bp := setFunctionBreakpoint(p, t, "main.sayhi") 2158 2159 // continue until a parked goroutine exists 2160 var parkedg *proc.G 2161 LookForParkedG: 2162 for { 2163 err := p.Continue() 2164 if _, exited := err.(proc.ErrProcessExited); exited { 2165 t.Log("could not find parked goroutine") 2166 return 2167 } 2168 assertNoError(err, t, "Continue()") 2169 2170 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 2171 assertNoError(err, t, "GoroutinesInfo()") 2172 2173 for _, g := range gs { 2174 if g.Thread == nil && g.CurrentLoc.Fn != nil && g.CurrentLoc.Fn.Name == "main.sayhi" { 2175 parkedg = g 2176 break LookForParkedG 2177 } 2178 } 2179 } 2180 2181 t.Logf("Parked g is: %v\n", parkedg) 2182 frames, _ := parkedg.Stacktrace(20, 0) 2183 for _, frame := range frames { 2184 name := "" 2185 if frame.Call.Fn != nil { 2186 name = frame.Call.Fn.Name 2187 } 2188 t.Logf("\t%s:%d in %s (%#x)", frame.Call.File, frame.Call.Line, name, frame.Current.PC) 2189 } 2190 2191 assertNoError(p.SwitchGoroutine(parkedg), t, "SwitchGoroutine()") 2192 p.ClearBreakpoint(bp.Addr) 2193 assertNoError(p.Step(), t, "Step()") 2194 2195 if p.SelectedGoroutine().ID != parkedg.ID { 2196 t.Fatalf("Step did not continue on the selected goroutine, expected %d got %d", parkedg.ID, p.SelectedGoroutine().ID) 2197 } 2198 }) 2199 } 2200 2201 func TestUnsupportedArch(t *testing.T) { 2202 ver, _ := goversion.Parse(runtime.Version()) 2203 if ver.Major < 0 || !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 6, Rev: -1}) || ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 7, Rev: -1}) { 2204 // cross compile (with -N?) works only on select versions of go 2205 return 2206 } 2207 2208 fixturesDir := protest.FindFixturesDir() 2209 infile := filepath.Join(fixturesDir, "math.go") 2210 outfile := filepath.Join(fixturesDir, "_math_debug_386") 2211 2212 cmd := exec.Command("go", "build", "-gcflags=-N -l", "-o", outfile, infile) 2213 for _, v := range os.Environ() { 2214 if !strings.HasPrefix(v, "GOARCH=") { 2215 cmd.Env = append(cmd.Env, v) 2216 } 2217 } 2218 cmd.Env = append(cmd.Env, "GOARCH=386") 2219 out, err := cmd.CombinedOutput() 2220 if err != nil { 2221 t.Fatalf("go build failed: %v: %v", err, string(out)) 2222 } 2223 defer os.Remove(outfile) 2224 2225 var p *proc.Target 2226 2227 switch testBackend { 2228 case "native": 2229 p, err = native.Launch([]string{outfile}, ".", 0, []string{}, "", [3]string{}) 2230 case "lldb": 2231 p, err = gdbserial.LLDBLaunch([]string{outfile}, ".", 0, []string{}, "", [3]string{}) 2232 default: 2233 t.Skip("test not valid for this backend") 2234 } 2235 2236 if err == nil { 2237 p.Detach(true) 2238 t.Fatal("Launch is expected to fail, but succeeded") 2239 } 2240 2241 if _, ok := err.(*proc.ErrUnsupportedArch); ok { 2242 // all good 2243 return 2244 } 2245 2246 t.Fatal(err) 2247 } 2248 2249 func TestIssue573(t *testing.T) { 2250 // calls to runtime.duffzero and runtime.duffcopy jump directly into the middle 2251 // of the function and the internal breakpoint set by StepInto may be missed. 2252 protest.AllowRecording(t) 2253 withTestProcess("issue573", t, func(p *proc.Target, fixture protest.Fixture) { 2254 setFunctionBreakpoint(p, t, "main.foo") 2255 assertNoError(p.Continue(), t, "Continue()") 2256 assertNoError(p.Step(), t, "Step() #1") 2257 assertNoError(p.Step(), t, "Step() #2") // Bug exits here. 2258 assertNoError(p.Step(), t, "Step() #3") // Third step ought to be possible; program ought not have exited. 2259 }) 2260 } 2261 2262 func TestTestvariables2Prologue(t *testing.T) { 2263 protest.AllowRecording(t) 2264 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 2265 addrEntry := p.BinInfo().LookupFunc["main.main"].Entry 2266 addrPrologue := findFunctionLocation(p, t, "main.main") 2267 if addrEntry == addrPrologue { 2268 t.Fatalf("Prologue detection failed on testvariables2.go/main.main") 2269 } 2270 }) 2271 } 2272 2273 func TestNextDeferReturnAndDirectCall(t *testing.T) { 2274 // Next should not step into a deferred function if it is called 2275 // directly, only if it is called through a panic or a deferreturn. 2276 // Here we test the case where the function is called by a deferreturn 2277 testseq("defercall", contNext, []nextTest{ 2278 {9, 10}, 2279 {10, 11}, 2280 {11, 12}, 2281 {12, 13}, 2282 {13, 28}}, "main.callAndDeferReturn", t) 2283 } 2284 2285 func TestNextPanicAndDirectCall(t *testing.T) { 2286 // Next should not step into a deferred function if it is called 2287 // directly, only if it is called through a panic or a deferreturn. 2288 // Here we test the case where the function is called by a panic 2289 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 2290 testseq("defercall", contNext, []nextTest{ 2291 {15, 16}, 2292 {16, 17}, 2293 {17, 18}, 2294 {18, 6}}, "main.callAndPanic2", t) 2295 } else { 2296 testseq("defercall", contNext, []nextTest{ 2297 {15, 16}, 2298 {16, 17}, 2299 {17, 18}, 2300 {18, 5}}, "main.callAndPanic2", t) 2301 } 2302 } 2303 2304 func TestStepCall(t *testing.T) { 2305 testseq("testnextprog", contStep, []nextTest{ 2306 {34, 13}, 2307 {13, 14}}, "", t) 2308 } 2309 2310 func TestStepCallPtr(t *testing.T) { 2311 // Tests that Step works correctly when calling functions with a 2312 // function pointer. 2313 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) && !protest.RegabiSupported() { 2314 testseq("teststepprog", contStep, []nextTest{ 2315 {9, 10}, 2316 {10, 6}, 2317 {6, 7}, 2318 {7, 11}}, "", t) 2319 } else { 2320 testseq("teststepprog", contStep, []nextTest{ 2321 {9, 10}, 2322 {10, 5}, 2323 {5, 6}, 2324 {6, 7}, 2325 {7, 11}}, "", t) 2326 } 2327 } 2328 2329 func TestStepReturnAndPanic(t *testing.T) { 2330 // Tests that Step works correctly when returning from functions 2331 // and when a deferred function is called when panic'ing. 2332 switch { 2333 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 11): 2334 testseq("defercall", contStep, []nextTest{ 2335 {17, 6}, 2336 {6, 7}, 2337 {7, 18}, 2338 {18, 6}, 2339 {6, 7}}, "", t) 2340 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 10): 2341 testseq("defercall", contStep, []nextTest{ 2342 {17, 5}, 2343 {5, 6}, 2344 {6, 7}, 2345 {7, 18}, 2346 {18, 5}, 2347 {5, 6}, 2348 {6, 7}}, "", t) 2349 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 9): 2350 testseq("defercall", contStep, []nextTest{ 2351 {17, 5}, 2352 {5, 6}, 2353 {6, 7}, 2354 {7, 17}, 2355 {17, 18}, 2356 {18, 5}, 2357 {5, 6}, 2358 {6, 7}}, "", t) 2359 default: 2360 testseq("defercall", contStep, []nextTest{ 2361 {17, 5}, 2362 {5, 6}, 2363 {6, 7}, 2364 {7, 18}, 2365 {18, 5}, 2366 {5, 6}, 2367 {6, 7}}, "", t) 2368 } 2369 } 2370 2371 func TestStepDeferReturn(t *testing.T) { 2372 // Tests that Step works correctly when a deferred function is 2373 // called during a return. 2374 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 2375 testseq("defercall", contStep, []nextTest{ 2376 {11, 6}, 2377 {6, 7}, 2378 {7, 12}, 2379 {12, 13}, 2380 {13, 6}, 2381 {6, 7}, 2382 {7, 13}, 2383 {13, 28}}, "", t) 2384 } else { 2385 testseq("defercall", contStep, []nextTest{ 2386 {11, 5}, 2387 {5, 6}, 2388 {6, 7}, 2389 {7, 12}, 2390 {12, 13}, 2391 {13, 5}, 2392 {5, 6}, 2393 {6, 7}, 2394 {7, 13}, 2395 {13, 28}}, "", t) 2396 } 2397 } 2398 2399 func TestStepIgnorePrivateRuntime(t *testing.T) { 2400 // Tests that Step will ignore calls to private runtime functions 2401 // (such as runtime.convT2E in this case) 2402 switch { 2403 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) && protest.RegabiSupported(): 2404 testseq("teststepprog", contStep, []nextTest{ 2405 {21, 13}, 2406 {13, 14}, 2407 {14, 15}, 2408 {15, 17}, 2409 {17, 22}}, "", t) 2410 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 17): 2411 testseq("teststepprog", contStep, []nextTest{ 2412 {21, 14}, 2413 {14, 15}, 2414 {15, 17}, 2415 {17, 22}}, "", t) 2416 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 11): 2417 testseq("teststepprog", contStep, []nextTest{ 2418 {21, 14}, 2419 {14, 15}, 2420 {15, 22}}, "", t) 2421 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 10): 2422 testseq("teststepprog", contStep, []nextTest{ 2423 {21, 13}, 2424 {13, 14}, 2425 {14, 15}, 2426 {15, 22}}, "", t) 2427 case goversion.VersionAfterOrEqual(runtime.Version(), 1, 7): 2428 testseq("teststepprog", contStep, []nextTest{ 2429 {21, 13}, 2430 {13, 14}, 2431 {14, 15}, 2432 {15, 14}, 2433 {14, 17}, 2434 {17, 22}}, "", t) 2435 default: 2436 testseq("teststepprog", contStep, []nextTest{ 2437 {21, 13}, 2438 {13, 14}, 2439 {14, 15}, 2440 {15, 17}, 2441 {17, 22}}, "", t) 2442 } 2443 } 2444 2445 func TestIssue561(t *testing.T) { 2446 // Step fails to make progress when PC is at a CALL instruction 2447 // where a breakpoint is also set. 2448 protest.AllowRecording(t) 2449 withTestProcess("issue561", t, func(p *proc.Target, fixture protest.Fixture) { 2450 setFileBreakpoint(p, t, fixture.Source, 10) 2451 assertNoError(p.Continue(), t, "Continue()") 2452 assertNoError(p.Step(), t, "Step()") 2453 assertLineNumber(p, t, 5, "wrong line number after Step,") 2454 }) 2455 } 2456 2457 func TestGoroutineLables(t *testing.T) { 2458 withTestProcess("goroutineLabels", t, func(p *proc.Target, fixture protest.Fixture) { 2459 assertNoError(p.Continue(), t, "Continue()") 2460 g, err := proc.GetG(p.CurrentThread()) 2461 assertNoError(err, t, "GetG()") 2462 if len(g.Labels()) != 0 { 2463 t.Fatalf("No labels expected") 2464 } 2465 2466 assertNoError(p.Continue(), t, "Continue()") 2467 g, err = proc.GetG(p.CurrentThread()) 2468 assertNoError(err, t, "GetG()") 2469 labels := g.Labels() 2470 if v := labels["k1"]; v != "v1" { 2471 t.Errorf("Unexpected label value k1=%v", v) 2472 } 2473 if v := labels["k2"]; v != "v2" { 2474 t.Errorf("Unexpected label value k2=%v", v) 2475 } 2476 }) 2477 } 2478 2479 func TestStepOut(t *testing.T) { 2480 testseq2(t, "testnextprog", "main.helloworld", []seqTest{{contContinue, 13}, {contStepout, 35}}) 2481 } 2482 2483 func TestStepConcurrentDirect(t *testing.T) { 2484 skipOn(t, "broken", "freebsd") 2485 protest.AllowRecording(t) 2486 withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { 2487 bp := setFileBreakpoint(p, t, fixture.Source, 37) 2488 2489 assertNoError(p.Continue(), t, "Continue()") 2490 err := p.ClearBreakpoint(bp.Addr) 2491 assertNoError(err, t, "ClearBreakpoint()") 2492 2493 for _, b := range p.Breakpoints().M { 2494 if b.Logical.Name == proc.UnrecoveredPanic { 2495 err := p.ClearBreakpoint(b.Addr) 2496 assertNoError(err, t, "ClearBreakpoint(unrecovered-panic)") 2497 break 2498 } 2499 } 2500 2501 gid := p.SelectedGoroutine().ID 2502 2503 seq := []int{37, 38, 13, 15, 16, 38} 2504 2505 i := 0 2506 count := 0 2507 for { 2508 anyerr := false 2509 if p.SelectedGoroutine().ID != gid { 2510 t.Errorf("Step switched to different goroutine %d %d\n", gid, p.SelectedGoroutine().ID) 2511 anyerr = true 2512 } 2513 f, ln := currentLineNumber(p, t) 2514 if ln != seq[i] { 2515 if i == 1 && ln == 40 { 2516 // loop exited 2517 break 2518 } 2519 frames, err := proc.ThreadStacktrace(p.CurrentThread(), 20) 2520 if err != nil { 2521 t.Errorf("Could not get stacktrace of goroutine %d\n", p.SelectedGoroutine().ID) 2522 } else { 2523 t.Logf("Goroutine %d (thread: %d):", p.SelectedGoroutine().ID, p.CurrentThread().ThreadID()) 2524 for _, frame := range frames { 2525 t.Logf("\t%s:%d (%#x)", frame.Call.File, frame.Call.Line, frame.Current.PC) 2526 } 2527 } 2528 t.Errorf("Program did not continue at expected location (%d) %s:%d [i %d count %d]", seq[i], f, ln, i, count) 2529 anyerr = true 2530 } 2531 if anyerr { 2532 t.FailNow() 2533 } 2534 i = (i + 1) % len(seq) 2535 if i == 0 { 2536 count++ 2537 } 2538 assertNoError(p.Step(), t, "Step()") 2539 } 2540 2541 if count != 100 { 2542 t.Fatalf("Program did not loop expected number of times: %d", count) 2543 } 2544 }) 2545 } 2546 2547 func TestStepConcurrentPtr(t *testing.T) { 2548 skipOn(t, "broken", "freebsd") 2549 protest.AllowRecording(t) 2550 withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { 2551 setFileBreakpoint(p, t, fixture.Source, 24) 2552 2553 for _, b := range p.Breakpoints().M { 2554 if b.Logical.Name == proc.UnrecoveredPanic { 2555 err := p.ClearBreakpoint(b.Addr) 2556 assertNoError(err, t, "ClearBreakpoint(unrecovered-panic)") 2557 break 2558 } 2559 } 2560 2561 kvals := map[int]int64{} 2562 count := 0 2563 for { 2564 err := p.Continue() 2565 _, exited := err.(proc.ErrProcessExited) 2566 if exited { 2567 break 2568 } 2569 assertNoError(err, t, "Continue()") 2570 2571 f, ln := currentLineNumber(p, t) 2572 if ln != 24 { 2573 for _, th := range p.ThreadList() { 2574 t.Logf("thread %d stopped on breakpoint %v", th.ThreadID(), th.Breakpoint()) 2575 } 2576 curbp := p.CurrentThread().Breakpoint() 2577 t.Fatalf("Program did not continue at expected location (24): %s:%d %#x [%v] (gid %d count %d)", f, ln, currentPC(p, t), curbp, p.SelectedGoroutine().ID, count) 2578 } 2579 2580 gid := p.SelectedGoroutine().ID 2581 2582 kvar := evalVariable(p, t, "k") 2583 k, _ := constant.Int64Val(kvar.Value) 2584 2585 if oldk, ok := kvals[gid]; ok { 2586 if oldk >= k { 2587 t.Fatalf("Goroutine %d did not make progress?", gid) 2588 } 2589 } 2590 kvals[gid] = k 2591 2592 assertNoError(p.Step(), t, "Step()") 2593 for p.Breakpoints().HasSteppingBreakpoints() { 2594 if p.SelectedGoroutine().ID == gid { 2595 t.Fatalf("step did not step into function call (but internal breakpoints still active?) (%d %d)", gid, p.SelectedGoroutine().ID) 2596 } 2597 assertNoError(p.Continue(), t, "Continue()") 2598 } 2599 2600 if p.SelectedGoroutine().ID != gid { 2601 t.Fatalf("Step switched goroutines (wanted: %d got: %d)", gid, p.SelectedGoroutine().ID) 2602 } 2603 2604 f, ln = assertLineNumber(p, t, 13, "Step did not step into function call") 2605 2606 count++ 2607 if count > 50 { 2608 // this test could potentially go on for 10000 cycles, since that's 2609 // too slow we cut the execution after 50 cycles 2610 break 2611 } 2612 } 2613 2614 if count == 0 { 2615 t.Fatalf("Breakpoint never hit") 2616 } 2617 }) 2618 } 2619 2620 func TestStepOutBreakpoint(t *testing.T) { 2621 protest.AllowRecording(t) 2622 withTestProcess("testnextprog", t, func(p *proc.Target, fixture protest.Fixture) { 2623 bp := setFileBreakpoint(p, t, fixture.Source, 13) 2624 assertNoError(p.Continue(), t, "Continue()") 2625 p.ClearBreakpoint(bp.Addr) 2626 2627 // StepOut should be interrupted by a breakpoint on the same goroutine. 2628 setFileBreakpoint(p, t, fixture.Source, 14) 2629 assertNoError(p.StepOut(), t, "StepOut()") 2630 assertLineNumber(p, t, 14, "wrong line number") 2631 if p.Breakpoints().HasSteppingBreakpoints() { 2632 t.Fatal("has internal breakpoints after hitting breakpoint on same goroutine") 2633 } 2634 }) 2635 } 2636 2637 func TestNextBreakpoint(t *testing.T) { 2638 protest.AllowRecording(t) 2639 withTestProcess("testnextprog", t, func(p *proc.Target, fixture protest.Fixture) { 2640 bp := setFileBreakpoint(p, t, fixture.Source, 34) 2641 assertNoError(p.Continue(), t, "Continue()") 2642 p.ClearBreakpoint(bp.Addr) 2643 2644 // Next should be interrupted by a breakpoint on the same goroutine. 2645 setFileBreakpoint(p, t, fixture.Source, 14) 2646 assertNoError(p.Next(), t, "Next()") 2647 assertLineNumber(p, t, 14, "wrong line number") 2648 if p.Breakpoints().HasSteppingBreakpoints() { 2649 t.Fatal("has internal breakpoints after hitting breakpoint on same goroutine") 2650 } 2651 }) 2652 } 2653 2654 func TestNextBreakpointKeepsSteppingBreakpoints(t *testing.T) { 2655 protest.AllowRecording(t) 2656 withTestProcess("testnextprog", t, func(p *proc.Target, fixture protest.Fixture) { 2657 p.KeepSteppingBreakpoints = proc.TracepointKeepsSteppingBreakpoints 2658 bp := setFileBreakpoint(p, t, fixture.Source, 34) 2659 assertNoError(p.Continue(), t, "Continue()") 2660 p.ClearBreakpoint(bp.Addr) 2661 2662 // Next should be interrupted by a tracepoint on the same goroutine. 2663 bp = setFileBreakpoint(p, t, fixture.Source, 14) 2664 bp.Logical.Tracepoint = true 2665 assertNoError(p.Next(), t, "Next()") 2666 assertLineNumber(p, t, 14, "wrong line number") 2667 if !p.Breakpoints().HasSteppingBreakpoints() { 2668 t.Fatal("does not have internal breakpoints after hitting tracepoint on same goroutine") 2669 } 2670 2671 // Continue to complete next. 2672 assertNoError(p.Continue(), t, "Continue()") 2673 assertLineNumber(p, t, 35, "wrong line number") 2674 if p.Breakpoints().HasSteppingBreakpoints() { 2675 t.Fatal("has internal breakpoints after completing next") 2676 } 2677 }) 2678 } 2679 2680 func TestStepOutDefer(t *testing.T) { 2681 protest.AllowRecording(t) 2682 withTestProcess("testnextdefer", t, func(p *proc.Target, fixture protest.Fixture) { 2683 bp := setFileBreakpoint(p, t, fixture.Source, 9) 2684 assertNoError(p.Continue(), t, "Continue()") 2685 p.ClearBreakpoint(bp.Addr) 2686 2687 assertLineNumber(p, t, 9, "wrong line number") 2688 2689 assertNoError(p.StepOut(), t, "StepOut()") 2690 2691 f, l, _ := p.BinInfo().PCToLine(currentPC(p, t)) 2692 if f == fixture.Source || l == 6 { 2693 t.Fatalf("wrong location %s:%d, expected to end somewhere in runtime", f, l) 2694 } 2695 }) 2696 } 2697 2698 func TestStepOutDeferReturnAndDirectCall(t *testing.T) { 2699 // StepOut should not step into a deferred function if it is called 2700 // directly, only if it is called through a panic. 2701 // Here we test the case where the function is called by a deferreturn 2702 testseq2(t, "defercall", "", []seqTest{ 2703 {contContinue, 11}, 2704 {contStepout, 28}}) 2705 } 2706 2707 func TestStepOnCallPtrInstr(t *testing.T) { 2708 protest.AllowRecording(t) 2709 withTestProcess("teststepprog", t, func(p *proc.Target, fixture protest.Fixture) { 2710 setFileBreakpoint(p, t, fixture.Source, 10) 2711 2712 assertNoError(p.Continue(), t, "Continue()") 2713 2714 found := false 2715 2716 for { 2717 _, ln := currentLineNumber(p, t) 2718 if ln != 10 { 2719 break 2720 } 2721 regs, err := p.CurrentThread().Registers() 2722 assertNoError(err, t, "Registers()") 2723 pc := regs.PC() 2724 text, err := proc.Disassemble(p.Memory(), regs, p.Breakpoints(), p.BinInfo(), pc, pc+uint64(p.BinInfo().Arch.MaxInstructionLength())) 2725 assertNoError(err, t, "Disassemble()") 2726 if text[0].IsCall() { 2727 found = true 2728 break 2729 } 2730 assertNoError(p.StepInstruction(), t, "StepInstruction()") 2731 } 2732 2733 if !found { 2734 t.Fatal("Could not find CALL instruction") 2735 } 2736 2737 assertNoError(p.Step(), t, "Step()") 2738 2739 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) && !protest.RegabiSupported() { 2740 assertLineNumber(p, t, 6, "Step continued to wrong line,") 2741 } else { 2742 assertLineNumber(p, t, 5, "Step continued to wrong line,") 2743 } 2744 }) 2745 } 2746 2747 func TestIssue594(t *testing.T) { 2748 skipOn(t, "upstream issue", "darwin", "lldb") 2749 // debugserver will receive an EXC_BAD_ACCESS for this, at that point 2750 // there is no way to reconvert this exception into a unix signal and send 2751 // it to the process. 2752 // This is a bug in debugserver/lldb: 2753 // https://bugs.llvm.org//show_bug.cgi?id=22868 2754 2755 // Exceptions that aren't caused by breakpoints should be propagated 2756 // back to the target. 2757 // In particular the target should be able to cause a nil pointer 2758 // dereference panic and recover from it. 2759 protest.AllowRecording(t) 2760 withTestProcess("issue594", t, func(p *proc.Target, fixture protest.Fixture) { 2761 assertNoError(p.Continue(), t, "Continue()") 2762 var f string 2763 var ln int 2764 if testBackend == "rr" || testBackend == "undo" { 2765 frame, err := findFirstNonRuntimeFrame(p) 2766 assertNoError(err, t, "findFirstNonRuntimeFrame") 2767 f, ln = frame.Current.File, frame.Current.Line 2768 } else { 2769 f, ln = currentLineNumber(p, t) 2770 } 2771 if ln != 21 { 2772 t.Fatalf("Program stopped at %s:%d, expected :21", f, ln) 2773 } 2774 }) 2775 } 2776 2777 func TestStepOutPanicAndDirectCall(t *testing.T) { 2778 // StepOut should not step into a deferred function if it is called 2779 // directly, only if it is called through a panic. 2780 // Here we test the case where the function is called by a panic 2781 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 2782 testseq2(t, "defercall", "", []seqTest{ 2783 {contContinue, 17}, 2784 {contStepout, 6}}) 2785 } else { 2786 testseq2(t, "defercall", "", []seqTest{ 2787 {contContinue, 17}, 2788 {contStepout, 5}}) 2789 } 2790 } 2791 2792 func TestWorkDir(t *testing.T) { 2793 wd := os.TempDir() 2794 // For Darwin `os.TempDir()` returns `/tmp` which is symlink to `/private/tmp`. 2795 if runtime.GOOS == "darwin" { 2796 wd = "/private/tmp" 2797 } 2798 protest.AllowRecording(t) 2799 withTestProcessArgs("workdir", t, wd, []string{}, 0, func(p *proc.Target, fixture protest.Fixture) { 2800 setFileBreakpoint(p, t, fixture.Source, 14) 2801 p.Continue() 2802 v := evalVariable(p, t, "pwd") 2803 str := constant.StringVal(v.Value) 2804 if wd != str { 2805 t.Fatalf("Expected %s got %s\n", wd, str) 2806 } 2807 }) 2808 } 2809 2810 func TestNegativeIntEvaluation(t *testing.T) { 2811 testcases := []struct { 2812 name string 2813 typ string 2814 value interface{} 2815 }{ 2816 {"ni8", "int8", int64(-5)}, 2817 {"ni16", "int16", int64(-5)}, 2818 {"ni32", "int32", int64(-5)}, 2819 } 2820 protest.AllowRecording(t) 2821 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 2822 assertNoError(p.Continue(), t, "Continue()") 2823 for _, tc := range testcases { 2824 v := evalVariable(p, t, tc.name) 2825 if typ := v.RealType.String(); typ != tc.typ { 2826 t.Fatalf("Wrong type for variable %q: %q (expected: %q)", tc.name, typ, tc.typ) 2827 } 2828 if val, _ := constant.Int64Val(v.Value); val != tc.value { 2829 t.Fatalf("Wrong value for variable %q: %v (expected: %v)", tc.name, val, tc.value) 2830 } 2831 } 2832 }) 2833 } 2834 2835 func TestIssue683(t *testing.T) { 2836 // Step panics when source file can not be found 2837 protest.AllowRecording(t) 2838 withTestProcess("issue683", t, func(p *proc.Target, fixture protest.Fixture) { 2839 setFunctionBreakpoint(p, t, "main.main") 2840 assertNoError(p.Continue(), t, "First Continue()") 2841 for i := 0; i < 20; i++ { 2842 // eventually an error about the source file not being found will be 2843 // returned, the important thing is that we shouldn't panic 2844 err := p.Step() 2845 if err != nil { 2846 break 2847 } 2848 } 2849 }) 2850 } 2851 2852 func TestIssue664(t *testing.T) { 2853 protest.AllowRecording(t) 2854 withTestProcess("issue664", t, func(p *proc.Target, fixture protest.Fixture) { 2855 setFileBreakpoint(p, t, fixture.Source, 4) 2856 assertNoError(p.Continue(), t, "Continue()") 2857 assertNoError(p.Next(), t, "Next()") 2858 assertLineNumber(p, t, 5, "Did not continue to correct location,") 2859 }) 2860 } 2861 2862 // Benchmarks (*Process).Continue + (*Scope).FunctionArguments 2863 func BenchmarkTrace(b *testing.B) { 2864 withTestProcess("traceperf", b, func(p *proc.Target, fixture protest.Fixture) { 2865 setFunctionBreakpoint(p, b, "main.PerfCheck") 2866 b.ResetTimer() 2867 for i := 0; i < b.N; i++ { 2868 assertNoError(p.Continue(), b, "Continue()") 2869 s, err := proc.GoroutineScope(p, p.CurrentThread()) 2870 assertNoError(err, b, "Scope()") 2871 _, err = s.FunctionArguments(proc.LoadConfig{false, 0, 64, 0, 3, 0}) 2872 assertNoError(err, b, "FunctionArguments()") 2873 } 2874 b.StopTimer() 2875 }) 2876 } 2877 2878 func TestNextInDeferReturn(t *testing.T) { 2879 // runtime.deferreturn updates the G struct in a way that for one 2880 // instruction leaves the curg._defer field non-nil but with curg._defer.fn 2881 // field being nil. 2882 // We need to deal with this without panicing. 2883 protest.AllowRecording(t) 2884 withTestProcess("defercall", t, func(p *proc.Target, fixture protest.Fixture) { 2885 setFunctionBreakpoint(p, t, "runtime.deferreturn") 2886 assertNoError(p.Continue(), t, "First Continue()") 2887 2888 // Set a breakpoint on the deferred function so that the following loop 2889 // can not step out of the runtime.deferreturn and all the way to the 2890 // point where the target program panics. 2891 setFunctionBreakpoint(p, t, "main.sampleFunction") 2892 for i := 0; i < 20; i++ { 2893 loc, err := p.CurrentThread().Location() 2894 assertNoError(err, t, "CurrentThread().Location()") 2895 t.Logf("at %#x %s:%d", loc.PC, loc.File, loc.Line) 2896 if loc.Fn != nil && loc.Fn.Name == "main.sampleFunction" { 2897 break 2898 } 2899 assertNoError(p.Next(), t, fmt.Sprintf("Next() %d", i)) 2900 } 2901 }) 2902 } 2903 2904 func getg(goid int, gs []*proc.G) *proc.G { 2905 for _, g := range gs { 2906 if g.ID == goid { 2907 return g 2908 } 2909 } 2910 return nil 2911 } 2912 2913 func TestAttachDetach(t *testing.T) { 2914 if testBackend == "lldb" && runtime.GOOS == "linux" { 2915 bs, _ := ioutil.ReadFile("/proc/sys/kernel/yama/ptrace_scope") 2916 if bs == nil || strings.TrimSpace(string(bs)) != "0" { 2917 t.Logf("can not run TestAttachDetach: %v\n", bs) 2918 return 2919 } 2920 } 2921 if testBackend == "rr" || testBackend == "undo" { 2922 return 2923 } 2924 var buildFlags protest.BuildFlags 2925 if buildMode == "pie" { 2926 buildFlags |= protest.BuildModePIE 2927 } 2928 fixture := protest.BuildFixture("testnextnethttp", buildFlags) 2929 cmd := exec.Command(fixture.Path) 2930 cmd.Stdout = os.Stdout 2931 cmd.Stderr = os.Stderr 2932 assertNoError(cmd.Start(), t, "starting fixture") 2933 2934 // wait for testnextnethttp to start listening 2935 t0 := time.Now() 2936 for { 2937 conn, err := net.Dial("tcp", "127.0.0.1:9191") 2938 if err == nil { 2939 conn.Close() 2940 break 2941 } 2942 time.Sleep(50 * time.Millisecond) 2943 if time.Since(t0) > 10*time.Second { 2944 t.Fatal("fixture did not start") 2945 } 2946 } 2947 2948 var p *proc.Target 2949 var err error 2950 2951 switch testBackend { 2952 case "native": 2953 p, err = native.Attach(cmd.Process.Pid, []string{}) 2954 case "lldb": 2955 path := "" 2956 if runtime.GOOS == "darwin" { 2957 path = fixture.Path 2958 } 2959 p, err = gdbserial.LLDBAttach(cmd.Process.Pid, path, []string{}) 2960 default: 2961 err = fmt.Errorf("unknown backend %q", testBackend) 2962 } 2963 2964 assertNoError(err, t, "Attach") 2965 go func() { 2966 time.Sleep(1 * time.Second) 2967 http.Get("http://127.0.0.1:9191") 2968 }() 2969 2970 assertNoError(p.Continue(), t, "Continue") 2971 assertLineNumber(p, t, 11, "Did not continue to correct location,") 2972 2973 assertNoError(p.Detach(false), t, "Detach") 2974 2975 if runtime.GOOS != "darwin" { 2976 // Debugserver sometimes will leave a zombie process after detaching, this 2977 // seems to be a bug with debugserver. 2978 resp, err := http.Get("http://127.0.0.1:9191/nobp") 2979 assertNoError(err, t, "Page request after detach") 2980 bs, err := ioutil.ReadAll(resp.Body) 2981 assertNoError(err, t, "Reading /nobp page") 2982 if out := string(bs); !strings.Contains(out, "hello, world!") { 2983 t.Fatalf("/nobp page does not contain \"hello, world!\": %q", out) 2984 } 2985 } 2986 2987 cmd.Process.Kill() 2988 } 2989 2990 func TestVarSum(t *testing.T) { 2991 protest.AllowRecording(t) 2992 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 2993 assertNoError(p.Continue(), t, "Continue()") 2994 sumvar := evalVariable(p, t, "s1[0] + s1[1]") 2995 sumvarstr := constant.StringVal(sumvar.Value) 2996 if sumvarstr != "onetwo" { 2997 t.Fatalf("s1[0] + s1[1] == %q (expected \"onetwo\")", sumvarstr) 2998 } 2999 if sumvar.Len != int64(len(sumvarstr)) { 3000 t.Fatalf("sumvar.Len == %d (expected %d)", sumvar.Len, len(sumvarstr)) 3001 } 3002 }) 3003 } 3004 3005 func TestPackageWithPathVar(t *testing.T) { 3006 protest.AllowRecording(t) 3007 withTestProcess("pkgrenames", t, func(p *proc.Target, fixture protest.Fixture) { 3008 assertNoError(p.Continue(), t, "Continue()") 3009 evalVariable(p, t, "pkg.SomeVar") 3010 evalVariable(p, t, "pkg.SomeVar.X") 3011 }) 3012 } 3013 3014 func TestEnvironment(t *testing.T) { 3015 protest.AllowRecording(t) 3016 os.Setenv("SOMEVAR", "bah") 3017 withTestProcess("testenv", t, func(p *proc.Target, fixture protest.Fixture) { 3018 assertNoError(p.Continue(), t, "Continue()") 3019 v := evalVariable(p, t, "x") 3020 vv := constant.StringVal(v.Value) 3021 t.Logf("v = %q", vv) 3022 if vv != "bah" { 3023 t.Fatalf("value of v is %q (expected \"bah\")", vv) 3024 } 3025 }) 3026 } 3027 3028 func getFrameOff(p *proc.Target, t *testing.T) int64 { 3029 frameoffvar := evalVariable(p, t, "runtime.frameoff") 3030 frameoff, _ := constant.Int64Val(frameoffvar.Value) 3031 return frameoff 3032 } 3033 3034 func TestRecursiveNext(t *testing.T) { 3035 protest.AllowRecording(t) 3036 testcases := []nextTest{ 3037 {6, 7}, 3038 {7, 10}, 3039 {10, 11}, 3040 {11, 17}, 3041 } 3042 testseq("increment", contNext, testcases, "main.Increment", t) 3043 3044 withTestProcess("increment", t, func(p *proc.Target, fixture protest.Fixture) { 3045 bp := setFunctionBreakpoint(p, t, "main.Increment") 3046 assertNoError(p.Continue(), t, "Continue") 3047 err := p.ClearBreakpoint(bp.Addr) 3048 assertNoError(err, t, "ClearBreakpoint") 3049 assertNoError(p.Next(), t, "Next 1") 3050 assertNoError(p.Next(), t, "Next 2") 3051 assertNoError(p.Next(), t, "Next 3") 3052 frameoff0 := getFrameOff(p, t) 3053 assertNoError(p.Step(), t, "Step") 3054 frameoff1 := getFrameOff(p, t) 3055 if frameoff0 == frameoff1 { 3056 t.Fatalf("did not step into function?") 3057 } 3058 assertLineNumber(p, t, 6, "program did not continue to expected location,") 3059 assertNoError(p.Next(), t, "Next 4") 3060 assertLineNumber(p, t, 7, "program did not continue to expected location,") 3061 assertNoError(p.StepOut(), t, "StepOut") 3062 assertLineNumber(p, t, 11, "program did not continue to expected location,") 3063 frameoff2 := getFrameOff(p, t) 3064 if frameoff0 != frameoff2 { 3065 t.Fatalf("frame offset mismatch %x != %x", frameoff0, frameoff2) 3066 } 3067 }) 3068 } 3069 3070 // TestIssue877 ensures that the environment variables starting with DYLD_ and LD_ 3071 // are passed when executing the binary on OSX via debugserver 3072 func TestIssue877(t *testing.T) { 3073 if runtime.GOOS != "darwin" && testBackend == "lldb" { 3074 return 3075 } 3076 if os.Getenv("TRAVIS") == "true" && runtime.GOOS == "darwin" { 3077 // Something changed on Travis side that makes the Go compiler fail if 3078 // DYLD_LIBRARY_PATH is set. 3079 t.Skip("broken") 3080 } 3081 const envval = "/usr/local/lib" 3082 os.Setenv("DYLD_LIBRARY_PATH", envval) 3083 protest.AllowRecording(t) 3084 withTestProcess("issue877", t, func(p *proc.Target, fixture protest.Fixture) { 3085 assertNoError(p.Continue(), t, "Continue()") 3086 v := evalVariable(p, t, "dyldenv") 3087 vv := constant.StringVal(v.Value) 3088 t.Logf("v = %q", vv) 3089 if vv != envval { 3090 t.Fatalf("value of v is %q (expected %q)", vv, envval) 3091 } 3092 }) 3093 } 3094 3095 func TestIssue893(t *testing.T) { 3096 // Test what happens when next is called immediately after launching the 3097 // executable, acceptable behaviors are: (a) no error, (b) no source at PC 3098 // error, (c) program runs to completion 3099 protest.AllowRecording(t) 3100 withTestProcess("increment", t, func(p *proc.Target, fixture protest.Fixture) { 3101 err := p.Next() 3102 if err == nil { 3103 return 3104 } 3105 if _, ok := err.(*frame.ErrNoFDEForPC); ok { 3106 return 3107 } 3108 if _, ok := err.(*proc.ErrNoSourceForPC); ok { 3109 return 3110 } 3111 if _, ok := err.(proc.ErrProcessExited); ok { 3112 return 3113 } 3114 assertNoError(err, t, "Next") 3115 }) 3116 } 3117 3118 func TestStepInstructionNoGoroutine(t *testing.T) { 3119 protest.AllowRecording(t) 3120 withTestProcess("increment", t, func(p *proc.Target, fixture protest.Fixture) { 3121 // Call StepInstruction immediately after launching the program, it should 3122 // work even though no goroutine is selected. 3123 assertNoError(p.StepInstruction(), t, "StepInstruction") 3124 }) 3125 } 3126 3127 func TestIssue871(t *testing.T) { 3128 protest.AllowRecording(t) 3129 withTestProcess("issue871", t, func(p *proc.Target, fixture protest.Fixture) { 3130 assertNoError(p.Continue(), t, "Continue") 3131 3132 var scope *proc.EvalScope 3133 var err error 3134 if testBackend == "rr" || testBackend == "undo" { 3135 var frame proc.Stackframe 3136 frame, err = findFirstNonRuntimeFrame(p) 3137 if err == nil { 3138 scope = proc.FrameToScope(p, p.Memory(), nil, frame) 3139 } 3140 } else { 3141 scope, err = proc.GoroutineScope(p, p.CurrentThread()) 3142 } 3143 assertNoError(err, t, "scope") 3144 3145 locals, err := scope.LocalVariables(normalLoadConfig) 3146 assertNoError(err, t, "LocalVariables") 3147 3148 foundA, foundB := false, false 3149 3150 for _, v := range locals { 3151 t.Logf("local %v", v) 3152 switch v.Name { 3153 case "a": 3154 foundA = true 3155 if v.Flags&proc.VariableEscaped == 0 { 3156 t.Errorf("variable a not flagged as escaped") 3157 } 3158 case "b": 3159 foundB = true 3160 } 3161 } 3162 3163 if !foundA { 3164 t.Errorf("variable a not found") 3165 } 3166 3167 if !foundB { 3168 t.Errorf("variable b not found") 3169 } 3170 }) 3171 } 3172 3173 func TestShadowedFlag(t *testing.T) { 3174 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) { 3175 return 3176 } 3177 withTestProcess("testshadow", t, func(p *proc.Target, fixture protest.Fixture) { 3178 assertNoError(p.Continue(), t, "Continue") 3179 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 3180 assertNoError(err, t, "GoroutineScope") 3181 locals, err := scope.LocalVariables(normalLoadConfig) 3182 assertNoError(err, t, "LocalVariables") 3183 foundShadowed := false 3184 foundNonShadowed := false 3185 for _, v := range locals { 3186 if v.Flags&proc.VariableShadowed != 0 { 3187 if v.Name != "a" { 3188 t.Errorf("wrong shadowed variable %s", v.Name) 3189 } 3190 foundShadowed = true 3191 if n, _ := constant.Int64Val(v.Value); n != 0 { 3192 t.Errorf("wrong value for shadowed variable a: %d", n) 3193 } 3194 } else { 3195 if v.Name != "a" { 3196 t.Errorf("wrong non-shadowed variable %s", v.Name) 3197 } 3198 foundNonShadowed = true 3199 if n, _ := constant.Int64Val(v.Value); n != 1 { 3200 t.Errorf("wrong value for non-shadowed variable a: %d", n) 3201 } 3202 } 3203 } 3204 if !foundShadowed { 3205 t.Error("could not find any shadowed variable") 3206 } 3207 if !foundNonShadowed { 3208 t.Error("could not find any non-shadowed variable") 3209 } 3210 }) 3211 } 3212 3213 func TestAttachStripped(t *testing.T) { 3214 if testBackend == "lldb" && runtime.GOOS == "linux" { 3215 bs, _ := ioutil.ReadFile("/proc/sys/kernel/yama/ptrace_scope") 3216 if bs == nil || strings.TrimSpace(string(bs)) != "0" { 3217 t.Logf("can not run TestAttachStripped: %v\n", bs) 3218 return 3219 } 3220 } 3221 if testBackend == "rr" || testBackend == "undo" { 3222 return 3223 } 3224 if runtime.GOOS == "darwin" { 3225 t.Log("-s does not produce stripped executables on macOS") 3226 return 3227 } 3228 if buildMode != "" { 3229 t.Skip("not enabled with buildmode=PIE") 3230 } 3231 fixture := protest.BuildFixture("testnextnethttp", protest.LinkStrip) 3232 cmd := exec.Command(fixture.Path) 3233 cmd.Stdout = os.Stdout 3234 cmd.Stderr = os.Stderr 3235 assertNoError(cmd.Start(), t, "starting fixture") 3236 3237 // wait for testnextnethttp to start listening 3238 t0 := time.Now() 3239 for { 3240 conn, err := net.Dial("tcp", "127.0.0.1:9191") 3241 if err == nil { 3242 conn.Close() 3243 break 3244 } 3245 time.Sleep(50 * time.Millisecond) 3246 if time.Since(t0) > 10*time.Second { 3247 t.Fatal("fixture did not start") 3248 } 3249 } 3250 3251 var p *proc.Target 3252 var err error 3253 3254 switch testBackend { 3255 case "native": 3256 p, err = native.Attach(cmd.Process.Pid, []string{}) 3257 case "lldb": 3258 path := "" 3259 if runtime.GOOS == "darwin" { 3260 path = fixture.Path 3261 } 3262 p, err = gdbserial.LLDBAttach(cmd.Process.Pid, path, []string{}) 3263 default: 3264 t.Fatalf("unknown backend %q", testBackend) 3265 } 3266 3267 t.Logf("error is %v", err) 3268 3269 if err == nil { 3270 p.Detach(true) 3271 t.Fatalf("expected error after attach, got nothing") 3272 } else { 3273 cmd.Process.Kill() 3274 } 3275 os.Remove(fixture.Path) 3276 } 3277 3278 func TestIssue844(t *testing.T) { 3279 // Conditional breakpoints should not prevent next from working if their 3280 // condition isn't met. 3281 protest.AllowRecording(t) 3282 withTestProcess("nextcond", t, func(p *proc.Target, fixture protest.Fixture) { 3283 setFileBreakpoint(p, t, fixture.Source, 9) 3284 condbp := setFileBreakpoint(p, t, fixture.Source, 10) 3285 condbp.UserBreaklet().Cond = &ast.BinaryExpr{ 3286 Op: token.EQL, 3287 X: &ast.Ident{Name: "n"}, 3288 Y: &ast.BasicLit{Kind: token.INT, Value: "11"}, 3289 } 3290 assertNoError(p.Continue(), t, "Continue") 3291 assertNoError(p.Next(), t, "Next") 3292 assertLineNumber(p, t, 10, "continued to wrong location,") 3293 }) 3294 } 3295 3296 func logStacktrace(t *testing.T, p *proc.Target, frames []proc.Stackframe) { 3297 for j := range frames { 3298 name := "?" 3299 if frames[j].Current.Fn != nil { 3300 name = frames[j].Current.Fn.Name 3301 } 3302 if frames[j].Call.Fn != nil && frames[j].Current.Fn != frames[j].Call.Fn { 3303 name = fmt.Sprintf("%s inlined in %s", frames[j].Call.Fn.Name, frames[j].Current.Fn.Name) 3304 } 3305 3306 t.Logf("\t%#x %#x %#x %s at %s:%d\n", frames[j].Call.PC, frames[j].FrameOffset(), frames[j].FramePointerOffset(), name, filepath.Base(frames[j].Call.File), frames[j].Call.Line) 3307 if frames[j].TopmostDefer != nil { 3308 _, _, fn := frames[j].TopmostDefer.DeferredFunc(p) 3309 fnname := "" 3310 if fn != nil { 3311 fnname = fn.Name 3312 } 3313 t.Logf("\t\ttopmost defer: %#x %s\n", frames[j].TopmostDefer.DwrapPC, fnname) 3314 } 3315 for deferIdx, _defer := range frames[j].Defers { 3316 _, _, fn := _defer.DeferredFunc(p) 3317 fnname := "" 3318 if fn != nil { 3319 fnname = fn.Name 3320 } 3321 t.Logf("\t\t%d defer: %#x %s\n", deferIdx, _defer.DwrapPC, fnname) 3322 3323 } 3324 } 3325 } 3326 3327 // stacktraceCheck checks that all the functions listed in tc appear in 3328 // frames in the same order. 3329 // Checks that all the functions in tc starting with "C." or with "!" are in 3330 // a systemstack frame. 3331 // Returns a slice m where m[i] is the index in frames of the function tc[i] 3332 // or nil if any check fails. 3333 func stacktraceCheck(t *testing.T, tc []string, frames []proc.Stackframe) []int { 3334 m := make([]int, len(tc)) 3335 i, j := 0, 0 3336 for i < len(tc) { 3337 tcname := tc[i] 3338 tcsystem := strings.HasPrefix(tcname, "C.") 3339 if tcname[0] == '!' { 3340 tcsystem = true 3341 tcname = tcname[1:] 3342 } 3343 for j < len(frames) { 3344 name := "?" 3345 if frames[j].Current.Fn != nil { 3346 name = frames[j].Current.Fn.Name 3347 } 3348 if name == tcname { 3349 m[i] = j 3350 if tcsystem != frames[j].SystemStack { 3351 t.Logf("system stack check failed for frame %d (expected %v got %v)", j, tcsystem, frames[j].SystemStack) 3352 t.Logf("expected: %v\n", tc) 3353 return nil 3354 } 3355 break 3356 } 3357 3358 j++ 3359 } 3360 if j >= len(frames) { 3361 t.Logf("couldn't find frame %d %s", i, tc) 3362 t.Logf("expected: %v\n", tc) 3363 return nil 3364 } 3365 3366 i++ 3367 } 3368 return m 3369 } 3370 3371 func frameInFile(frame proc.Stackframe, file string) bool { 3372 for _, loc := range []proc.Location{frame.Current, frame.Call} { 3373 if !strings.HasSuffix(loc.File, file) && !strings.HasSuffix(loc.File, "/"+file) && !strings.HasSuffix(loc.File, "\\"+file) { 3374 return false 3375 } 3376 if loc.Line <= 0 { 3377 return false 3378 } 3379 } 3380 return true 3381 } 3382 3383 func TestCgoStacktrace(t *testing.T) { 3384 if runtime.GOOS == "windows" { 3385 ver, _ := goversion.Parse(runtime.Version()) 3386 if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) { 3387 t.Skip("disabled on windows with go before version 1.9") 3388 } 3389 } 3390 if runtime.GOOS == "darwin" { 3391 ver, _ := goversion.Parse(runtime.Version()) 3392 if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 8, Rev: -1}) { 3393 t.Skip("disabled on macOS with go before version 1.8") 3394 } 3395 } 3396 3397 skipOn(t, "broken - cgo stacktraces", "386") 3398 skipOn(t, "broken - cgo stacktraces", "linux", "arm64") 3399 protest.MustHaveCgo(t) 3400 3401 // Tests that: 3402 // a) we correctly identify the goroutine while we are executing cgo code 3403 // b) that we can stitch together the system stack (where cgo code 3404 // executes) and the normal goroutine stack 3405 3406 // Each test case describes how the stack trace should appear after a 3407 // continue. The first function on each test case is the topmost function 3408 // that should be found on the stack, the actual stack trace can have more 3409 // frame than those listed here but all the frames listed must appear in 3410 // the specified order. 3411 testCases := [][]string{ 3412 []string{"main.main"}, 3413 []string{"C.helloworld_pt2", "C.helloworld", "main.main"}, 3414 []string{"main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"}, 3415 []string{"C.helloworld_pt4", "C.helloworld_pt3", "main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"}, 3416 []string{"main.helloWorld2", "C.helloworld_pt4", "C.helloworld_pt3", "main.helloWorldS", "main.helloWorld", "C.helloworld_pt2", "C.helloworld", "main.main"}} 3417 3418 var gid int 3419 3420 frameOffs := map[string]int64{} 3421 framePointerOffs := map[string]int64{} 3422 3423 withTestProcess("cgostacktest/", t, func(p *proc.Target, fixture protest.Fixture) { 3424 for itidx, tc := range testCases { 3425 assertNoError(p.Continue(), t, fmt.Sprintf("Continue at iteration step %d", itidx)) 3426 3427 g, err := proc.GetG(p.CurrentThread()) 3428 assertNoError(err, t, fmt.Sprintf("GetG at iteration step %d", itidx)) 3429 3430 if itidx == 0 { 3431 gid = g.ID 3432 } else { 3433 if gid != g.ID { 3434 t.Fatalf("wrong goroutine id at iteration step %d (expected %d got %d)", itidx, gid, g.ID) 3435 } 3436 } 3437 3438 frames, err := g.Stacktrace(100, 0) 3439 assertNoError(err, t, fmt.Sprintf("Stacktrace at iteration step %d", itidx)) 3440 3441 t.Logf("iteration step %d", itidx) 3442 logStacktrace(t, p, frames) 3443 3444 m := stacktraceCheck(t, tc, frames) 3445 mismatch := (m == nil) 3446 3447 for i, j := range m { 3448 if strings.HasPrefix(tc[i], "C.hellow") { 3449 if !frameInFile(frames[j], "hello.c") { 3450 t.Logf("position in %q is %s:%d (call %s:%d)", tc[i], frames[j].Current.File, frames[j].Current.Line, frames[j].Call.File, frames[j].Call.Line) 3451 mismatch = true 3452 break 3453 } 3454 } 3455 if frameOff, ok := frameOffs[tc[i]]; ok { 3456 if frameOff != frames[j].FrameOffset() { 3457 t.Logf("frame %s offset mismatch", tc[i]) 3458 } 3459 if framePointerOffs[tc[i]] != frames[j].FramePointerOffset() { 3460 t.Logf("frame %s pointer offset mismatch", tc[i]) 3461 } 3462 } else { 3463 frameOffs[tc[i]] = frames[j].FrameOffset() 3464 framePointerOffs[tc[i]] = frames[j].FramePointerOffset() 3465 } 3466 } 3467 3468 // also check that ThreadStacktrace produces the same list of frames 3469 threadFrames, err := proc.ThreadStacktrace(p.CurrentThread(), 100) 3470 assertNoError(err, t, fmt.Sprintf("ThreadStacktrace at iteration step %d", itidx)) 3471 3472 if len(threadFrames) != len(frames) { 3473 mismatch = true 3474 } else { 3475 for j := range frames { 3476 if frames[j].Current.File != threadFrames[j].Current.File || frames[j].Current.Line != threadFrames[j].Current.Line { 3477 t.Logf("stack mismatch between goroutine stacktrace and thread stacktrace") 3478 t.Logf("thread stacktrace:") 3479 logStacktrace(t, p, threadFrames) 3480 mismatch = true 3481 break 3482 } 3483 } 3484 } 3485 if mismatch { 3486 t.Fatal("see previous loglines") 3487 } 3488 } 3489 }) 3490 } 3491 3492 func TestCgoSources(t *testing.T) { 3493 if runtime.GOOS == "windows" { 3494 ver, _ := goversion.Parse(runtime.Version()) 3495 if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) { 3496 t.Skip("disabled on windows with go before version 1.9") 3497 } 3498 } 3499 3500 if runtime.GOARCH == "386" { 3501 t.Skip("cgo stacktraces not supported on i386 for now") 3502 } 3503 3504 protest.MustHaveCgo(t) 3505 3506 protest.AllowRecording(t) 3507 withTestProcess("cgostacktest/", t, func(p *proc.Target, fixture protest.Fixture) { 3508 sources := p.BinInfo().Sources 3509 for _, needle := range []string{"main.go", "hello.c"} { 3510 found := false 3511 for _, k := range sources { 3512 if strings.HasSuffix(k, needle) || strings.HasSuffix(k, "/"+needle) || strings.HasSuffix(k, "\\"+needle) { 3513 found = true 3514 break 3515 } 3516 } 3517 if !found { 3518 t.Errorf("File %s not found", needle) 3519 } 3520 } 3521 }) 3522 } 3523 3524 func TestSystemstackStacktrace(t *testing.T) { 3525 // check that we can follow a stack switch initiated by runtime.systemstack() 3526 protest.AllowRecording(t) 3527 withTestProcess("panic", t, func(p *proc.Target, fixture protest.Fixture) { 3528 setFunctionBreakpoint(p, t, "runtime.startpanic_m") 3529 assertNoError(p.Continue(), t, "first continue") 3530 assertNoError(p.Continue(), t, "second continue") 3531 g, err := proc.GetG(p.CurrentThread()) 3532 assertNoError(err, t, "GetG") 3533 frames, err := g.Stacktrace(100, 0) 3534 assertNoError(err, t, "stacktrace") 3535 logStacktrace(t, p, frames) 3536 m := stacktraceCheck(t, []string{"!runtime.startpanic_m", "runtime.gopanic", "main.main"}, frames) 3537 if m == nil { 3538 t.Fatal("see previous loglines") 3539 } 3540 }) 3541 } 3542 3543 func TestSystemstackOnRuntimeNewstack(t *testing.T) { 3544 // The bug being tested here manifests as follows: 3545 // - set a breakpoint somewhere or interrupt the program with Ctrl-C 3546 // - try to look at stacktraces of other goroutines 3547 // If one of the other goroutines is resizing its own stack the stack 3548 // command won't work for it. 3549 withTestProcess("binarytrees", t, func(p *proc.Target, fixture protest.Fixture) { 3550 setFunctionBreakpoint(p, t, "main.main") 3551 assertNoError(p.Continue(), t, "first continue") 3552 3553 g, err := proc.GetG(p.CurrentThread()) 3554 assertNoError(err, t, "GetG") 3555 mainGoroutineID := g.ID 3556 3557 setFunctionBreakpoint(p, t, "runtime.newstack") 3558 for { 3559 assertNoError(p.Continue(), t, "second continue") 3560 g, err = proc.GetG(p.CurrentThread()) 3561 assertNoError(err, t, "GetG") 3562 if g.ID == mainGoroutineID { 3563 break 3564 } 3565 } 3566 frames, err := g.Stacktrace(100, 0) 3567 assertNoError(err, t, "stacktrace") 3568 logStacktrace(t, p, frames) 3569 m := stacktraceCheck(t, []string{"!runtime.newstack", "main.main"}, frames) 3570 if m == nil { 3571 t.Fatal("see previous loglines") 3572 } 3573 }) 3574 } 3575 3576 func TestIssue1034(t *testing.T) { 3577 skipOn(t, "broken - cgo stacktraces", "386") 3578 protest.MustHaveCgo(t) 3579 3580 // The external linker on macOS produces an abbrev for DW_TAG_subprogram 3581 // without the "has children" flag, we should support this. 3582 protest.AllowRecording(t) 3583 withTestProcess("cgostacktest/", t, func(p *proc.Target, fixture protest.Fixture) { 3584 setFunctionBreakpoint(p, t, "main.main") 3585 assertNoError(p.Continue(), t, "Continue()") 3586 frames, err := p.SelectedGoroutine().Stacktrace(10, 0) 3587 assertNoError(err, t, "Stacktrace") 3588 scope := proc.FrameToScope(p, p.Memory(), nil, frames[2:]...) 3589 args, _ := scope.FunctionArguments(normalLoadConfig) 3590 assertNoError(err, t, "FunctionArguments()") 3591 if len(args) > 0 { 3592 t.Fatalf("wrong number of arguments for frame %v (%d)", frames[2], len(args)) 3593 } 3594 }) 3595 } 3596 3597 func TestIssue1008(t *testing.T) { 3598 skipOn(t, "broken - cgo stacktraces", "386") 3599 protest.MustHaveCgo(t) 3600 3601 // The external linker on macOS inserts "end of sequence" extended opcodes 3602 // in debug_line. which we should support correctly. 3603 protest.AllowRecording(t) 3604 withTestProcess("cgostacktest/", t, func(p *proc.Target, fixture protest.Fixture) { 3605 setFunctionBreakpoint(p, t, "main.main") 3606 assertNoError(p.Continue(), t, "Continue()") 3607 loc, err := p.CurrentThread().Location() 3608 assertNoError(err, t, "CurrentThread().Location()") 3609 t.Logf("location %v\n", loc) 3610 if !strings.HasSuffix(loc.File, "/main.go") { 3611 t.Errorf("unexpected location %s:%d\n", loc.File, loc.Line) 3612 } 3613 if loc.Line > 31 { 3614 t.Errorf("unexpected location %s:%d (file only has 30 lines)\n", loc.File, loc.Line) 3615 } 3616 }) 3617 } 3618 3619 func testDeclLineCount(t *testing.T, p *proc.Target, lineno int, tgtvars []string) { 3620 sort.Strings(tgtvars) 3621 3622 assertLineNumber(p, t, lineno, "Program did not continue to correct next location") 3623 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 3624 assertNoError(err, t, fmt.Sprintf("GoroutineScope (:%d)", lineno)) 3625 vars, err := scope.Locals(0) 3626 assertNoError(err, t, fmt.Sprintf("Locals (:%d)", lineno)) 3627 if len(vars) != len(tgtvars) { 3628 t.Fatalf("wrong number of variables %d (:%d)", len(vars), lineno) 3629 } 3630 outvars := make([]string, len(vars)) 3631 for i, v := range vars { 3632 outvars[i] = v.Name 3633 } 3634 sort.Strings(outvars) 3635 3636 for i := range outvars { 3637 if tgtvars[i] != outvars[i] { 3638 t.Fatalf("wrong variables, got: %q expected %q\n", outvars, tgtvars) 3639 } 3640 } 3641 } 3642 3643 func TestDeclLine(t *testing.T) { 3644 ver, _ := goversion.Parse(runtime.Version()) 3645 if ver.Major > 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 3646 t.Skip("go 1.9 and prior versions do not emit DW_AT_decl_line") 3647 } 3648 3649 protest.AllowRecording(t) 3650 withTestProcess("decllinetest", t, func(p *proc.Target, fixture protest.Fixture) { 3651 setFileBreakpoint(p, t, fixture.Source, 8) 3652 setFileBreakpoint(p, t, fixture.Source, 9) 3653 setFileBreakpoint(p, t, fixture.Source, 10) 3654 setFileBreakpoint(p, t, fixture.Source, 11) 3655 setFileBreakpoint(p, t, fixture.Source, 14) 3656 3657 assertNoError(p.Continue(), t, "Continue 1") 3658 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) { 3659 testDeclLineCount(t, p, 8, []string{}) 3660 } else { 3661 testDeclLineCount(t, p, 8, []string{"a"}) 3662 } 3663 3664 assertNoError(p.Continue(), t, "Continue 2") 3665 testDeclLineCount(t, p, 9, []string{"a"}) 3666 3667 assertNoError(p.Continue(), t, "Continue 3") 3668 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 15) { 3669 testDeclLineCount(t, p, 10, []string{"a"}) 3670 } else { 3671 testDeclLineCount(t, p, 10, []string{"a", "b"}) 3672 } 3673 3674 assertNoError(p.Continue(), t, "Continue 4") 3675 testDeclLineCount(t, p, 11, []string{"a", "b"}) 3676 3677 assertNoError(p.Continue(), t, "Continue 5") 3678 testDeclLineCount(t, p, 14, []string{"a", "b"}) 3679 }) 3680 } 3681 3682 func TestIssue1137(t *testing.T) { 3683 protest.AllowRecording(t) 3684 withTestProcess("dotpackagesiface", t, func(p *proc.Target, fixture protest.Fixture) { 3685 assertNoError(p.Continue(), t, "Continue()") 3686 v := evalVariable(p, t, "iface") 3687 assertNoError(v.Unreadable, t, "iface unreadable") 3688 v2 := evalVariable(p, t, "iface2") 3689 assertNoError(v2.Unreadable, t, "iface2 unreadable") 3690 }) 3691 } 3692 3693 func TestIssue1101(t *testing.T) { 3694 // If a breakpoint is hit close to process death on a thread that isn't the 3695 // group leader the process could die while we are trying to stop it. 3696 // 3697 // This can be easily reproduced by having the goroutine that's executing 3698 // main.main (which will almost always run on the thread group leader) wait 3699 // for a second goroutine before exiting, then setting a breakpoint on the 3700 // second goroutine and stepping through it (see TestIssue1101 in 3701 // proc_test.go). 3702 // 3703 // When stepping over the return instruction of main.f the deferred 3704 // wg.Done() call will be executed which will cause the main goroutine to 3705 // resume and proceed to exit. Both the temporary breakpoint on wg.Done and 3706 // the temporary breakpoint on the return address of main.f will be in 3707 // close proximity to main.main calling os.Exit() and causing the death of 3708 // the thread group leader. 3709 3710 withTestProcess("issue1101", t, func(p *proc.Target, fixture protest.Fixture) { 3711 setFunctionBreakpoint(p, t, "main.f") 3712 assertNoError(p.Continue(), t, "Continue()") 3713 assertNoError(p.Next(), t, "Next() 1") 3714 assertNoError(p.Next(), t, "Next() 2") 3715 lastCmd := "Next() 3" 3716 exitErr := p.Next() 3717 if exitErr == nil { 3718 lastCmd = "final Continue()" 3719 exitErr = p.Continue() 3720 } 3721 if pexit, exited := exitErr.(proc.ErrProcessExited); exited { 3722 if pexit.Status != 2 && testBackend != "lldb" && (runtime.GOOS != "linux" || runtime.GOARCH != "386") { 3723 // Looks like there's a bug with debugserver on macOS that sometimes 3724 // will report exit status 0 instead of the proper exit status. 3725 // 3726 // Also it seems that sometimes on linux/386 we will not receive the 3727 // exit status. This happens if the process exits at the same time as it 3728 // receives a signal. 3729 t.Fatalf("process exited status %d (expected 2)", pexit.Status) 3730 } 3731 } else { 3732 assertNoError(exitErr, t, lastCmd) 3733 t.Fatalf("process did not exit after %s", lastCmd) 3734 } 3735 }) 3736 } 3737 3738 func TestIssue1145(t *testing.T) { 3739 withTestProcess("sleep", t, func(p *proc.Target, fixture protest.Fixture) { 3740 setFileBreakpoint(p, t, fixture.Source, 18) 3741 assertNoError(p.Continue(), t, "Continue()") 3742 resumeChan := make(chan struct{}, 1) 3743 p.ResumeNotify(resumeChan) 3744 go func() { 3745 <-resumeChan 3746 time.Sleep(100 * time.Millisecond) 3747 p.RequestManualStop() 3748 }() 3749 3750 assertNoError(p.Next(), t, "Next()") 3751 if p.Breakpoints().HasSteppingBreakpoints() { 3752 t.Fatal("has internal breakpoints after manual stop request") 3753 } 3754 }) 3755 } 3756 3757 func TestHaltKeepsSteppingBreakpoints(t *testing.T) { 3758 withTestProcess("sleep", t, func(p *proc.Target, fixture protest.Fixture) { 3759 p.KeepSteppingBreakpoints = proc.HaltKeepsSteppingBreakpoints 3760 setFileBreakpoint(p, t, fixture.Source, 18) 3761 assertNoError(p.Continue(), t, "Continue()") 3762 resumeChan := make(chan struct{}, 1) 3763 p.ResumeNotify(resumeChan) 3764 go func() { 3765 <-resumeChan 3766 time.Sleep(100 * time.Millisecond) 3767 p.RequestManualStop() 3768 }() 3769 3770 assertNoError(p.Next(), t, "Next()") 3771 if !p.Breakpoints().HasSteppingBreakpoints() { 3772 t.Fatal("does not have internal breakpoints after manual stop request") 3773 } 3774 }) 3775 } 3776 3777 func TestDisassembleGlobalVars(t *testing.T) { 3778 skipOn(t, "broken - global variable symbolication", "arm64") // On ARM64 symLookup can't look up variables due to how they are loaded, see issue #1778 3779 // On 386 linux when pie, the genered code use __x86.get_pc_thunk to ensure position-independent. 3780 // Locate global variable by 3781 // `CALL __x86.get_pc_thunk.ax(SB) 0xb0f7f 3782 // LEAL 0xc0a19(AX), AX` 3783 // dynamically. 3784 if runtime.GOARCH == "386" && runtime.GOOS == "linux" && buildMode == "pie" { 3785 t.Skip("On 386 linux when pie, symLookup can't look up global variables") 3786 } 3787 protest.AllowRecording(t) 3788 withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { 3789 mainfn := p.BinInfo().LookupFunc["main.main"] 3790 regs, _ := p.CurrentThread().Registers() 3791 text, err := proc.Disassemble(p.Memory(), regs, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End) 3792 assertNoError(err, t, "Disassemble") 3793 found := false 3794 for i := range text { 3795 if strings.Index(text[i].Text(proc.IntelFlavour, p.BinInfo()), "main.v") > 0 { 3796 found = true 3797 break 3798 } 3799 } 3800 if !found { 3801 t.Fatalf("could not find main.v reference in disassembly") 3802 } 3803 }) 3804 } 3805 3806 func checkFrame(frame proc.Stackframe, fnname, file string, line int, inlined bool) error { 3807 if frame.Call.Fn == nil || frame.Call.Fn.Name != fnname { 3808 return fmt.Errorf("wrong function name: %s", fnname) 3809 } 3810 if file != "" { 3811 if frame.Call.File != file || frame.Call.Line != line { 3812 return fmt.Errorf("wrong file:line %s:%d", frame.Call.File, frame.Call.Line) 3813 } 3814 } 3815 if frame.Inlined != inlined { 3816 if inlined { 3817 return fmt.Errorf("not inlined") 3818 } else { 3819 return fmt.Errorf("inlined") 3820 } 3821 } 3822 return nil 3823 } 3824 3825 func TestAllPCsForFileLines(t *testing.T) { 3826 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 3827 // Versions of go before 1.10 do not have DWARF information for inlined calls 3828 t.Skip("inlining not supported") 3829 } 3830 protest.AllowRecording(t) 3831 withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p *proc.Target, fixture protest.Fixture) { 3832 l2pcs := p.BinInfo().AllPCsForFileLines(fixture.Source, []int{7, 20}) 3833 if len(l2pcs) != 2 { 3834 t.Fatalf("expected two map entries for %s:{%d,%d} (got %d: %v)", fixture.Source, 7, 20, len(l2pcs), l2pcs) 3835 } 3836 pcs := l2pcs[20] 3837 if len(pcs) < 1 { 3838 t.Fatalf("expected at least one location for %s:%d (got %d: %#x)", fixture.Source, 20, len(pcs), pcs) 3839 } 3840 pcs = l2pcs[7] 3841 if len(pcs) < 2 { 3842 t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 7, len(pcs), pcs) 3843 } 3844 }) 3845 } 3846 3847 func TestInlinedStacktraceAndVariables(t *testing.T) { 3848 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 3849 // Versions of go before 1.10 do not have DWARF information for inlined calls 3850 t.Skip("inlining not supported") 3851 } 3852 3853 firstCallCheck := &scopeCheck{ 3854 line: 7, 3855 ok: false, 3856 varChecks: []varCheck{ 3857 varCheck{ 3858 name: "a", 3859 typ: "int", 3860 kind: reflect.Int, 3861 hasVal: true, 3862 intVal: 3, 3863 }, 3864 varCheck{ 3865 name: "z", 3866 typ: "int", 3867 kind: reflect.Int, 3868 hasVal: true, 3869 intVal: 9, 3870 }, 3871 }, 3872 } 3873 3874 secondCallCheck := &scopeCheck{ 3875 line: 7, 3876 ok: false, 3877 varChecks: []varCheck{ 3878 varCheck{ 3879 name: "a", 3880 typ: "int", 3881 kind: reflect.Int, 3882 hasVal: true, 3883 intVal: 4, 3884 }, 3885 varCheck{ 3886 name: "z", 3887 typ: "int", 3888 kind: reflect.Int, 3889 hasVal: true, 3890 intVal: 16, 3891 }, 3892 }, 3893 } 3894 3895 protest.AllowRecording(t) 3896 withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining, func(p *proc.Target, fixture protest.Fixture) { 3897 pcs, err := proc.FindFileLocation(p, fixture.Source, 7) 3898 assertNoError(err, t, "LineToPC") 3899 if len(pcs) < 2 { 3900 t.Fatalf("expected at least two locations for %s:%d (got %d: %#x)", fixture.Source, 7, len(pcs), pcs) 3901 } 3902 for _, pc := range pcs { 3903 t.Logf("setting breakpoint at %#x\n", pc) 3904 _, err := p.SetBreakpoint(0, pc, proc.UserBreakpoint, nil) 3905 assertNoError(err, t, fmt.Sprintf("SetBreakpoint(%#x)", pc)) 3906 } 3907 3908 // first inlined call 3909 assertNoError(p.Continue(), t, "Continue") 3910 frames, err := proc.ThreadStacktrace(p.CurrentThread(), 20) 3911 assertNoError(err, t, "ThreadStacktrace") 3912 t.Logf("Stacktrace:\n") 3913 for i := range frames { 3914 t.Logf("\t%s at %s:%d (%#x)\n", frames[i].Call.Fn.Name, frames[i].Call.File, frames[i].Call.Line, frames[i].Current.PC) 3915 } 3916 3917 if err := checkFrame(frames[0], "main.inlineThis", fixture.Source, 7, true); err != nil { 3918 t.Fatalf("Wrong frame 0: %v", err) 3919 } 3920 if err := checkFrame(frames[1], "main.main", fixture.Source, 18, false); err != nil { 3921 t.Fatalf("Wrong frame 1: %v", err) 3922 } 3923 3924 if avar, _ := constant.Int64Val(evalVariable(p, t, "a").Value); avar != 3 { 3925 t.Fatalf("value of 'a' variable is not 3 (%d)", avar) 3926 } 3927 if zvar, _ := constant.Int64Val(evalVariable(p, t, "z").Value); zvar != 9 { 3928 t.Fatalf("value of 'z' variable is not 9 (%d)", zvar) 3929 } 3930 3931 if _, ok := firstCallCheck.checkLocalsAndArgs(p, t); !ok { 3932 t.Fatalf("exiting for past errors") 3933 } 3934 3935 // second inlined call 3936 assertNoError(p.Continue(), t, "Continue") 3937 frames, err = proc.ThreadStacktrace(p.CurrentThread(), 20) 3938 assertNoError(err, t, "ThreadStacktrace (2)") 3939 t.Logf("Stacktrace 2:\n") 3940 for i := range frames { 3941 t.Logf("\t%s at %s:%d (%#x)\n", frames[i].Call.Fn.Name, frames[i].Call.File, frames[i].Call.Line, frames[i].Current.PC) 3942 } 3943 3944 if err := checkFrame(frames[0], "main.inlineThis", fixture.Source, 7, true); err != nil { 3945 t.Fatalf("Wrong frame 0: %v", err) 3946 } 3947 if err := checkFrame(frames[1], "main.main", fixture.Source, 19, false); err != nil { 3948 t.Fatalf("Wrong frame 1: %v", err) 3949 } 3950 3951 if avar, _ := constant.Int64Val(evalVariable(p, t, "a").Value); avar != 4 { 3952 t.Fatalf("value of 'a' variable is not 3 (%d)", avar) 3953 } 3954 if zvar, _ := constant.Int64Val(evalVariable(p, t, "z").Value); zvar != 16 { 3955 t.Fatalf("value of 'z' variable is not 9 (%d)", zvar) 3956 } 3957 if bvar, err := evalVariableOrError(p, "b"); err == nil { 3958 t.Fatalf("expected error evaluating 'b', but it succeeded instead: %v", bvar) 3959 } 3960 3961 if _, ok := secondCallCheck.checkLocalsAndArgs(p, t); !ok { 3962 t.Fatalf("exiting for past errors") 3963 } 3964 }) 3965 } 3966 3967 func TestInlineStep(t *testing.T) { 3968 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 3969 // Versions of go before 1.10 do not have DWARF information for inlined calls 3970 t.Skip("inlining not supported") 3971 } 3972 testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{ 3973 {contContinue, 18}, 3974 {contStep, 6}, 3975 {contStep, 7}, 3976 {contStep, 18}, 3977 {contStep, 19}, 3978 }) 3979 } 3980 3981 func TestInlineNext(t *testing.T) { 3982 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 3983 // Versions of go before 1.10 do not have DWARF information for inlined calls 3984 t.Skip("inlining not supported") 3985 } 3986 testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{ 3987 {contContinue, 18}, 3988 {contStep, 6}, 3989 {contNext, 7}, 3990 {contNext, 18}, 3991 {contNext, 19}, 3992 }) 3993 } 3994 3995 func TestInlineStepOver(t *testing.T) { 3996 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 3997 // Versions of go before 1.10 do not have DWARF information for inlined calls 3998 t.Skip("inlining not supported") 3999 } 4000 testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{ 4001 {contContinue, 18}, 4002 {contNext, 19}, 4003 {contNext, 20}, 4004 }) 4005 } 4006 4007 func TestInlineStepOut(t *testing.T) { 4008 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 4009 // Versions of go before 1.10 do not have DWARF information for inlined calls 4010 t.Skip("inlining not supported") 4011 } 4012 testseq2Args(".", []string{}, protest.EnableInlining, t, "testinline", "", []seqTest{ 4013 {contContinue, 18}, 4014 {contStep, 6}, 4015 {contStepout, 18}, 4016 }) 4017 } 4018 4019 func TestInlineFunctionList(t *testing.T) { 4020 // We should be able to list all functions, even inlined ones. 4021 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 4022 // Versions of go before 1.10 do not have DWARF information for inlined calls 4023 t.Skip("inlining not supported") 4024 } 4025 protest.AllowRecording(t) 4026 withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) { 4027 var found bool 4028 for _, fn := range p.BinInfo().Functions { 4029 if strings.Contains(fn.Name, "inlineThis") { 4030 found = true 4031 break 4032 } 4033 } 4034 if !found { 4035 t.Fatal("inline function not returned") 4036 } 4037 }) 4038 } 4039 4040 func TestInlineBreakpoint(t *testing.T) { 4041 // We should be able to set a breakpoint on the call site of an inlined function. 4042 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 4043 // Versions of go before 1.10 do not have DWARF information for inlined calls 4044 t.Skip("inlining not supported") 4045 } 4046 protest.AllowRecording(t) 4047 withTestProcessArgs("testinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) { 4048 pcs, err := proc.FindFileLocation(p, fixture.Source, 17) 4049 if err != nil { 4050 t.Fatal(err) 4051 } 4052 t.Logf("%#v\n", pcs) 4053 if len(pcs) != 1 { 4054 t.Fatalf("unable to get PC for inlined function call: %v", pcs) 4055 } 4056 fn := p.BinInfo().PCToFunc(pcs[0]) 4057 expectedFn := "main.main" 4058 if fn.Name != expectedFn { 4059 t.Fatalf("incorrect function returned, expected %s, got %s", expectedFn, fn.Name) 4060 } 4061 _, err = p.SetBreakpoint(0, pcs[0], proc.UserBreakpoint, nil) 4062 if err != nil { 4063 t.Fatalf("unable to set breakpoint: %v", err) 4064 } 4065 }) 4066 } 4067 4068 func TestDoubleInlineBreakpoint(t *testing.T) { 4069 // We should be able to set a breakpoint on an inlined function that 4070 // has been inlined within an inlined function. 4071 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 4072 // Versions of go before 1.10 do not have DWARF information for inlined calls 4073 t.Skip("inlining not supported") 4074 } 4075 withTestProcessArgs("doubleinline", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) { 4076 fns, err := p.BinInfo().FindFunction("main.(*Rectangle).Height") 4077 if err != nil { 4078 t.Fatal(err) 4079 } 4080 if len(fns) != 1 { 4081 t.Fatalf("expected one function for Height, got %d", len(fns)) 4082 } 4083 if len(fns[0].InlinedCalls) != 1 { 4084 t.Fatalf("expected one inlined call for Height, got %d", len(fns[0].InlinedCalls)) 4085 } 4086 }) 4087 } 4088 4089 func TestIssue951(t *testing.T) { 4090 if ver, _ := goversion.Parse(runtime.Version()); ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 9, Rev: -1}) { 4091 t.Skip("scopes not implemented in <=go1.8") 4092 } 4093 4094 withTestProcess("issue951", t, func(p *proc.Target, fixture protest.Fixture) { 4095 assertNoError(p.Continue(), t, "Continue()") 4096 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 4097 assertNoError(err, t, "GoroutineScope") 4098 args, err := scope.FunctionArguments(normalLoadConfig) 4099 assertNoError(err, t, "FunctionArguments") 4100 t.Logf("%#v", args[0]) 4101 if args[0].Flags&proc.VariableShadowed == 0 { 4102 t.Error("argument is not shadowed") 4103 } 4104 vars, err := scope.LocalVariables(normalLoadConfig) 4105 assertNoError(err, t, "LocalVariables") 4106 shadowed, notShadowed := 0, 0 4107 for i := range vars { 4108 t.Logf("var %d: %#v\n", i, vars[i]) 4109 if vars[i].Flags&proc.VariableShadowed != 0 { 4110 shadowed++ 4111 } else { 4112 notShadowed++ 4113 } 4114 } 4115 if shadowed != 1 || notShadowed != 1 { 4116 t.Errorf("Wrong number of shadowed/non-shadowed local variables: %d %d", shadowed, notShadowed) 4117 } 4118 }) 4119 } 4120 4121 func TestDWZCompression(t *testing.T) { 4122 // If dwz is not available in the system, skip this test 4123 if _, err := exec.LookPath("dwz"); err != nil { 4124 t.Skip("dwz not installed") 4125 } 4126 4127 withTestProcessArgs("dwzcompression", t, ".", []string{}, protest.EnableDWZCompression, func(p *proc.Target, fixture protest.Fixture) { 4128 setFunctionBreakpoint(p, t, "C.fortytwo") 4129 assertNoError(p.Continue(), t, "first Continue()") 4130 val := evalVariable(p, t, "stdin") 4131 if val.RealType == nil { 4132 t.Errorf("Can't find type for \"stdin\" global variable") 4133 } 4134 }) 4135 } 4136 4137 func TestMapLoadConfigWithReslice(t *testing.T) { 4138 // Check that load configuration is respected for resliced maps. 4139 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 4140 zolotovLoadCfg := proc.LoadConfig{FollowPointers: true, MaxStructFields: -1, MaxVariableRecurse: 3, MaxStringLen: 10, MaxArrayValues: 10} 4141 assertNoError(p.Continue(), t, "First Continue()") 4142 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 4143 assertNoError(err, t, "GoroutineScope") 4144 m1, err := scope.EvalExpression("m1", zolotovLoadCfg) 4145 assertNoError(err, t, "EvalVariable") 4146 t.Logf("m1 returned children %d (%d)", len(m1.Children)/2, m1.Len) 4147 4148 expr := fmt.Sprintf("(*(*%q)(%d))[10:]", m1.DwarfType.String(), m1.Addr) 4149 t.Logf("expr %q\n", expr) 4150 4151 m1cont, err := scope.EvalExpression(expr, zolotovLoadCfg) 4152 assertNoError(err, t, "EvalVariable") 4153 4154 t.Logf("m1cont returned children %d", len(m1cont.Children)/2) 4155 4156 if len(m1cont.Children) != 20 { 4157 t.Fatalf("wrong number of children returned %d\n", len(m1cont.Children)/2) 4158 } 4159 }) 4160 } 4161 4162 func TestStepOutReturn(t *testing.T) { 4163 ver, _ := goversion.Parse(runtime.Version()) 4164 if ver.Major >= 0 && !ver.AfterOrEqual(goversion.GoVersion{Major: 1, Minor: 10, Rev: -1}) { 4165 t.Skip("return variables aren't marked on 1.9 or earlier") 4166 } 4167 protest.AllowRecording(t) 4168 withTestProcess("stepoutret", t, func(p *proc.Target, fixture protest.Fixture) { 4169 setFunctionBreakpoint(p, t, "main.stepout") 4170 assertNoError(p.Continue(), t, "Continue") 4171 assertNoError(p.StepOut(), t, "StepOut") 4172 ret := p.CurrentThread().Common().ReturnValues(normalLoadConfig) 4173 if len(ret) != 2 { 4174 t.Fatalf("wrong number of return values %v", ret) 4175 } 4176 4177 stridx := 0 4178 numidx := 1 4179 4180 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 12) { 4181 // in 1.11 and earlier the order of return values in DWARF is 4182 // unspecified, in 1.11 and later it follows the order of definition 4183 // specified by the user 4184 for i := range ret { 4185 if ret[i].Name == "str" { 4186 stridx = i 4187 numidx = 1 - i 4188 break 4189 } 4190 } 4191 } 4192 4193 if ret[stridx].Name != "str" { 4194 t.Fatalf("(str) bad return value name %s", ret[stridx].Name) 4195 } 4196 if ret[stridx].Kind != reflect.String { 4197 t.Fatalf("(str) bad return value kind %v", ret[stridx].Kind) 4198 } 4199 if s := constant.StringVal(ret[stridx].Value); s != "return 47" { 4200 t.Fatalf("(str) bad return value %q", s) 4201 } 4202 4203 if ret[numidx].Name != "num" { 4204 t.Fatalf("(num) bad return value name %s", ret[numidx].Name) 4205 } 4206 if ret[numidx].Kind != reflect.Int { 4207 t.Fatalf("(num) bad return value kind %v", ret[numidx].Kind) 4208 } 4209 if n, _ := constant.Int64Val(ret[numidx].Value); n != 48 { 4210 t.Fatalf("(num) bad return value %d", n) 4211 } 4212 }) 4213 } 4214 4215 func TestOptimizationCheck(t *testing.T) { 4216 protest.AllowRecording(t) 4217 withTestProcess("continuetestprog", t, func(p *proc.Target, fixture protest.Fixture) { 4218 fn := p.BinInfo().LookupFunc["main.main"] 4219 if fn.Optimized() { 4220 t.Fatalf("main.main is optimized") 4221 } 4222 }) 4223 4224 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 10) { 4225 withTestProcessArgs("continuetestprog", t, ".", []string{}, protest.EnableOptimization|protest.EnableInlining, func(p *proc.Target, fixture protest.Fixture) { 4226 fn := p.BinInfo().LookupFunc["main.main"] 4227 if !fn.Optimized() { 4228 t.Fatalf("main.main is not optimized") 4229 } 4230 }) 4231 } 4232 } 4233 4234 func TestIssue1264(t *testing.T) { 4235 // It should be possible to set a breakpoint condition that consists only 4236 // of evaluating a single boolean variable. 4237 protest.AllowRecording(t) 4238 withTestProcess("issue1264", t, func(p *proc.Target, fixture protest.Fixture) { 4239 bp := setFileBreakpoint(p, t, fixture.Source, 8) 4240 bp.UserBreaklet().Cond = &ast.Ident{Name: "equalsTwo"} 4241 assertNoError(p.Continue(), t, "Continue()") 4242 assertLineNumber(p, t, 8, "after continue") 4243 }) 4244 } 4245 4246 func TestReadDefer(t *testing.T) { 4247 withTestProcess("deferstack", t, func(p *proc.Target, fixture protest.Fixture) { 4248 assertNoError(p.Continue(), t, "Continue") 4249 frames, err := p.SelectedGoroutine().Stacktrace(10, proc.StacktraceReadDefers) 4250 assertNoError(err, t, "Stacktrace") 4251 4252 logStacktrace(t, p, frames) 4253 4254 examples := []struct { 4255 frameIdx int 4256 topmostDefer string 4257 defers []string 4258 }{ 4259 // main.call3 (defers nothing, topmost defer main.f2) 4260 {0, "main.f2", []string{}}, 4261 4262 // main.call2 (defers main.f2, main.f3, topmost defer main.f2) 4263 {1, "main.f2", []string{"main.f2", "main.f3"}}, 4264 4265 // main.call1 (defers main.f1, main.f2, topmost defer main.f1) 4266 {2, "main.f1", []string{"main.f1", "main.f2"}}, 4267 4268 // main.main (defers nothing) 4269 {3, "", []string{}}} 4270 4271 defercheck := func(d *proc.Defer, deferName, tgt string, frameIdx int) { 4272 if d == nil { 4273 t.Fatalf("expected %q as %s of frame %d, got nothing", tgt, deferName, frameIdx) 4274 } 4275 if d.Unreadable != nil { 4276 t.Fatalf("expected %q as %s of frame %d, got unreadable defer: %v", tgt, deferName, frameIdx, d.Unreadable) 4277 } 4278 _, _, dfn := d.DeferredFunc(p) 4279 if dfn == nil { 4280 t.Fatalf("expected %q as %s of frame %d, got %#x", tgt, deferName, frameIdx, d.DwrapPC) 4281 } 4282 if dfn.Name != tgt { 4283 t.Fatalf("expected %q as %s of frame %d, got %q", tgt, deferName, frameIdx, dfn.Name) 4284 } 4285 } 4286 4287 for _, example := range examples { 4288 frame := &frames[example.frameIdx] 4289 4290 if example.topmostDefer != "" { 4291 defercheck(frame.TopmostDefer, "topmost defer", example.topmostDefer, example.frameIdx) 4292 } 4293 4294 if len(example.defers) != len(frames[example.frameIdx].Defers) { 4295 t.Fatalf("expected %d defers for %d, got %v", len(example.defers), example.frameIdx, frame.Defers) 4296 } 4297 4298 for deferIdx := range example.defers { 4299 defercheck(frame.Defers[deferIdx], fmt.Sprintf("defer %d", deferIdx), example.defers[deferIdx], example.frameIdx) 4300 } 4301 } 4302 }) 4303 } 4304 4305 func TestNextUnknownInstr(t *testing.T) { 4306 skipUnlessOn(t, "amd64 only", "amd64") 4307 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 10) { 4308 t.Skip("versions of Go before 1.10 can't assemble the instruction VPUNPCKLWD") 4309 } 4310 protest.AllowRecording(t) 4311 withTestProcess("nodisasm/", t, func(p *proc.Target, fixture protest.Fixture) { 4312 setFunctionBreakpoint(p, t, "main.asmFunc") 4313 assertNoError(p.Continue(), t, "Continue()") 4314 assertNoError(p.Next(), t, "Next()") 4315 }) 4316 } 4317 4318 func TestReadDeferArgs(t *testing.T) { 4319 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) { 4320 // When regabi is enabled in Go 1.17 and later, reading arguments of 4321 // deferred functions becomes significantly more complicated because of 4322 // the autogenerated code used to unpack the argument frame stored in 4323 // runtime._defer into registers. 4324 // We either need to know how to do the translation, implementing the ABI1 4325 // rules in Delve, or have some assistance from the compiler (for example 4326 // have the dwrap function contain entries for each of the captured 4327 // variables with a location describing their offset from DX). 4328 // Ultimately this feature is unimportant enough that we can leave it 4329 // disabled for now. 4330 t.Skip("unsupported") 4331 } 4332 var tests = []struct { 4333 frame, deferCall int 4334 a, b int64 4335 }{ 4336 {1, 1, 42, 61}, 4337 {2, 2, 1, -1}, 4338 } 4339 4340 withTestProcess("deferstack", t, func(p *proc.Target, fixture protest.Fixture) { 4341 assertNoError(p.Continue(), t, "Continue()") 4342 4343 for _, test := range tests { 4344 scope, err := proc.ConvertEvalScope(p, -1, test.frame, test.deferCall) 4345 assertNoError(err, t, fmt.Sprintf("ConvertEvalScope(-1, %d, %d)", test.frame, test.deferCall)) 4346 4347 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 17) { 4348 // In Go 1.17 deferred function calls can end up inside a wrapper, and 4349 // the scope for this evaluation needs to be the wrapper. 4350 if scope.Fn.Name != "main.f2" { 4351 t.Fatalf("expected function \"main.f2\" got %q", scope.Fn.Name) 4352 } 4353 } 4354 4355 avar, err := scope.EvalExpression("a", normalLoadConfig) 4356 if err != nil { 4357 t.Fatal(err) 4358 } 4359 bvar, err := scope.EvalExpression("b", normalLoadConfig) 4360 if err != nil { 4361 t.Fatal(err) 4362 } 4363 4364 a, _ := constant.Int64Val(avar.Value) 4365 b, _ := constant.Int64Val(bvar.Value) 4366 4367 if a != test.a { 4368 t.Errorf("value of argument 'a' at frame %d, deferred call %d: %d (expected %d)", test.frame, test.deferCall, a, test.a) 4369 } 4370 4371 if b != test.b { 4372 t.Errorf("value of argument 'b' at frame %d, deferred call %d: %d (expected %d)", test.frame, test.deferCall, b, test.b) 4373 } 4374 } 4375 }) 4376 } 4377 4378 func TestIssue1374(t *testing.T) { 4379 // Continue did not work when stopped at a breakpoint immediately after calling CallFunction. 4380 protest.MustSupportFunctionCalls(t, testBackend) 4381 withTestProcess("issue1374", t, func(p *proc.Target, fixture protest.Fixture) { 4382 setFileBreakpoint(p, t, fixture.Source, 7) 4383 assertNoError(p.Continue(), t, "First Continue") 4384 assertLineNumber(p, t, 7, "Did not continue to correct location (first continue),") 4385 assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "getNum()", normalLoadConfig, true), t, "Call") 4386 err := p.Continue() 4387 if _, isexited := err.(proc.ErrProcessExited); !isexited { 4388 regs, _ := p.CurrentThread().Registers() 4389 f, l, _ := p.BinInfo().PCToLine(regs.PC()) 4390 t.Fatalf("expected process exited error got %v at %s:%d", err, f, l) 4391 } 4392 }) 4393 } 4394 4395 func TestIssue1432(t *testing.T) { 4396 // Check that taking the address of a struct, casting it into a pointer to 4397 // the struct's type and then accessing a member field will still: 4398 // - perform auto-dereferencing on struct member access 4399 // - yield a Variable that's ultimately assignable (i.e. has an address) 4400 withTestProcess("issue1432", t, func(p *proc.Target, fixture protest.Fixture) { 4401 assertNoError(p.Continue(), t, "Continue") 4402 svar := evalVariable(p, t, "s") 4403 t.Logf("%#x", svar.Addr) 4404 4405 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 4406 assertNoError(err, t, "GoroutineScope()") 4407 4408 err = scope.SetVariable(fmt.Sprintf("(*\"main.s\")(%#x).i", svar.Addr), "10") 4409 assertNoError(err, t, "SetVariable") 4410 }) 4411 } 4412 4413 func TestGoroutinesInfoLimit(t *testing.T) { 4414 protest.AllowRecording(t) 4415 withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { 4416 setFileBreakpoint(p, t, fixture.Source, 37) 4417 assertNoError(p.Continue(), t, "Continue()") 4418 4419 gcount := 0 4420 nextg := 0 4421 const goroutinesInfoLimit = 10 4422 for nextg >= 0 { 4423 oldnextg := nextg 4424 var gs []*proc.G 4425 var err error 4426 gs, nextg, err = proc.GoroutinesInfo(p, nextg, goroutinesInfoLimit) 4427 assertNoError(err, t, fmt.Sprintf("GoroutinesInfo(%d, %d)", oldnextg, goroutinesInfoLimit)) 4428 gcount += len(gs) 4429 t.Logf("got %d goroutines\n", len(gs)) 4430 } 4431 4432 t.Logf("number of goroutines: %d\n", gcount) 4433 4434 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 4435 assertNoError(err, t, "GoroutinesInfo(0, 0)") 4436 t.Logf("number of goroutines (full scan): %d\n", gcount) 4437 if len(gs) != gcount { 4438 t.Fatalf("mismatch in the number of goroutines %d %d\n", gcount, len(gs)) 4439 } 4440 }) 4441 } 4442 4443 func TestIssue1469(t *testing.T) { 4444 protest.AllowRecording(t) 4445 withTestProcess("issue1469", t, func(p *proc.Target, fixture protest.Fixture) { 4446 setFileBreakpoint(p, t, fixture.Source, 13) 4447 assertNoError(p.Continue(), t, "Continue()") 4448 4449 gid2thread := make(map[int][]proc.Thread) 4450 for _, thread := range p.ThreadList() { 4451 g, _ := proc.GetG(thread) 4452 if g == nil { 4453 continue 4454 } 4455 gid2thread[g.ID] = append(gid2thread[g.ID], thread) 4456 } 4457 4458 for gid := range gid2thread { 4459 if len(gid2thread[gid]) > 1 { 4460 t.Logf("too many threads running goroutine %d", gid) 4461 for _, thread := range gid2thread[gid] { 4462 t.Logf("\tThread %d", thread.ThreadID()) 4463 frames, err := proc.ThreadStacktrace(thread, 20) 4464 if err != nil { 4465 t.Logf("\t\tcould not get stacktrace %v", err) 4466 } 4467 for _, frame := range frames { 4468 t.Logf("\t\t%#x at %s:%d (systemstack: %v)", frame.Call.PC, frame.Call.File, frame.Call.Line, frame.SystemStack) 4469 } 4470 } 4471 } 4472 } 4473 }) 4474 } 4475 4476 func TestDeadlockBreakpoint(t *testing.T) { 4477 skipOn(t, "upstream issue - https://github.com/golang/go/issues/29322", "pie") 4478 deadlockBp := proc.FatalThrow 4479 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 4480 deadlockBp = proc.UnrecoveredPanic 4481 } 4482 protest.AllowRecording(t) 4483 withTestProcess("testdeadlock", t, func(p *proc.Target, fixture protest.Fixture) { 4484 assertNoError(p.Continue(), t, "Continue()") 4485 4486 bp := p.CurrentThread().Breakpoint() 4487 if bp.Breakpoint == nil || bp.Logical.Name != deadlockBp { 4488 t.Fatalf("did not stop at deadlock breakpoint %v", bp) 4489 } 4490 }) 4491 } 4492 4493 func findSource(source string, sources []string) bool { 4494 for _, s := range sources { 4495 if s == source { 4496 return true 4497 } 4498 } 4499 return false 4500 } 4501 4502 func TestListImages(t *testing.T) { 4503 pluginFixtures := protest.WithPlugins(t, protest.AllNonOptimized, "plugin1/", "plugin2/") 4504 4505 withTestProcessArgs("plugintest", t, ".", []string{pluginFixtures[0].Path, pluginFixtures[1].Path}, protest.AllNonOptimized, func(p *proc.Target, fixture protest.Fixture) { 4506 if !findSource(fixture.Source, p.BinInfo().Sources) { 4507 t.Fatalf("could not find %s in sources: %q\n", fixture.Source, p.BinInfo().Sources) 4508 } 4509 4510 assertNoError(p.Continue(), t, "first continue") 4511 f, l := currentLineNumber(p, t) 4512 plugin1Found := false 4513 t.Logf("Libraries before %s:%d:", f, l) 4514 for _, image := range p.BinInfo().Images { 4515 t.Logf("\t%#x %q err:%v", image.StaticBase, image.Path, image.LoadError()) 4516 if image.Path == pluginFixtures[0].Path { 4517 plugin1Found = true 4518 } 4519 } 4520 if !plugin1Found { 4521 t.Fatalf("Could not find plugin1") 4522 } 4523 if !findSource(fixture.Source, p.BinInfo().Sources) { 4524 // Source files for the base program must be available even after a plugin is loaded. Issue #2074. 4525 t.Fatalf("could not find %s in sources (after loading plugin): %q\n", fixture.Source, p.BinInfo().Sources) 4526 } 4527 assertNoError(p.Continue(), t, "second continue") 4528 f, l = currentLineNumber(p, t) 4529 plugin1Found, plugin2Found := false, false 4530 t.Logf("Libraries after %s:%d:", f, l) 4531 for _, image := range p.BinInfo().Images { 4532 t.Logf("\t%#x %q err:%v", image.StaticBase, image.Path, image.LoadError()) 4533 switch image.Path { 4534 case pluginFixtures[0].Path: 4535 plugin1Found = true 4536 case pluginFixtures[1].Path: 4537 plugin2Found = true 4538 } 4539 } 4540 if !plugin1Found { 4541 t.Fatalf("Could not find plugin1") 4542 } 4543 if !plugin2Found { 4544 t.Fatalf("Could not find plugin2") 4545 } 4546 }) 4547 } 4548 4549 func TestAncestors(t *testing.T) { 4550 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 11) { 4551 t.Skip("not supported on Go <= 1.10") 4552 } 4553 savedGodebug := os.Getenv("GODEBUG") 4554 os.Setenv("GODEBUG", "tracebackancestors=100") 4555 defer os.Setenv("GODEBUG", savedGodebug) 4556 protest.AllowRecording(t) 4557 withTestProcess("testnextprog", t, func(p *proc.Target, fixture protest.Fixture) { 4558 setFunctionBreakpoint(p, t, "main.testgoroutine") 4559 assertNoError(p.Continue(), t, "Continue()") 4560 as, err := proc.Ancestors(p, p.SelectedGoroutine(), 1000) 4561 assertNoError(err, t, "Ancestors") 4562 t.Logf("ancestors: %#v\n", as) 4563 if len(as) != 1 { 4564 t.Fatalf("expected only one ancestor got %d", len(as)) 4565 } 4566 mainFound := false 4567 for i, a := range as { 4568 astack, err := a.Stack(100) 4569 assertNoError(err, t, fmt.Sprintf("Ancestor %d stack", i)) 4570 t.Logf("ancestor %d\n", i) 4571 logStacktrace(t, p, astack) 4572 for _, frame := range astack { 4573 if frame.Current.Fn != nil && frame.Current.Fn.Name == "main.main" { 4574 mainFound = true 4575 } 4576 } 4577 } 4578 if !mainFound { 4579 t.Fatal("could not find main.main function in ancestors") 4580 } 4581 }) 4582 } 4583 4584 func testCallConcurrentCheckReturns(p *proc.Target, t *testing.T, gid1, gid2 int) int { 4585 found := 0 4586 for _, thread := range p.ThreadList() { 4587 g, _ := proc.GetG(thread) 4588 if g == nil || (g.ID != gid1 && g.ID != gid2) { 4589 continue 4590 } 4591 retvals := thread.Common().ReturnValues(normalLoadConfig) 4592 if len(retvals) == 0 { 4593 continue 4594 } 4595 n, _ := constant.Int64Val(retvals[0].Value) 4596 t.Logf("injection on goroutine %d (thread %d) returned %v\n", g.ID, thread.ThreadID(), n) 4597 switch g.ID { 4598 case gid1: 4599 if n != 11 { 4600 t.Errorf("wrong return value for goroutine %d", g.ID) 4601 } 4602 found++ 4603 case gid2: 4604 if n != 12 { 4605 t.Errorf("wrong return value for goroutine %d", g.ID) 4606 } 4607 found++ 4608 } 4609 } 4610 return found 4611 } 4612 4613 func TestCallConcurrent(t *testing.T) { 4614 skipOn(t, "broken", "freebsd") 4615 protest.MustSupportFunctionCalls(t, testBackend) 4616 withTestProcess("teststepconcurrent", t, func(p *proc.Target, fixture protest.Fixture) { 4617 bp := setFileBreakpoint(p, t, fixture.Source, 24) 4618 assertNoError(p.Continue(), t, "Continue()") 4619 //_, err := p.ClearBreakpoint(bp.Addr) 4620 //assertNoError(err, t, "ClearBreakpoint() returned an error") 4621 4622 gid1 := p.SelectedGoroutine().ID 4623 t.Logf("starting injection in %d / %d", p.SelectedGoroutine().ID, p.CurrentThread().ThreadID()) 4624 assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "Foo(10, 1)", normalLoadConfig, false), t, "EvalExpressionWithCalls()") 4625 4626 returned := testCallConcurrentCheckReturns(p, t, gid1, -1) 4627 4628 curthread := p.CurrentThread() 4629 if curbp := curthread.Breakpoint(); curbp.Breakpoint == nil || curbp.LogicalID() != bp.LogicalID() || returned > 0 { 4630 t.Logf("skipping test, the call injection terminated before we hit a breakpoint in a different thread") 4631 return 4632 } 4633 4634 err := p.ClearBreakpoint(bp.Addr) 4635 assertNoError(err, t, "ClearBreakpoint() returned an error") 4636 4637 gid2 := p.SelectedGoroutine().ID 4638 t.Logf("starting second injection in %d / %d", p.SelectedGoroutine().ID, p.CurrentThread().ThreadID()) 4639 assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "Foo(10, 2)", normalLoadConfig, false), t, "EvalExpressioniWithCalls") 4640 4641 for { 4642 returned += testCallConcurrentCheckReturns(p, t, gid1, gid2) 4643 if returned >= 2 { 4644 break 4645 } 4646 t.Logf("Continuing... %d", returned) 4647 assertNoError(p.Continue(), t, "Continue()") 4648 } 4649 4650 p.Continue() 4651 }) 4652 } 4653 4654 func TestPluginStepping(t *testing.T) { 4655 pluginFixtures := protest.WithPlugins(t, protest.AllNonOptimized, "plugin1/", "plugin2/") 4656 4657 testseq2Args(".", []string{pluginFixtures[0].Path, pluginFixtures[1].Path}, protest.AllNonOptimized, t, "plugintest2", "", []seqTest{ 4658 {contContinue, 41}, 4659 {contStep, "plugin1.go:9"}, 4660 {contStep, "plugin1.go:10"}, 4661 {contStep, "plugin1.go:11"}, 4662 {contNext, "plugin1.go:12"}, 4663 {contNext, "plugintest2.go:41"}, 4664 {contNext, "plugintest2.go:42"}, 4665 {contStep, "plugin2.go:22"}, 4666 {contNext, "plugin2.go:23"}, 4667 {contNext, "plugin2.go:26"}, 4668 {contNext, "plugintest2.go:42"}}) 4669 } 4670 4671 func TestIssue1601(t *testing.T) { 4672 protest.MustHaveCgo(t) 4673 //Tests that recursive types involving C qualifiers and typedefs are parsed correctly 4674 protest.AllowRecording(t) 4675 withTestProcess("issue1601", t, func(p *proc.Target, fixture protest.Fixture) { 4676 assertNoError(p.Continue(), t, "Continue") 4677 evalVariable(p, t, "C.globalq") 4678 }) 4679 } 4680 4681 func TestIssue1615(t *testing.T) { 4682 // A breakpoint condition that tests for string equality with a constant string shouldn't fail with 'string too long for comparison' error 4683 4684 protest.AllowRecording(t) 4685 withTestProcess("issue1615", t, func(p *proc.Target, fixture protest.Fixture) { 4686 bp := setFileBreakpoint(p, t, fixture.Source, 19) 4687 bp.UserBreaklet().Cond = &ast.BinaryExpr{ 4688 Op: token.EQL, 4689 X: &ast.Ident{Name: "s"}, 4690 Y: &ast.BasicLit{Kind: token.STRING, Value: `"projects/my-gcp-project-id-string/locations/us-central1/queues/my-task-queue-name"`}, 4691 } 4692 4693 assertNoError(p.Continue(), t, "Continue") 4694 assertLineNumber(p, t, 19, "") 4695 }) 4696 } 4697 4698 func TestCgoStacktrace2(t *testing.T) { 4699 skipOn(t, "upstream issue", "windows") 4700 skipOn(t, "broken", "386") 4701 skipOn(t, "broken", "arm64") 4702 protest.MustHaveCgo(t) 4703 // If a panic happens during cgo execution the stacktrace should show the C 4704 // function that caused the problem. 4705 protest.AllowRecording(t) 4706 withTestProcess("cgosigsegvstack", t, func(p *proc.Target, fixture protest.Fixture) { 4707 p.Continue() 4708 frames, err := proc.ThreadStacktrace(p.CurrentThread(), 100) 4709 assertNoError(err, t, "Stacktrace()") 4710 logStacktrace(t, p, frames) 4711 m := stacktraceCheck(t, []string{"C.sigsegv", "C.testfn", "main.main"}, frames) 4712 if m == nil { 4713 t.Fatal("see previous loglines") 4714 } 4715 }) 4716 } 4717 4718 func TestIssue1656(t *testing.T) { 4719 skipUnlessOn(t, "amd64 only", "amd64") 4720 protest.AllowRecording(t) 4721 withTestProcess("issue1656/", t, func(p *proc.Target, fixture protest.Fixture) { 4722 setFileBreakpoint(p, t, filepath.ToSlash(filepath.Join(fixture.BuildDir, "main.s")), 5) 4723 assertNoError(p.Continue(), t, "Continue()") 4724 t.Logf("step1\n") 4725 assertNoError(p.Step(), t, "Step()") 4726 assertLineNumber(p, t, 8, "wrong line number after first step") 4727 t.Logf("step2\n") 4728 assertNoError(p.Step(), t, "Step()") 4729 assertLineNumber(p, t, 9, "wrong line number after second step") 4730 }) 4731 } 4732 4733 func TestBreakpointConfusionOnResume(t *testing.T) { 4734 // Checks that SetCurrentBreakpoint, (*Thread).StepInstruction and 4735 // native.(*Thread).singleStep all agree on which breakpoint the thread is 4736 // stopped at. 4737 // This test checks for a regression introduced when fixing Issue #1656 4738 skipUnlessOn(t, "amd64 only", "amd64") 4739 protest.AllowRecording(t) 4740 withTestProcess("nopbreakpoint/", t, func(p *proc.Target, fixture protest.Fixture) { 4741 maindots := filepath.ToSlash(filepath.Join(fixture.BuildDir, "main.s")) 4742 maindotgo := filepath.ToSlash(filepath.Join(fixture.BuildDir, "main.go")) 4743 setFileBreakpoint(p, t, maindots, 5) // line immediately after the NOP 4744 assertNoError(p.Continue(), t, "First Continue") 4745 assertLineNumber(p, t, 5, "not on main.s:5") 4746 setFileBreakpoint(p, t, maindots, 4) // sets a breakpoint on the NOP line, which will be one byte before the breakpoint we currently are stopped at. 4747 setFileBreakpoint(p, t, maindotgo, 18) // set one extra breakpoint so that we can recover execution and check the global variable g 4748 assertNoError(p.Continue(), t, "Second Continue") 4749 gvar := evalVariable(p, t, "g") 4750 if n, _ := constant.Int64Val(gvar.Value); n != 1 { 4751 t.Fatalf("wrong value of global variable 'g': %v (expected 1)", gvar.Value) 4752 } 4753 }) 4754 } 4755 4756 func TestIssue1736(t *testing.T) { 4757 protest.AllowRecording(t) 4758 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 4759 assertNoError(p.Continue(), t, "Continue()") 4760 ch1BufVar := evalVariable(p, t, "*(ch1.buf)") 4761 q := fmt.Sprintf("*(*%q)(%d)", ch1BufVar.DwarfType.Common().Name, ch1BufVar.Addr) 4762 t.Logf("%s", q) 4763 ch1BufVar2 := evalVariable(p, t, q) 4764 if ch1BufVar2.Unreadable != nil { 4765 t.Fatal(ch1BufVar2.Unreadable) 4766 } 4767 }) 4768 } 4769 4770 func TestIssue1817(t *testing.T) { 4771 // Setting a breakpoint on a line that doesn't have any PC addresses marked 4772 // is_stmt should work. 4773 protest.AllowRecording(t) 4774 withTestProcess("issue1817", t, func(p *proc.Target, fixture protest.Fixture) { 4775 setFileBreakpoint(p, t, fixture.Source, 16) 4776 }) 4777 } 4778 4779 func TestListPackagesBuildInfo(t *testing.T) { 4780 protest.AllowRecording(t) 4781 withTestProcess("pkgrenames", t, func(p *proc.Target, fixture protest.Fixture) { 4782 pkgs := p.BinInfo().ListPackagesBuildInfo(true) 4783 t.Logf("returned %d", len(pkgs)) 4784 if len(pkgs) < 10 { 4785 t.Errorf("very few packages returned") 4786 } 4787 for _, pkg := range pkgs { 4788 t.Logf("%q %q", pkg.ImportPath, pkg.DirectoryPath) 4789 const _fixtures = "_fixtures" 4790 fidx := strings.Index(pkg.ImportPath, _fixtures) 4791 if fidx < 0 { 4792 continue 4793 } 4794 if !strings.HasSuffix(strings.Replace(pkg.DirectoryPath, "\\", "/", -1), pkg.ImportPath[fidx:]) { 4795 t.Errorf("unexpected suffix: %q %q", pkg.ImportPath, pkg.DirectoryPath) 4796 } 4797 } 4798 }) 4799 } 4800 4801 func TestIssue1795(t *testing.T) { 4802 // When doing midstack inlining the Go compiler sometimes (always?) emits 4803 // the toplevel inlined call with ranges that do not cover the inlining of 4804 // other nested inlined calls. 4805 // For example if a function A calls B which calls C and both the calls to 4806 // B and C are inlined the DW_AT_inlined_subroutine entry for A might have 4807 // ranges that do not cover the ranges of the inlined call to C. 4808 // This is probably a violation of the DWARF standard (it's unclear) but we 4809 // might as well support it as best as possible anyway. 4810 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 13) { 4811 t.Skip("Test not relevant to Go < 1.13") 4812 } 4813 withTestProcessArgs("issue1795", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) { 4814 assertNoError(p.Continue(), t, "Continue()") 4815 assertLineNumber(p, t, 12, "wrong line number after Continue,") 4816 assertNoError(p.Next(), t, "Next()") 4817 assertLineNumber(p, t, 13, "wrong line number after Next,") 4818 }) 4819 withTestProcessArgs("issue1795", t, ".", []string{}, protest.EnableInlining|protest.EnableOptimization, func(p *proc.Target, fixture protest.Fixture) { 4820 setFunctionBreakpoint(p, t, "regexp.(*Regexp).doExecute") 4821 assertNoError(p.Continue(), t, "Continue()") 4822 assertLineNumber(p, t, 12, "wrong line number after Continue (1),") 4823 assertNoError(p.Continue(), t, "Continue()") 4824 frames, err := proc.ThreadStacktrace(p.CurrentThread(), 40) 4825 assertNoError(err, t, "ThreadStacktrace()") 4826 logStacktrace(t, p, frames) 4827 if err := checkFrame(frames[0], "regexp.(*Regexp).doExecute", "", 0, false); err != nil { 4828 t.Errorf("Wrong frame 0: %v", err) 4829 } 4830 if err := checkFrame(frames[1], "regexp.(*Regexp).doMatch", "", 0, true); err != nil { 4831 t.Errorf("Wrong frame 1: %v", err) 4832 } 4833 if err := checkFrame(frames[2], "regexp.(*Regexp).MatchString", "", 0, true); err != nil { 4834 t.Errorf("Wrong frame 2: %v", err) 4835 } 4836 if err := checkFrame(frames[3], "main.main", fixture.Source, 12, false); err != nil { 4837 t.Errorf("Wrong frame 3: %v", err) 4838 } 4839 }) 4840 } 4841 4842 func BenchmarkConditionalBreakpoints(b *testing.B) { 4843 b.N = 1 4844 withTestProcess("issue1549", b, func(p *proc.Target, fixture protest.Fixture) { 4845 bp := setFileBreakpoint(p, b, fixture.Source, 12) 4846 bp.UserBreaklet().Cond = &ast.BinaryExpr{ 4847 Op: token.EQL, 4848 X: &ast.Ident{Name: "value"}, 4849 Y: &ast.BasicLit{Kind: token.INT, Value: "-1"}, 4850 } 4851 err := p.Continue() 4852 if _, exited := err.(proc.ErrProcessExited); !exited { 4853 b.Fatalf("Unexpected error on Continue(): %v", err) 4854 } 4855 }) 4856 } 4857 4858 func TestBackwardNextGeneral(t *testing.T) { 4859 if testBackend != "rr" && testBackend != "undo" { 4860 t.Skip("Reverse stepping test needs rr or undo") 4861 } 4862 testseq2(t, "testnextprog", "main.helloworld", []seqTest{ 4863 {contContinue, 13}, 4864 {contNext, 14}, 4865 {contReverseNext, 13}, 4866 {contReverseNext, 34}, 4867 {contReverseNext, 28}, 4868 {contReverseNext, 27}, 4869 {contReverseNext, 26}, 4870 {contReverseNext, 24}, 4871 {contReverseNext, 23}, 4872 {contReverseNext, 31}, 4873 {contReverseNext, 26}, 4874 {contReverseNext, 24}, 4875 {contReverseNext, 23}, 4876 {contReverseNext, 31}, 4877 {contReverseNext, 26}, 4878 {contReverseNext, 24}, 4879 {contReverseNext, 23}, 4880 {contReverseNext, 20}, 4881 {contReverseNext, 19}, 4882 {contReverseNext, 17}, 4883 {contReverseNext, 39}, 4884 {contReverseNext, 38}, 4885 {contReverseNext, 37}, 4886 }) 4887 } 4888 4889 func TestBackwardStepOutGeneral(t *testing.T) { 4890 if testBackend != "rr" && testBackend != "undo" { 4891 t.Skip("Reverse stepping test needs rr or undo") 4892 } 4893 testseq2(t, "testnextprog", "main.helloworld", []seqTest{ 4894 {contContinue, 13}, 4895 {contNext, 14}, 4896 {contReverseStepout, 34}, 4897 {contReverseStepout, 39}, 4898 }) 4899 } 4900 4901 func TestBackwardStepGeneral(t *testing.T) { 4902 if testBackend != "rr" && testBackend != "undo" { 4903 t.Skip("Reverse stepping test needs rr or undo") 4904 } 4905 testseq2(t, "testnextprog", "main.helloworld", []seqTest{ 4906 {contContinue, 13}, 4907 {contNext, 14}, 4908 {contReverseStep, 13}, 4909 {contReverseStep, 34}, 4910 {contReverseStep, 28}, 4911 {contReverseNext, 27}, // skip fmt.Printf 4912 {contReverseStep, 26}, 4913 {contReverseStep, 24}, 4914 {contReverseStep, 23}, 4915 {contReverseStep, 11}, 4916 {contReverseNext, 10}, // skip time.Sleep 4917 {contReverseStep, 9}, 4918 4919 {contReverseStep, 31}, 4920 {contReverseStep, 26}, 4921 {contReverseStep, 24}, 4922 {contReverseStep, 23}, 4923 {contReverseStep, 11}, 4924 {contReverseNext, 10}, // skip time.Sleep 4925 {contReverseStep, 9}, 4926 4927 {contReverseStep, 31}, 4928 {contReverseStep, 26}, 4929 {contReverseStep, 24}, 4930 {contReverseStep, 23}, 4931 {contReverseStep, 20}, 4932 {contReverseStep, 19}, 4933 {contReverseStep, 17}, 4934 {contReverseStep, 39}, 4935 {contReverseStep, 38}, 4936 {contReverseStep, 37}, 4937 }) 4938 } 4939 4940 func TestBackwardNextDeferPanic(t *testing.T) { 4941 if testBackend != "rr" && testBackend != "undo" { 4942 t.Skip("Reverse stepping test needs rr or undo") 4943 } 4944 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 18) { 4945 testseq2(t, "defercall", "", []seqTest{ 4946 {contContinue, 12}, 4947 {contReverseNext, 11}, 4948 {contReverseNext, 10}, 4949 {contReverseNext, 9}, 4950 {contReverseNext, 27}, 4951 4952 {contContinueToBreakpoint, 12}, // skip first call to sampleFunction 4953 {contContinueToBreakpoint, 6}, // go to call to sampleFunction through deferreturn 4954 {contReverseNext, -1}, // runtime.deferreturn, maybe we should try to skip this 4955 {contReverseStepout, 13}, 4956 {contReverseNext, 12}, 4957 {contReverseNext, 11}, 4958 {contReverseNext, 10}, 4959 {contReverseNext, 9}, 4960 {contReverseNext, 27}, 4961 4962 {contContinueToBreakpoint, 18}, // go to panic call 4963 {contNext, 6}, // panic so the deferred call happens 4964 {contReverseNext, 18}, 4965 {contReverseNext, 17}, 4966 {contReverseNext, 16}, 4967 {contReverseNext, 15}, 4968 {contReverseNext, 23}, 4969 {contReverseNext, 22}, 4970 {contReverseNext, 21}, 4971 {contReverseNext, 28}, 4972 }) 4973 } else { 4974 testseq2(t, "defercall", "", []seqTest{ 4975 {contContinue, 12}, 4976 {contReverseNext, 11}, 4977 {contReverseNext, 10}, 4978 {contReverseNext, 9}, 4979 {contReverseNext, 27}, 4980 4981 {contContinueToBreakpoint, 12}, // skip first call to sampleFunction 4982 {contContinueToBreakpoint, 6}, // go to call to sampleFunction through deferreturn 4983 {contReverseNext, 13}, 4984 {contReverseNext, 12}, 4985 {contReverseNext, 11}, 4986 {contReverseNext, 10}, 4987 {contReverseNext, 9}, 4988 {contReverseNext, 27}, 4989 4990 {contContinueToBreakpoint, 18}, // go to panic call 4991 {contNext, 6}, // panic so the deferred call happens 4992 {contReverseNext, 18}, 4993 {contReverseNext, 17}, 4994 {contReverseNext, 16}, 4995 {contReverseNext, 15}, 4996 {contReverseNext, 23}, 4997 {contReverseNext, 22}, 4998 {contReverseNext, 21}, 4999 {contReverseNext, 28}, 5000 }) 5001 } 5002 } 5003 5004 func TestIssue1925(t *testing.T) { 5005 // Calling a function should not leave cached goroutine information in an 5006 // inconsistent state. 5007 // In particular the stepInstructionOut function called at the end of a 5008 // 'call' procedure should clean the G cache like every other function 5009 // altering the state of the target process. 5010 protest.MustSupportFunctionCalls(t, testBackend) 5011 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 5012 assertNoError(p.Continue(), t, "Continue()") 5013 assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "afunc(2)", normalLoadConfig, true), t, "Call") 5014 t.Logf("%v\n", p.SelectedGoroutine().CurrentLoc) 5015 if loc := p.SelectedGoroutine().CurrentLoc; loc.File != fixture.Source { 5016 t.Errorf("wrong location for selected goroutine after call: %s:%d", loc.File, loc.Line) 5017 } 5018 }) 5019 } 5020 5021 func TestStepIntoWrapperForEmbeddedPointer(t *testing.T) { 5022 skipOn(t, "N/A", "linux", "386", "pie") // skipping wrappers doesn't work on linux/386/PIE due to the use of get_pc_thunk 5023 // Under some circumstances (when using an interface to call a method on an 5024 // embedded field, see _fixtures/ifaceembcall.go) the compiler will 5025 // autogenerate a wrapper function that uses a tail call (i.e. it ends in 5026 // an unconditional jump instruction to a different function). 5027 // Delve should be able to step into this tail call. 5028 testseq2(t, "ifaceembcall", "", []seqTest{ 5029 {contContinue, 28}, // main.main, the line calling iface.PtrReceiver() 5030 {contStep, 18}, // main.(*A).PtrReceiver 5031 {contStep, 19}, 5032 {contStepout, 28}, 5033 {contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver() 5034 {contStep, 22}, // main.(A).NonPtrReceiver 5035 {contStep, 23}, 5036 {contStepout, 29}}) 5037 5038 // same test but with next instead of stepout 5039 if goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) && runtime.GOARCH != "386" && !goversion.VersionAfterOrEqualRev(runtime.Version(), 1, 15, 4) { 5040 // Line numbers generated for versions 1.14 through 1.15.3 on any system except linux/386 5041 testseq2(t, "ifaceembcall", "", []seqTest{ 5042 {contContinue, 28}, // main.main, the line calling iface.PtrReceiver() 5043 {contStep, 18}, // main.(*A).PtrReceiver 5044 {contNext, 19}, 5045 {contNext, 19}, 5046 {contNext, 28}, 5047 {contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver() 5048 {contStep, 22}, 5049 {contNext, 23}, 5050 {contNext, 23}, 5051 {contNext, 29}}) 5052 } else { 5053 testseq2(t, "ifaceembcall", "", []seqTest{ 5054 {contContinue, 28}, // main.main, the line calling iface.PtrReceiver() 5055 {contStep, 18}, // main.(*A).PtrReceiver 5056 {contNext, 19}, 5057 {contNext, 28}, 5058 {contContinueToBreakpoint, 29}, // main.main, the line calling iface.NonPtrReceiver() 5059 {contStep, 22}, 5060 {contNext, 23}, 5061 {contNext, 29}}) 5062 5063 } 5064 } 5065 5066 func TestRefreshCurThreadSelGAfterContinueOnceError(t *testing.T) { 5067 // Issue #2078: 5068 // Tests that on macOS/lldb the current thread/selected goroutine are 5069 // refreshed after ContinueOnce returns an error due to a segmentation 5070 // fault. 5071 5072 skipUnlessOn(t, "N/A", "darwin", "lldb") 5073 5074 withTestProcess("issue2078", t, func(p *proc.Target, fixture protest.Fixture) { 5075 setFileBreakpoint(p, t, fixture.Source, 4) 5076 assertNoError(p.Continue(), t, "Continue() (first)") 5077 if p.Continue() == nil { 5078 t.Fatalf("Second continue did not return an error") 5079 } 5080 g := p.SelectedGoroutine() 5081 if g.CurrentLoc.Line != 9 { 5082 t.Fatalf("wrong current location %s:%d (expected :9)", g.CurrentLoc.File, g.CurrentLoc.Line) 5083 } 5084 }) 5085 } 5086 5087 func TestStepoutOneliner(t *testing.T) { 5088 // The heuristic detecting autogenerated wrappers when stepping out should 5089 // not skip oneliner functions. 5090 withTestProcess("issue2086", t, func(p *proc.Target, fixture protest.Fixture) { 5091 assertNoError(p.Continue(), t, "Continue()") 5092 assertLineNumber(p, t, 15, "after first continue") 5093 assertNoError(p.StepOut(), t, "StepOut()") 5094 if fn := p.BinInfo().PCToFunc(currentPC(p, t)); fn == nil || fn.Name != "main.T.m" { 5095 t.Fatalf("wrong function after stepout %#v", fn) 5096 } 5097 assertNoError(p.StepOut(), t, "second StepOut()") 5098 if fn := p.BinInfo().PCToFunc(currentPC(p, t)); fn == nil || fn.Name != "main.main" { 5099 t.Fatalf("wrong fnuction after second stepout %#v", fn) 5100 } 5101 }) 5102 } 5103 5104 func TestRequestManualStopWhileStopped(t *testing.T) { 5105 // Requesting a manual stop while stopped shouldn't cause problems (issue #2138). 5106 withTestProcess("issue2138", t, func(p *proc.Target, fixture protest.Fixture) { 5107 resumed := make(chan struct{}) 5108 setFileBreakpoint(p, t, fixture.Source, 8) 5109 assertNoError(p.Continue(), t, "Continue() 1") 5110 p.ResumeNotify(resumed) 5111 go func() { 5112 <-resumed 5113 time.Sleep(1 * time.Second) 5114 p.RequestManualStop() 5115 }() 5116 t.Logf("at time.Sleep call") 5117 assertNoError(p.Continue(), t, "Continue() 2") 5118 t.Logf("manually stopped") 5119 p.RequestManualStop() 5120 p.RequestManualStop() 5121 p.RequestManualStop() 5122 5123 resumed = make(chan struct{}) 5124 p.ResumeNotify(resumed) 5125 go func() { 5126 <-resumed 5127 time.Sleep(1 * time.Second) 5128 p.RequestManualStop() 5129 }() 5130 t.Logf("resuming sleep") 5131 assertNoError(p.Continue(), t, "Continue() 3") 5132 t.Logf("done") 5133 }) 5134 } 5135 5136 func TestStepOutPreservesGoroutine(t *testing.T) { 5137 // Checks that StepOut preserves the currently selected goroutine. 5138 skipOn(t, "broken", "freebsd") 5139 rand.Seed(time.Now().Unix()) 5140 protest.AllowRecording(t) 5141 withTestProcess("issue2113", t, func(p *proc.Target, fixture protest.Fixture) { 5142 assertNoError(p.Continue(), t, "Continue()") 5143 5144 logState := func() { 5145 g := p.SelectedGoroutine() 5146 var goid int = -42 5147 if g != nil { 5148 goid = g.ID 5149 } 5150 pc := currentPC(p, t) 5151 f, l, fn := p.BinInfo().PCToLine(pc) 5152 var fnname string = "???" 5153 if fn != nil { 5154 fnname = fn.Name 5155 } 5156 t.Logf("goroutine %d at %s:%d in %s", goid, f, l, fnname) 5157 } 5158 5159 logState() 5160 5161 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 5162 assertNoError(err, t, "GoroutinesInfo") 5163 candg := []*proc.G{} 5164 bestg := []*proc.G{} 5165 for _, g := range gs { 5166 frames, err := g.Stacktrace(20, 0) 5167 assertNoError(err, t, "Stacktrace") 5168 for _, frame := range frames { 5169 if frame.Call.Fn != nil && frame.Call.Fn.Name == "main.coroutine" { 5170 candg = append(candg, g) 5171 if g.Thread != nil && frames[0].Call.Fn != nil && strings.HasPrefix(frames[0].Call.Fn.Name, "runtime.") { 5172 bestg = append(bestg, g) 5173 } 5174 break 5175 } 5176 } 5177 } 5178 var pickg *proc.G 5179 if len(bestg) > 0 { 5180 pickg = bestg[rand.Intn(len(bestg))] 5181 t.Logf("selected goroutine %d (best)\n", pickg.ID) 5182 } else { 5183 pickg = candg[rand.Intn(len(candg))] 5184 t.Logf("selected goroutine %d\n", pickg.ID) 5185 5186 } 5187 goid := pickg.ID 5188 assertNoError(p.SwitchGoroutine(pickg), t, "SwitchGoroutine") 5189 5190 logState() 5191 5192 err = p.StepOut() 5193 if err != nil { 5194 _, isexited := err.(proc.ErrProcessExited) 5195 if !isexited { 5196 assertNoError(err, t, "StepOut()") 5197 } else { 5198 return 5199 } 5200 } 5201 5202 logState() 5203 5204 g2 := p.SelectedGoroutine() 5205 if g2 == nil { 5206 t.Fatalf("no selected goroutine after stepout") 5207 } else if g2.ID != goid { 5208 t.Fatalf("unexpected selected goroutine %d", g2.ID) 5209 } 5210 }) 5211 } 5212 5213 func TestIssue2319(t *testing.T) { 5214 // Check to make sure we don't crash on startup when the target is 5215 // a binary with a mix of DWARF-5 C++ compilation units and 5216 // DWARF-4 Go compilation units. 5217 5218 // Require CGO, since we need to use the external linker for this test. 5219 protest.MustHaveCgo(t) 5220 5221 // The test fixture uses linux/amd64 assembly and a *.syso file 5222 // that is linux/amd64, so skip for other architectures. 5223 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 5224 t.Skipf("skipping since not linux/amd64") 5225 } 5226 5227 // Skip unless on 1.14 or later. The test fixture uses a *.syso 5228 // file, which in 1.13 is not loaded unless we're in internal 5229 // linking mode (we need external linking here). 5230 if !goversion.VersionAfterOrEqual(runtime.Version(), 1, 14) { 5231 t.Skip("test contains fixture that is specific to go 1.14+") 5232 } 5233 5234 fixture := protest.BuildFixture("issue2319/", protest.BuildModeExternalLinker) 5235 5236 // Load up the binary and make sure there are no crashes. 5237 bi := proc.NewBinaryInfo("linux", "amd64") 5238 assertNoError(bi.LoadBinaryInfo(fixture.Path, 0, nil), t, "LoadBinaryInfo") 5239 } 5240 5241 func TestDump(t *testing.T) { 5242 if runtime.GOOS == "freebsd" || (runtime.GOOS == "darwin" && testBackend == "native") { 5243 t.Skip("not supported") 5244 } 5245 5246 convertRegisters := func(arch *proc.Arch, dregs op.DwarfRegisters) string { 5247 dregs.Reg(^uint64(0)) 5248 buf := new(bytes.Buffer) 5249 for i := 0; i < dregs.CurrentSize(); i++ { 5250 reg := dregs.Reg(uint64(i)) 5251 if reg == nil { 5252 continue 5253 } 5254 name, _, repr := arch.DwarfRegisterToString(i, reg) 5255 fmt.Fprintf(buf, " %s=%s", name, repr) 5256 } 5257 return buf.String() 5258 } 5259 5260 convertThread := func(thread proc.Thread) string { 5261 regs, err := thread.Registers() 5262 assertNoError(err, t, fmt.Sprintf("Thread registers %d", thread.ThreadID())) 5263 arch := thread.BinInfo().Arch 5264 dregs := arch.RegistersToDwarfRegisters(0, regs) 5265 return fmt.Sprintf("%08d %s", thread.ThreadID(), convertRegisters(arch, *dregs)) 5266 } 5267 5268 convertThreads := func(threads []proc.Thread) []string { 5269 r := make([]string, len(threads)) 5270 for i := range threads { 5271 r[i] = convertThread(threads[i]) 5272 } 5273 sort.Strings(r) 5274 return r 5275 } 5276 5277 convertGoroutine := func(g *proc.G) string { 5278 threadID := 0 5279 if g.Thread != nil { 5280 threadID = g.Thread.ThreadID() 5281 } 5282 return fmt.Sprintf("%d pc=%#x sp=%#x bp=%#x lr=%#x gopc=%#x startpc=%#x systemstack=%v thread=%d", g.ID, g.PC, g.SP, g.BP, g.LR, g.GoPC, g.StartPC, g.SystemStack, threadID) 5283 } 5284 5285 convertFrame := func(arch *proc.Arch, frame *proc.Stackframe) string { 5286 return fmt.Sprintf("currentPC=%#x callPC=%#x frameOff=%#x\n", frame.Current.PC, frame.Call.PC, frame.FrameOffset()) 5287 } 5288 5289 makeDump := func(p *proc.Target, corePath, exePath string, flags proc.DumpFlags) *proc.Target { 5290 fh, err := os.Create(corePath) 5291 assertNoError(err, t, "Create()") 5292 var state proc.DumpState 5293 p.Dump(fh, flags, &state) 5294 assertNoError(state.Err, t, "Dump()") 5295 if state.ThreadsDone != state.ThreadsTotal || state.MemDone != state.MemTotal || !state.AllDone || state.Dumping || state.Canceled { 5296 t.Fatalf("bad DumpState %#v", &state) 5297 } 5298 c, err := core.OpenCore(corePath, exePath, nil) 5299 assertNoError(err, t, "OpenCore()") 5300 return c 5301 } 5302 5303 testDump := func(p, c *proc.Target) { 5304 if p.Pid() != c.Pid() { 5305 t.Errorf("Pid mismatch %x %x", p.Pid(), c.Pid()) 5306 } 5307 5308 threads := convertThreads(p.ThreadList()) 5309 cthreads := convertThreads(c.ThreadList()) 5310 5311 if len(threads) != len(cthreads) { 5312 t.Errorf("Thread number mismatch %d %d", len(threads), len(cthreads)) 5313 } 5314 5315 for i := range threads { 5316 if threads[i] != cthreads[i] { 5317 t.Errorf("Thread mismatch\nlive:\t%s\ncore:\t%s", threads[i], cthreads[i]) 5318 } 5319 } 5320 5321 gos, _, err := proc.GoroutinesInfo(p, 0, 0) 5322 assertNoError(err, t, "GoroutinesInfo() - live process") 5323 cgos, _, err := proc.GoroutinesInfo(c, 0, 0) 5324 assertNoError(err, t, "GoroutinesInfo() - core dump") 5325 5326 if len(gos) != len(cgos) { 5327 t.Errorf("Goroutine number mismatch %d %d", len(gos), len(cgos)) 5328 } 5329 5330 var scope, cscope *proc.EvalScope 5331 5332 for i := range gos { 5333 if convertGoroutine(gos[i]) != convertGoroutine(cgos[i]) { 5334 t.Errorf("Goroutine mismatch\nlive:\t%s\ncore:\t%s", convertGoroutine(gos[i]), convertGoroutine(cgos[i])) 5335 } 5336 5337 frames, err := gos[i].Stacktrace(20, 0) 5338 assertNoError(err, t, fmt.Sprintf("Stacktrace for goroutine %d - live process", gos[i].ID)) 5339 cframes, err := cgos[i].Stacktrace(20, 0) 5340 assertNoError(err, t, fmt.Sprintf("Stacktrace for goroutine %d - core dump", gos[i].ID)) 5341 5342 if len(frames) != len(cframes) { 5343 t.Errorf("Frame number mismatch for goroutine %d: %d %d", gos[i].ID, len(frames), len(cframes)) 5344 } 5345 5346 for j := range frames { 5347 if convertFrame(p.BinInfo().Arch, &frames[j]) != convertFrame(p.BinInfo().Arch, &cframes[j]) { 5348 t.Errorf("Frame mismatch %d.%d\nlive:\t%s\ncore:\t%s", gos[i].ID, j, convertFrame(p.BinInfo().Arch, &frames[j]), convertFrame(p.BinInfo().Arch, &cframes[j])) 5349 } 5350 if frames[j].Call.Fn != nil && frames[j].Call.Fn.Name == "main.main" { 5351 scope = proc.FrameToScope(p, p.Memory(), gos[i], frames[j:]...) 5352 cscope = proc.FrameToScope(c, c.Memory(), cgos[i], cframes[j:]...) 5353 } 5354 } 5355 } 5356 5357 vars, err := scope.LocalVariables(normalLoadConfig) 5358 assertNoError(err, t, "LocalVariables - live process") 5359 cvars, err := cscope.LocalVariables(normalLoadConfig) 5360 assertNoError(err, t, "LocalVariables - core dump") 5361 5362 if len(vars) != len(cvars) { 5363 t.Errorf("Variable number mismatch %d %d", len(vars), len(cvars)) 5364 } 5365 5366 for i := range vars { 5367 varstr := vars[i].Name + "=" + api.ConvertVar(vars[i]).SinglelineString() 5368 cvarstr := cvars[i].Name + "=" + api.ConvertVar(cvars[i]).SinglelineString() 5369 if strings.Contains(varstr, "(unreadable") { 5370 // errors reading from unmapped memory differ between live process and core 5371 continue 5372 } 5373 if varstr != cvarstr { 5374 t.Errorf("Variable mismatch %s %s", varstr, cvarstr) 5375 } 5376 } 5377 } 5378 5379 withTestProcess("testvariables2", t, func(p *proc.Target, fixture protest.Fixture) { 5380 assertNoError(p.Continue(), t, "Continue()") 5381 corePath := filepath.Join(fixture.BuildDir, "coredump") 5382 corePathPlatIndep := filepath.Join(fixture.BuildDir, "coredump-indep") 5383 5384 t.Logf("testing normal dump") 5385 5386 c := makeDump(p, corePath, fixture.Path, 0) 5387 defer os.Remove(corePath) 5388 testDump(p, c) 5389 5390 if runtime.GOOS == "linux" && runtime.GOARCH == "amd64" { 5391 // No reason to do this test on other goos/goarch because they use the 5392 // platform-independent format anyway. 5393 t.Logf("testing platform-independent dump") 5394 c2 := makeDump(p, corePathPlatIndep, fixture.Path, proc.DumpPlatformIndependent) 5395 defer os.Remove(corePathPlatIndep) 5396 testDump(p, c2) 5397 } 5398 }) 5399 } 5400 5401 func TestCompositeMemoryWrite(t *testing.T) { 5402 if runtime.GOARCH != "amd64" { 5403 t.Skip("only valid on amd64") 5404 } 5405 skipOn(t, "not implemented", "freebsd") 5406 withTestProcess("fputest/", t, func(p *proc.Target, fixture protest.Fixture) { 5407 getregs := func() (pc, rax, xmm1 uint64) { 5408 regs, err := p.CurrentThread().Registers() 5409 assertNoError(err, t, "Registers") 5410 fmtregs, err := regs.Slice(true) 5411 assertNoError(err, t, "register slice") 5412 5413 var xmm1buf []byte 5414 5415 for _, reg := range fmtregs { 5416 switch strings.ToLower(reg.Name) { 5417 case "rax": 5418 rax = reg.Reg.Uint64Val 5419 case "xmm1": 5420 xmm1buf = reg.Reg.Bytes 5421 } 5422 } 5423 5424 xmm1 = binary.LittleEndian.Uint64(xmm1buf[:8]) 5425 5426 return regs.PC(), rax, xmm1 5427 } 5428 5429 const fakeAddress = 0xbeef0000 5430 5431 getmem := func(mem proc.MemoryReader) uint64 { 5432 buf := make([]byte, 8) 5433 _, err := mem.ReadMemory(buf, fakeAddress) 5434 assertNoError(err, t, "ReadMemory") 5435 return binary.LittleEndian.Uint64(buf) 5436 } 5437 5438 assertNoError(p.Continue(), t, "Continue()") 5439 oldPc, oldRax, oldXmm1 := getregs() 5440 t.Logf("PC %#x AX %#x XMM1 %#x", oldPc, oldRax, oldXmm1) 5441 5442 memRax, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 0, Kind: op.RegPiece}}, fakeAddress) 5443 assertNoError(err, t, "NewCompositeMemory (rax)") 5444 memXmm1, err := proc.NewCompositeMemory(p, []op.Piece{{Size: 0, Val: 18, Kind: op.RegPiece}}, fakeAddress) 5445 assertNoError(err, t, "NewCompositeMemory (xmm1)") 5446 5447 if memRax := getmem(memRax); memRax != oldRax { 5448 t.Errorf("reading rax memory, expected %#x got %#x", oldRax, memRax) 5449 } 5450 if memXmm1 := getmem(memXmm1); memXmm1 != oldXmm1 { 5451 t.Errorf("reading xmm1 memory, expected %#x got %#x", oldXmm1, memXmm1) 5452 } 5453 5454 _, err = memRax.WriteMemory(0xbeef0000, []byte{0xef, 0xbe, 0x0d, 0xf0, 0xef, 0xbe, 0x0d, 0xf0}) 5455 assertNoError(err, t, "WriteMemory (rax)") 5456 _, err = memXmm1.WriteMemory(0xbeef0000, []byte{0xef, 0xbe, 0x0d, 0xf0, 0xef, 0xbe, 0x0d, 0xf0}) 5457 assertNoError(err, t, "WriteMemory (xmm1)") 5458 5459 newPc, newRax, newXmm1 := getregs() 5460 t.Logf("PC %#x AX %#x XMM1 %#x", newPc, newRax, newXmm1) 5461 5462 const tgt = 0xf00dbeeff00dbeef 5463 if newRax != tgt { 5464 t.Errorf("reading rax register, expected %#x, got %#x", uint64(tgt), newRax) 5465 } 5466 if newXmm1 != tgt { 5467 t.Errorf("reading xmm1 register, expected %#x, got %#x", uint64(tgt), newXmm1) 5468 } 5469 }) 5470 } 5471 5472 func TestVariablesWithExternalLinking(t *testing.T) { 5473 protest.MustHaveCgo(t) 5474 // Tests that macOSDebugFrameBugWorkaround works. 5475 // See: 5476 // https://github.com/golang/go/issues/25841 5477 // https://github.com/go-delve/delve/issues/2346 5478 protest.AllowRecording(t) 5479 withTestProcessArgs("testvariables2", t, ".", []string{}, protest.BuildModeExternalLinker, func(p *proc.Target, fixture protest.Fixture) { 5480 assertNoError(p.Continue(), t, "Continue()") 5481 str1Var := evalVariable(p, t, "str1") 5482 if str1Var.Unreadable != nil { 5483 t.Fatalf("variable str1 is unreadable: %v", str1Var.Unreadable) 5484 } 5485 t.Logf("%#v", str1Var) 5486 if constant.StringVal(str1Var.Value) != "01234567890" { 5487 t.Fatalf("wrong value for str1: %v", str1Var.Value) 5488 } 5489 }) 5490 } 5491 5492 func TestWatchpointsBasic(t *testing.T) { 5493 skipOn(t, "not implemented", "freebsd") 5494 skipOn(t, "not implemented", "386") 5495 skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows") 5496 protest.AllowRecording(t) 5497 5498 position1 := 19 5499 position5 := 41 5500 5501 if runtime.GOARCH == "arm64" { 5502 position1 = 18 5503 position5 = 40 5504 } 5505 5506 withTestProcess("databpeasy", t, func(p *proc.Target, fixture protest.Fixture) { 5507 setFunctionBreakpoint(p, t, "main.main") 5508 setFileBreakpoint(p, t, fixture.Source, 21) // Position 2 breakpoint 5509 setFileBreakpoint(p, t, fixture.Source, 27) // Position 4 breakpoint 5510 assertNoError(p.Continue(), t, "Continue 0") 5511 assertLineNumber(p, t, 13, "Continue 0") // Position 0 5512 5513 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 5514 assertNoError(err, t, "GoroutineScope") 5515 5516 bp, err := p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite, nil) 5517 assertNoError(err, t, "SetDataBreakpoint(write-only)") 5518 5519 assertNoError(p.Continue(), t, "Continue 1") 5520 assertLineNumber(p, t, position1, "Continue 1") // Position 1 5521 5522 if curbp := p.CurrentThread().Breakpoint().Breakpoint; curbp == nil || (curbp.LogicalID() != bp.LogicalID()) { 5523 t.Fatal("breakpoint not set") 5524 } 5525 5526 assertNoError(p.ClearBreakpoint(bp.Addr), t, "ClearBreakpoint") 5527 5528 assertNoError(p.Continue(), t, "Continue 2") 5529 assertLineNumber(p, t, 21, "Continue 2") // Position 2 5530 5531 _, err = p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite|proc.WatchRead, nil) 5532 assertNoError(err, t, "SetDataBreakpoint(read-write)") 5533 5534 assertNoError(p.Continue(), t, "Continue 3") 5535 assertLineNumber(p, t, 22, "Continue 3") // Position 3 5536 5537 p.ClearBreakpoint(bp.Addr) 5538 5539 assertNoError(p.Continue(), t, "Continue 4") 5540 assertLineNumber(p, t, 27, "Continue 4") // Position 4 5541 5542 t.Logf("setting final breakpoint") 5543 _, err = p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite, nil) 5544 assertNoError(err, t, "SetDataBreakpoint(write-only, again)") 5545 5546 assertNoError(p.Continue(), t, "Continue 5") 5547 assertLineNumber(p, t, position5, "Continue 5") // Position 5 5548 }) 5549 } 5550 5551 func TestWatchpointCounts(t *testing.T) { 5552 skipOn(t, "not implemented", "freebsd") 5553 skipOn(t, "not implemented", "386") 5554 skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows") 5555 protest.AllowRecording(t) 5556 5557 withTestProcess("databpcountstest", t, func(p *proc.Target, fixture protest.Fixture) { 5558 setFunctionBreakpoint(p, t, "main.main") 5559 assertNoError(p.Continue(), t, "Continue 0") 5560 5561 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 5562 assertNoError(err, t, "GoroutineScope") 5563 5564 bp, err := p.SetWatchpoint(0, scope, "globalvar1", proc.WatchWrite, nil) 5565 assertNoError(err, t, "SetWatchpoint(write-only)") 5566 5567 for { 5568 if err := p.Continue(); err != nil { 5569 if _, exited := err.(proc.ErrProcessExited); exited { 5570 break 5571 } 5572 assertNoError(err, t, "Continue()") 5573 } 5574 } 5575 5576 t.Logf("TotalHitCount: %d", bp.Logical.TotalHitCount) 5577 if bp.Logical.TotalHitCount != 200 { 5578 t.Fatalf("Wrong TotalHitCount for the breakpoint (%d)", bp.Logical.TotalHitCount) 5579 } 5580 5581 if len(bp.Logical.HitCount) != 2 { 5582 t.Fatalf("Wrong number of goroutines for breakpoint (%d)", len(bp.Logical.HitCount)) 5583 } 5584 5585 for _, v := range bp.Logical.HitCount { 5586 if v != 100 { 5587 t.Fatalf("Wrong HitCount for breakpoint (%v)", bp.Logical.HitCount) 5588 } 5589 } 5590 }) 5591 } 5592 5593 func TestManualStopWhileStopped(t *testing.T) { 5594 // Checks that RequestManualStop sent to a stopped thread does not cause the target process to die. 5595 withTestProcess("loopprog", t, func(p *proc.Target, fixture protest.Fixture) { 5596 asyncCont := func(done chan struct{}) { 5597 defer close(done) 5598 err := p.Continue() 5599 t.Logf("%v\n", err) 5600 if err != nil { 5601 panic(err) 5602 } 5603 for _, th := range p.ThreadList() { 5604 if th.Breakpoint().Breakpoint != nil { 5605 t.Logf("unexpected stop at breakpoint: %v", th.Breakpoint().Breakpoint) 5606 panic("unexpected stop at breakpoint") 5607 } 5608 } 5609 } 5610 5611 const ( 5612 repeatsSlow = 3 5613 repeatsFast = 5 5614 ) 5615 5616 for i := 0; i < repeatsSlow; i++ { 5617 t.Logf("Continue %d (slow)", i) 5618 done := make(chan struct{}) 5619 go asyncCont(done) 5620 time.Sleep(1 * time.Second) 5621 p.RequestManualStop() 5622 time.Sleep(1 * time.Second) 5623 p.RequestManualStop() 5624 time.Sleep(1 * time.Second) 5625 <-done 5626 } 5627 for i := 0; i < repeatsFast; i++ { 5628 t.Logf("Continue %d (fast)", i) 5629 rch := make(chan struct{}) 5630 done := make(chan struct{}) 5631 p.ResumeNotify(rch) 5632 go asyncCont(done) 5633 <-rch 5634 p.RequestManualStop() 5635 p.RequestManualStop() 5636 <-done 5637 } 5638 }) 5639 } 5640 5641 func TestDwrapStartLocation(t *testing.T) { 5642 // Tests that the start location of a goroutine is unwrapped in Go 1.17 and later. 5643 protest.AllowRecording(t) 5644 withTestProcess("goroutinestackprog", t, func(p *proc.Target, fixture protest.Fixture) { 5645 setFunctionBreakpoint(p, t, "main.stacktraceme") 5646 assertNoError(p.Continue(), t, "Continue()") 5647 gs, _, err := proc.GoroutinesInfo(p, 0, 0) 5648 assertNoError(err, t, "GoroutinesInfo") 5649 found := false 5650 for _, g := range gs { 5651 startLoc := g.StartLoc(p) 5652 if startLoc.Fn == nil { 5653 continue 5654 } 5655 t.Logf("%#v\n", startLoc.Fn.Name) 5656 if startLoc.Fn.Name == "main.agoroutine" { 5657 found = true 5658 break 5659 } 5660 } 5661 if !found { 5662 t.Errorf("could not find any goroutine with a start location of main.agoroutine") 5663 } 5664 }) 5665 } 5666 5667 func TestWatchpointStack(t *testing.T) { 5668 skipOn(t, "not implemented", "freebsd") 5669 skipOn(t, "not implemented", "386") 5670 skipOn(t, "see https://github.com/go-delve/delve/issues/2768", "windows") 5671 protest.AllowRecording(t) 5672 5673 position1 := 17 5674 5675 if runtime.GOARCH == "arm64" { 5676 position1 = 16 5677 } 5678 5679 withTestProcess("databpstack", t, func(p *proc.Target, fixture protest.Fixture) { 5680 setFileBreakpoint(p, t, fixture.Source, 11) // Position 0 breakpoint 5681 clearlen := len(p.Breakpoints().M) 5682 5683 assertNoError(p.Continue(), t, "Continue 0") 5684 assertLineNumber(p, t, 11, "Continue 0") // Position 0 5685 5686 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 5687 assertNoError(err, t, "GoroutineScope") 5688 5689 _, err = p.SetWatchpoint(0, scope, "w", proc.WatchWrite, nil) 5690 assertNoError(err, t, "SetDataBreakpoint(write-only)") 5691 5692 watchbpnum := 3 5693 if recorded, _ := p.Recorded(); recorded { 5694 watchbpnum = 4 5695 } 5696 5697 if len(p.Breakpoints().M) != clearlen+watchbpnum { 5698 // want 1 watchpoint, 1 stack resize breakpoint, 1 out of scope sentinel (2 if recorded) 5699 t.Errorf("wrong number of breakpoints after setting watchpoint: %d", len(p.Breakpoints().M)-clearlen) 5700 } 5701 5702 var retaddr uint64 5703 for _, bp := range p.Breakpoints().M { 5704 for _, breaklet := range bp.Breaklets { 5705 if breaklet.Kind&proc.WatchOutOfScopeBreakpoint != 0 { 5706 retaddr = bp.Addr 5707 break 5708 } 5709 } 5710 } 5711 5712 // Note: for recorded processes retaddr will not always be the return 5713 // address, ~50% of the times it will be the address of the CALL 5714 // instruction preceding the return address, this does not matter for this 5715 // test. 5716 5717 _, err = p.SetBreakpoint(0, retaddr, proc.UserBreakpoint, nil) 5718 assertNoError(err, t, "SetBreakpoint") 5719 5720 if len(p.Breakpoints().M) != clearlen+watchbpnum { 5721 // want 1 watchpoint, 1 stack resize breakpoint, 1 out of scope sentinel (which is also a user breakpoint) (and another out of scope sentinel if recorded) 5722 t.Errorf("wrong number of breakpoints after setting watchpoint: %d", len(p.Breakpoints().M)-clearlen) 5723 } 5724 5725 assertNoError(p.Continue(), t, "Continue 1") 5726 assertLineNumber(p, t, position1, "Continue 1") // Position 1 5727 5728 assertNoError(p.Continue(), t, "Continue 2") 5729 t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint) 5730 assertLineNumber(p, t, 24, "Continue 2") // Position 2 (watchpoint gone out of scope) 5731 5732 if len(p.Breakpoints().M) != clearlen+1 { 5733 // want 1 user breakpoint set at retaddr 5734 t.Errorf("wrong number of breakpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().M)-clearlen) 5735 } 5736 5737 if len(p.Breakpoints().WatchOutOfScope) != 1 { 5738 t.Errorf("wrong number of out-of-scope watchpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().WatchOutOfScope)) 5739 } 5740 5741 err = p.ClearBreakpoint(retaddr) 5742 assertNoError(err, t, "ClearBreakpoint") 5743 5744 if len(p.Breakpoints().M) != clearlen { 5745 // want 1 user breakpoint set at retaddr 5746 t.Errorf("wrong number of breakpoints after removing user breakpoint: %d", len(p.Breakpoints().M)-clearlen) 5747 } 5748 }) 5749 } 5750 5751 func TestWatchpointStackBackwardsOutOfScope(t *testing.T) { 5752 skipUnlessOn(t, "only for recorded targets", "rr") 5753 protest.AllowRecording(t) 5754 5755 withTestProcess("databpstack", t, func(p *proc.Target, fixture protest.Fixture) { 5756 setFileBreakpoint(p, t, fixture.Source, 11) // Position 0 breakpoint 5757 clearlen := len(p.Breakpoints().M) 5758 5759 assertNoError(p.Continue(), t, "Continue 0") 5760 assertLineNumber(p, t, 11, "Continue 0") // Position 0 5761 5762 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 5763 assertNoError(err, t, "GoroutineScope") 5764 5765 _, err = p.SetWatchpoint(0, scope, "w", proc.WatchWrite, nil) 5766 assertNoError(err, t, "SetDataBreakpoint(write-only)") 5767 5768 assertNoError(p.Continue(), t, "Continue 1") 5769 assertLineNumber(p, t, 17, "Continue 1") // Position 1 5770 5771 p.ChangeDirection(proc.Backward) 5772 5773 assertNoError(p.Continue(), t, "Continue 2") 5774 t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint) 5775 assertLineNumber(p, t, 16, "Continue 2") // Position 1 again (because of inverted movement) 5776 5777 assertNoError(p.Continue(), t, "Continue 3") 5778 t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint) 5779 assertLineNumber(p, t, 11, "Continue 3") // Position 0 (breakpoint 1 hit) 5780 5781 assertNoError(p.Continue(), t, "Continue 4") 5782 t.Logf("%#v", p.CurrentThread().Breakpoint().Breakpoint) 5783 assertLineNumber(p, t, 23, "Continue 4") // Position 2 (watchpoint gone out of scope) 5784 5785 if len(p.Breakpoints().M) != clearlen { 5786 t.Errorf("wrong number of breakpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().M)-clearlen) 5787 } 5788 5789 if len(p.Breakpoints().WatchOutOfScope) != 1 { 5790 t.Errorf("wrong number of out-of-scope watchpoints after watchpoint goes out of scope: %d", len(p.Breakpoints().WatchOutOfScope)) 5791 } 5792 5793 if len(p.Breakpoints().M) != clearlen { 5794 // want 1 user breakpoint set at retaddr 5795 t.Errorf("wrong number of breakpoints after removing user breakpoint: %d", len(p.Breakpoints().M)-clearlen) 5796 } 5797 }) 5798 } 5799 5800 func TestSetOnFunctions(t *testing.T) { 5801 // The set command between function variables should fail with an error 5802 // Issue #2691 5803 protest.AllowRecording(t) 5804 withTestProcess("goroutinestackprog", t, func(p *proc.Target, fixture protest.Fixture) { 5805 setFunctionBreakpoint(p, t, "main.main") 5806 assertNoError(p.Continue(), t, "Continue()") 5807 scope, err := proc.GoroutineScope(p, p.CurrentThread()) 5808 assertNoError(err, t, "GoroutineScope") 5809 err = scope.SetVariable("main.func1", "main.func2") 5810 if err == nil { 5811 t.Fatal("expected error when assigning between function variables") 5812 } 5813 }) 5814 } 5815 5816 func TestSetYMMRegister(t *testing.T) { 5817 skipUnlessOn(t, "N/A", "darwin", "amd64") 5818 // Checks that setting a XMM register works. This checks that the 5819 // workaround for a bug in debugserver works. 5820 // See issue #2767. 5821 withTestProcess("setymmreg/", t, func(p *proc.Target, fixture protest.Fixture) { 5822 setFunctionBreakpoint(p, t, "main.asmFunc") 5823 assertNoError(p.Continue(), t, "Continue()") 5824 5825 getReg := func(pos string) *op.DwarfRegister { 5826 regs := getRegisters(p, t) 5827 5828 arch := p.BinInfo().Arch 5829 dregs := arch.RegistersToDwarfRegisters(0, regs) 5830 5831 r := dregs.Reg(regnum.AMD64_XMM0) 5832 t.Logf("%s: %#v", pos, r) 5833 return r 5834 } 5835 5836 getReg("before") 5837 5838 p.CurrentThread().SetReg(regnum.AMD64_XMM0, op.DwarfRegisterFromBytes([]byte{ 5839 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 5840 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 5841 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 5842 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44})) 5843 assertNoError(p.CurrentThread().StepInstruction(), t, "SetpInstruction") 5844 5845 xmm0 := getReg("after") 5846 5847 for i := range xmm0.Bytes { 5848 if xmm0.Bytes[i] != 0x44 { 5849 t.Fatalf("wrong register value") 5850 } 5851 } 5852 }) 5853 } 5854 5855 func TestNilPtrDerefInBreakInstr(t *testing.T) { 5856 // Checks that having a breakpoint on the exact instruction that causes a 5857 // nil pointer dereference does not cause problems. 5858 5859 var asmfile string 5860 switch runtime.GOARCH { 5861 case "amd64": 5862 asmfile = "main_amd64.s" 5863 case "arm64": 5864 asmfile = "main_arm64.s" 5865 case "386": 5866 asmfile = "main_386.s" 5867 default: 5868 t.Fatalf("assembly file for %s not provided", runtime.GOARCH) 5869 } 5870 5871 withTestProcess("asmnilptr/", t, func(p *proc.Target, fixture protest.Fixture) { 5872 f := filepath.Join(fixture.BuildDir, asmfile) 5873 f = strings.Replace(f, "\\", "/", -1) 5874 setFileBreakpoint(p, t, f, 5) 5875 t.Logf("first continue") 5876 assertNoError(p.Continue(), t, "Continue()") 5877 t.Logf("second continue") 5878 err := p.Continue() 5879 if runtime.GOOS == "darwin" && err != nil && err.Error() == "bad access" { 5880 // this is also ok 5881 return 5882 } 5883 assertNoError(err, t, "Continue()") 5884 bp := p.CurrentThread().Breakpoint() 5885 if bp != nil { 5886 t.Logf("%#v\n", bp.Breakpoint) 5887 } 5888 if bp == nil || (bp.Logical.Name != proc.UnrecoveredPanic) { 5889 t.Fatalf("no breakpoint hit or wrong breakpoint hit: %#v", bp) 5890 } 5891 }) 5892 } 5893 5894 func TestStepIntoAutogeneratedSkip(t *testing.T) { 5895 // Tests that autogenerated functions are skipped with the new naming 5896 // scheme for autogenerated functions (issue #2948). 5897 withTestProcess("stepintobug", t, func(p *proc.Target, fixture protest.Fixture) { 5898 setFileBreakpoint(p, t, fixture.Source, 9) 5899 assertNoError(p.Continue(), t, "Continue()") 5900 assertNoError(p.Step(), t, "Step") 5901 assertLineNumber(p, t, 12, "After step") 5902 }) 5903 } 5904 5905 func TestCallInjectionFlagCorruption(t *testing.T) { 5906 // debugCallV2 has a bug in amd64 where its tail corrupts the FLAGS register by running an ADD instruction. 5907 // Since this problem exists in many versions of Go, instead of fixing 5908 // debugCallV2, we work around this problem by restoring FLAGS, one extra 5909 // time, after stepping out of debugCallV2. 5910 // Fixes issue https://github.com/go-delve/delve/issues/2985 5911 skipUnlessOn(t, "not relevant", "amd64") 5912 protest.MustSupportFunctionCalls(t, testBackend) 5913 5914 withTestProcessArgs("badflags", t, ".", []string{"0"}, 0, func(p *proc.Target, fixture protest.Fixture) { 5915 mainfn := p.BinInfo().LookupFunc["main.main"] 5916 5917 // Find JNZ instruction on line :14 5918 var addr uint64 5919 text, err := proc.Disassemble(p.Memory(), nil, p.Breakpoints(), p.BinInfo(), mainfn.Entry, mainfn.End) 5920 assertNoError(err, t, "Disassemble") 5921 for _, instr := range text { 5922 if instr.Loc.Line != 14 { 5923 continue 5924 } 5925 if proc.IsJNZ(instr.Inst) { 5926 addr = instr.Loc.PC 5927 } 5928 } 5929 if addr == 0 { 5930 t.Fatalf("Could not find JNZ instruction at line :14") 5931 } 5932 5933 // Create breakpoint 5934 _, err = p.SetBreakpoint(0, addr, proc.UserBreakpoint, nil) 5935 assertNoError(err, t, "SetBreakpoint") 5936 5937 // Continue to breakpoint 5938 assertNoError(p.Continue(), t, "Continue()") 5939 assertLineNumber(p, t, 14, "expected line :14") 5940 5941 // Save RFLAGS register 5942 rflagsBeforeCall := p.BinInfo().Arch.RegistersToDwarfRegisters(0, getRegisters(p, t)).Uint64Val(regnum.AMD64_Rflags) 5943 t.Logf("rflags before = %#x", rflagsBeforeCall) 5944 5945 // Inject call to main.g() 5946 assertNoError(proc.EvalExpressionWithCalls(p, p.SelectedGoroutine(), "g()", normalLoadConfig, true), t, "Call") 5947 5948 // Check RFLAGS register after the call 5949 rflagsAfterCall := p.BinInfo().Arch.RegistersToDwarfRegisters(0, getRegisters(p, t)).Uint64Val(regnum.AMD64_Rflags) 5950 t.Logf("rflags after = %#x", rflagsAfterCall) 5951 5952 if rflagsBeforeCall != rflagsAfterCall { 5953 t.Errorf("mismatched rflags value") 5954 } 5955 5956 // Single step and check where we end up 5957 assertNoError(p.Step(), t, "Step()") 5958 assertLineNumber(p, t, 17, "expected line :17") // since we passed "0" as argument we should be going into the false branch at line :17 5959 }) 5960 }