Skip to content

Commit 778a60c

Browse files
prattmicgopherbot
authored andcommitted
cmd/link/internal/ld: split TestInlinedRoutineRecords
A later CL will add additional test cases for CallFile and CallLine with a //line directive. The parameter/variable checks have nothing to do with line numbers and will only serve to make the test more difficult to follow, so split this single mega-test into two: one for testing file/line and the other for testing parameters/variables. There are a few additional minor changes: 1. A missing AttrName is now an error. 2. Check added for AttrCallLine, which was previously untested. For golang#58648. Change-Id: I35e75ead766bcf910c58eb20541769349841f2b5 Reviewed-on: https://go-review.googlesource.com/c/go/+/470875 TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Than McIntosh <[email protected]> Auto-Submit: Michael Pratt <[email protected]> Reviewed-by: Than McIntosh <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 20da76d commit 778a60c

File tree

1 file changed

+179
-84
lines changed

1 file changed

+179
-84
lines changed

src/cmd/link/internal/ld/dwarf_test.go

Lines changed: 179 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,121 @@ func main() {
505505
}
506506
}
507507

508-
func TestInlinedRoutineRecords(t *testing.T) {
508+
// TestInlinedRoutineCallFileLine tests the call file and line records for an
509+
// inlined subroutine.
510+
func TestInlinedRoutineCallFileLine(t *testing.T) {
511+
testenv.MustHaveGoBuild(t)
512+
513+
if runtime.GOOS == "plan9" {
514+
t.Skip("skipping on plan9; no DWARF symbol table in executables")
515+
}
516+
517+
t.Parallel()
518+
519+
const prog = `
520+
package main
521+
522+
var G int
523+
524+
//go:noinline
525+
func notinlined() int {
526+
return 42
527+
}
528+
529+
func inlined() int {
530+
return notinlined()
531+
}
532+
533+
func main() {
534+
x := inlined()
535+
G = x
536+
}
537+
`
538+
// Note: this is a build with "-l=4", as opposed to "-l -N". The
539+
// test is intended to verify DWARF that is only generated when
540+
// the inliner is active. We're only going to look at the DWARF for
541+
// main.main, however, hence we build with "-gcflags=-l=4" as opposed
542+
// to "-gcflags=all=-l=4".
543+
d, ex := gobuildAndExamine(t, prog, OptInl4)
544+
545+
const (
546+
callFile = "test.go" // basename
547+
callLine = 16
548+
)
549+
550+
maindie := findSubprogramDIE(t, ex, "main.main")
551+
552+
// Walk main's children and pick out the inlined subroutines
553+
mainIdx := ex.IdxFromOffset(maindie.Offset)
554+
childDies := ex.Children(mainIdx)
555+
found := false
556+
for _, child := range childDies {
557+
if child.Tag != dwarf.TagInlinedSubroutine {
558+
continue
559+
}
560+
561+
// Found an inlined subroutine.
562+
if found {
563+
t.Fatalf("Found multiple inlined subroutines, expect only one")
564+
}
565+
found = true
566+
567+
// Locate abstract origin.
568+
ooff, originOK := child.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
569+
if !originOK {
570+
t.Fatalf("no abstract origin attr for inlined subroutine at offset %v", child.Offset)
571+
}
572+
originDIE := ex.EntryFromOffset(ooff)
573+
if originDIE == nil {
574+
t.Fatalf("can't locate origin DIE at off %v", ooff)
575+
}
576+
577+
// Name should check out.
578+
name, ok := originDIE.Val(dwarf.AttrName).(string)
579+
if !ok {
580+
t.Fatalf("no name attr for inlined subroutine at offset %v", child.Offset)
581+
}
582+
if name != "main.inlined" {
583+
t.Fatalf("expected inlined routine %s got %s", "main.cand", name)
584+
}
585+
586+
// Verify that the call_file attribute for the inlined
587+
// instance is ok. In this case it should match the file
588+
// for the main routine. To do this we need to locate the
589+
// compilation unit DIE that encloses what we're looking
590+
// at; this can be done with the examiner.
591+
cf, cfOK := child.Val(dwarf.AttrCallFile).(int64)
592+
if !cfOK {
593+
t.Fatalf("no call_file attr for inlined subroutine at offset %v", child.Offset)
594+
}
595+
file, err := ex.FileRef(d, mainIdx, cf)
596+
if err != nil {
597+
t.Errorf("FileRef: %v", err)
598+
continue
599+
}
600+
base := filepath.Base(file)
601+
if base != callFile {
602+
t.Errorf("bad call_file attribute, found '%s', want '%s'",
603+
file, callFile)
604+
}
605+
606+
// Verify that the call_line attribute for the inlined
607+
// instance is ok.
608+
cl, clOK := child.Val(dwarf.AttrCallLine).(int64)
609+
if !clOK {
610+
t.Fatalf("no call_line attr for inlined subroutine at offset %v", child.Offset)
611+
}
612+
if cl != callLine {
613+
t.Errorf("bad call_line attribute, found %d, want %d", cl, callLine)
614+
}
615+
}
616+
if !found {
617+
t.Fatalf("not enough inlined subroutines found in main.main")
618+
}
619+
}
620+
621+
// TestInlinedRoutineArgsVars tests the argument and variable records for an inlined subroutine.
622+
func TestInlinedRoutineArgsVars(t *testing.T) {
509623
testenv.MustHaveGoBuild(t)
510624

511625
if runtime.GOOS == "plan9" {
@@ -529,112 +643,93 @@ func cand(x, y int) int {
529643
}
530644
531645
func main() {
532-
x := cand(G*G,G|7%G)
533-
G = x
646+
x := cand(G*G,G|7%G)
647+
G = x
534648
}
535649
`
536650
// Note: this is a build with "-l=4", as opposed to "-l -N". The
537651
// test is intended to verify DWARF that is only generated when
538652
// the inliner is active. We're only going to look at the DWARF for
539653
// main.main, however, hence we build with "-gcflags=-l=4" as opposed
540654
// to "-gcflags=all=-l=4".
541-
d, ex := gobuildAndExamine(t, prog, OptInl4)
542-
543-
// The inlined subroutines we expect to visit
544-
expectedInl := []string{"main.cand"}
655+
_, ex := gobuildAndExamine(t, prog, OptInl4)
545656

546657
maindie := findSubprogramDIE(t, ex, "main.main")
547658

548659
// Walk main's children and pick out the inlined subroutines
549660
mainIdx := ex.IdxFromOffset(maindie.Offset)
550661
childDies := ex.Children(mainIdx)
551-
exCount := 0
662+
found := false
552663
for _, child := range childDies {
553-
if child.Tag == dwarf.TagInlinedSubroutine {
554-
// Found an inlined subroutine, locate abstract origin.
555-
ooff, originOK := child.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
556-
if !originOK {
557-
t.Fatalf("no abstract origin attr for inlined subroutine at offset %v", child.Offset)
558-
}
559-
originDIE := ex.EntryFromOffset(ooff)
560-
if originDIE == nil {
561-
t.Fatalf("can't locate origin DIE at off %v", ooff)
562-
}
664+
if child.Tag != dwarf.TagInlinedSubroutine {
665+
continue
666+
}
563667

564-
// Walk the children of the abstract subroutine. We expect
565-
// to see child variables there, even if (perhaps due to
566-
// optimization) there are no references to them from the
567-
// inlined subroutine DIE.
568-
absFcnIdx := ex.IdxFromOffset(ooff)
569-
absFcnChildDies := ex.Children(absFcnIdx)
570-
if len(absFcnChildDies) != 2 {
571-
t.Fatalf("expected abstract function: expected 2 children, got %d children", len(absFcnChildDies))
572-
}
573-
formalCount := 0
574-
for _, absChild := range absFcnChildDies {
575-
if absChild.Tag == dwarf.TagFormalParameter {
576-
formalCount += 1
577-
continue
578-
}
579-
t.Fatalf("abstract function child DIE: expected formal, got %v", absChild.Tag)
580-
}
581-
if formalCount != 2 {
582-
t.Fatalf("abstract function DIE: expected 2 formals, got %d", formalCount)
583-
}
668+
// Found an inlined subroutine.
669+
if found {
670+
t.Fatalf("Found multiple inlined subroutines, expect only one")
671+
}
672+
found = true
584673

585-
if exCount >= len(expectedInl) {
586-
t.Fatalf("too many inlined subroutines found in main.main")
587-
}
674+
// Locate abstract origin.
675+
ooff, originOK := child.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
676+
if !originOK {
677+
t.Fatalf("no abstract origin attr for inlined subroutine at offset %v", child.Offset)
678+
}
679+
originDIE := ex.EntryFromOffset(ooff)
680+
if originDIE == nil {
681+
t.Fatalf("can't locate origin DIE at off %v", ooff)
682+
}
588683

589-
// Name should check out.
590-
expected := expectedInl[exCount]
591-
if name, ok := originDIE.Val(dwarf.AttrName).(string); ok {
592-
if name != expected {
593-
t.Fatalf("expected inlined routine %s got %s", name, expected)
594-
}
595-
}
596-
exCount++
597-
598-
// Verify that the call_file attribute for the inlined
599-
// instance is ok. In this case it should match the file
600-
// for the main routine. To do this we need to locate the
601-
// compilation unit DIE that encloses what we're looking
602-
// at; this can be done with the examiner.
603-
cf, cfOK := child.Val(dwarf.AttrCallFile).(int64)
604-
if !cfOK {
605-
t.Fatalf("no call_file attr for inlined subroutine at offset %v", child.Offset)
606-
}
607-
file, err := ex.FileRef(d, mainIdx, cf)
608-
if err != nil {
609-
t.Errorf("FileRef: %v", err)
684+
// Name should check out.
685+
name, ok := originDIE.Val(dwarf.AttrName).(string)
686+
if !ok {
687+
t.Fatalf("no name attr for inlined subroutine at offset %v", child.Offset)
688+
}
689+
if name != "main.cand" {
690+
t.Fatalf("expected inlined routine %s got %s", "main.cand", name)
691+
}
692+
693+
// Walk the children of the abstract subroutine. We expect
694+
// to see child variables there, even if (perhaps due to
695+
// optimization) there are no references to them from the
696+
// inlined subroutine DIE.
697+
absFcnIdx := ex.IdxFromOffset(ooff)
698+
absFcnChildDies := ex.Children(absFcnIdx)
699+
if len(absFcnChildDies) != 2 {
700+
t.Fatalf("expected abstract function: expected 2 children, got %d children", len(absFcnChildDies))
701+
}
702+
formalCount := 0
703+
for _, absChild := range absFcnChildDies {
704+
if absChild.Tag == dwarf.TagFormalParameter {
705+
formalCount += 1
610706
continue
611707
}
612-
base := filepath.Base(file)
613-
if base != "test.go" {
614-
t.Errorf("bad call_file attribute, found '%s', want '%s'",
615-
file, "test.go")
616-
}
708+
t.Fatalf("abstract function child DIE: expected formal, got %v", absChild.Tag)
709+
}
710+
if formalCount != 2 {
711+
t.Fatalf("abstract function DIE: expected 2 formals, got %d", formalCount)
712+
}
617713

618-
omap := make(map[dwarf.Offset]bool)
619-
620-
// Walk the child variables of the inlined routine. Each
621-
// of them should have a distinct abstract origin-- if two
622-
// vars point to the same origin things are definitely broken.
623-
inlIdx := ex.IdxFromOffset(child.Offset)
624-
inlChildDies := ex.Children(inlIdx)
625-
for _, k := range inlChildDies {
626-
ooff, originOK := k.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
627-
if !originOK {
628-
t.Fatalf("no abstract origin attr for child of inlined subroutine at offset %v", k.Offset)
629-
}
630-
if _, found := omap[ooff]; found {
631-
t.Fatalf("duplicate abstract origin at child of inlined subroutine at offset %v", k.Offset)
632-
}
633-
omap[ooff] = true
714+
omap := make(map[dwarf.Offset]bool)
715+
716+
// Walk the child variables of the inlined routine. Each
717+
// of them should have a distinct abstract origin-- if two
718+
// vars point to the same origin things are definitely broken.
719+
inlIdx := ex.IdxFromOffset(child.Offset)
720+
inlChildDies := ex.Children(inlIdx)
721+
for _, k := range inlChildDies {
722+
ooff, originOK := k.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
723+
if !originOK {
724+
t.Fatalf("no abstract origin attr for child of inlined subroutine at offset %v", k.Offset)
725+
}
726+
if _, found := omap[ooff]; found {
727+
t.Fatalf("duplicate abstract origin at child of inlined subroutine at offset %v", k.Offset)
634728
}
729+
omap[ooff] = true
635730
}
636731
}
637-
if exCount != len(expectedInl) {
732+
if !found {
638733
t.Fatalf("not enough inlined subroutines found in main.main")
639734
}
640735
}

0 commit comments

Comments
 (0)