github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/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 varDeclCoordsAndSubrogramDeclFile(t *testing.T, testpoint string, expectFile int, expectLine int, directive string) { 312 313 prog := fmt.Sprintf("package main\n\nfunc main() {\n%s\nvar i int\ni = i\n}\n", directive) 314 315 dir, err := ioutil.TempDir("", testpoint) 316 if err != nil { 317 t.Fatalf("could not create directory: %v", err) 318 } 319 defer os.RemoveAll(dir) 320 321 f := gobuild(t, dir, prog, NoOpt) 322 323 d, err := f.DWARF() 324 if err != nil { 325 t.Fatalf("error reading DWARF: %v", err) 326 } 327 328 rdr := d.Reader() 329 ex := examiner{} 330 if err := ex.populate(rdr); err != nil { 331 t.Fatalf("error reading DWARF: %v", err) 332 } 333 334 // Locate the main.main DIE 335 mains := ex.Named("main.main") 336 if len(mains) == 0 { 337 t.Fatalf("unable to locate DIE for main.main") 338 } 339 if len(mains) != 1 { 340 t.Fatalf("more than one main.main DIE") 341 } 342 maindie := mains[0] 343 344 // Vet the main.main DIE 345 if maindie.Tag != dwarf.TagSubprogram { 346 t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag) 347 } 348 349 // Walk main's children and select variable "i". 350 mainIdx := ex.idxFromOffset(maindie.Offset) 351 childDies := ex.Children(mainIdx) 352 var iEntry *dwarf.Entry 353 for _, child := range childDies { 354 if child.Tag == dwarf.TagVariable && child.Val(dwarf.AttrName).(string) == "i" { 355 iEntry = child 356 break 357 } 358 } 359 if iEntry == nil { 360 t.Fatalf("didn't find DW_TAG_variable for i in main.main") 361 } 362 363 // Verify line/file attributes. 364 line := iEntry.Val(dwarf.AttrDeclLine) 365 if line == nil || line.(int64) != int64(expectLine) { 366 t.Errorf("DW_AT_decl_line for i is %v, want %d", line, expectLine) 367 } 368 369 file := maindie.Val(dwarf.AttrDeclFile) 370 if file == nil || file.(int64) != 1 { 371 t.Errorf("DW_AT_decl_file for main is %v, want %d", file, expectFile) 372 } 373 } 374 375 func TestVarDeclCoordsAndSubrogramDeclFile(t *testing.T) { 376 testenv.MustHaveGoBuild(t) 377 378 if runtime.GOOS == "plan9" { 379 t.Skip("skipping on plan9; no DWARF symbol table in executables") 380 } 381 382 varDeclCoordsAndSubrogramDeclFile(t, "TestVarDeclCoords", 1, 5, "") 383 } 384 385 func TestVarDeclCoordsWithLineDirective(t *testing.T) { 386 testenv.MustHaveGoBuild(t) 387 388 if runtime.GOOS == "plan9" { 389 t.Skip("skipping on plan9; no DWARF symbol table in executables") 390 } 391 392 varDeclCoordsAndSubrogramDeclFile(t, "TestVarDeclCoordsWithLineDirective", 393 2, 200, "//line /foobar.go:200") 394 } 395 396 // Helper class for supporting queries on DIEs within a DWARF .debug_info 397 // section. Invoke the populate() method below passing in a dwarf.Reader, 398 // which will read in all DIEs and keep track of parent/child 399 // relationships. Queries can then be made to ask for DIEs by name or 400 // by offset. This will hopefully reduce boilerplate for future test 401 // writing. 402 403 type examiner struct { 404 dies []*dwarf.Entry 405 idxByOffset map[dwarf.Offset]int 406 kids map[int][]int 407 parent map[int]int 408 byname map[string][]int 409 } 410 411 // Populate the examiner using the DIEs read from rdr. 412 func (ex *examiner) populate(rdr *dwarf.Reader) error { 413 ex.idxByOffset = make(map[dwarf.Offset]int) 414 ex.kids = make(map[int][]int) 415 ex.parent = make(map[int]int) 416 ex.byname = make(map[string][]int) 417 var nesting []int 418 for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() { 419 if err != nil { 420 return err 421 } 422 if entry.Tag == 0 { 423 // terminator 424 if len(nesting) == 0 { 425 return errors.New("nesting stack underflow") 426 } 427 nesting = nesting[:len(nesting)-1] 428 continue 429 } 430 idx := len(ex.dies) 431 ex.dies = append(ex.dies, entry) 432 if _, found := ex.idxByOffset[entry.Offset]; found { 433 return errors.New("DIE clash on offset") 434 } 435 ex.idxByOffset[entry.Offset] = idx 436 if name, ok := entry.Val(dwarf.AttrName).(string); ok { 437 ex.byname[name] = append(ex.byname[name], idx) 438 } 439 if len(nesting) > 0 { 440 parent := nesting[len(nesting)-1] 441 ex.kids[parent] = append(ex.kids[parent], idx) 442 ex.parent[idx] = parent 443 } 444 if entry.Children { 445 nesting = append(nesting, idx) 446 } 447 } 448 if len(nesting) > 0 { 449 return errors.New("unterminated child sequence") 450 } 451 return nil 452 } 453 454 func indent(ilevel int) { 455 for i := 0; i < ilevel; i++ { 456 fmt.Printf(" ") 457 } 458 } 459 460 // For debugging new tests 461 func (ex *examiner) dumpEntry(idx int, dumpKids bool, ilevel int) error { 462 if idx >= len(ex.dies) { 463 msg := fmt.Sprintf("bad DIE %d: index out of range\n", idx) 464 return errors.New(msg) 465 } 466 entry := ex.dies[idx] 467 indent(ilevel) 468 fmt.Printf("0x%x: %v\n", idx, entry.Tag) 469 for _, f := range entry.Field { 470 indent(ilevel) 471 fmt.Printf("at=%v val=0x%x\n", f.Attr, f.Val) 472 } 473 if dumpKids { 474 ksl := ex.kids[idx] 475 for _, k := range ksl { 476 ex.dumpEntry(k, true, ilevel+2) 477 } 478 } 479 return nil 480 } 481 482 // Given a DIE offset, return the previously read dwarf.Entry, or nil 483 func (ex *examiner) entryFromOffset(off dwarf.Offset) *dwarf.Entry { 484 if idx, found := ex.idxByOffset[off]; found && idx != -1 { 485 return ex.entryFromIdx(idx) 486 } 487 return nil 488 } 489 490 // Return the ID that that examiner uses to refer to the DIE at offset off 491 func (ex *examiner) idxFromOffset(off dwarf.Offset) int { 492 if idx, found := ex.idxByOffset[off]; found { 493 return idx 494 } 495 return -1 496 } 497 498 // Return the dwarf.Entry pointer for the DIE with id 'idx' 499 func (ex *examiner) entryFromIdx(idx int) *dwarf.Entry { 500 if idx >= len(ex.dies) || idx < 0 { 501 return nil 502 } 503 return ex.dies[idx] 504 } 505 506 // Returns a list of child entries for a die with ID 'idx' 507 func (ex *examiner) Children(idx int) []*dwarf.Entry { 508 sl := ex.kids[idx] 509 ret := make([]*dwarf.Entry, len(sl)) 510 for i, k := range sl { 511 ret[i] = ex.entryFromIdx(k) 512 } 513 return ret 514 } 515 516 // Returns parent DIE for DIE 'idx', or nil if the DIE is top level 517 func (ex *examiner) Parent(idx int) *dwarf.Entry { 518 p, found := ex.parent[idx] 519 if !found { 520 return nil 521 } 522 return ex.entryFromIdx(p) 523 } 524 525 // Return a list of all DIEs with name 'name'. When searching for DIEs 526 // by name, keep in mind that the returned results will include child 527 // DIEs such as params/variables. For example, asking for all DIEs named 528 // "p" for even a small program will give you 400-500 entries. 529 func (ex *examiner) Named(name string) []*dwarf.Entry { 530 sl := ex.byname[name] 531 ret := make([]*dwarf.Entry, len(sl)) 532 for i, k := range sl { 533 ret[i] = ex.entryFromIdx(k) 534 } 535 return ret 536 } 537 538 func TestInlinedRoutineRecords(t *testing.T) { 539 testenv.MustHaveGoBuild(t) 540 541 if runtime.GOOS == "plan9" { 542 t.Skip("skipping on plan9; no DWARF symbol table in executables") 543 } 544 if runtime.GOOS == "solaris" { 545 t.Skip("skipping on solaris, pending resolution of issue #23168") 546 } 547 548 const prog = ` 549 package main 550 551 var G int 552 553 func noinline(x int) int { 554 defer func() { G += x }() 555 return x 556 } 557 558 func cand(x, y int) int { 559 return noinline(x+y) ^ (y - x) 560 } 561 562 func main() { 563 x := cand(G*G,G|7%G) 564 G = x 565 } 566 ` 567 dir, err := ioutil.TempDir("", "TestInlinedRoutineRecords") 568 if err != nil { 569 t.Fatalf("could not create directory: %v", err) 570 } 571 defer os.RemoveAll(dir) 572 573 // Note: this is a build with "-l=4", as opposed to "-l -N". The 574 // test is intended to verify DWARF that is only generated when 575 // the inliner is active. 576 f := gobuild(t, dir, prog, OptInl4) 577 578 d, err := f.DWARF() 579 if err != nil { 580 t.Fatalf("error reading DWARF: %v", err) 581 } 582 583 // The inlined subroutines we expect to visit 584 expectedInl := []string{"main.cand"} 585 586 rdr := d.Reader() 587 ex := examiner{} 588 if err := ex.populate(rdr); err != nil { 589 t.Fatalf("error reading DWARF: %v", err) 590 } 591 592 // Locate the main.main DIE 593 mains := ex.Named("main.main") 594 if len(mains) == 0 { 595 t.Fatalf("unable to locate DIE for main.main") 596 } 597 if len(mains) != 1 { 598 t.Fatalf("more than one main.main DIE") 599 } 600 maindie := mains[0] 601 602 // Vet the main.main DIE 603 if maindie.Tag != dwarf.TagSubprogram { 604 t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag) 605 } 606 607 // Walk main's children and pick out the inlined subroutines 608 mainIdx := ex.idxFromOffset(maindie.Offset) 609 childDies := ex.Children(mainIdx) 610 exCount := 0 611 for _, child := range childDies { 612 if child.Tag == dwarf.TagInlinedSubroutine { 613 // Found an inlined subroutine, locate abstract origin. 614 ooff, originOK := child.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 615 if !originOK { 616 t.Fatalf("no abstract origin attr for inlined subroutine at offset %v", child.Offset) 617 } 618 originDIE := ex.entryFromOffset(ooff) 619 if originDIE == nil { 620 t.Fatalf("can't locate origin DIE at off %v", ooff) 621 } 622 623 if exCount >= len(expectedInl) { 624 t.Fatalf("too many inlined subroutines found in main.main") 625 } 626 627 // Name should check out. 628 expected := expectedInl[exCount] 629 if name, ok := originDIE.Val(dwarf.AttrName).(string); ok { 630 if name != expected { 631 t.Fatalf("expected inlined routine %s got %s", name, expected) 632 } 633 } 634 exCount++ 635 636 omap := make(map[dwarf.Offset]bool) 637 638 // Walk the child variables of the inlined routine. Each 639 // of them should have a distinct abstract origin-- if two 640 // vars point to the same origin things are definitely broken. 641 inlIdx := ex.idxFromOffset(child.Offset) 642 inlChildDies := ex.Children(inlIdx) 643 for _, k := range inlChildDies { 644 ooff, originOK := k.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 645 if !originOK { 646 t.Fatalf("no abstract origin attr for child of inlined subroutine at offset %v", k.Offset) 647 } 648 if _, found := omap[ooff]; found { 649 t.Fatalf("duplicate abstract origin at child of inlined subroutine at offset %v", k.Offset) 650 } 651 omap[ooff] = true 652 } 653 } 654 } 655 if exCount != len(expectedInl) { 656 t.Fatalf("not enough inlined subroutines found in main.main") 657 } 658 } 659 660 func abstractOriginSanity(t *testing.T, flags string) { 661 662 // Nothing special about net/http here, this is just a convenient 663 // way to pull in a lot of code. 664 const prog = ` 665 package main 666 667 import ( 668 "net/http" 669 "net/http/httptest" 670 ) 671 672 type statusHandler int 673 674 func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 675 w.WriteHeader(int(*h)) 676 } 677 678 func main() { 679 status := statusHandler(http.StatusNotFound) 680 s := httptest.NewServer(&status) 681 defer s.Close() 682 } 683 ` 684 dir, err := ioutil.TempDir("", "TestAbstractOriginSanity") 685 if err != nil { 686 t.Fatalf("could not create directory: %v", err) 687 } 688 defer os.RemoveAll(dir) 689 690 // Build with inlining, to exercise DWARF inlining support. 691 f := gobuild(t, dir, prog, flags) 692 693 d, err := f.DWARF() 694 if err != nil { 695 t.Fatalf("error reading DWARF: %v", err) 696 } 697 rdr := d.Reader() 698 ex := examiner{} 699 if err := ex.populate(rdr); err != nil { 700 t.Fatalf("error reading DWARF: %v", err) 701 } 702 703 // Make a pass through all DIEs looking for abstract origin 704 // references. 705 abscount := 0 706 for i, die := range ex.dies { 707 708 // Does it have an abstract origin? 709 ooff, originOK := die.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 710 if !originOK { 711 continue 712 } 713 714 // All abstract origin references should be resolvable. 715 abscount += 1 716 originDIE := ex.entryFromOffset(ooff) 717 if originDIE == nil { 718 ex.dumpEntry(i, false, 0) 719 t.Fatalf("unresolved abstract origin ref in DIE at offset 0x%x\n", die.Offset) 720 } 721 722 // Suppose that DIE X has parameter/variable children {K1, 723 // K2, ... KN}. If X has an abstract origin of A, then for 724 // each KJ, the abstract origin of KJ should be a child of A. 725 // Note that this same rule doesn't hold for non-variable DIEs. 726 pidx := ex.idxFromOffset(die.Offset) 727 if pidx < 0 { 728 t.Fatalf("can't locate DIE id") 729 } 730 kids := ex.Children(pidx) 731 for _, kid := range kids { 732 if kid.Tag != dwarf.TagVariable && 733 kid.Tag != dwarf.TagFormalParameter { 734 continue 735 } 736 kooff, originOK := kid.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 737 if !originOK { 738 continue 739 } 740 childOriginDIE := ex.entryFromOffset(kooff) 741 if childOriginDIE == nil { 742 ex.dumpEntry(i, false, 0) 743 t.Fatalf("unresolved abstract origin ref in DIE at offset %x", kid.Offset) 744 } 745 coidx := ex.idxFromOffset(childOriginDIE.Offset) 746 childOriginParent := ex.Parent(coidx) 747 if childOriginParent != originDIE { 748 ex.dumpEntry(i, false, 0) 749 t.Fatalf("unexpected parent of abstract origin DIE at offset %v", childOriginDIE.Offset) 750 } 751 } 752 } 753 if abscount == 0 { 754 t.Fatalf("no abstract origin refs found, something is wrong") 755 } 756 } 757 758 func TestAbstractOriginSanity(t *testing.T) { 759 testenv.MustHaveGoBuild(t) 760 761 if runtime.GOOS == "plan9" { 762 t.Skip("skipping on plan9; no DWARF symbol table in executables") 763 } 764 if runtime.GOOS == "solaris" { 765 t.Skip("skipping on solaris, pending resolution of issue #23168") 766 } 767 768 abstractOriginSanity(t, OptInl4) 769 } 770 771 func TestAbstractOriginSanityWithLocationLists(t *testing.T) { 772 testenv.MustHaveGoBuild(t) 773 774 if runtime.GOOS == "plan9" { 775 t.Skip("skipping on plan9; no DWARF symbol table in executables") 776 } 777 if runtime.GOOS == "solaris" { 778 t.Skip("skipping on solaris, pending resolution of issue #23168") 779 } 780 if runtime.GOARCH != "amd64" && runtime.GOARCH != "x86" { 781 t.Skip("skipping on not-amd64 not-x86; location lists not supported") 782 } 783 784 abstractOriginSanity(t, OptInl4DwLoc) 785 }