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