blob: 4e7413f7394985921402322e57710a4d1ab72777 [file] [log] [blame]
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ld
import (
objfilepkg "cmd/internal/objfile" // renamed to avoid conflict with objfile function
"debug/dwarf"
"internal/testenv"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"reflect"
"runtime"
"testing"
)
func TestRuntimeTypeDIEs(t *testing.T) {
testenv.MustHaveGoBuild(t)
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}
dir, err := ioutil.TempDir("", "TestRuntimeTypeDIEs")
if err != nil {
t.Fatalf("could not create directory: %v", err)
}
defer os.RemoveAll(dir)
f := gobuild(t, dir, `package main; func main() { }`)
defer f.Close()
dwarf, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
want := map[string]bool{
"runtime._type": true,
"runtime.arraytype": true,
"runtime.chantype": true,
"runtime.functype": true,
"runtime.maptype": true,
"runtime.ptrtype": true,
"runtime.slicetype": true,
"runtime.structtype": true,
"runtime.interfacetype": true,
"runtime.itab": true,
"runtime.imethod": true,
}
found := findTypes(t, dwarf, want)
if len(found) != len(want) {
t.Errorf("found %v, want %v", found, want)
}
}
func findTypes(t *testing.T, dw *dwarf.Data, want map[string]bool) (found map[string]bool) {
found = make(map[string]bool)
rdr := dw.Reader()
for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
switch entry.Tag {
case dwarf.TagTypedef:
if name, ok := entry.Val(dwarf.AttrName).(string); ok && want[name] {
found[name] = true
}
}
}
return
}
func gobuild(t *testing.T, dir string, testfile string) *objfilepkg.File {
src := filepath.Join(dir, "test.go")
dst := filepath.Join(dir, "out")
if err := ioutil.WriteFile(src, []byte(testfile), 0666); err != nil {
t.Fatal(err)
}
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", dst, src)
if b, err := cmd.CombinedOutput(); err != nil {
t.Logf("build: %s\n", b)
t.Fatalf("build error: %v", err)
}
f, err := objfilepkg.Open(dst)
if err != nil {
t.Fatal(err)
}
return f
}
func TestEmbeddedStructMarker(t *testing.T) {
testenv.MustHaveGoBuild(t)
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}
const prog = `
package main
import "fmt"
type Foo struct { v int }
type Bar struct {
Foo
name string
}
type Baz struct {
*Foo
name string
}
func main() {
bar := Bar{ Foo: Foo{v: 123}, name: "onetwothree"}
baz := Baz{ Foo: &bar.Foo, name: "123" }
fmt.Println(bar, baz)
}`
want := map[string]map[string]bool{
"main.Foo": map[string]bool{"v": false},
"main.Bar": map[string]bool{"Foo": true, "name": false},
"main.Baz": map[string]bool{"Foo": true, "name": false},
}
dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker")
if err != nil {
t.Fatalf("could not create directory: %v", err)
}
defer os.RemoveAll(dir)
f := gobuild(t, dir, prog)
defer f.Close()
d, err := f.DWARF()
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
rdr := d.Reader()
for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
switch entry.Tag {
case dwarf.TagStructType:
name := entry.Val(dwarf.AttrName).(string)
wantMembers := want[name]
if wantMembers == nil {
continue
}
gotMembers, err := findMembers(rdr)
if err != nil {
t.Fatalf("error reading DWARF: %v", err)
}
if !reflect.DeepEqual(gotMembers, wantMembers) {
t.Errorf("type %v: got map[member]embedded = %+v, want %+v", name, wantMembers, gotMembers)
}
delete(want, name)
}
}
if len(want) != 0 {
t.Errorf("failed to check all expected types: missing types = %+v", want)
}
}
func findMembers(rdr *dwarf.Reader) (map[string]bool, error) {
memberEmbedded := map[string]bool{}
// TODO(hyangah): define in debug/dwarf package
const goEmbeddedStruct = dwarf.Attr(0x2903)
for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
if err != nil {
return nil, err
}
switch entry.Tag {
case dwarf.TagMember:
name := entry.Val(dwarf.AttrName).(string)
embedded := entry.Val(goEmbeddedStruct).(bool)
memberEmbedded[name] = embedded
case 0:
return memberEmbedded, nil
}
}
return memberEmbedded, nil
}