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 }