github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/debug/elf/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 elf
     6  
     7  import (
     8  	"bytes"
     9  	"compress/gzip"
    10  	"debug/dwarf"
    11  	"encoding/binary"
    12  	"io"
    13  	"net"
    14  	"os"
    15  	"path"
    16  	"reflect"
    17  	"runtime"
    18  	"testing"
    19  )
    20  
    21  type fileTest struct {
    22  	file     string
    23  	hdr      FileHeader
    24  	sections []SectionHeader
    25  	progs    []ProgHeader
    26  	needed   []string
    27  }
    28  
    29  var fileTests = []fileTest{
    30  	{
    31  		"testdata/gcc-386-freebsd-exec",
    32  		FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
    33  		[]SectionHeader{
    34  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
    35  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
    36  			{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
    37  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
    38  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
    39  			{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
    40  			{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
    41  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
    42  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
    43  			{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
    44  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
    45  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
    46  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
    47  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
    48  			{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
    49  			{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
    50  			{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
    51  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
    52  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
    53  			{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
    54  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
    55  			{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
    56  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
    57  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
    58  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
    59  			{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
    60  			{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
    61  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
    62  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
    63  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
    64  		},
    65  		[]ProgHeader{
    66  			{PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
    67  			{PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
    68  			{PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
    69  			{PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
    70  			{PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
    71  		},
    72  		[]string{"libc.so.6"},
    73  	},
    74  	{
    75  		"testdata/gcc-amd64-linux-exec",
    76  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
    77  		[]SectionHeader{
    78  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
    79  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
    80  			{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
    81  			{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
    82  			{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
    83  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
    84  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
    85  			{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
    86  			{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
    87  			{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
    88  			{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
    89  			{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
    90  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
    91  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
    92  			{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
    93  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
    94  			{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
    95  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
    96  			{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
    97  			{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
    98  			{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
    99  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
   100  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
   101  			{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
   102  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
   103  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
   104  			{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
   105  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
   106  			{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
   107  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
   108  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
   109  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
   110  			{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
   111  			{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
   112  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
   113  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
   114  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
   115  		},
   116  		[]ProgHeader{
   117  			{PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
   118  			{PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
   119  			{PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
   120  			{PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
   121  			{PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
   122  			{PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
   123  			{PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
   124  			{PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
   125  		},
   126  		[]string{"libc.so.6"},
   127  	},
   128  	{
   129  		"testdata/hello-world-core.gz",
   130  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
   131  		[]SectionHeader{},
   132  		[]ProgHeader{
   133  			{Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
   134  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
   135  			{Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   136  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   137  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
   138  			{Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
   139  			{Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
   140  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
   141  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
   142  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
   143  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
   144  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
   145  			{Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   146  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
   147  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
   148  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   149  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   150  		},
   151  		nil,
   152  	},
   153  }
   154  
   155  func TestOpen(t *testing.T) {
   156  	for i := range fileTests {
   157  		tt := &fileTests[i]
   158  
   159  		var f *File
   160  		var err error
   161  		if path.Ext(tt.file) == ".gz" {
   162  			var r io.ReaderAt
   163  			if r, err = decompress(tt.file); err == nil {
   164  				f, err = NewFile(r)
   165  			}
   166  		} else {
   167  			f, err = Open(tt.file)
   168  		}
   169  		if err != nil {
   170  			t.Errorf("cannot open file %s: %v", tt.file, err)
   171  			continue
   172  		}
   173  		defer f.Close()
   174  		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
   175  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
   176  			continue
   177  		}
   178  		for i, s := range f.Sections {
   179  			if i >= len(tt.sections) {
   180  				break
   181  			}
   182  			sh := &tt.sections[i]
   183  			if !reflect.DeepEqual(&s.SectionHeader, sh) {
   184  				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
   185  			}
   186  		}
   187  		for i, p := range f.Progs {
   188  			if i >= len(tt.progs) {
   189  				break
   190  			}
   191  			ph := &tt.progs[i]
   192  			if !reflect.DeepEqual(&p.ProgHeader, ph) {
   193  				t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
   194  			}
   195  		}
   196  		tn := len(tt.sections)
   197  		fn := len(f.Sections)
   198  		if tn != fn {
   199  			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
   200  		}
   201  		tn = len(tt.progs)
   202  		fn = len(f.Progs)
   203  		if tn != fn {
   204  			t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
   205  		}
   206  		tl := tt.needed
   207  		fl, err := f.ImportedLibraries()
   208  		if err != nil {
   209  			t.Error(err)
   210  		}
   211  		if !reflect.DeepEqual(tl, fl) {
   212  			t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
   213  		}
   214  	}
   215  }
   216  
   217  // elf.NewFile requires io.ReaderAt, which compress/gzip cannot
   218  // provide. Decompress the file to a bytes.Reader.
   219  func decompress(gz string) (io.ReaderAt, error) {
   220  	in, err := os.Open(gz)
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  	defer in.Close()
   225  	r, err := gzip.NewReader(in)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	var out bytes.Buffer
   230  	_, err = io.Copy(&out, r)
   231  	return bytes.NewReader(out.Bytes()), err
   232  }
   233  
   234  type relocationTestEntry struct {
   235  	entryNumber int
   236  	entry       *dwarf.Entry
   237  }
   238  
   239  type relocationTest struct {
   240  	file    string
   241  	entries []relocationTestEntry
   242  }
   243  
   244  var relocationTests = []relocationTest{
   245  	{
   246  		"testdata/go-relocation-test-gcc441-x86-64.obj",
   247  		[]relocationTestEntry{
   248  			{0, &dwarf.Entry{
   249  				Offset:   0xb,
   250  				Tag:      dwarf.TagCompileUnit,
   251  				Children: true,
   252  				Field: []dwarf.Field{
   253  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   254  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   255  					{Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString},
   256  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   257  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   258  					{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   259  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   260  				},
   261  			}},
   262  		},
   263  	},
   264  	{
   265  		"testdata/go-relocation-test-gcc441-x86.obj",
   266  		[]relocationTestEntry{
   267  			{0, &dwarf.Entry{
   268  				Offset:   0xb,
   269  				Tag:      dwarf.TagCompileUnit,
   270  				Children: true,
   271  				Field: []dwarf.Field{
   272  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   273  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   274  					{Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString},
   275  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   276  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   277  					{Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress},
   278  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   279  				},
   280  			}},
   281  		},
   282  	},
   283  	{
   284  		"testdata/go-relocation-test-gcc424-x86-64.obj",
   285  		[]relocationTestEntry{
   286  			{0, &dwarf.Entry{
   287  				Offset:   0xb,
   288  				Tag:      dwarf.TagCompileUnit,
   289  				Children: true,
   290  				Field: []dwarf.Field{
   291  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString},
   292  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   293  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString},
   294  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   295  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   296  					{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   297  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   298  				},
   299  			}},
   300  		},
   301  	},
   302  	{
   303  		"testdata/go-relocation-test-gcc482-aarch64.obj",
   304  		[]relocationTestEntry{
   305  			{0, &dwarf.Entry{
   306  				Offset:   0xb,
   307  				Tag:      dwarf.TagCompileUnit,
   308  				Children: true,
   309  				Field: []dwarf.Field{
   310  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString},
   311  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   312  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString},
   313  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   314  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   315  					{Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant},
   316  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   317  				},
   318  			}},
   319  		},
   320  	},
   321  	{
   322  		"testdata/go-relocation-test-gcc492-arm.obj",
   323  		[]relocationTestEntry{
   324  			{0, &dwarf.Entry{
   325  				Offset:   0xb,
   326  				Tag:      dwarf.TagCompileUnit,
   327  				Children: true,
   328  				Field: []dwarf.Field{
   329  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString},
   330  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   331  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString},
   332  					{Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString},
   333  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   334  					{Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant},
   335  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   336  				},
   337  			}},
   338  		},
   339  	},
   340  	{
   341  		"testdata/go-relocation-test-clang-arm.obj",
   342  		[]relocationTestEntry{
   343  			{0, &dwarf.Entry{
   344  				Offset:   0xb,
   345  				Tag:      dwarf.TagCompileUnit,
   346  				Children: true,
   347  				Field: []dwarf.Field{
   348  					{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString},
   349  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   350  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   351  					{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr},
   352  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   353  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   354  					{Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant},
   355  				},
   356  			}},
   357  		},
   358  	},
   359  	{
   360  		"testdata/go-relocation-test-gcc5-ppc.obj",
   361  		[]relocationTestEntry{
   362  			{0, &dwarf.Entry{
   363  				Offset:   0xb,
   364  				Tag:      dwarf.TagCompileUnit,
   365  				Children: true,
   366  				Field: []dwarf.Field{
   367  					{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString},
   368  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   369  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString},
   370  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   371  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   372  					{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant},
   373  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   374  				},
   375  			}},
   376  		},
   377  	},
   378  	{
   379  		"testdata/go-relocation-test-gcc482-ppc64le.obj",
   380  		[]relocationTestEntry{
   381  			{0, &dwarf.Entry{
   382  				Offset:   0xb,
   383  				Tag:      dwarf.TagCompileUnit,
   384  				Children: true,
   385  				Field: []dwarf.Field{
   386  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString},
   387  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   388  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString},
   389  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   390  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   391  					{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress},
   392  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   393  				},
   394  			}},
   395  		},
   396  	},
   397  	{
   398  		"testdata/go-relocation-test-gcc492-mips64.obj",
   399  		[]relocationTestEntry{
   400  			{0, &dwarf.Entry{
   401  				Offset:   0xb,
   402  				Tag:      dwarf.TagCompileUnit,
   403  				Children: true,
   404  				Field: []dwarf.Field{
   405  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString},
   406  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   407  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   408  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   409  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   410  					{Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant},
   411  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   412  				},
   413  			}},
   414  		},
   415  	},
   416  	{
   417  		"testdata/go-relocation-test-gcc493-mips64le.obj",
   418  		[]relocationTestEntry{
   419  			{0, &dwarf.Entry{
   420  				Offset:   0xb,
   421  				Tag:      dwarf.TagCompileUnit,
   422  				Children: true,
   423  				Field: []dwarf.Field{
   424  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString},
   425  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   426  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   427  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   428  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   429  					{Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant},
   430  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   431  				},
   432  			}},
   433  		},
   434  	},
   435  	{
   436  		"testdata/go-relocation-test-clang-x86.obj",
   437  		[]relocationTestEntry{
   438  			{0, &dwarf.Entry{
   439  				Offset:   0xb,
   440  				Tag:      dwarf.TagCompileUnit,
   441  				Children: true,
   442  				Field: []dwarf.Field{
   443  					{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
   444  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   445  					{Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
   446  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   447  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   448  				},
   449  			}},
   450  		},
   451  	},
   452  	{
   453  		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
   454  		[]relocationTestEntry{
   455  			{203, &dwarf.Entry{
   456  				Offset:   0xc62,
   457  				Tag:      dwarf.TagMember,
   458  				Children: false,
   459  				Field: []dwarf.Field{
   460  					{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
   461  					{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   462  					{Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
   463  					{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   464  					{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
   465  				},
   466  			}},
   467  			{204, &dwarf.Entry{
   468  				Offset:   0xc70,
   469  				Tag:      dwarf.TagMember,
   470  				Children: false,
   471  				Field: []dwarf.Field{
   472  					{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
   473  					{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   474  					{Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
   475  					{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   476  					{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
   477  				},
   478  			}},
   479  		},
   480  	},
   481  }
   482  
   483  func TestDWARFRelocations(t *testing.T) {
   484  	for i, test := range relocationTests {
   485  		f, err := Open(test.file)
   486  		if err != nil {
   487  			t.Error(err)
   488  			continue
   489  		}
   490  		dwarf, err := f.DWARF()
   491  		if err != nil {
   492  			t.Error(err)
   493  			continue
   494  		}
   495  		for _, testEntry := range test.entries {
   496  			reader := dwarf.Reader()
   497  			for j := 0; j < testEntry.entryNumber; j++ {
   498  				entry, err := reader.Next()
   499  				if entry == nil || err != nil {
   500  					t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
   501  					continue
   502  				}
   503  			}
   504  			entry, err := reader.Next()
   505  			if err != nil {
   506  				t.Error(err)
   507  				continue
   508  			}
   509  			if !reflect.DeepEqual(testEntry.entry, entry) {
   510  				t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
   511  				continue
   512  			}
   513  		}
   514  	}
   515  }
   516  
   517  func TestNoSectionOverlaps(t *testing.T) {
   518  	// Ensure 6l outputs sections without overlaps.
   519  	if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
   520  		return // not ELF
   521  	}
   522  	_ = net.ResolveIPAddr // force dynamic linkage
   523  	f, err := Open(os.Args[0])
   524  	if err != nil {
   525  		t.Error(err)
   526  		return
   527  	}
   528  	for i, si := range f.Sections {
   529  		sih := si.SectionHeader
   530  		if sih.Type == SHT_NOBITS {
   531  			continue
   532  		}
   533  		for j, sj := range f.Sections {
   534  			sjh := sj.SectionHeader
   535  			if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
   536  				continue
   537  			}
   538  			if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
   539  				t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
   540  					sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
   541  			}
   542  		}
   543  	}
   544  }