github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/cmd/link/internal/ld/dwarf_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ld 6 7 import ( 8 objfilepkg "cmd/internal/objfile" // renamed to avoid conflict with objfile function 9 "debug/dwarf" 10 "errors" 11 "fmt" 12 "internal/testenv" 13 "io/ioutil" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "reflect" 18 "runtime" 19 "testing" 20 ) 21 22 const ( 23 NoOpt = "-gcflags=-l -N" 24 Opt = "" 25 OptInl4 = "-gcflags=all=-l=4" 26 OptInl4DwLoc = "-gcflags=all=-l=4 -dwarflocationlists" 27 ) 28 29 func TestRuntimeTypeDIEs(t *testing.T) { 30 testenv.MustHaveGoBuild(t) 31 32 if runtime.GOOS == "plan9" { 33 t.Skip("skipping on plan9; no DWARF symbol table in executables") 34 } 35 36 dir, err := ioutil.TempDir("", "TestRuntimeTypeDIEs") 37 if err != nil { 38 t.Fatalf("could not create directory: %v", err) 39 } 40 defer os.RemoveAll(dir) 41 42 f := gobuild(t, dir, `package main; func main() { }`, NoOpt) 43 defer f.Close() 44 45 dwarf, err := f.DWARF() 46 if err != nil { 47 t.Fatalf("error reading DWARF: %v", err) 48 } 49 50 want := map[string]bool{ 51 "runtime._type": true, 52 "runtime.arraytype": true, 53 "runtime.chantype": true, 54 "runtime.functype": true, 55 "runtime.maptype": true, 56 "runtime.ptrtype": true, 57 "runtime.slicetype": true, 58 "runtime.structtype": true, 59 "runtime.interfacetype": true, 60 "runtime.itab": true, 61 "runtime.imethod": true, 62 } 63 64 found := findTypes(t, dwarf, want) 65 if len(found) != len(want) { 66 t.Errorf("found %v, want %v", found, want) 67 } 68 } 69 70 func findTypes(t *testing.T, dw *dwarf.Data, want map[string]bool) (found map[string]bool) { 71 found = make(map[string]bool) 72 rdr := dw.Reader() 73 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 74 if err != nil { 75 t.Fatalf("error reading DWARF: %v", err) 76 } 77 switch entry.Tag { 78 case dwarf.TagTypedef: 79 if name, ok := entry.Val(dwarf.AttrName).(string); ok && want[name] { 80 found[name] = true 81 } 82 } 83 } 84 return 85 } 86 87 func gobuild(t *testing.T, dir string, testfile string, gcflags string) *objfilepkg.File { 88 src := filepath.Join(dir, "test.go") 89 dst := filepath.Join(dir, "out") 90 91 if err := ioutil.WriteFile(src, []byte(testfile), 0666); err != nil { 92 t.Fatal(err) 93 } 94 95 cmd := exec.Command(testenv.GoToolPath(t), "build", gcflags, "-o", dst, src) 96 if b, err := cmd.CombinedOutput(); err != nil { 97 t.Logf("build: %s\n", b) 98 t.Fatalf("build error: %v", err) 99 } 100 101 f, err := objfilepkg.Open(dst) 102 if err != nil { 103 t.Fatal(err) 104 } 105 return f 106 } 107 108 func TestEmbeddedStructMarker(t *testing.T) { 109 testenv.MustHaveGoBuild(t) 110 111 if runtime.GOOS == "plan9" { 112 t.Skip("skipping on plan9; no DWARF symbol table in executables") 113 } 114 115 const prog = ` 116 package main 117 118 import "fmt" 119 120 type Foo struct { v int } 121 type Bar struct { 122 Foo 123 name string 124 } 125 type Baz struct { 126 *Foo 127 name string 128 } 129 130 func main() { 131 bar := Bar{ Foo: Foo{v: 123}, name: "onetwothree"} 132 baz := Baz{ Foo: &bar.Foo, name: "123" } 133 fmt.Println(bar, baz) 134 }` 135 136 want := map[string]map[string]bool{ 137 "main.Foo": map[string]bool{"v": false}, 138 "main.Bar": map[string]bool{"Foo": true, "name": false}, 139 "main.Baz": map[string]bool{"Foo": true, "name": false}, 140 } 141 142 dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker") 143 if err != nil { 144 t.Fatalf("could not create directory: %v", err) 145 } 146 defer os.RemoveAll(dir) 147 148 f := gobuild(t, dir, prog, NoOpt) 149 150 defer f.Close() 151 152 d, err := f.DWARF() 153 if err != nil { 154 t.Fatalf("error reading DWARF: %v", err) 155 } 156 157 rdr := d.Reader() 158 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 159 if err != nil { 160 t.Fatalf("error reading DWARF: %v", err) 161 } 162 switch entry.Tag { 163 case dwarf.TagStructType: 164 name := entry.Val(dwarf.AttrName).(string) 165 wantMembers := want[name] 166 if wantMembers == nil { 167 continue 168 } 169 gotMembers, err := findMembers(rdr) 170 if err != nil { 171 t.Fatalf("error reading DWARF: %v", err) 172 } 173 174 if !reflect.DeepEqual(gotMembers, wantMembers) { 175 t.Errorf("type %v: got map[member]embedded = %+v, want %+v", name, wantMembers, gotMembers) 176 } 177 delete(want, name) 178 } 179 } 180 if len(want) != 0 { 181 t.Errorf("failed to check all expected types: missing types = %+v", want) 182 } 183 } 184 185 func findMembers(rdr *dwarf.Reader) (map[string]bool, error) { 186 memberEmbedded := map[string]bool{} 187 // TODO(hyangah): define in debug/dwarf package 188 const goEmbeddedStruct = dwarf.Attr(0x2903) 189 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 190 if err != nil { 191 return nil, err 192 } 193 switch entry.Tag { 194 case dwarf.TagMember: 195 name := entry.Val(dwarf.AttrName).(string) 196 embedded := entry.Val(goEmbeddedStruct).(bool) 197 memberEmbedded[name] = embedded 198 case 0: 199 return memberEmbedded, nil 200 } 201 } 202 return memberEmbedded, nil 203 } 204 205 func TestSizes(t *testing.T) { 206 if runtime.GOOS == "plan9" { 207 t.Skip("skipping on plan9; no DWARF symbol table in executables") 208 } 209 210 // DWARF sizes should never be -1. 211 // See issue #21097 212 const prog = ` 213 package main 214 var x func() 215 var y [4]func() 216 func main() { 217 x = nil 218 y[0] = nil 219 } 220 ` 221 dir, err := ioutil.TempDir("", "TestSizes") 222 if err != nil { 223 t.Fatalf("could not create directory: %v", err) 224 } 225 defer os.RemoveAll(dir) 226 f := gobuild(t, dir, prog, NoOpt) 227 defer f.Close() 228 d, err := f.DWARF() 229 if err != nil { 230 t.Fatalf("error reading DWARF: %v", err) 231 } 232 rdr := d.Reader() 233 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 234 if err != nil { 235 t.Fatalf("error reading DWARF: %v", err) 236 } 237 switch entry.Tag { 238 case dwarf.TagArrayType, dwarf.TagPointerType, dwarf.TagStructType, dwarf.TagBaseType, dwarf.TagSubroutineType, dwarf.TagTypedef: 239 default: 240 continue 241 } 242 typ, err := d.Type(entry.Offset) 243 if err != nil { 244 t.Fatalf("can't read type: %v", err) 245 } 246 if typ.Size() < 0 { 247 t.Errorf("subzero size %s %s %T", typ, entry.Tag, typ) 248 } 249 } 250 } 251 252 func TestFieldOverlap(t *testing.T) { 253 if runtime.GOOS == "plan9" { 254 t.Skip("skipping on plan9; no DWARF symbol table in executables") 255 } 256 257 // This test grew out of issue 21094, where specific sudog<T> DWARF types 258 // had elem fields set to values instead of pointers. 259 const prog = ` 260 package main 261 262 var c chan string 263 264 func main() { 265 c <- "foo" 266 } 267 ` 268 dir, err := ioutil.TempDir("", "TestFieldOverlap") 269 if err != nil { 270 t.Fatalf("could not create directory: %v", err) 271 } 272 defer os.RemoveAll(dir) 273 274 f := gobuild(t, dir, prog, NoOpt) 275 defer f.Close() 276 277 d, err := f.DWARF() 278 if err != nil { 279 t.Fatalf("error reading DWARF: %v", err) 280 } 281 282 rdr := d.Reader() 283 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 284 if err != nil { 285 t.Fatalf("error reading DWARF: %v", err) 286 } 287 if entry.Tag != dwarf.TagStructType { 288 continue 289 } 290 typ, err := d.Type(entry.Offset) 291 if err != nil { 292 t.Fatalf("can't read type: %v", err) 293 } 294 s := typ.(*dwarf.StructType) 295 for i := 0; i < len(s.Field); i++ { 296 end := s.Field[i].ByteOffset + s.Field[i].Type.Size() 297 var limit int64 298 if i == len(s.Field)-1 { 299 limit = s.Size() 300 } else { 301 limit = s.Field[i+1].ByteOffset 302 } 303 if end > limit { 304 name := entry.Val(dwarf.AttrName).(string) 305 t.Fatalf("field %s.%s overlaps next field", name, s.Field[i].Name) 306 } 307 } 308 } 309 } 310 311 func TestVarDeclCoordsAndSubrogramDeclFile(t *testing.T) { 312 testenv.MustHaveGoBuild(t) 313 314 if runtime.GOOS == "plan9" { 315 t.Skip("skipping on plan9; no DWARF symbol table in executables") 316 } 317 318 const prog = ` 319 package main 320 321 func main() { 322 var i int 323 i = i 324 } 325 ` 326 dir, err := ioutil.TempDir("", "TestVarDeclCoords") 327 if err != nil { 328 t.Fatalf("could not create directory: %v", err) 329 } 330 defer os.RemoveAll(dir) 331 332 f := gobuild(t, dir, prog, NoOpt) 333 334 d, err := f.DWARF() 335 if err != nil { 336 t.Fatalf("error reading DWARF: %v", err) 337 } 338 339 rdr := d.Reader() 340 ex := examiner{} 341 if err := ex.populate(rdr); err != nil { 342 t.Fatalf("error reading DWARF: %v", err) 343 } 344 345 // Locate the main.main DIE 346 mains := ex.Named("main.main") 347 if len(mains) == 0 { 348 t.Fatalf("unable to locate DIE for main.main") 349 } 350 if len(mains) != 1 { 351 t.Fatalf("more than one main.main DIE") 352 } 353 maindie := mains[0] 354 355 // Vet the main.main DIE 356 if maindie.Tag != dwarf.TagSubprogram { 357 t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag) 358 } 359 360 // Walk main's children and select variable "i". 361 mainIdx := ex.idxFromOffset(maindie.Offset) 362 childDies := ex.Children(mainIdx) 363 var iEntry *dwarf.Entry 364 for _, child := range childDies { 365 if child.Tag == dwarf.TagVariable && child.Val(dwarf.AttrName).(string) == "i" { 366 iEntry = child 367 break 368 } 369 } 370 if iEntry == nil { 371 t.Fatalf("didn't find DW_TAG_variable for i in main.main") 372 } 373 374 // Verify line/file attributes. 375 line := iEntry.Val(dwarf.AttrDeclLine) 376 if line == nil || line.(int64) != 5 { 377 t.Errorf("DW_AT_decl_line for i is %v, want 5", line) 378 } 379 380 file := maindie.Val(dwarf.AttrDeclFile) 381 if file == nil || file.(int64) != 1 { 382 t.Errorf("DW_AT_decl_file for main is %v, want 1", file) 383 } 384 } 385 386 // Helper class for supporting queries on DIEs within a DWARF .debug_info 387 // section. Invoke the populate() method below passing in a dwarf.Reader, 388 // which will read in all DIEs and keep track of parent/child 389 // relationships. Queries can then be made to ask for DIEs by name or 390 // by offset. This will hopefully reduce boilerplate for future test 391 // writing. 392 393 type examiner struct { 394 dies []*dwarf.Entry 395 idxByOffset map[dwarf.Offset]int 396 kids map[int][]int 397 parent map[int]int 398 byname map[string][]int 399 } 400 401 // Populate the examiner using the DIEs read from rdr. 402 func (ex *examiner) populate(rdr *dwarf.Reader) error { 403 ex.idxByOffset = make(map[dwarf.Offset]int) 404 ex.kids = make(map[int][]int) 405 ex.parent = make(map[int]int) 406 ex.byname = make(map[string][]int) 407 var nesting []int 408 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 409 if err != nil { 410 return err 411 } 412 if entry.Tag == 0 { 413 // terminator 414 if len(nesting) == 0 { 415 return errors.New("nesting stack underflow") 416 } 417 nesting = nesting[:len(nesting)-1] 418 continue 419 } 420 idx := len(ex.dies) 421 ex.dies = append(ex.dies, entry) 422 if _, found := ex.idxByOffset[entry.Offset]; found { 423 return errors.New("DIE clash on offset") 424 } 425 ex.idxByOffset[entry.Offset] = idx 426 if name, ok := entry.Val(dwarf.AttrName).(string); ok { 427 ex.byname[name] = append(ex.byname[name], idx) 428 } 429 if len(nesting) > 0 { 430 parent := nesting[len(nesting)-1] 431 ex.kids[parent] = append(ex.kids[parent], idx) 432 ex.parent[idx] = parent 433 } 434 if entry.Children { 435 nesting = append(nesting, idx) 436 } 437 } 438 if len(nesting) > 0 { 439 return errors.New("unterminated child sequence") 440 } 441 return nil 442 } 443 444 func indent(ilevel int) { 445 for i := 0; i < ilevel; i++ { 446 fmt.Printf(" ") 447 } 448 } 449 450 // For debugging new tests 451 func (ex *examiner) dumpEntry(idx int, dumpKids bool, ilevel int) error { 452 if idx >= len(ex.dies) { 453 msg := fmt.Sprintf("bad DIE %d: index out of range\n", idx) 454 return errors.New(msg) 455 } 456 entry := ex.dies[idx] 457 indent(ilevel) 458 fmt.Printf("0x%x: %v\n", idx, entry.Tag) 459 for _, f := range entry.Field { 460 indent(ilevel) 461 fmt.Printf("at=%v val=0x%x\n", f.Attr, f.Val) 462 } 463 if dumpKids { 464 ksl := ex.kids[idx] 465 for _, k := range ksl { 466 ex.dumpEntry(k, true, ilevel+2) 467 } 468 } 469 return nil 470 } 471 472 // Given a DIE offset, return the previously read dwarf.Entry, or nil 473 func (ex *examiner) entryFromOffset(off dwarf.Offset) *dwarf.Entry { 474 if idx, found := ex.idxByOffset[off]; found && idx != -1 { 475 return ex.entryFromIdx(idx) 476 } 477 return nil 478 } 479 480 // Return the ID that that examiner uses to refer to the DIE at offset off 481 func (ex *examiner) idxFromOffset(off dwarf.Offset) int { 482 if idx, found := ex.idxByOffset[off]; found { 483 return idx 484 } 485 return -1 486 } 487 488 // Return the dwarf.Entry pointer for the DIE with id 'idx' 489 func (ex *examiner) entryFromIdx(idx int) *dwarf.Entry { 490 if idx >= len(ex.dies) || idx < 0 { 491 return nil 492 } 493 return ex.dies[idx] 494 } 495 496 // Returns a list of child entries for a die with ID 'idx' 497 func (ex *examiner) Children(idx int) []*dwarf.Entry { 498 sl := ex.kids[idx] 499 ret := make([]*dwarf.Entry, len(sl)) 500 for i, k := range sl { 501 ret[i] = ex.entryFromIdx(k) 502 } 503 return ret 504 } 505 506 // Returns parent DIE for DIE 'idx', or nil if the DIE is top level 507 func (ex *examiner) Parent(idx int) *dwarf.Entry { 508 p, found := ex.parent[idx] 509 if !found { 510 return nil 511 } 512 return ex.entryFromIdx(p) 513 } 514 515 // Return a list of all DIEs with name 'name'. When searching for DIEs 516 // by name, keep in mind that the returned results will include child 517 // DIEs such as params/variables. For example, asking for all DIEs named 518 // "p" for even a small program will give you 400-500 entries. 519 func (ex *examiner) Named(name string) []*dwarf.Entry { 520 sl := ex.byname[name] 521 ret := make([]*dwarf.Entry, len(sl)) 522 for i, k := range sl { 523 ret[i] = ex.entryFromIdx(k) 524 } 525 return ret 526 } 527 528 func TestInlinedRoutineRecords(t *testing.T) { 529 testenv.MustHaveGoBuild(t) 530 531 if runtime.GOOS == "plan9" { 532 t.Skip("skipping on plan9; no DWARF symbol table in executables") 533 } 534 if runtime.GOOS == "solaris" { 535 t.Skip("skipping on solaris, pending resolution of issue #23168") 536 } 537 538 const prog = ` 539 package main 540 541 var G int 542 543 func noinline(x int) int { 544 defer func() { G += x }() 545 return x 546 } 547 548 func cand(x, y int) int { 549 return noinline(x+y) ^ (y - x) 550 } 551 552 func main() { 553 x := cand(G*G,G|7%G) 554 G = x 555 } 556 ` 557 dir, err := ioutil.TempDir("", "TestInlinedRoutineRecords") 558 if err != nil { 559 t.Fatalf("could not create directory: %v", err) 560 } 561 defer os.RemoveAll(dir) 562 563 // Note: this is a build with "-l=4", as opposed to "-l -N". The 564 // test is intended to verify DWARF that is only generated when 565 // the inliner is active. 566 f := gobuild(t, dir, prog, OptInl4) 567 568 d, err := f.DWARF() 569 if err != nil { 570 t.Fatalf("error reading DWARF: %v", err) 571 } 572 573 // The inlined subroutines we expect to visit 574 expectedInl := []string{"main.cand"} 575 576 rdr := d.Reader() 577 ex := examiner{} 578 if err := ex.populate(rdr); err != nil { 579 t.Fatalf("error reading DWARF: %v", err) 580 } 581 582 // Locate the main.main DIE 583 mains := ex.Named("main.main") 584 if len(mains) == 0 { 585 t.Fatalf("unable to locate DIE for main.main") 586 } 587 if len(mains) != 1 { 588 t.Fatalf("more than one main.main DIE") 589 } 590 maindie := mains[0] 591 592 // Vet the main.main DIE 593 if maindie.Tag != dwarf.TagSubprogram { 594 t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag) 595 } 596 597 // Walk main's children and pick out the inlined subroutines 598 mainIdx := ex.idxFromOffset(maindie.Offset) 599 childDies := ex.Children(mainIdx) 600 exCount := 0 601 for _, child := range childDies { 602 if child.Tag == dwarf.TagInlinedSubroutine { 603 // Found an inlined subroutine, locate abstract origin. 604 ooff, originOK := child.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 605 if !originOK { 606 t.Fatalf("no abstract origin attr for inlined subroutine at offset %v", child.Offset) 607 } 608 originDIE := ex.entryFromOffset(ooff) 609 if originDIE == nil { 610 t.Fatalf("can't locate origin DIE at off %v", ooff) 611 } 612 613 if exCount >= len(expectedInl) { 614 t.Fatalf("too many inlined subroutines found in main.main") 615 } 616 617 // Name should check out. 618 expected := expectedInl[exCount] 619 if name, ok := originDIE.Val(dwarf.AttrName).(string); ok { 620 if name != expected { 621 t.Fatalf("expected inlined routine %s got %s", name, expected) 622 } 623 } 624 exCount++ 625 626 omap := make(map[dwarf.Offset]bool) 627 628 // Walk the child variables of the inlined routine. Each 629 // of them should have a distinct abstract origin-- if two 630 // vars point to the same origin things are definitely broken. 631 inlIdx := ex.idxFromOffset(child.Offset) 632 inlChildDies := ex.Children(inlIdx) 633 for _, k := range inlChildDies { 634 ooff, originOK := k.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 635 if !originOK { 636 t.Fatalf("no abstract origin attr for child of inlined subroutine at offset %v", k.Offset) 637 } 638 if _, found := omap[ooff]; found { 639 t.Fatalf("duplicate abstract origin at child of inlined subroutine at offset %v", k.Offset) 640 } 641 omap[ooff] = true 642 } 643 } 644 } 645 if exCount != len(expectedInl) { 646 t.Fatalf("not enough inlined subroutines found in main.main") 647 } 648 } 649 650 func abstractOriginSanity(t *testing.T, flags string) { 651 652 // Nothing special about net/http here, this is just a convenient 653 // way to pull in a lot of code. 654 const prog = ` 655 package main 656 657 import ( 658 "net/http" 659 "net/http/httptest" 660 ) 661 662 type statusHandler int 663 664 func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 665 w.WriteHeader(int(*h)) 666 } 667 668 func main() { 669 status := statusHandler(http.StatusNotFound) 670 s := httptest.NewServer(&status) 671 defer s.Close() 672 } 673 ` 674 dir, err := ioutil.TempDir("", "TestAbstractOriginSanity") 675 if err != nil { 676 t.Fatalf("could not create directory: %v", err) 677 } 678 defer os.RemoveAll(dir) 679 680 // Build with inlining, to exercise DWARF inlining support. 681 f := gobuild(t, dir, prog, flags) 682 683 d, err := f.DWARF() 684 if err != nil { 685 t.Fatalf("error reading DWARF: %v", err) 686 } 687 rdr := d.Reader() 688 ex := examiner{} 689 if err := ex.populate(rdr); err != nil { 690 t.Fatalf("error reading DWARF: %v", err) 691 } 692 693 // Make a pass through all DIEs looking for abstract origin 694 // references. 695 abscount := 0 696 for i, die := range ex.dies { 697 698 // Does it have an abstract origin? 699 ooff, originOK := die.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 700 if !originOK { 701 continue 702 } 703 704 // All abstract origin references should be resolvable. 705 abscount += 1 706 originDIE := ex.entryFromOffset(ooff) 707 if originDIE == nil { 708 ex.dumpEntry(i, false, 0) 709 t.Fatalf("unresolved abstract origin ref in DIE at offset 0x%x\n", die.Offset) 710 } 711 712 // Suppose that DIE X has parameter/variable children {K1, 713 // K2, ... KN}. If X has an abstract origin of A, then for 714 // each KJ, the abstract origin of KJ should be a child of A. 715 // Note that this same rule doesn't hold for non-variable DIEs. 716 pidx := ex.idxFromOffset(die.Offset) 717 if pidx < 0 { 718 t.Fatalf("can't locate DIE id") 719 } 720 kids := ex.Children(pidx) 721 for _, kid := range kids { 722 if kid.Tag != dwarf.TagVariable && 723 kid.Tag != dwarf.TagFormalParameter { 724 continue 725 } 726 kooff, originOK := kid.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 727 if !originOK { 728 continue 729 } 730 childOriginDIE := ex.entryFromOffset(kooff) 731 if childOriginDIE == nil { 732 ex.dumpEntry(i, false, 0) 733 t.Fatalf("unresolved abstract origin ref in DIE at offset %x", kid.Offset) 734 } 735 coidx := ex.idxFromOffset(childOriginDIE.Offset) 736 childOriginParent := ex.Parent(coidx) 737 if childOriginParent != originDIE { 738 ex.dumpEntry(i, false, 0) 739 t.Fatalf("unexpected parent of abstract origin DIE at offset %v", childOriginDIE.Offset) 740 } 741 } 742 } 743 if abscount == 0 { 744 t.Fatalf("no abstract origin refs found, something is wrong") 745 } 746 } 747 748 func TestAbstractOriginSanity(t *testing.T) { 749 testenv.MustHaveGoBuild(t) 750 751 if runtime.GOOS == "plan9" { 752 t.Skip("skipping on plan9; no DWARF symbol table in executables") 753 } 754 if runtime.GOOS == "solaris" { 755 t.Skip("skipping on solaris, pending resolution of issue #23168") 756 } 757 758 abstractOriginSanity(t, OptInl4) 759 } 760 761 func TestAbstractOriginSanityWithLocationLists(t *testing.T) { 762 testenv.MustHaveGoBuild(t) 763 764 if runtime.GOOS == "plan9" { 765 t.Skip("skipping on plan9; no DWARF symbol table in executables") 766 } 767 if runtime.GOOS == "solaris" { 768 t.Skip("skipping on solaris, pending resolution of issue #23168") 769 } 770 if runtime.GOARCH != "amd64" && runtime.GOARCH != "x86" { 771 t.Skip("skipping on not-amd64 not-x86; location lists not supported") 772 } 773 774 abstractOriginSanity(t, OptInl4DwLoc) 775 }