...
Run Format

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

Documentation: cmd/link/internal/ld

  // 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
  }
  

View as plain text