github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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  	"internal/testenv"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"reflect"
    16  	"runtime"
    17  	"testing"
    18  )
    19  
    20  func TestRuntimeTypeDIEs(t *testing.T) {
    21  	testenv.MustHaveGoBuild(t)
    22  
    23  	if runtime.GOOS == "plan9" {
    24  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
    25  	}
    26  
    27  	dir, err := ioutil.TempDir("", "TestRuntimeTypeDIEs")
    28  	if err != nil {
    29  		t.Fatalf("could not create directory: %v", err)
    30  	}
    31  	defer os.RemoveAll(dir)
    32  
    33  	f := gobuild(t, dir, `package main; func main() { }`)
    34  	defer f.Close()
    35  
    36  	dwarf, err := f.DWARF()
    37  	if err != nil {
    38  		t.Fatalf("error reading DWARF: %v", err)
    39  	}
    40  
    41  	want := map[string]bool{
    42  		"runtime._type":         true,
    43  		"runtime.arraytype":     true,
    44  		"runtime.chantype":      true,
    45  		"runtime.functype":      true,
    46  		"runtime.maptype":       true,
    47  		"runtime.ptrtype":       true,
    48  		"runtime.slicetype":     true,
    49  		"runtime.structtype":    true,
    50  		"runtime.interfacetype": true,
    51  		"runtime.itab":          true,
    52  		"runtime.imethod":       true,
    53  	}
    54  
    55  	found := findTypes(t, dwarf, want)
    56  	if len(found) != len(want) {
    57  		t.Errorf("found %v, want %v", found, want)
    58  	}
    59  }
    60  
    61  func findTypes(t *testing.T, dw *dwarf.Data, want map[string]bool) (found map[string]bool) {
    62  	found = make(map[string]bool)
    63  	rdr := dw.Reader()
    64  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
    65  		if err != nil {
    66  			t.Fatalf("error reading DWARF: %v", err)
    67  		}
    68  		switch entry.Tag {
    69  		case dwarf.TagTypedef:
    70  			if name, ok := entry.Val(dwarf.AttrName).(string); ok && want[name] {
    71  				found[name] = true
    72  			}
    73  		}
    74  	}
    75  	return
    76  }
    77  
    78  func gobuild(t *testing.T, dir string, testfile string) *objfilepkg.File {
    79  	src := filepath.Join(dir, "test.go")
    80  	dst := filepath.Join(dir, "out")
    81  
    82  	if err := ioutil.WriteFile(src, []byte(testfile), 0666); err != nil {
    83  		t.Fatal(err)
    84  	}
    85  
    86  	cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dst, src)
    87  	if b, err := cmd.CombinedOutput(); err != nil {
    88  		t.Logf("build: %s\n", b)
    89  		t.Fatalf("build error: %v", err)
    90  	}
    91  
    92  	f, err := objfilepkg.Open(dst)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  	return f
    97  }
    98  
    99  func TestEmbeddedStructMarker(t *testing.T) {
   100  	testenv.MustHaveGoBuild(t)
   101  
   102  	if runtime.GOOS == "plan9" {
   103  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   104  	}
   105  
   106  	const prog = `
   107  package main
   108  
   109  import "fmt"
   110  
   111  type Foo struct { v int }
   112  type Bar struct {
   113  	Foo
   114  	name string
   115  }
   116  type Baz struct {
   117  	*Foo
   118  	name string
   119  }
   120  
   121  func main() {
   122  	bar := Bar{ Foo: Foo{v: 123}, name: "onetwothree"}
   123  	baz := Baz{ Foo: &bar.Foo, name: "123" }
   124  	fmt.Println(bar, baz)
   125  }`
   126  
   127  	want := map[string]map[string]bool{
   128  		"main.Foo": map[string]bool{"v": false},
   129  		"main.Bar": map[string]bool{"Foo": true, "name": false},
   130  		"main.Baz": map[string]bool{"Foo": true, "name": false},
   131  	}
   132  
   133  	dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker")
   134  	if err != nil {
   135  		t.Fatalf("could not create directory: %v", err)
   136  	}
   137  	defer os.RemoveAll(dir)
   138  
   139  	f := gobuild(t, dir, prog)
   140  
   141  	defer f.Close()
   142  
   143  	d, err := f.DWARF()
   144  	if err != nil {
   145  		t.Fatalf("error reading DWARF: %v", err)
   146  	}
   147  
   148  	rdr := d.Reader()
   149  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   150  		if err != nil {
   151  			t.Fatalf("error reading DWARF: %v", err)
   152  		}
   153  		switch entry.Tag {
   154  		case dwarf.TagStructType:
   155  			name := entry.Val(dwarf.AttrName).(string)
   156  			wantMembers := want[name]
   157  			if wantMembers == nil {
   158  				continue
   159  			}
   160  			gotMembers, err := findMembers(rdr)
   161  			if err != nil {
   162  				t.Fatalf("error reading DWARF: %v", err)
   163  			}
   164  
   165  			if !reflect.DeepEqual(gotMembers, wantMembers) {
   166  				t.Errorf("type %v: got map[member]embedded = %+v, want %+v", name, wantMembers, gotMembers)
   167  			}
   168  			delete(want, name)
   169  		}
   170  	}
   171  	if len(want) != 0 {
   172  		t.Errorf("failed to check all expected types: missing types = %+v", want)
   173  	}
   174  }
   175  
   176  func findMembers(rdr *dwarf.Reader) (map[string]bool, error) {
   177  	memberEmbedded := map[string]bool{}
   178  	// TODO(hyangah): define in debug/dwarf package
   179  	const goEmbeddedStruct = dwarf.Attr(0x2903)
   180  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   181  		if err != nil {
   182  			return nil, err
   183  		}
   184  		switch entry.Tag {
   185  		case dwarf.TagMember:
   186  			name := entry.Val(dwarf.AttrName).(string)
   187  			embedded := entry.Val(goEmbeddedStruct).(bool)
   188  			memberEmbedded[name] = embedded
   189  		case 0:
   190  			return memberEmbedded, nil
   191  		}
   192  	}
   193  	return memberEmbedded, nil
   194  }