...
Run Format

Source file src/debug/elf/file_test.go

Documentation: debug/elf

     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  	"math/rand"
    14  	"net"
    15  	"os"
    16  	"path"
    17  	"reflect"
    18  	"runtime"
    19  	"testing"
    20  )
    21  
    22  type fileTest struct {
    23  	file     string
    24  	hdr      FileHeader
    25  	sections []SectionHeader
    26  	progs    []ProgHeader
    27  	needed   []string
    28  }
    29  
    30  var fileTests = []fileTest{
    31  	{
    32  		"testdata/gcc-386-freebsd-exec",
    33  		FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
    34  		[]SectionHeader{
    35  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
    36  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15},
    37  			{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90},
    38  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110},
    39  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb},
    40  			{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20},
    41  			{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
    42  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50},
    43  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180},
    44  			{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
    45  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3},
    46  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
    47  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
    48  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98},
    49  			{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
    50  			{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
    51  			{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
    52  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c},
    53  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
    54  			{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d},
    55  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
    56  			{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
    57  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d},
    58  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41},
    59  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35},
    60  			{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30},
    61  			{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
    62  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8},
    63  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0},
    64  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206},
    65  		},
    66  		[]ProgHeader{
    67  			{PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
    68  			{PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
    69  			{PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
    70  			{PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
    71  			{PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
    72  		},
    73  		[]string{"libc.so.6"},
    74  	},
    75  	{
    76  		"testdata/gcc-amd64-linux-exec",
    77  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
    78  		[]SectionHeader{
    79  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
    80  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c},
    81  			{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
    82  			{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24},
    83  			{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c},
    84  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
    85  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d},
    86  			{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
    87  			{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20},
    88  			{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18},
    89  			{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30},
    90  			{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18},
    91  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30},
    92  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4},
    93  			{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe},
    94  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
    95  			{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
    96  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4},
    97  			{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
    98  			{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
    99  			{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
   100  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0},
   101  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
   102  			{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28},
   103  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18},
   104  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
   105  			{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126},
   106  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
   107  			{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25},
   108  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7},
   109  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f},
   110  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f},
   111  			{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1},
   112  			{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
   113  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149},
   114  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0},
   115  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc},
   116  		},
   117  		[]ProgHeader{
   118  			{PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
   119  			{PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
   120  			{PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
   121  			{PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
   122  			{PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
   123  			{PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
   124  			{PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
   125  			{PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
   126  		},
   127  		[]string{"libc.so.6"},
   128  	},
   129  	{
   130  		"testdata/hello-world-core.gz",
   131  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
   132  		[]SectionHeader{},
   133  		[]ProgHeader{
   134  			{Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
   135  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
   136  			{Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   137  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   138  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
   139  			{Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
   140  			{Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
   141  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
   142  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
   143  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
   144  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
   145  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
   146  			{Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   147  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
   148  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
   149  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   150  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   151  		},
   152  		nil,
   153  	},
   154  	{
   155  		"testdata/compressed-32.obj",
   156  		FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0},
   157  		[]SectionHeader{
   158  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   159  			{".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17},
   160  			{".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10},
   161  			{".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   162  			{".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   163  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
   164  			{".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84},
   165  			{".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0},
   166  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a},
   167  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
   168  			{".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10},
   169  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
   170  			{".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8},
   171  			{".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3},
   172  			{".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
   173  			{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   174  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38},
   175  			{".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8},
   176  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab},
   177  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100},
   178  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
   179  		},
   180  		[]ProgHeader{},
   181  		nil,
   182  	},
   183  	{
   184  		"testdata/compressed-64.obj",
   185  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0},
   186  		[]SectionHeader{
   187  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   188  			{".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
   189  			{".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30},
   190  			{".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   191  			{".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   192  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
   193  			{".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72},
   194  			{".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8},
   195  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
   196  			{".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f},
   197  			{".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
   198  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60},
   199  			{".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
   200  			{".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3},
   201  			{".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
   202  			{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   203  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
   204  			{".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18},
   205  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0},
   206  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
   207  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
   208  		},
   209  		[]ProgHeader{},
   210  		nil,
   211  	},
   212  }
   213  
   214  func TestOpen(t *testing.T) {
   215  	for i := range fileTests {
   216  		tt := &fileTests[i]
   217  
   218  		var f *File
   219  		var err error
   220  		if path.Ext(tt.file) == ".gz" {
   221  			var r io.ReaderAt
   222  			if r, err = decompress(tt.file); err == nil {
   223  				f, err = NewFile(r)
   224  			}
   225  		} else {
   226  			f, err = Open(tt.file)
   227  		}
   228  		if err != nil {
   229  			t.Errorf("cannot open file %s: %v", tt.file, err)
   230  			continue
   231  		}
   232  		defer f.Close()
   233  		if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
   234  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
   235  			continue
   236  		}
   237  		for i, s := range f.Sections {
   238  			if i >= len(tt.sections) {
   239  				break
   240  			}
   241  			sh := &tt.sections[i]
   242  			if !reflect.DeepEqual(&s.SectionHeader, sh) {
   243  				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &s.SectionHeader, sh)
   244  			}
   245  		}
   246  		for i, p := range f.Progs {
   247  			if i >= len(tt.progs) {
   248  				break
   249  			}
   250  			ph := &tt.progs[i]
   251  			if !reflect.DeepEqual(&p.ProgHeader, ph) {
   252  				t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, &p.ProgHeader, ph)
   253  			}
   254  		}
   255  		tn := len(tt.sections)
   256  		fn := len(f.Sections)
   257  		if tn != fn {
   258  			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
   259  		}
   260  		tn = len(tt.progs)
   261  		fn = len(f.Progs)
   262  		if tn != fn {
   263  			t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
   264  		}
   265  		tl := tt.needed
   266  		fl, err := f.ImportedLibraries()
   267  		if err != nil {
   268  			t.Error(err)
   269  		}
   270  		if !reflect.DeepEqual(tl, fl) {
   271  			t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
   272  		}
   273  	}
   274  }
   275  
   276  // elf.NewFile requires io.ReaderAt, which compress/gzip cannot
   277  // provide. Decompress the file to a bytes.Reader.
   278  func decompress(gz string) (io.ReaderAt, error) {
   279  	in, err := os.Open(gz)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  	defer in.Close()
   284  	r, err := gzip.NewReader(in)
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  	var out bytes.Buffer
   289  	_, err = io.Copy(&out, r)
   290  	return bytes.NewReader(out.Bytes()), err
   291  }
   292  
   293  type relocationTestEntry struct {
   294  	entryNumber int
   295  	entry       *dwarf.Entry
   296  }
   297  
   298  type relocationTest struct {
   299  	file    string
   300  	entries []relocationTestEntry
   301  }
   302  
   303  var relocationTests = []relocationTest{
   304  	{
   305  		"testdata/go-relocation-test-gcc441-x86-64.obj",
   306  		[]relocationTestEntry{
   307  			{0, &dwarf.Entry{
   308  				Offset:   0xb,
   309  				Tag:      dwarf.TagCompileUnit,
   310  				Children: true,
   311  				Field: []dwarf.Field{
   312  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   313  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   314  					{Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString},
   315  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   316  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   317  					{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   318  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   319  				},
   320  			}},
   321  		},
   322  	},
   323  	{
   324  		"testdata/go-relocation-test-gcc441-x86.obj",
   325  		[]relocationTestEntry{
   326  			{0, &dwarf.Entry{
   327  				Offset:   0xb,
   328  				Tag:      dwarf.TagCompileUnit,
   329  				Children: true,
   330  				Field: []dwarf.Field{
   331  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   332  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   333  					{Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString},
   334  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   335  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   336  					{Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress},
   337  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   338  				},
   339  			}},
   340  		},
   341  	},
   342  	{
   343  		"testdata/go-relocation-test-gcc424-x86-64.obj",
   344  		[]relocationTestEntry{
   345  			{0, &dwarf.Entry{
   346  				Offset:   0xb,
   347  				Tag:      dwarf.TagCompileUnit,
   348  				Children: true,
   349  				Field: []dwarf.Field{
   350  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString},
   351  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   352  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString},
   353  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   354  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   355  					{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   356  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   357  				},
   358  			}},
   359  		},
   360  	},
   361  	{
   362  		"testdata/go-relocation-test-gcc482-aarch64.obj",
   363  		[]relocationTestEntry{
   364  			{0, &dwarf.Entry{
   365  				Offset:   0xb,
   366  				Tag:      dwarf.TagCompileUnit,
   367  				Children: true,
   368  				Field: []dwarf.Field{
   369  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString},
   370  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   371  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString},
   372  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   373  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   374  					{Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant},
   375  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   376  				},
   377  			}},
   378  		},
   379  	},
   380  	{
   381  		"testdata/go-relocation-test-gcc492-arm.obj",
   382  		[]relocationTestEntry{
   383  			{0, &dwarf.Entry{
   384  				Offset:   0xb,
   385  				Tag:      dwarf.TagCompileUnit,
   386  				Children: true,
   387  				Field: []dwarf.Field{
   388  					{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},
   389  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   390  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString},
   391  					{Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString},
   392  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   393  					{Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant},
   394  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   395  				},
   396  			}},
   397  		},
   398  	},
   399  	{
   400  		"testdata/go-relocation-test-clang-arm.obj",
   401  		[]relocationTestEntry{
   402  			{0, &dwarf.Entry{
   403  				Offset:   0xb,
   404  				Tag:      dwarf.TagCompileUnit,
   405  				Children: true,
   406  				Field: []dwarf.Field{
   407  					{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString},
   408  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   409  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   410  					{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr},
   411  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   412  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   413  					{Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant},
   414  				},
   415  			}},
   416  		},
   417  	},
   418  	{
   419  		"testdata/go-relocation-test-gcc5-ppc.obj",
   420  		[]relocationTestEntry{
   421  			{0, &dwarf.Entry{
   422  				Offset:   0xb,
   423  				Tag:      dwarf.TagCompileUnit,
   424  				Children: true,
   425  				Field: []dwarf.Field{
   426  					{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString},
   427  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   428  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString},
   429  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   430  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   431  					{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant},
   432  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   433  				},
   434  			}},
   435  		},
   436  	},
   437  	{
   438  		"testdata/go-relocation-test-gcc482-ppc64le.obj",
   439  		[]relocationTestEntry{
   440  			{0, &dwarf.Entry{
   441  				Offset:   0xb,
   442  				Tag:      dwarf.TagCompileUnit,
   443  				Children: true,
   444  				Field: []dwarf.Field{
   445  					{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},
   446  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   447  					{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString},
   448  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   449  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   450  					{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress},
   451  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   452  				},
   453  			}},
   454  		},
   455  	},
   456  	{
   457  		"testdata/go-relocation-test-gcc492-mips64.obj",
   458  		[]relocationTestEntry{
   459  			{0, &dwarf.Entry{
   460  				Offset:   0xb,
   461  				Tag:      dwarf.TagCompileUnit,
   462  				Children: true,
   463  				Field: []dwarf.Field{
   464  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString},
   465  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   466  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   467  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   468  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   469  					{Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant},
   470  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   471  				},
   472  			}},
   473  		},
   474  	},
   475  	{
   476  		"testdata/go-relocation-test-gcc531-s390x.obj",
   477  		[]relocationTestEntry{
   478  			{0, &dwarf.Entry{
   479  				Offset:   0xb,
   480  				Tag:      dwarf.TagCompileUnit,
   481  				Children: true,
   482  				Field: []dwarf.Field{
   483  					{Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong", Class: dwarf.ClassString},
   484  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   485  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   486  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   487  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   488  					{Attr: dwarf.AttrHighpc, Val: int64(58), Class: dwarf.ClassConstant},
   489  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   490  				},
   491  			}},
   492  		},
   493  	},
   494  	{
   495  		"testdata/go-relocation-test-gcc620-sparc64.obj",
   496  		[]relocationTestEntry{
   497  			{0, &dwarf.Entry{
   498  				Offset:   0xb,
   499  				Tag:      dwarf.TagCompileUnit,
   500  				Children: true,
   501  				Field: []dwarf.Field{
   502  					{Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong", Class: dwarf.ClassString},
   503  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   504  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   505  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   506  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   507  					{Attr: dwarf.AttrHighpc, Val: int64(0x2c), Class: dwarf.ClassConstant},
   508  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   509  				},
   510  			}},
   511  		},
   512  	},
   513  	{
   514  		"testdata/go-relocation-test-gcc492-mipsle.obj",
   515  		[]relocationTestEntry{
   516  			{0, &dwarf.Entry{
   517  				Offset:   0xb,
   518  				Tag:      dwarf.TagCompileUnit,
   519  				Children: true,
   520  				Field: []dwarf.Field{
   521  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g", Class: dwarf.ClassString},
   522  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   523  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   524  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   525  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   526  					{Attr: dwarf.AttrHighpc, Val: int64(0x58), Class: dwarf.ClassConstant},
   527  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   528  				},
   529  			}},
   530  		},
   531  	},
   532  	{
   533  		"testdata/go-relocation-test-gcc540-mips.obj",
   534  		[]relocationTestEntry{
   535  			{0, &dwarf.Entry{
   536  				Offset:   0xb,
   537  				Tag:      dwarf.TagCompileUnit,
   538  				Children: true,
   539  				Field: []dwarf.Field{
   540  					{Attr: dwarf.AttrProducer, Val: "GNU C11 5.4.0 20160609 -meb -mips32 -mtune=mips32r2 -mfpxx -mllsc -mno-shared -mabi=32 -g -gdwarf-2", Class: dwarf.ClassString},
   541  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   542  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   543  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   544  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   545  					{Attr: dwarf.AttrHighpc, Val: uint64(0x5c), Class: dwarf.ClassAddress},
   546  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   547  				},
   548  			}},
   549  		},
   550  	},
   551  	{
   552  		"testdata/go-relocation-test-gcc493-mips64le.obj",
   553  		[]relocationTestEntry{
   554  			{0, &dwarf.Entry{
   555  				Offset:   0xb,
   556  				Tag:      dwarf.TagCompileUnit,
   557  				Children: true,
   558  				Field: []dwarf.Field{
   559  					{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString},
   560  					{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   561  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   562  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   563  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   564  					{Attr: dwarf.AttrHighpc, Val: int64(100), Class: dwarf.ClassConstant},
   565  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   566  				},
   567  			}},
   568  		},
   569  	},
   570  	{
   571  		"testdata/go-relocation-test-gcc720-riscv64.obj",
   572  		[]relocationTestEntry{
   573  			{0, &dwarf.Entry{
   574  				Offset:   0xb,
   575  				Tag:      dwarf.TagCompileUnit,
   576  				Children: true,
   577  				Field: []dwarf.Field{
   578  					{Attr: dwarf.AttrProducer, Val: "GNU C11 7.2.0 -march=rv64imafdc -mabi=lp64d -g -gdwarf-2", Class: dwarf.ClassString},
   579  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   580  					{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   581  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   582  					{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   583  					{Attr: dwarf.AttrHighpc, Val: uint64(0x2c), Class: dwarf.ClassAddress},
   584  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   585  				},
   586  			}},
   587  		},
   588  	},
   589  	{
   590  		"testdata/go-relocation-test-clang-x86.obj",
   591  		[]relocationTestEntry{
   592  			{0, &dwarf.Entry{
   593  				Offset:   0xb,
   594  				Tag:      dwarf.TagCompileUnit,
   595  				Children: true,
   596  				Field: []dwarf.Field{
   597  					{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
   598  					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   599  					{Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
   600  					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   601  					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   602  				},
   603  			}},
   604  		},
   605  	},
   606  	{
   607  		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
   608  		[]relocationTestEntry{
   609  			{203, &dwarf.Entry{
   610  				Offset:   0xc62,
   611  				Tag:      dwarf.TagMember,
   612  				Children: false,
   613  				Field: []dwarf.Field{
   614  					{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
   615  					{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   616  					{Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
   617  					{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   618  					{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
   619  				},
   620  			}},
   621  			{204, &dwarf.Entry{
   622  				Offset:   0xc70,
   623  				Tag:      dwarf.TagMember,
   624  				Children: false,
   625  				Field: []dwarf.Field{
   626  					{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
   627  					{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   628  					{Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
   629  					{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   630  					{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
   631  				},
   632  			}},
   633  		},
   634  	},
   635  }
   636  
   637  func TestDWARFRelocations(t *testing.T) {
   638  	for i, test := range relocationTests {
   639  		f, err := Open(test.file)
   640  		if err != nil {
   641  			t.Error(err)
   642  			continue
   643  		}
   644  		dwarf, err := f.DWARF()
   645  		if err != nil {
   646  			t.Error(err)
   647  			continue
   648  		}
   649  		for _, testEntry := range test.entries {
   650  			reader := dwarf.Reader()
   651  			for j := 0; j < testEntry.entryNumber; j++ {
   652  				entry, err := reader.Next()
   653  				if entry == nil || err != nil {
   654  					t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
   655  					continue
   656  				}
   657  			}
   658  			entry, err := reader.Next()
   659  			if err != nil {
   660  				t.Error(err)
   661  				continue
   662  			}
   663  			if !reflect.DeepEqual(testEntry.entry, entry) {
   664  				t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
   665  				continue
   666  			}
   667  		}
   668  	}
   669  }
   670  
   671  func TestCompressedDWARF(t *testing.T) {
   672  	// Test file built with GCC 4.8.4 and as 2.24 using:
   673  	// gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
   674  	f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
   675  	if err != nil {
   676  		t.Fatal(err)
   677  	}
   678  	dwarf, err := f.DWARF()
   679  	if err != nil {
   680  		t.Fatal(err)
   681  	}
   682  	reader := dwarf.Reader()
   683  	n := 0
   684  	for {
   685  		entry, err := reader.Next()
   686  		if err != nil {
   687  			t.Fatal(err)
   688  		}
   689  		if entry == nil {
   690  			break
   691  		}
   692  		n++
   693  	}
   694  	if n != 18 {
   695  		t.Fatalf("want %d DWARF entries, got %d", 18, n)
   696  	}
   697  }
   698  
   699  func TestCompressedSection(t *testing.T) {
   700  	// Test files built with gcc -g -S hello.c and assembled with
   701  	// --compress-debug-sections=zlib-gabi.
   702  	f, err := Open("testdata/compressed-64.obj")
   703  	if err != nil {
   704  		t.Fatal(err)
   705  	}
   706  	sec := f.Section(".debug_info")
   707  	wantData := []byte{
   708  		182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
   709  		1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   710  		0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
   711  		0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
   712  		0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
   713  		2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
   714  		5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
   715  		0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
   716  		0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
   717  		1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
   718  		0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
   719  		145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
   720  	}
   721  
   722  	// Test Data method.
   723  	b, err := sec.Data()
   724  	if err != nil {
   725  		t.Fatal(err)
   726  	}
   727  	if !bytes.Equal(wantData, b) {
   728  		t.Fatalf("want data %x, got %x", wantData, b)
   729  	}
   730  
   731  	// Test Open method and seeking.
   732  	buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
   733  	sf := sec.Open()
   734  	if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
   735  		t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
   736  	}
   737  	if n, err := sf.Read(buf); n != 0 || err != io.EOF {
   738  		t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
   739  	}
   740  	pos := int64(len(buf))
   741  	for count < len(buf) {
   742  		// Construct random seek arguments.
   743  		whence := rand.Intn(3)
   744  		target := rand.Int63n(int64(len(buf)))
   745  		var offset int64
   746  		switch whence {
   747  		case io.SeekStart:
   748  			offset = target
   749  		case io.SeekCurrent:
   750  			offset = target - pos
   751  		case io.SeekEnd:
   752  			offset = target - int64(len(buf))
   753  		}
   754  		pos, err = sf.Seek(offset, whence)
   755  		if err != nil {
   756  			t.Fatal(err)
   757  		}
   758  		if pos != target {
   759  			t.Fatalf("want position %d, got %d", target, pos)
   760  		}
   761  
   762  		// Read data from the new position.
   763  		end := pos + 16
   764  		if end > int64(len(buf)) {
   765  			end = int64(len(buf))
   766  		}
   767  		n, err := io.ReadFull(sf, buf[pos:end])
   768  		if err != nil {
   769  			t.Fatal(err)
   770  		}
   771  		for i := 0; i < n; i++ {
   772  			if !have[pos] {
   773  				have[pos] = true
   774  				count++
   775  			}
   776  			pos++
   777  		}
   778  	}
   779  	if !bytes.Equal(wantData, buf) {
   780  		t.Fatalf("want data %x, got %x", wantData, buf)
   781  	}
   782  }
   783  
   784  func TestNoSectionOverlaps(t *testing.T) {
   785  	// Ensure cmd/link outputs sections without overlaps.
   786  	switch runtime.GOOS {
   787  	case "android", "darwin", "js", "nacl", "plan9", "windows":
   788  		t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS)
   789  	}
   790  	_ = net.ResolveIPAddr // force dynamic linkage
   791  	f, err := Open(os.Args[0])
   792  	if err != nil {
   793  		t.Error(err)
   794  		return
   795  	}
   796  	for i, si := range f.Sections {
   797  		sih := si.SectionHeader
   798  		if sih.Type == SHT_NOBITS {
   799  			continue
   800  		}
   801  		for j, sj := range f.Sections {
   802  			sjh := sj.SectionHeader
   803  			if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
   804  				continue
   805  			}
   806  			if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
   807  				t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
   808  					sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
   809  			}
   810  		}
   811  	}
   812  }
   813  

View as plain text