github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/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  	intdwarf "github.com/gagliardetto/golang-go/cmd/internal/dwarf"
     9  	objfilepkg "github.com/gagliardetto/golang-go/cmd/internal/objfile" // renamed to avoid conflict with objfile function
    10  	"debug/dwarf"
    11  	"debug/pe"
    12  	"errors"
    13  	"fmt"
    14  	"github.com/gagliardetto/golang-go/not-internal/testenv"
    15  	"io"
    16  	"io/ioutil"
    17  	"os"
    18  	"os/exec"
    19  	"path/filepath"
    20  	"reflect"
    21  	"runtime"
    22  	"strconv"
    23  	"strings"
    24  	"testing"
    25  )
    26  
    27  const (
    28  	DefaultOpt = "-gcflags="
    29  	NoOpt      = "-gcflags=-l -N"
    30  	OptInl4    = "-gcflags=-l=4"
    31  	OptAllInl4 = "-gcflags=all=-l=4"
    32  )
    33  
    34  func TestRuntimeTypesPresent(t *testing.T) {
    35  	t.Parallel()
    36  	testenv.MustHaveGoBuild(t)
    37  
    38  	if runtime.GOOS == "plan9" {
    39  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
    40  	}
    41  
    42  	dir, err := ioutil.TempDir("", "TestRuntimeTypesPresent")
    43  	if err != nil {
    44  		t.Fatalf("could not create directory: %v", err)
    45  	}
    46  	defer os.RemoveAll(dir)
    47  
    48  	f := gobuild(t, dir, `package main; func main() { }`, NoOpt)
    49  	defer f.Close()
    50  
    51  	dwarf, err := f.DWARF()
    52  	if err != nil {
    53  		t.Fatalf("error reading DWARF: %v", err)
    54  	}
    55  
    56  	want := map[string]bool{
    57  		"runtime._type":         true,
    58  		"runtime.arraytype":     true,
    59  		"runtime.chantype":      true,
    60  		"runtime.functype":      true,
    61  		"runtime.maptype":       true,
    62  		"runtime.ptrtype":       true,
    63  		"runtime.slicetype":     true,
    64  		"runtime.structtype":    true,
    65  		"runtime.interfacetype": true,
    66  		"runtime.itab":          true,
    67  		"runtime.imethod":       true,
    68  	}
    69  
    70  	found := findTypes(t, dwarf, want)
    71  	if len(found) != len(want) {
    72  		t.Errorf("found %v, want %v", found, want)
    73  	}
    74  }
    75  
    76  func findTypes(t *testing.T, dw *dwarf.Data, want map[string]bool) (found map[string]bool) {
    77  	found = make(map[string]bool)
    78  	rdr := dw.Reader()
    79  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
    80  		if err != nil {
    81  			t.Fatalf("error reading DWARF: %v", err)
    82  		}
    83  		switch entry.Tag {
    84  		case dwarf.TagTypedef:
    85  			if name, ok := entry.Val(dwarf.AttrName).(string); ok && want[name] {
    86  				found[name] = true
    87  			}
    88  		}
    89  	}
    90  	return
    91  }
    92  
    93  type builtFile struct {
    94  	*objfilepkg.File
    95  	path string
    96  }
    97  
    98  func gobuild(t *testing.T, dir string, testfile string, gcflags string) *builtFile {
    99  	src := filepath.Join(dir, "test.go")
   100  	dst := filepath.Join(dir, "out.exe")
   101  
   102  	if err := ioutil.WriteFile(src, []byte(testfile), 0666); err != nil {
   103  		t.Fatal(err)
   104  	}
   105  
   106  	cmd := exec.Command(testenv.GoToolPath(t), "build", gcflags, "-o", dst, src)
   107  	if b, err := cmd.CombinedOutput(); err != nil {
   108  		t.Logf("build: %s\n", b)
   109  		t.Fatalf("build error: %v", err)
   110  	}
   111  
   112  	f, err := objfilepkg.Open(dst)
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	return &builtFile{f, dst}
   117  }
   118  
   119  // Similar to gobuild() above, but uses a main package instead of a test.go file.
   120  
   121  func gobuildTestdata(t *testing.T, tdir string, pkgDir string, gcflags string) *builtFile {
   122  	dst := filepath.Join(tdir, "out.exe")
   123  
   124  	// Run a build with an updated GOPATH
   125  	cmd := exec.Command(testenv.GoToolPath(t), "build", gcflags, "-o", dst)
   126  	cmd.Dir = pkgDir
   127  	if b, err := cmd.CombinedOutput(); err != nil {
   128  		t.Logf("build: %s\n", b)
   129  		t.Fatalf("build error: %v", err)
   130  	}
   131  
   132  	f, err := objfilepkg.Open(dst)
   133  	if err != nil {
   134  		t.Fatal(err)
   135  	}
   136  	return &builtFile{f, dst}
   137  }
   138  
   139  func TestEmbeddedStructMarker(t *testing.T) {
   140  	t.Parallel()
   141  	testenv.MustHaveGoBuild(t)
   142  
   143  	if runtime.GOOS == "plan9" {
   144  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   145  	}
   146  
   147  	const prog = `
   148  package main
   149  
   150  import "fmt"
   151  
   152  type Foo struct { v int }
   153  type Bar struct {
   154  	Foo
   155  	name string
   156  }
   157  type Baz struct {
   158  	*Foo
   159  	name string
   160  }
   161  
   162  func main() {
   163  	bar := Bar{ Foo: Foo{v: 123}, name: "onetwothree"}
   164  	baz := Baz{ Foo: &bar.Foo, name: "123" }
   165  	fmt.Println(bar, baz)
   166  }`
   167  
   168  	want := map[string]map[string]bool{
   169  		"main.Foo": {"v": false},
   170  		"main.Bar": {"Foo": true, "name": false},
   171  		"main.Baz": {"Foo": true, "name": false},
   172  	}
   173  
   174  	dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker")
   175  	if err != nil {
   176  		t.Fatalf("could not create directory: %v", err)
   177  	}
   178  	defer os.RemoveAll(dir)
   179  
   180  	f := gobuild(t, dir, prog, NoOpt)
   181  
   182  	defer f.Close()
   183  
   184  	d, err := f.DWARF()
   185  	if err != nil {
   186  		t.Fatalf("error reading DWARF: %v", err)
   187  	}
   188  
   189  	rdr := d.Reader()
   190  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   191  		if err != nil {
   192  			t.Fatalf("error reading DWARF: %v", err)
   193  		}
   194  		switch entry.Tag {
   195  		case dwarf.TagStructType:
   196  			name := entry.Val(dwarf.AttrName).(string)
   197  			wantMembers := want[name]
   198  			if wantMembers == nil {
   199  				continue
   200  			}
   201  			gotMembers, err := findMembers(rdr)
   202  			if err != nil {
   203  				t.Fatalf("error reading DWARF: %v", err)
   204  			}
   205  
   206  			if !reflect.DeepEqual(gotMembers, wantMembers) {
   207  				t.Errorf("type %v: got map[member]embedded = %+v, want %+v", name, wantMembers, gotMembers)
   208  			}
   209  			delete(want, name)
   210  		}
   211  	}
   212  	if len(want) != 0 {
   213  		t.Errorf("failed to check all expected types: missing types = %+v", want)
   214  	}
   215  }
   216  
   217  func findMembers(rdr *dwarf.Reader) (map[string]bool, error) {
   218  	memberEmbedded := map[string]bool{}
   219  	// TODO(hyangah): define in debug/dwarf package
   220  	const goEmbeddedStruct = dwarf.Attr(intdwarf.DW_AT_go_embedded_field)
   221  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   222  		if err != nil {
   223  			return nil, err
   224  		}
   225  		switch entry.Tag {
   226  		case dwarf.TagMember:
   227  			name := entry.Val(dwarf.AttrName).(string)
   228  			embedded := entry.Val(goEmbeddedStruct).(bool)
   229  			memberEmbedded[name] = embedded
   230  		case 0:
   231  			return memberEmbedded, nil
   232  		}
   233  	}
   234  	return memberEmbedded, nil
   235  }
   236  
   237  func TestSizes(t *testing.T) {
   238  	if runtime.GOOS == "plan9" {
   239  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   240  	}
   241  	t.Parallel()
   242  
   243  	// DWARF sizes should never be -1.
   244  	// See issue #21097
   245  	const prog = `
   246  package main
   247  var x func()
   248  var y [4]func()
   249  func main() {
   250  	x = nil
   251  	y[0] = nil
   252  }
   253  `
   254  	dir, err := ioutil.TempDir("", "TestSizes")
   255  	if err != nil {
   256  		t.Fatalf("could not create directory: %v", err)
   257  	}
   258  	defer os.RemoveAll(dir)
   259  	f := gobuild(t, dir, prog, NoOpt)
   260  	defer f.Close()
   261  	d, err := f.DWARF()
   262  	if err != nil {
   263  		t.Fatalf("error reading DWARF: %v", err)
   264  	}
   265  	rdr := d.Reader()
   266  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   267  		if err != nil {
   268  			t.Fatalf("error reading DWARF: %v", err)
   269  		}
   270  		switch entry.Tag {
   271  		case dwarf.TagArrayType, dwarf.TagPointerType, dwarf.TagStructType, dwarf.TagBaseType, dwarf.TagSubroutineType, dwarf.TagTypedef:
   272  		default:
   273  			continue
   274  		}
   275  		typ, err := d.Type(entry.Offset)
   276  		if err != nil {
   277  			t.Fatalf("can't read type: %v", err)
   278  		}
   279  		if typ.Size() < 0 {
   280  			t.Errorf("subzero size %s %s %T", typ, entry.Tag, typ)
   281  		}
   282  	}
   283  }
   284  
   285  func TestFieldOverlap(t *testing.T) {
   286  	if runtime.GOOS == "plan9" {
   287  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   288  	}
   289  	t.Parallel()
   290  
   291  	// This test grew out of issue 21094, where specific sudog<T> DWARF types
   292  	// had elem fields set to values instead of pointers.
   293  	const prog = `
   294  package main
   295  
   296  var c chan string
   297  
   298  func main() {
   299  	c <- "foo"
   300  }
   301  `
   302  	dir, err := ioutil.TempDir("", "TestFieldOverlap")
   303  	if err != nil {
   304  		t.Fatalf("could not create directory: %v", err)
   305  	}
   306  	defer os.RemoveAll(dir)
   307  
   308  	f := gobuild(t, dir, prog, NoOpt)
   309  	defer f.Close()
   310  
   311  	d, err := f.DWARF()
   312  	if err != nil {
   313  		t.Fatalf("error reading DWARF: %v", err)
   314  	}
   315  
   316  	rdr := d.Reader()
   317  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   318  		if err != nil {
   319  			t.Fatalf("error reading DWARF: %v", err)
   320  		}
   321  		if entry.Tag != dwarf.TagStructType {
   322  			continue
   323  		}
   324  		typ, err := d.Type(entry.Offset)
   325  		if err != nil {
   326  			t.Fatalf("can't read type: %v", err)
   327  		}
   328  		s := typ.(*dwarf.StructType)
   329  		for i := 0; i < len(s.Field); i++ {
   330  			end := s.Field[i].ByteOffset + s.Field[i].Type.Size()
   331  			var limit int64
   332  			if i == len(s.Field)-1 {
   333  				limit = s.Size()
   334  			} else {
   335  				limit = s.Field[i+1].ByteOffset
   336  			}
   337  			if end > limit {
   338  				name := entry.Val(dwarf.AttrName).(string)
   339  				t.Fatalf("field %s.%s overlaps next field", name, s.Field[i].Name)
   340  			}
   341  		}
   342  	}
   343  }
   344  
   345  func varDeclCoordsAndSubrogramDeclFile(t *testing.T, testpoint string, expectFile string, expectLine int, directive string) {
   346  	t.Parallel()
   347  
   348  	prog := fmt.Sprintf("package main\n%s\nfunc main() {\n\nvar i int\ni = i\n}\n", directive)
   349  
   350  	dir, err := ioutil.TempDir("", testpoint)
   351  	if err != nil {
   352  		t.Fatalf("could not create directory: %v", err)
   353  	}
   354  	defer os.RemoveAll(dir)
   355  
   356  	f := gobuild(t, dir, prog, NoOpt)
   357  
   358  	d, err := f.DWARF()
   359  	if err != nil {
   360  		t.Fatalf("error reading DWARF: %v", err)
   361  	}
   362  
   363  	rdr := d.Reader()
   364  	ex := examiner{}
   365  	if err := ex.populate(rdr); err != nil {
   366  		t.Fatalf("error reading DWARF: %v", err)
   367  	}
   368  
   369  	// Locate the main.main DIE
   370  	mains := ex.Named("main.main")
   371  	if len(mains) == 0 {
   372  		t.Fatalf("unable to locate DIE for main.main")
   373  	}
   374  	if len(mains) != 1 {
   375  		t.Fatalf("more than one main.main DIE")
   376  	}
   377  	maindie := mains[0]
   378  
   379  	// Vet the main.main DIE
   380  	if maindie.Tag != dwarf.TagSubprogram {
   381  		t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag)
   382  	}
   383  
   384  	// Walk main's children and select variable "i".
   385  	mainIdx := ex.idxFromOffset(maindie.Offset)
   386  	childDies := ex.Children(mainIdx)
   387  	var iEntry *dwarf.Entry
   388  	for _, child := range childDies {
   389  		if child.Tag == dwarf.TagVariable && child.Val(dwarf.AttrName).(string) == "i" {
   390  			iEntry = child
   391  			break
   392  		}
   393  	}
   394  	if iEntry == nil {
   395  		t.Fatalf("didn't find DW_TAG_variable for i in main.main")
   396  	}
   397  
   398  	// Verify line/file attributes.
   399  	line := iEntry.Val(dwarf.AttrDeclLine)
   400  	if line == nil || line.(int64) != int64(expectLine) {
   401  		t.Errorf("DW_AT_decl_line for i is %v, want %d", line, expectLine)
   402  	}
   403  
   404  	fileIdx, fileIdxOK := maindie.Val(dwarf.AttrDeclFile).(int64)
   405  	if !fileIdxOK {
   406  		t.Errorf("missing or invalid DW_AT_decl_file for main")
   407  	}
   408  	file := ex.FileRef(t, d, mainIdx, fileIdx)
   409  	base := filepath.Base(file)
   410  	if base != expectFile {
   411  		t.Errorf("DW_AT_decl_file for main is %v, want %v", base, expectFile)
   412  	}
   413  }
   414  
   415  func TestVarDeclCoordsAndSubrogramDeclFile(t *testing.T) {
   416  	testenv.MustHaveGoBuild(t)
   417  
   418  	if runtime.GOOS == "plan9" {
   419  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   420  	}
   421  
   422  	varDeclCoordsAndSubrogramDeclFile(t, "TestVarDeclCoords", "test.go", 5, "")
   423  }
   424  
   425  func TestVarDeclCoordsWithLineDirective(t *testing.T) {
   426  	testenv.MustHaveGoBuild(t)
   427  
   428  	if runtime.GOOS == "plan9" {
   429  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   430  	}
   431  
   432  	varDeclCoordsAndSubrogramDeclFile(t, "TestVarDeclCoordsWithLineDirective",
   433  		"foobar.go", 202, "//line /foobar.go:200")
   434  }
   435  
   436  // Helper class for supporting queries on DIEs within a DWARF .debug_info
   437  // section. Invoke the populate() method below passing in a dwarf.Reader,
   438  // which will read in all DIEs and keep track of parent/child
   439  // relationships. Queries can then be made to ask for DIEs by name or
   440  // by offset. This will hopefully reduce boilerplate for future test
   441  // writing.
   442  
   443  type examiner struct {
   444  	dies        []*dwarf.Entry
   445  	idxByOffset map[dwarf.Offset]int
   446  	kids        map[int][]int
   447  	parent      map[int]int
   448  	byname      map[string][]int
   449  }
   450  
   451  // Populate the examiner using the DIEs read from rdr.
   452  func (ex *examiner) populate(rdr *dwarf.Reader) error {
   453  	ex.idxByOffset = make(map[dwarf.Offset]int)
   454  	ex.kids = make(map[int][]int)
   455  	ex.parent = make(map[int]int)
   456  	ex.byname = make(map[string][]int)
   457  	var nesting []int
   458  	for entry, err := rdr.Next(); entry != nil; entry, err = rdr.Next() {
   459  		if err != nil {
   460  			return err
   461  		}
   462  		if entry.Tag == 0 {
   463  			// terminator
   464  			if len(nesting) == 0 {
   465  				return errors.New("nesting stack underflow")
   466  			}
   467  			nesting = nesting[:len(nesting)-1]
   468  			continue
   469  		}
   470  		idx := len(ex.dies)
   471  		ex.dies = append(ex.dies, entry)
   472  		if _, found := ex.idxByOffset[entry.Offset]; found {
   473  			return errors.New("DIE clash on offset")
   474  		}
   475  		ex.idxByOffset[entry.Offset] = idx
   476  		if name, ok := entry.Val(dwarf.AttrName).(string); ok {
   477  			ex.byname[name] = append(ex.byname[name], idx)
   478  		}
   479  		if len(nesting) > 0 {
   480  			parent := nesting[len(nesting)-1]
   481  			ex.kids[parent] = append(ex.kids[parent], idx)
   482  			ex.parent[idx] = parent
   483  		}
   484  		if entry.Children {
   485  			nesting = append(nesting, idx)
   486  		}
   487  	}
   488  	if len(nesting) > 0 {
   489  		return errors.New("unterminated child sequence")
   490  	}
   491  	return nil
   492  }
   493  
   494  func indent(ilevel int) {
   495  	for i := 0; i < ilevel; i++ {
   496  		fmt.Printf("  ")
   497  	}
   498  }
   499  
   500  // For debugging new tests
   501  func (ex *examiner) dumpEntry(idx int, dumpKids bool, ilevel int) error {
   502  	if idx >= len(ex.dies) {
   503  		msg := fmt.Sprintf("bad DIE %d: index out of range\n", idx)
   504  		return errors.New(msg)
   505  	}
   506  	entry := ex.dies[idx]
   507  	indent(ilevel)
   508  	fmt.Printf("0x%x: %v\n", idx, entry.Tag)
   509  	for _, f := range entry.Field {
   510  		indent(ilevel)
   511  		fmt.Printf("at=%v val=0x%x\n", f.Attr, f.Val)
   512  	}
   513  	if dumpKids {
   514  		ksl := ex.kids[idx]
   515  		for _, k := range ksl {
   516  			ex.dumpEntry(k, true, ilevel+2)
   517  		}
   518  	}
   519  	return nil
   520  }
   521  
   522  // Given a DIE offset, return the previously read dwarf.Entry, or nil
   523  func (ex *examiner) entryFromOffset(off dwarf.Offset) *dwarf.Entry {
   524  	if idx, found := ex.idxByOffset[off]; found && idx != -1 {
   525  		return ex.entryFromIdx(idx)
   526  	}
   527  	return nil
   528  }
   529  
   530  // Return the ID that examiner uses to refer to the DIE at offset off
   531  func (ex *examiner) idxFromOffset(off dwarf.Offset) int {
   532  	if idx, found := ex.idxByOffset[off]; found {
   533  		return idx
   534  	}
   535  	return -1
   536  }
   537  
   538  // Return the dwarf.Entry pointer for the DIE with id 'idx'
   539  func (ex *examiner) entryFromIdx(idx int) *dwarf.Entry {
   540  	if idx >= len(ex.dies) || idx < 0 {
   541  		return nil
   542  	}
   543  	return ex.dies[idx]
   544  }
   545  
   546  // Returns a list of child entries for a die with ID 'idx'
   547  func (ex *examiner) Children(idx int) []*dwarf.Entry {
   548  	sl := ex.kids[idx]
   549  	ret := make([]*dwarf.Entry, len(sl))
   550  	for i, k := range sl {
   551  		ret[i] = ex.entryFromIdx(k)
   552  	}
   553  	return ret
   554  }
   555  
   556  // Returns parent DIE for DIE 'idx', or nil if the DIE is top level
   557  func (ex *examiner) Parent(idx int) *dwarf.Entry {
   558  	p, found := ex.parent[idx]
   559  	if !found {
   560  		return nil
   561  	}
   562  	return ex.entryFromIdx(p)
   563  }
   564  
   565  // ParentCU returns the enclosing compilation unit DIE for the DIE
   566  // with a given index, or nil if for some reason we can't establish a
   567  // parent.
   568  func (ex *examiner) ParentCU(idx int) *dwarf.Entry {
   569  	for {
   570  		parentDie := ex.Parent(idx)
   571  		if parentDie == nil {
   572  			return nil
   573  		}
   574  		if parentDie.Tag == dwarf.TagCompileUnit {
   575  			return parentDie
   576  		}
   577  		idx = ex.idxFromOffset(parentDie.Offset)
   578  	}
   579  }
   580  
   581  // FileRef takes a given DIE by index and a numeric file reference
   582  // (presumably from a decl_file or call_file attribute), looks up the
   583  // reference in the .debug_line file table, and returns the proper
   584  // string for it. We need to know which DIE is making the reference
   585  // so as find the right compilation unit.
   586  func (ex *examiner) FileRef(t *testing.T, dw *dwarf.Data, dieIdx int, fileRef int64) string {
   587  
   588  	// Find the parent compilation unit DIE for the specified DIE.
   589  	cuDie := ex.ParentCU(dieIdx)
   590  	if cuDie == nil {
   591  		t.Fatalf("no parent CU DIE for DIE with idx %d?", dieIdx)
   592  		return ""
   593  	}
   594  	// Construct a line reader and then use it to get the file string.
   595  	lr, lrerr := dw.LineReader(cuDie)
   596  	if lrerr != nil {
   597  		t.Fatal("d.LineReader: ", lrerr)
   598  		return ""
   599  	}
   600  	files := lr.Files()
   601  	if fileRef < 0 || int(fileRef) > len(files)-1 {
   602  		t.Fatalf("examiner.FileRef: malformed file reference %d", fileRef)
   603  		return ""
   604  	}
   605  	return files[fileRef].Name
   606  }
   607  
   608  // Return a list of all DIEs with name 'name'. When searching for DIEs
   609  // by name, keep in mind that the returned results will include child
   610  // DIEs such as params/variables. For example, asking for all DIEs named
   611  // "p" for even a small program will give you 400-500 entries.
   612  func (ex *examiner) Named(name string) []*dwarf.Entry {
   613  	sl := ex.byname[name]
   614  	ret := make([]*dwarf.Entry, len(sl))
   615  	for i, k := range sl {
   616  		ret[i] = ex.entryFromIdx(k)
   617  	}
   618  	return ret
   619  }
   620  
   621  func TestInlinedRoutineRecords(t *testing.T) {
   622  	testenv.MustHaveGoBuild(t)
   623  
   624  	if runtime.GOOS == "plan9" {
   625  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   626  	}
   627  	if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "darwin" {
   628  		t.Skip("skipping on solaris, illumos, and darwin, pending resolution of issue #23168")
   629  	}
   630  
   631  	t.Parallel()
   632  
   633  	const prog = `
   634  package main
   635  
   636  var G int
   637  
   638  func noinline(x int) int {
   639  	defer func() { G += x }()
   640  	return x
   641  }
   642  
   643  func cand(x, y int) int {
   644  	return noinline(x+y) ^ (y - x)
   645  }
   646  
   647  func main() {
   648      x := cand(G*G,G|7%G)
   649      G = x
   650  }
   651  `
   652  	dir, err := ioutil.TempDir("", "TestInlinedRoutineRecords")
   653  	if err != nil {
   654  		t.Fatalf("could not create directory: %v", err)
   655  	}
   656  	defer os.RemoveAll(dir)
   657  
   658  	// Note: this is a build with "-l=4", as opposed to "-l -N". The
   659  	// test is intended to verify DWARF that is only generated when
   660  	// the inliner is active. We're only going to look at the DWARF for
   661  	// main.main, however, hence we build with "-gcflags=-l=4" as opposed
   662  	// to "-gcflags=all=-l=4".
   663  	f := gobuild(t, dir, prog, OptInl4)
   664  
   665  	d, err := f.DWARF()
   666  	if err != nil {
   667  		t.Fatalf("error reading DWARF: %v", err)
   668  	}
   669  
   670  	// The inlined subroutines we expect to visit
   671  	expectedInl := []string{"main.cand"}
   672  
   673  	rdr := d.Reader()
   674  	ex := examiner{}
   675  	if err := ex.populate(rdr); err != nil {
   676  		t.Fatalf("error reading DWARF: %v", err)
   677  	}
   678  
   679  	// Locate the main.main DIE
   680  	mains := ex.Named("main.main")
   681  	if len(mains) == 0 {
   682  		t.Fatalf("unable to locate DIE for main.main")
   683  	}
   684  	if len(mains) != 1 {
   685  		t.Fatalf("more than one main.main DIE")
   686  	}
   687  	maindie := mains[0]
   688  
   689  	// Vet the main.main DIE
   690  	if maindie.Tag != dwarf.TagSubprogram {
   691  		t.Fatalf("unexpected tag %v on main.main DIE", maindie.Tag)
   692  	}
   693  
   694  	// Walk main's children and pick out the inlined subroutines
   695  	mainIdx := ex.idxFromOffset(maindie.Offset)
   696  	childDies := ex.Children(mainIdx)
   697  	exCount := 0
   698  	for _, child := range childDies {
   699  		if child.Tag == dwarf.TagInlinedSubroutine {
   700  			// Found an inlined subroutine, locate abstract origin.
   701  			ooff, originOK := child.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
   702  			if !originOK {
   703  				t.Fatalf("no abstract origin attr for inlined subroutine at offset %v", child.Offset)
   704  			}
   705  			originDIE := ex.entryFromOffset(ooff)
   706  			if originDIE == nil {
   707  				t.Fatalf("can't locate origin DIE at off %v", ooff)
   708  			}
   709  
   710  			// Walk the children of the abstract subroutine. We expect
   711  			// to see child variables there, even if (perhaps due to
   712  			// optimization) there are no references to them from the
   713  			// inlined subroutine DIE.
   714  			absFcnIdx := ex.idxFromOffset(ooff)
   715  			absFcnChildDies := ex.Children(absFcnIdx)
   716  			if len(absFcnChildDies) != 2 {
   717  				t.Fatalf("expected abstract function: expected 2 children, got %d children", len(absFcnChildDies))
   718  			}
   719  			formalCount := 0
   720  			for _, absChild := range absFcnChildDies {
   721  				if absChild.Tag == dwarf.TagFormalParameter {
   722  					formalCount += 1
   723  					continue
   724  				}
   725  				t.Fatalf("abstract function child DIE: expected formal, got %v", absChild.Tag)
   726  			}
   727  			if formalCount != 2 {
   728  				t.Fatalf("abstract function DIE: expected 2 formals, got %d", formalCount)
   729  			}
   730  
   731  			if exCount >= len(expectedInl) {
   732  				t.Fatalf("too many inlined subroutines found in main.main")
   733  			}
   734  
   735  			// Name should check out.
   736  			expected := expectedInl[exCount]
   737  			if name, ok := originDIE.Val(dwarf.AttrName).(string); ok {
   738  				if name != expected {
   739  					t.Fatalf("expected inlined routine %s got %s", name, expected)
   740  				}
   741  			}
   742  			exCount++
   743  
   744  			// Verify that the call_file attribute for the inlined
   745  			// instance is ok. In this case it should match the file
   746  			// for the main routine. To do this we need to locate the
   747  			// compilation unit DIE that encloses what we're looking
   748  			// at; this can be done with the examiner.
   749  			cf, cfOK := child.Val(dwarf.AttrCallFile).(int64)
   750  			if !cfOK {
   751  				t.Fatalf("no call_file attr for inlined subroutine at offset %v", child.Offset)
   752  			}
   753  			file := ex.FileRef(t, d, mainIdx, cf)
   754  			base := filepath.Base(file)
   755  			if base != "test.go" {
   756  				t.Errorf("bad call_file attribute, found '%s', want '%s'",
   757  					file, "test.go")
   758  			}
   759  
   760  			omap := make(map[dwarf.Offset]bool)
   761  
   762  			// Walk the child variables of the inlined routine. Each
   763  			// of them should have a distinct abstract origin-- if two
   764  			// vars point to the same origin things are definitely broken.
   765  			inlIdx := ex.idxFromOffset(child.Offset)
   766  			inlChildDies := ex.Children(inlIdx)
   767  			for _, k := range inlChildDies {
   768  				ooff, originOK := k.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
   769  				if !originOK {
   770  					t.Fatalf("no abstract origin attr for child of inlined subroutine at offset %v", k.Offset)
   771  				}
   772  				if _, found := omap[ooff]; found {
   773  					t.Fatalf("duplicate abstract origin at child of inlined subroutine at offset %v", k.Offset)
   774  				}
   775  				omap[ooff] = true
   776  			}
   777  		}
   778  	}
   779  	if exCount != len(expectedInl) {
   780  		t.Fatalf("not enough inlined subroutines found in main.main")
   781  	}
   782  }
   783  
   784  func abstractOriginSanity(t *testing.T, pkgDir string, flags string) {
   785  	t.Parallel()
   786  
   787  	dir, err := ioutil.TempDir("", "TestAbstractOriginSanity")
   788  	if err != nil {
   789  		t.Fatalf("could not create directory: %v", err)
   790  	}
   791  	defer os.RemoveAll(dir)
   792  
   793  	// Build with inlining, to exercise DWARF inlining support.
   794  	f := gobuildTestdata(t, dir, filepath.Join(pkgDir, "main"), flags)
   795  
   796  	d, err := f.DWARF()
   797  	if err != nil {
   798  		t.Fatalf("error reading DWARF: %v", err)
   799  	}
   800  	rdr := d.Reader()
   801  	ex := examiner{}
   802  	if err := ex.populate(rdr); err != nil {
   803  		t.Fatalf("error reading DWARF: %v", err)
   804  	}
   805  
   806  	// Make a pass through all DIEs looking for abstract origin
   807  	// references.
   808  	abscount := 0
   809  	for i, die := range ex.dies {
   810  		// Does it have an abstract origin?
   811  		ooff, originOK := die.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
   812  		if !originOK {
   813  			continue
   814  		}
   815  
   816  		// All abstract origin references should be resolvable.
   817  		abscount += 1
   818  		originDIE := ex.entryFromOffset(ooff)
   819  		if originDIE == nil {
   820  			ex.dumpEntry(i, false, 0)
   821  			t.Fatalf("unresolved abstract origin ref in DIE at offset 0x%x\n", die.Offset)
   822  		}
   823  
   824  		// Suppose that DIE X has parameter/variable children {K1,
   825  		// K2, ... KN}. If X has an abstract origin of A, then for
   826  		// each KJ, the abstract origin of KJ should be a child of A.
   827  		// Note that this same rule doesn't hold for non-variable DIEs.
   828  		pidx := ex.idxFromOffset(die.Offset)
   829  		if pidx < 0 {
   830  			t.Fatalf("can't locate DIE id")
   831  		}
   832  		kids := ex.Children(pidx)
   833  		for _, kid := range kids {
   834  			if kid.Tag != dwarf.TagVariable &&
   835  				kid.Tag != dwarf.TagFormalParameter {
   836  				continue
   837  			}
   838  			kooff, originOK := kid.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset)
   839  			if !originOK {
   840  				continue
   841  			}
   842  			childOriginDIE := ex.entryFromOffset(kooff)
   843  			if childOriginDIE == nil {
   844  				ex.dumpEntry(i, false, 0)
   845  				t.Fatalf("unresolved abstract origin ref in DIE at offset %x", kid.Offset)
   846  			}
   847  			coidx := ex.idxFromOffset(childOriginDIE.Offset)
   848  			childOriginParent := ex.Parent(coidx)
   849  			if childOriginParent != originDIE {
   850  				ex.dumpEntry(i, false, 0)
   851  				t.Fatalf("unexpected parent of abstract origin DIE at offset %v", childOriginDIE.Offset)
   852  			}
   853  		}
   854  	}
   855  	if abscount == 0 {
   856  		t.Fatalf("no abstract origin refs found, something is wrong")
   857  	}
   858  }
   859  
   860  func TestAbstractOriginSanity(t *testing.T) {
   861  	testenv.MustHaveGoBuild(t)
   862  
   863  	if testing.Short() {
   864  		t.Skip("skipping test in short mode.")
   865  	}
   866  
   867  	if runtime.GOOS == "plan9" {
   868  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   869  	}
   870  	if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "darwin" {
   871  		t.Skip("skipping on solaris, illumos, and darwin, pending resolution of issue #23168")
   872  	}
   873  
   874  	if wd, err := os.Getwd(); err == nil {
   875  		gopathdir := filepath.Join(wd, "testdata", "httptest")
   876  		abstractOriginSanity(t, gopathdir, OptAllInl4)
   877  	} else {
   878  		t.Fatalf("os.Getwd() failed %v", err)
   879  	}
   880  }
   881  
   882  func TestAbstractOriginSanityIssue25459(t *testing.T) {
   883  	testenv.MustHaveGoBuild(t)
   884  
   885  	if runtime.GOOS == "plan9" {
   886  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   887  	}
   888  	if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "darwin" {
   889  		t.Skip("skipping on solaris, illumos, and darwin, pending resolution of issue #23168")
   890  	}
   891  	if runtime.GOARCH != "amd64" && runtime.GOARCH != "x86" {
   892  		t.Skip("skipping on not-amd64 not-x86; location lists not supported")
   893  	}
   894  
   895  	if wd, err := os.Getwd(); err == nil {
   896  		gopathdir := filepath.Join(wd, "testdata", "issue25459")
   897  		abstractOriginSanity(t, gopathdir, DefaultOpt)
   898  	} else {
   899  		t.Fatalf("os.Getwd() failed %v", err)
   900  	}
   901  }
   902  
   903  func TestAbstractOriginSanityIssue26237(t *testing.T) {
   904  	testenv.MustHaveGoBuild(t)
   905  
   906  	if runtime.GOOS == "plan9" {
   907  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   908  	}
   909  	if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "darwin" {
   910  		t.Skip("skipping on solaris, illumos, and darwin, pending resolution of issue #23168")
   911  	}
   912  	if wd, err := os.Getwd(); err == nil {
   913  		gopathdir := filepath.Join(wd, "testdata", "issue26237")
   914  		abstractOriginSanity(t, gopathdir, DefaultOpt)
   915  	} else {
   916  		t.Fatalf("os.Getwd() failed %v", err)
   917  	}
   918  }
   919  
   920  func TestRuntimeTypeAttrInternal(t *testing.T) {
   921  	testenv.MustHaveGoBuild(t)
   922  
   923  	if runtime.GOOS == "plan9" {
   924  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   925  	}
   926  
   927  	if runtime.GOOS == "windows" && runtime.GOARCH == "arm" {
   928  		t.Skip("skipping on windows/arm; test is incompatible with relocatable binaries")
   929  	}
   930  
   931  	testRuntimeTypeAttr(t, "-ldflags=-linkmode=internal")
   932  }
   933  
   934  // External linking requires a host linker (https://golang.org/src/cmd/cgo/doc.go l.732)
   935  func TestRuntimeTypeAttrExternal(t *testing.T) {
   936  	testenv.MustHaveGoBuild(t)
   937  	testenv.MustHaveCGO(t)
   938  
   939  	if runtime.GOOS == "plan9" {
   940  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
   941  	}
   942  
   943  	// Explicitly test external linking, for dsymutil compatibility on Darwin.
   944  	if runtime.GOARCH == "ppc64" {
   945  		t.Skip("-linkmode=external not supported on ppc64")
   946  	}
   947  	testRuntimeTypeAttr(t, "-ldflags=-linkmode=external")
   948  }
   949  
   950  func testRuntimeTypeAttr(t *testing.T, flags string) {
   951  	t.Parallel()
   952  
   953  	const prog = `
   954  package main
   955  
   956  import "unsafe"
   957  
   958  type X struct{ _ int }
   959  
   960  func main() {
   961  	var x interface{} = &X{}
   962  	p := *(*uintptr)(unsafe.Pointer(&x))
   963  	print(p)
   964  }
   965  `
   966  	dir, err := ioutil.TempDir("", "TestRuntimeType")
   967  	if err != nil {
   968  		t.Fatalf("could not create directory: %v", err)
   969  	}
   970  	defer os.RemoveAll(dir)
   971  
   972  	f := gobuild(t, dir, prog, flags)
   973  	out, err := exec.Command(f.path).CombinedOutput()
   974  	if err != nil {
   975  		t.Fatalf("could not run test program: %v", err)
   976  	}
   977  	addr, err := strconv.ParseUint(string(out), 10, 64)
   978  	if err != nil {
   979  		t.Fatalf("could not parse type address from program output %q: %v", out, err)
   980  	}
   981  
   982  	symbols, err := f.Symbols()
   983  	if err != nil {
   984  		t.Fatalf("error reading symbols: %v", err)
   985  	}
   986  	var types *objfilepkg.Sym
   987  	for _, sym := range symbols {
   988  		if sym.Name == "runtime.types" {
   989  			types = &sym
   990  			break
   991  		}
   992  	}
   993  	if types == nil {
   994  		t.Fatal("couldn't find runtime.types in symbols")
   995  	}
   996  
   997  	d, err := f.DWARF()
   998  	if err != nil {
   999  		t.Fatalf("error reading DWARF: %v", err)
  1000  	}
  1001  
  1002  	rdr := d.Reader()
  1003  	ex := examiner{}
  1004  	if err := ex.populate(rdr); err != nil {
  1005  		t.Fatalf("error reading DWARF: %v", err)
  1006  	}
  1007  	dies := ex.Named("*main.X")
  1008  	if len(dies) != 1 {
  1009  		t.Fatalf("wanted 1 DIE named *main.X, found %v", len(dies))
  1010  	}
  1011  	rtAttr := dies[0].Val(intdwarf.DW_AT_go_runtime_type)
  1012  	if rtAttr == nil {
  1013  		t.Fatalf("*main.X DIE had no runtime type attr. DIE: %v", dies[0])
  1014  	}
  1015  
  1016  	if rtAttr.(uint64)+types.Addr != addr {
  1017  		t.Errorf("DWARF type offset was %#x+%#x, but test program said %#x", rtAttr.(uint64), types.Addr, addr)
  1018  	}
  1019  }
  1020  
  1021  func TestIssue27614(t *testing.T) {
  1022  	// Type references in debug_info should always use the DW_TAG_typedef_type
  1023  	// for the type, when that's generated.
  1024  
  1025  	testenv.MustHaveGoBuild(t)
  1026  
  1027  	if runtime.GOOS == "plan9" {
  1028  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
  1029  	}
  1030  
  1031  	t.Parallel()
  1032  
  1033  	dir, err := ioutil.TempDir("", "go-build")
  1034  	if err != nil {
  1035  		t.Fatal(err)
  1036  	}
  1037  	defer os.RemoveAll(dir)
  1038  
  1039  	const prog = `package main
  1040  
  1041  import "fmt"
  1042  
  1043  type astruct struct {
  1044  	X int
  1045  }
  1046  
  1047  type bstruct struct {
  1048  	X float32
  1049  }
  1050  
  1051  var globalptr *astruct
  1052  var globalvar astruct
  1053  var bvar0, bvar1, bvar2 bstruct
  1054  
  1055  func main() {
  1056  	fmt.Println(globalptr, globalvar, bvar0, bvar1, bvar2)
  1057  }
  1058  `
  1059  
  1060  	f := gobuild(t, dir, prog, NoOpt)
  1061  
  1062  	defer f.Close()
  1063  
  1064  	data, err := f.DWARF()
  1065  	if err != nil {
  1066  		t.Fatal(err)
  1067  	}
  1068  
  1069  	rdr := data.Reader()
  1070  
  1071  	var astructTypeDIE, bstructTypeDIE, ptrastructTypeDIE *dwarf.Entry
  1072  	var globalptrDIE, globalvarDIE *dwarf.Entry
  1073  	var bvarDIE [3]*dwarf.Entry
  1074  
  1075  	for {
  1076  		e, err := rdr.Next()
  1077  		if err != nil {
  1078  			t.Fatal(err)
  1079  		}
  1080  		if e == nil {
  1081  			break
  1082  		}
  1083  
  1084  		name, _ := e.Val(dwarf.AttrName).(string)
  1085  
  1086  		switch e.Tag {
  1087  		case dwarf.TagTypedef:
  1088  			switch name {
  1089  			case "main.astruct":
  1090  				astructTypeDIE = e
  1091  			case "main.bstruct":
  1092  				bstructTypeDIE = e
  1093  			}
  1094  		case dwarf.TagPointerType:
  1095  			if name == "*main.astruct" {
  1096  				ptrastructTypeDIE = e
  1097  			}
  1098  		case dwarf.TagVariable:
  1099  			switch name {
  1100  			case "main.globalptr":
  1101  				globalptrDIE = e
  1102  			case "main.globalvar":
  1103  				globalvarDIE = e
  1104  			default:
  1105  				const bvarprefix = "main.bvar"
  1106  				if strings.HasPrefix(name, bvarprefix) {
  1107  					i, _ := strconv.Atoi(name[len(bvarprefix):])
  1108  					bvarDIE[i] = e
  1109  				}
  1110  			}
  1111  		}
  1112  	}
  1113  
  1114  	typedieof := func(e *dwarf.Entry) dwarf.Offset {
  1115  		return e.Val(dwarf.AttrType).(dwarf.Offset)
  1116  	}
  1117  
  1118  	if off := typedieof(ptrastructTypeDIE); off != astructTypeDIE.Offset {
  1119  		t.Errorf("type attribute of *main.astruct references %#x, not main.astruct DIE at %#x\n", off, astructTypeDIE.Offset)
  1120  	}
  1121  
  1122  	if off := typedieof(globalptrDIE); off != ptrastructTypeDIE.Offset {
  1123  		t.Errorf("type attribute of main.globalptr references %#x, not *main.astruct DIE at %#x\n", off, ptrastructTypeDIE.Offset)
  1124  	}
  1125  
  1126  	if off := typedieof(globalvarDIE); off != astructTypeDIE.Offset {
  1127  		t.Errorf("type attribute of main.globalvar1 references %#x, not main.astruct DIE at %#x\n", off, astructTypeDIE.Offset)
  1128  	}
  1129  
  1130  	for i := range bvarDIE {
  1131  		if off := typedieof(bvarDIE[i]); off != bstructTypeDIE.Offset {
  1132  			t.Errorf("type attribute of main.bvar%d references %#x, not main.bstruct DIE at %#x\n", i, off, bstructTypeDIE.Offset)
  1133  		}
  1134  	}
  1135  }
  1136  
  1137  func TestStaticTmp(t *testing.T) {
  1138  	// Checks that statictmp variables do not appear in debug_info or the
  1139  	// symbol table.
  1140  	// Also checks that statictmp variables do not collide with user defined
  1141  	// variables (issue #25113)
  1142  
  1143  	testenv.MustHaveGoBuild(t)
  1144  
  1145  	if runtime.GOOS == "plan9" {
  1146  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
  1147  	}
  1148  
  1149  	t.Parallel()
  1150  
  1151  	dir, err := ioutil.TempDir("", "go-build")
  1152  	if err != nil {
  1153  		t.Fatal(err)
  1154  	}
  1155  	defer os.RemoveAll(dir)
  1156  
  1157  	const prog = `package main
  1158  
  1159  var stmp_0 string
  1160  var a []int
  1161  
  1162  func init() {
  1163  	a = []int{ 7 }
  1164  }
  1165  
  1166  func main() {
  1167  	println(a[0])
  1168  }
  1169  `
  1170  
  1171  	f := gobuild(t, dir, prog, NoOpt)
  1172  
  1173  	defer f.Close()
  1174  
  1175  	d, err := f.DWARF()
  1176  	if err != nil {
  1177  		t.Fatalf("error reading DWARF: %v", err)
  1178  	}
  1179  
  1180  	rdr := d.Reader()
  1181  	for {
  1182  		e, err := rdr.Next()
  1183  		if err != nil {
  1184  			t.Fatal(err)
  1185  		}
  1186  		if e == nil {
  1187  			break
  1188  		}
  1189  		if e.Tag != dwarf.TagVariable {
  1190  			continue
  1191  		}
  1192  		name, ok := e.Val(dwarf.AttrName).(string)
  1193  		if !ok {
  1194  			continue
  1195  		}
  1196  		if strings.Contains(name, "stmp") {
  1197  			t.Errorf("statictmp variable found in debug_info: %s at %x", name, e.Offset)
  1198  		}
  1199  	}
  1200  
  1201  	syms, err := f.Symbols()
  1202  	if err != nil {
  1203  		t.Fatalf("error reading symbols: %v", err)
  1204  	}
  1205  	for _, sym := range syms {
  1206  		if strings.Contains(sym.Name, "stmp") {
  1207  			t.Errorf("statictmp variable found in symbol table: %s", sym.Name)
  1208  		}
  1209  	}
  1210  }
  1211  
  1212  func TestPackageNameAttr(t *testing.T) {
  1213  	const dwarfAttrGoPackageName = dwarf.Attr(0x2905)
  1214  	const dwarfGoLanguage = 22
  1215  
  1216  	testenv.MustHaveGoBuild(t)
  1217  
  1218  	if runtime.GOOS == "plan9" {
  1219  		t.Skip("skipping on plan9; no DWARF symbol table in executables")
  1220  	}
  1221  
  1222  	t.Parallel()
  1223  
  1224  	dir, err := ioutil.TempDir("", "go-build")
  1225  	if err != nil {
  1226  		t.Fatal(err)
  1227  	}
  1228  	defer os.RemoveAll(dir)
  1229  
  1230  	const prog = "package main\nfunc main() {\nprintln(\"hello world\")\n}\n"
  1231  
  1232  	f := gobuild(t, dir, prog, NoOpt)
  1233  
  1234  	defer f.Close()
  1235  
  1236  	d, err := f.DWARF()
  1237  	if err != nil {
  1238  		t.Fatalf("error reading DWARF: %v", err)
  1239  	}
  1240  
  1241  	rdr := d.Reader()
  1242  	for {
  1243  		e, err := rdr.Next()
  1244  		if err != nil {
  1245  			t.Fatal(err)
  1246  		}
  1247  		if e == nil {
  1248  			break
  1249  		}
  1250  		if e.Tag != dwarf.TagCompileUnit {
  1251  			continue
  1252  		}
  1253  		if lang, _ := e.Val(dwarf.AttrLanguage).(int64); lang != dwarfGoLanguage {
  1254  			continue
  1255  		}
  1256  
  1257  		_, ok := e.Val(dwarfAttrGoPackageName).(string)
  1258  		if !ok {
  1259  			name, _ := e.Val(dwarf.AttrName).(string)
  1260  			t.Errorf("found compile unit without package name: %s", name)
  1261  		}
  1262  	}
  1263  }
  1264  
  1265  func TestMachoIssue32233(t *testing.T) {
  1266  	testenv.MustHaveGoBuild(t)
  1267  	testenv.MustHaveCGO(t)
  1268  
  1269  	if runtime.GOOS != "darwin" {
  1270  		t.Skip("skipping; test only interesting on darwin")
  1271  	}
  1272  
  1273  	tmpdir, err := ioutil.TempDir("", "TestMachoIssue32233")
  1274  	if err != nil {
  1275  		t.Fatalf("could not create directory: %v", err)
  1276  	}
  1277  	defer os.RemoveAll(tmpdir)
  1278  
  1279  	wd, err2 := os.Getwd()
  1280  	if err2 != nil {
  1281  		t.Fatalf("where am I? %v", err)
  1282  	}
  1283  	pdir := filepath.Join(wd, "testdata", "issue32233", "main")
  1284  	f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt)
  1285  	f.Close()
  1286  }
  1287  
  1288  func TestWindowsIssue36495(t *testing.T) {
  1289  	testenv.MustHaveGoBuild(t)
  1290  	if runtime.GOOS != "windows" {
  1291  		t.Skip("skipping: test only on windows")
  1292  	}
  1293  
  1294  	dir, err := ioutil.TempDir("", "TestEmbeddedStructMarker")
  1295  	if err != nil {
  1296  		t.Fatalf("could not create directory: %v", err)
  1297  	}
  1298  	defer os.RemoveAll(dir)
  1299  
  1300  	prog := `
  1301  package main
  1302  
  1303  import "fmt"
  1304  
  1305  func main() {
  1306    fmt.Println("Hello World")
  1307  }`
  1308  	f := gobuild(t, dir, prog, NoOpt)
  1309  	exe, err := pe.Open(f.path)
  1310  	if err != nil {
  1311  		t.Fatalf("error opening pe file: %v", err)
  1312  	}
  1313  	dw, err := exe.DWARF()
  1314  	if err != nil {
  1315  		t.Fatalf("error parsing DWARF: %v", err)
  1316  	}
  1317  	rdr := dw.Reader()
  1318  	for {
  1319  		e, err := rdr.Next()
  1320  		if err != nil {
  1321  			t.Fatalf("error reading DWARF: %v", err)
  1322  		}
  1323  		if e == nil {
  1324  			break
  1325  		}
  1326  		if e.Tag != dwarf.TagCompileUnit {
  1327  			continue
  1328  		}
  1329  		lnrdr, err := dw.LineReader(e)
  1330  		if err != nil {
  1331  			t.Fatalf("error creating DWARF line reader: %v", err)
  1332  		}
  1333  		if lnrdr != nil {
  1334  			var lne dwarf.LineEntry
  1335  			for {
  1336  				err := lnrdr.Next(&lne)
  1337  				if err == io.EOF {
  1338  					break
  1339  				}
  1340  				if err != nil {
  1341  					t.Fatalf("error reading next DWARF line: %v", err)
  1342  				}
  1343  				if strings.Contains(lne.File.Name, `\`) {
  1344  					t.Errorf("filename should not contain backslash: %v", lne.File.Name)
  1345  				}
  1346  			}
  1347  		}
  1348  		rdr.SkipChildren()
  1349  	}
  1350  }