github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/debug/pe/file_test.go (about)

     1  // Copyright 2009 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 pe
     6  
     7  import (
     8  	"debug/dwarf"
     9  	"internal/testenv"
    10  	"io/ioutil"
    11  	"os"
    12  	"os/exec"
    13  	"path/filepath"
    14  	"reflect"
    15  	"runtime"
    16  	"testing"
    17  )
    18  
    19  type fileTest struct {
    20  	file           string
    21  	hdr            FileHeader
    22  	opthdr         interface{}
    23  	sections       []*SectionHeader
    24  	symbols        []*Symbol
    25  	hasNoDwarfInfo bool
    26  }
    27  
    28  var fileTests = []fileTest{
    29  	{
    30  		file: "testdata/gcc-386-mingw-obj",
    31  		hdr:  FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
    32  		sections: []*SectionHeader{
    33  			{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
    34  			{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
    35  			{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
    36  			{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
    37  			{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
    38  			{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
    39  			{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
    40  			{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
    41  			{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
    42  			{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
    43  			{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
    44  			{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
    45  		},
    46  		symbols: []*Symbol{
    47  			{".file", 0x0, -2, 0x0, 0x67},
    48  			{"_main", 0x0, 1, 0x20, 0x2},
    49  			{".text", 0x0, 1, 0x0, 0x3},
    50  			{".data", 0x0, 2, 0x0, 0x3},
    51  			{".bss", 0x0, 3, 0x0, 0x3},
    52  			{".debug_abbrev", 0x0, 4, 0x0, 0x3},
    53  			{".debug_info", 0x0, 5, 0x0, 0x3},
    54  			{".debug_line", 0x0, 6, 0x0, 0x3},
    55  			{".rdata", 0x0, 7, 0x0, 0x3},
    56  			{".debug_frame", 0x0, 8, 0x0, 0x3},
    57  			{".debug_loc", 0x0, 9, 0x0, 0x3},
    58  			{".debug_pubnames", 0x0, 10, 0x0, 0x3},
    59  			{".debug_pubtypes", 0x0, 11, 0x0, 0x3},
    60  			{".debug_aranges", 0x0, 12, 0x0, 0x3},
    61  			{"___main", 0x0, 0, 0x20, 0x2},
    62  			{"_puts", 0x0, 0, 0x20, 0x2},
    63  		},
    64  	},
    65  	{
    66  		file: "testdata/gcc-386-mingw-exec",
    67  		hdr:  FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
    68  		opthdr: &OptionalHeader32{
    69  			0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
    70  			[16]DataDirectory{
    71  				{0x0, 0x0},
    72  				{0x5000, 0x3c8},
    73  				{0x0, 0x0},
    74  				{0x0, 0x0},
    75  				{0x0, 0x0},
    76  				{0x0, 0x0},
    77  				{0x0, 0x0},
    78  				{0x0, 0x0},
    79  				{0x0, 0x0},
    80  				{0x7000, 0x18},
    81  				{0x0, 0x0},
    82  				{0x0, 0x0},
    83  				{0x0, 0x0},
    84  				{0x0, 0x0},
    85  				{0x0, 0x0},
    86  				{0x0, 0x0},
    87  			},
    88  		},
    89  		sections: []*SectionHeader{
    90  			{".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
    91  			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    92  			{".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
    93  			{".bss", 0xdc, 0x4000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0400080},
    94  			{".idata", 0x3c8, 0x5000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    95  			{".CRT", 0x18, 0x6000, 0x200, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    96  			{".tls", 0x20, 0x7000, 0x200, 0x1c00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
    97  			{".debug_aranges", 0x20, 0x8000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    98  			{".debug_pubnames", 0x51, 0x9000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0x42100000},
    99  			{".debug_pubtypes", 0x91, 0xa000, 0x200, 0x2200, 0x0, 0x0, 0x0, 0x0, 0x42100000},
   100  			{".debug_info", 0xe22, 0xb000, 0x1000, 0x2400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
   101  			{".debug_abbrev", 0x157, 0xc000, 0x200, 0x3400, 0x0, 0x0, 0x0, 0x0, 0x42100000},
   102  			{".debug_line", 0x144, 0xd000, 0x200, 0x3600, 0x0, 0x0, 0x0, 0x0, 0x42100000},
   103  			{".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
   104  			{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
   105  		},
   106  	},
   107  	{
   108  		file: "testdata/gcc-386-mingw-no-symbols-exec",
   109  		hdr:  FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
   110  		opthdr: &OptionalHeader32{0x10b, 0x2, 0x18, 0xe00, 0x1e00, 0x200, 0x1280, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x9000, 0x400, 0x5306, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
   111  			[16]DataDirectory{
   112  				{0x0, 0x0},
   113  				{0x6000, 0x378},
   114  				{0x0, 0x0},
   115  				{0x0, 0x0},
   116  				{0x0, 0x0},
   117  				{0x0, 0x0},
   118  				{0x0, 0x0},
   119  				{0x0, 0x0},
   120  				{0x0, 0x0},
   121  				{0x8004, 0x18},
   122  				{0x0, 0x0},
   123  				{0x0, 0x0},
   124  				{0x60b8, 0x7c},
   125  				{0x0, 0x0},
   126  				{0x0, 0x0},
   127  				{0x0, 0x0},
   128  			},
   129  		},
   130  		sections: []*SectionHeader{
   131  			{".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
   132  			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
   133  			{".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   134  			{".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   135  			{".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
   136  			{".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
   137  			{".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
   138  			{".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
   139  		},
   140  		hasNoDwarfInfo: true,
   141  	},
   142  	{
   143  		file: "testdata/gcc-amd64-mingw-obj",
   144  		hdr:  FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
   145  		sections: []*SectionHeader{
   146  			{".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
   147  			{".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
   148  			{".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
   149  			{".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
   150  			{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   151  			{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
   152  		},
   153  		symbols: []*Symbol{
   154  			{".file", 0x0, -2, 0x0, 0x67},
   155  			{"main", 0x0, 1, 0x20, 0x2},
   156  			{".text", 0x0, 1, 0x0, 0x3},
   157  			{".data", 0x0, 2, 0x0, 0x3},
   158  			{".bss", 0x0, 3, 0x0, 0x3},
   159  			{".rdata", 0x0, 4, 0x0, 0x3},
   160  			{".xdata", 0x0, 5, 0x0, 0x3},
   161  			{".pdata", 0x0, 6, 0x0, 0x3},
   162  			{"__main", 0x0, 0, 0x20, 0x2},
   163  			{"puts", 0x0, 0, 0x20, 0x2},
   164  		},
   165  		hasNoDwarfInfo: true,
   166  	},
   167  	{
   168  		file: "testdata/gcc-amd64-mingw-exec",
   169  		hdr:  FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
   170  		opthdr: &OptionalHeader64{
   171  			0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x45000, 0x600, 0x46f19, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
   172  			[16]DataDirectory{
   173  				{0x0, 0x0},
   174  				{0xe000, 0x990},
   175  				{0x0, 0x0},
   176  				{0xa000, 0x498},
   177  				{0x0, 0x0},
   178  				{0x0, 0x0},
   179  				{0x0, 0x0},
   180  				{0x0, 0x0},
   181  				{0x0, 0x0},
   182  				{0x10000, 0x28},
   183  				{0x0, 0x0},
   184  				{0x0, 0x0},
   185  				{0xe254, 0x218},
   186  				{0x0, 0x0},
   187  				{0x0, 0x0},
   188  				{0x0, 0x0},
   189  			}},
   190  		sections: []*SectionHeader{
   191  			{".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
   192  			{".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
   193  			{".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
   194  			{".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   195  			{".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   196  			{".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
   197  			{".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
   198  			{".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
   199  			{".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
   200  			{".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040},
   201  			{".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   202  			{".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   203  			{".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   204  			{".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040},
   205  			{".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   206  			{".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   207  			{".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   208  		},
   209  	},
   210  }
   211  
   212  func isOptHdrEq(a, b interface{}) bool {
   213  	switch va := a.(type) {
   214  	case *OptionalHeader32:
   215  		vb, ok := b.(*OptionalHeader32)
   216  		if !ok {
   217  			return false
   218  		}
   219  		return *vb == *va
   220  	case *OptionalHeader64:
   221  		vb, ok := b.(*OptionalHeader64)
   222  		if !ok {
   223  			return false
   224  		}
   225  		return *vb == *va
   226  	case nil:
   227  		return b == nil
   228  	}
   229  	return false
   230  }
   231  
   232  func TestOpen(t *testing.T) {
   233  	for i := range fileTests {
   234  		tt := &fileTests[i]
   235  
   236  		f, err := Open(tt.file)
   237  		if err != nil {
   238  			t.Error(err)
   239  			continue
   240  		}
   241  		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
   242  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
   243  			continue
   244  		}
   245  		if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
   246  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
   247  			continue
   248  		}
   249  
   250  		for i, sh := range f.Sections {
   251  			if i >= len(tt.sections) {
   252  				break
   253  			}
   254  			have := &sh.SectionHeader
   255  			want := tt.sections[i]
   256  			if !reflect.DeepEqual(have, want) {
   257  				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
   258  			}
   259  		}
   260  		tn := len(tt.sections)
   261  		fn := len(f.Sections)
   262  		if tn != fn {
   263  			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
   264  		}
   265  		for i, have := range f.Symbols {
   266  			if i >= len(tt.symbols) {
   267  				break
   268  			}
   269  			want := tt.symbols[i]
   270  			if !reflect.DeepEqual(have, want) {
   271  				t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
   272  			}
   273  		}
   274  		if !tt.hasNoDwarfInfo {
   275  			_, err = f.DWARF()
   276  			if err != nil {
   277  				t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
   278  			}
   279  		}
   280  	}
   281  }
   282  
   283  func TestOpenFailure(t *testing.T) {
   284  	filename := "file.go"    // not a PE file
   285  	_, err := Open(filename) // don't crash
   286  	if err == nil {
   287  		t.Errorf("open %s: succeeded unexpectedly", filename)
   288  	}
   289  }
   290  
   291  func TestDWARF(t *testing.T) {
   292  	if runtime.GOOS != "windows" {
   293  		t.Skip("skipping windows only test")
   294  	}
   295  
   296  	tmpdir, err := ioutil.TempDir("", "TestDWARF")
   297  	if err != nil {
   298  		t.Fatal("TempDir failed: ", err)
   299  	}
   300  	defer os.RemoveAll(tmpdir)
   301  
   302  	prog := `
   303  package main
   304  func main() {
   305  }
   306  `
   307  	src := filepath.Join(tmpdir, "a.go")
   308  	exe := filepath.Join(tmpdir, "a.exe")
   309  	err = ioutil.WriteFile(src, []byte(prog), 0644)
   310  	output, err := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
   311  	if err != nil {
   312  		t.Fatalf("building test executable failed: %s %s", err, output)
   313  	}
   314  
   315  	f, err := Open(exe)
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	defer f.Close()
   320  
   321  	d, err := f.DWARF()
   322  	if err != nil {
   323  		t.Fatal(err)
   324  	}
   325  
   326  	// look for main.main
   327  	r := d.Reader()
   328  	for {
   329  		e, err := r.Next()
   330  		if err != nil {
   331  			t.Fatal("r.Next:", err)
   332  		}
   333  		if e == nil {
   334  			break
   335  		}
   336  		if e.Tag == dwarf.TagSubprogram {
   337  			for _, f := range e.Field {
   338  				if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
   339  					return
   340  				}
   341  			}
   342  		}
   343  	}
   344  	t.Fatal("main.main not found")
   345  }
   346  
   347  func TestBSSHasZeros(t *testing.T) {
   348  	testenv.MustHaveExec(t)
   349  
   350  	if runtime.GOOS != "windows" {
   351  		t.Skip("skipping windows only test")
   352  	}
   353  	gccpath, err := exec.LookPath("gcc")
   354  	if err != nil {
   355  		t.Skip("skipping test: gcc is missing")
   356  	}
   357  
   358  	tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	defer os.RemoveAll(tmpdir)
   363  
   364  	srcpath := filepath.Join(tmpdir, "a.c")
   365  	src := `
   366  #include <stdio.h>
   367  
   368  int zero = 0;
   369  
   370  int
   371  main(void)
   372  {
   373  	printf("%d\n", zero);
   374  	return 0;
   375  }
   376  `
   377  	err = ioutil.WriteFile(srcpath, []byte(src), 0644)
   378  	if err != nil {
   379  		t.Fatal(err)
   380  	}
   381  
   382  	objpath := filepath.Join(tmpdir, "a.obj")
   383  	cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
   384  	out, err := cmd.CombinedOutput()
   385  	if err != nil {
   386  		t.Fatalf("failed to build object file: %v - %v", err, string(out))
   387  	}
   388  
   389  	f, err := Open(objpath)
   390  	if err != nil {
   391  		t.Fatal(err)
   392  	}
   393  	defer f.Close()
   394  
   395  	var bss *Section
   396  	for _, sect := range f.Sections {
   397  		if sect.Name == ".bss" {
   398  			bss = sect
   399  			break
   400  		}
   401  	}
   402  	if bss == nil {
   403  		t.Fatal("could not find .bss section")
   404  	}
   405  	data, err := bss.Data()
   406  	if err != nil {
   407  		t.Fatal(err)
   408  	}
   409  	if len(data) == 0 {
   410  		t.Fatalf("%s file .bss section cannot be empty", objpath)
   411  	}
   412  	for _, b := range data {
   413  		if b != 0 {
   414  			t.Fatalf(".bss section has non zero bytes: %v", data)
   415  		}
   416  	}
   417  }