github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/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-amd64-mingw-obj",
   109  		hdr:  FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
   110  		sections: []*SectionHeader{
   111  			{".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
   112  			{".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
   113  			{".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
   114  			{".rdata", 0x0, 0x0, 0x10, 0x134, 0x0, 0x0, 0x0, 0x0, 0x40500040},
   115  			{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   116  			{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
   117  		},
   118  		symbols: []*Symbol{
   119  			{".file", 0x0, -2, 0x0, 0x67},
   120  			{"main", 0x0, 1, 0x20, 0x2},
   121  			{".text", 0x0, 1, 0x0, 0x3},
   122  			{".data", 0x0, 2, 0x0, 0x3},
   123  			{".bss", 0x0, 3, 0x0, 0x3},
   124  			{".rdata", 0x0, 4, 0x0, 0x3},
   125  			{".xdata", 0x0, 5, 0x0, 0x3},
   126  			{".pdata", 0x0, 6, 0x0, 0x3},
   127  			{"__main", 0x0, 0, 0x20, 0x2},
   128  			{"puts", 0x0, 0, 0x20, 0x2},
   129  		},
   130  		hasNoDwarfInfo: true,
   131  	},
   132  	{
   133  		file: "testdata/gcc-amd64-mingw-exec",
   134  		hdr:  FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
   135  		opthdr: &OptionalHeader64{
   136  			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,
   137  			[16]DataDirectory{
   138  				{0x0, 0x0},
   139  				{0xe000, 0x990},
   140  				{0x0, 0x0},
   141  				{0xa000, 0x498},
   142  				{0x0, 0x0},
   143  				{0x0, 0x0},
   144  				{0x0, 0x0},
   145  				{0x0, 0x0},
   146  				{0x0, 0x0},
   147  				{0x10000, 0x28},
   148  				{0x0, 0x0},
   149  				{0x0, 0x0},
   150  				{0xe254, 0x218},
   151  				{0x0, 0x0},
   152  				{0x0, 0x0},
   153  				{0x0, 0x0},
   154  			}},
   155  		sections: []*SectionHeader{
   156  			{".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
   157  			{".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
   158  			{".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
   159  			{".pdata", 0x498, 0xa000, 0x600, 0x7a00, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   160  			{".xdata", 0x488, 0xb000, 0x600, 0x8000, 0x0, 0x0, 0x0, 0x0, 0x40300040},
   161  			{".bss", 0x1410, 0xc000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0600080},
   162  			{".idata", 0x990, 0xe000, 0xa00, 0x8600, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
   163  			{".CRT", 0x68, 0xf000, 0x200, 0x9000, 0x0, 0x0, 0x0, 0x0, 0xc0400040},
   164  			{".tls", 0x48, 0x10000, 0x200, 0x9200, 0x0, 0x0, 0x0, 0x0, 0xc0600040},
   165  			{".debug_aranges", 0x600, 0x11000, 0x600, 0x9400, 0x0, 0x0, 0x0, 0x0, 0x42500040},
   166  			{".debug_info", 0x1316e, 0x12000, 0x13200, 0x9a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   167  			{".debug_abbrev", 0x2ccb, 0x26000, 0x2e00, 0x1cc00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   168  			{".debug_line", 0x3c4d, 0x29000, 0x3e00, 0x1fa00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   169  			{".debug_frame", 0x18b8, 0x2d000, 0x1a00, 0x23800, 0x0, 0x0, 0x0, 0x0, 0x42400040},
   170  			{".debug_str", 0x396, 0x2f000, 0x400, 0x25200, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   171  			{".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   172  			{".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
   173  		},
   174  	},
   175  }
   176  
   177  func isOptHdrEq(a, b interface{}) bool {
   178  	switch va := a.(type) {
   179  	case *OptionalHeader32:
   180  		vb, ok := b.(*OptionalHeader32)
   181  		if !ok {
   182  			return false
   183  		}
   184  		return *vb == *va
   185  	case *OptionalHeader64:
   186  		vb, ok := b.(*OptionalHeader64)
   187  		if !ok {
   188  			return false
   189  		}
   190  		return *vb == *va
   191  	case nil:
   192  		return b == nil
   193  	}
   194  	return false
   195  }
   196  
   197  func TestOpen(t *testing.T) {
   198  	for i := range fileTests {
   199  		tt := &fileTests[i]
   200  
   201  		f, err := Open(tt.file)
   202  		if err != nil {
   203  			t.Error(err)
   204  			continue
   205  		}
   206  		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
   207  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
   208  			continue
   209  		}
   210  		if !isOptHdrEq(tt.opthdr, f.OptionalHeader) {
   211  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.OptionalHeader, tt.opthdr)
   212  			continue
   213  		}
   214  
   215  		for i, sh := range f.Sections {
   216  			if i >= len(tt.sections) {
   217  				break
   218  			}
   219  			have := &sh.SectionHeader
   220  			want := tt.sections[i]
   221  			if !reflect.DeepEqual(have, want) {
   222  				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
   223  			}
   224  		}
   225  		tn := len(tt.sections)
   226  		fn := len(f.Sections)
   227  		if tn != fn {
   228  			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
   229  		}
   230  		for i, have := range f.Symbols {
   231  			if i >= len(tt.symbols) {
   232  				break
   233  			}
   234  			want := tt.symbols[i]
   235  			if !reflect.DeepEqual(have, want) {
   236  				t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
   237  			}
   238  		}
   239  		if !tt.hasNoDwarfInfo {
   240  			_, err = f.DWARF()
   241  			if err != nil {
   242  				t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
   243  			}
   244  		}
   245  	}
   246  }
   247  
   248  func TestOpenFailure(t *testing.T) {
   249  	filename := "file.go"    // not a PE file
   250  	_, err := Open(filename) // don't crash
   251  	if err == nil {
   252  		t.Errorf("open %s: succeeded unexpectedly", filename)
   253  	}
   254  }
   255  
   256  func TestDWARF(t *testing.T) {
   257  	if runtime.GOOS != "windows" {
   258  		t.Skip("skipping windows only test")
   259  	}
   260  
   261  	tmpdir, err := ioutil.TempDir("", "TestDWARF")
   262  	if err != nil {
   263  		t.Fatal("TempDir failed: ", err)
   264  	}
   265  	defer os.RemoveAll(tmpdir)
   266  
   267  	prog := `
   268  package main
   269  func main() {
   270  }
   271  `
   272  	src := filepath.Join(tmpdir, "a.go")
   273  	exe := filepath.Join(tmpdir, "a.exe")
   274  	err = ioutil.WriteFile(src, []byte(prog), 0644)
   275  	output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
   276  	if err != nil {
   277  		t.Fatalf("building test executable failed: %s %s", err, output)
   278  	}
   279  
   280  	f, err := Open(exe)
   281  	if err != nil {
   282  		t.Fatal(err)
   283  	}
   284  	defer f.Close()
   285  
   286  	d, err := f.DWARF()
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  
   291  	// look for main.main
   292  	r := d.Reader()
   293  	for {
   294  		e, err := r.Next()
   295  		if err != nil {
   296  			t.Fatal("r.Next:", err)
   297  		}
   298  		if e == nil {
   299  			break
   300  		}
   301  		if e.Tag == dwarf.TagSubprogram {
   302  			for _, f := range e.Field {
   303  				if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
   304  					return
   305  				}
   306  			}
   307  		}
   308  	}
   309  	t.Fatal("main.main not found")
   310  }
   311  
   312  func TestBSSHasZeros(t *testing.T) {
   313  	testenv.MustHaveExec(t)
   314  
   315  	if runtime.GOOS != "windows" {
   316  		t.Skip("skipping windows only test")
   317  	}
   318  	gccpath, err := exec.LookPath("gcc")
   319  	if err != nil {
   320  		t.Skip("skipping test: gcc is missing")
   321  	}
   322  
   323  	tmpdir, err := ioutil.TempDir("", "TestBSSHasZeros")
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	defer os.RemoveAll(tmpdir)
   328  
   329  	srcpath := filepath.Join(tmpdir, "a.c")
   330  	src := `
   331  #include <stdio.h>
   332  
   333  int zero = 0;
   334  
   335  int
   336  main(void)
   337  {
   338  	printf("%d\n", zero);
   339  	return 0;
   340  }
   341  `
   342  	err = ioutil.WriteFile(srcpath, []byte(src), 0644)
   343  	if err != nil {
   344  		t.Fatal(err)
   345  	}
   346  
   347  	objpath := filepath.Join(tmpdir, "a.obj")
   348  	cmd := exec.Command(gccpath, "-c", srcpath, "-o", objpath)
   349  	out, err := cmd.CombinedOutput()
   350  	if err != nil {
   351  		t.Fatalf("failed to build object file: %v - %v", err, string(out))
   352  	}
   353  
   354  	f, err := Open(objpath)
   355  	if err != nil {
   356  		t.Fatal(err)
   357  	}
   358  	defer f.Close()
   359  
   360  	var bss *Section
   361  	for _, sect := range f.Sections {
   362  		if sect.Name == ".bss" {
   363  			bss = sect
   364  			break
   365  		}
   366  	}
   367  	if bss == nil {
   368  		t.Fatal("could not find .bss section")
   369  	}
   370  	data, err := bss.Data()
   371  	if err != nil {
   372  		t.Fatal(err)
   373  	}
   374  	if len(data) == 0 {
   375  		t.Fatalf("%s file .bss section cannot be empty", objpath)
   376  	}
   377  	for _, b := range data {
   378  		if b != 0 {
   379  			t.Fatalf(".bss section has non zero bytes: %v", data)
   380  		}
   381  	}
   382  }