Source file src/debug/elf/file_test.go

     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  	pcRanges    [][2]uint64
   297  }
   298  
   299  type relocationTest struct {
   300  	file    string
   301  	entries []relocationTestEntry
   302  }
   303  
   304  var relocationTests = []relocationTest{
   305  	{
   306  		"testdata/go-relocation-test-gcc441-x86-64.obj",
   307  		[]relocationTestEntry{
   308  			{
   309  				entry: &dwarf.Entry{
   310  					Offset:   0xb,
   311  					Tag:      dwarf.TagCompileUnit,
   312  					Children: true,
   313  					Field: []dwarf.Field{
   314  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   315  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   316  						{Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString},
   317  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   318  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   319  						{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   320  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   321  					},
   322  				},
   323  				pcRanges: [][2]uint64{{0x0, 0x6}},
   324  			},
   325  		},
   326  	},
   327  	{
   328  		"testdata/go-relocation-test-gcc441-x86.obj",
   329  		[]relocationTestEntry{
   330  			{
   331  				entry: &dwarf.Entry{
   332  					Offset:   0xb,
   333  					Tag:      dwarf.TagCompileUnit,
   334  					Children: true,
   335  					Field: []dwarf.Field{
   336  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   337  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   338  						{Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString},
   339  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   340  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   341  						{Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress},
   342  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   343  					},
   344  				},
   345  				pcRanges: [][2]uint64{{0x0, 0x5}},
   346  			},
   347  		},
   348  	},
   349  	{
   350  		"testdata/go-relocation-test-gcc424-x86-64.obj",
   351  		[]relocationTestEntry{
   352  			{
   353  				entry: &dwarf.Entry{
   354  					Offset:   0xb,
   355  					Tag:      dwarf.TagCompileUnit,
   356  					Children: true,
   357  					Field: []dwarf.Field{
   358  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString},
   359  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   360  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString},
   361  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   362  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   363  						{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   364  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   365  					},
   366  				},
   367  				pcRanges: [][2]uint64{{0x0, 0x6}},
   368  			},
   369  		},
   370  	},
   371  	{
   372  		"testdata/go-relocation-test-gcc482-aarch64.obj",
   373  		[]relocationTestEntry{
   374  			{
   375  				entry: &dwarf.Entry{
   376  					Offset:   0xb,
   377  					Tag:      dwarf.TagCompileUnit,
   378  					Children: true,
   379  					Field: []dwarf.Field{
   380  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString},
   381  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   382  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString},
   383  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   384  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   385  						{Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant},
   386  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   387  					},
   388  				},
   389  				pcRanges: [][2]uint64{{0x0, 0x24}},
   390  			},
   391  		},
   392  	},
   393  	{
   394  		"testdata/go-relocation-test-gcc492-arm.obj",
   395  		[]relocationTestEntry{
   396  			{
   397  				entry: &dwarf.Entry{
   398  					Offset:   0xb,
   399  					Tag:      dwarf.TagCompileUnit,
   400  					Children: true,
   401  					Field: []dwarf.Field{
   402  						{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},
   403  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   404  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString},
   405  						{Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString},
   406  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   407  						{Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant},
   408  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   409  					},
   410  				},
   411  				pcRanges: [][2]uint64{{0x0, 0x28}},
   412  			},
   413  		},
   414  	},
   415  	{
   416  		"testdata/go-relocation-test-clang-arm.obj",
   417  		[]relocationTestEntry{
   418  			{
   419  				entry: &dwarf.Entry{
   420  					Offset:   0xb,
   421  					Tag:      dwarf.TagCompileUnit,
   422  					Children: true,
   423  					Field: []dwarf.Field{
   424  						{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString},
   425  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   426  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   427  						{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr},
   428  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   429  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   430  						{Attr: dwarf.AttrHighpc, Val: int64(0x30), Class: dwarf.ClassConstant},
   431  					},
   432  				},
   433  				pcRanges: [][2]uint64{{0x0, 0x30}},
   434  			},
   435  		},
   436  	},
   437  	{
   438  		"testdata/go-relocation-test-gcc5-ppc.obj",
   439  		[]relocationTestEntry{
   440  			{
   441  				entry: &dwarf.Entry{
   442  					Offset:   0xb,
   443  					Tag:      dwarf.TagCompileUnit,
   444  					Children: true,
   445  					Field: []dwarf.Field{
   446  						{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString},
   447  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   448  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString},
   449  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   450  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   451  						{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant},
   452  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   453  					},
   454  				},
   455  				pcRanges: [][2]uint64{{0x0, 0x44}},
   456  			},
   457  		},
   458  	},
   459  	{
   460  		"testdata/go-relocation-test-gcc482-ppc64le.obj",
   461  		[]relocationTestEntry{
   462  			{
   463  				entry: &dwarf.Entry{
   464  					Offset:   0xb,
   465  					Tag:      dwarf.TagCompileUnit,
   466  					Children: true,
   467  					Field: []dwarf.Field{
   468  						{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},
   469  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   470  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString},
   471  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   472  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   473  						{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress},
   474  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   475  					},
   476  				},
   477  				pcRanges: [][2]uint64{{0x0, 0x24}},
   478  			},
   479  		},
   480  	},
   481  	{
   482  		"testdata/go-relocation-test-gcc492-mips64.obj",
   483  		[]relocationTestEntry{
   484  			{
   485  				entry: &dwarf.Entry{
   486  					Offset:   0xb,
   487  					Tag:      dwarf.TagCompileUnit,
   488  					Children: true,
   489  					Field: []dwarf.Field{
   490  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString},
   491  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   492  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   493  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   494  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   495  						{Attr: dwarf.AttrHighpc, Val: int64(0x64), Class: dwarf.ClassConstant},
   496  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   497  					},
   498  				},
   499  				pcRanges: [][2]uint64{{0x0, 0x64}},
   500  			},
   501  		},
   502  	},
   503  	{
   504  		"testdata/go-relocation-test-gcc531-s390x.obj",
   505  		[]relocationTestEntry{
   506  			{
   507  				entry: &dwarf.Entry{
   508  					Offset:   0xb,
   509  					Tag:      dwarf.TagCompileUnit,
   510  					Children: true,
   511  					Field: []dwarf.Field{
   512  						{Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong", Class: dwarf.ClassString},
   513  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   514  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   515  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   516  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   517  						{Attr: dwarf.AttrHighpc, Val: int64(0x3a), Class: dwarf.ClassConstant},
   518  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   519  					},
   520  				},
   521  				pcRanges: [][2]uint64{{0x0, 0x3a}},
   522  			},
   523  		},
   524  	},
   525  	{
   526  		"testdata/go-relocation-test-gcc620-sparc64.obj",
   527  		[]relocationTestEntry{
   528  			{
   529  				entry: &dwarf.Entry{
   530  					Offset:   0xb,
   531  					Tag:      dwarf.TagCompileUnit,
   532  					Children: true,
   533  					Field: []dwarf.Field{
   534  						{Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong", Class: dwarf.ClassString},
   535  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   536  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   537  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   538  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   539  						{Attr: dwarf.AttrHighpc, Val: int64(0x2c), Class: dwarf.ClassConstant},
   540  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   541  					},
   542  				},
   543  				pcRanges: [][2]uint64{{0x0, 0x2c}},
   544  			},
   545  		},
   546  	},
   547  	{
   548  		"testdata/go-relocation-test-gcc492-mipsle.obj",
   549  		[]relocationTestEntry{
   550  			{
   551  				entry: &dwarf.Entry{
   552  					Offset:   0xb,
   553  					Tag:      dwarf.TagCompileUnit,
   554  					Children: true,
   555  					Field: []dwarf.Field{
   556  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g", Class: dwarf.ClassString},
   557  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   558  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   559  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   560  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   561  						{Attr: dwarf.AttrHighpc, Val: int64(0x58), Class: dwarf.ClassConstant},
   562  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   563  					},
   564  				},
   565  				pcRanges: [][2]uint64{{0x0, 0x58}},
   566  			},
   567  		},
   568  	},
   569  	{
   570  		"testdata/go-relocation-test-gcc540-mips.obj",
   571  		[]relocationTestEntry{
   572  			{
   573  				entry: &dwarf.Entry{
   574  					Offset:   0xb,
   575  					Tag:      dwarf.TagCompileUnit,
   576  					Children: true,
   577  					Field: []dwarf.Field{
   578  						{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},
   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(0x5c), Class: dwarf.ClassAddress},
   584  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   585  					},
   586  				},
   587  				pcRanges: [][2]uint64{{0x0, 0x5c}},
   588  			},
   589  		},
   590  	},
   591  	{
   592  		"testdata/go-relocation-test-gcc493-mips64le.obj",
   593  		[]relocationTestEntry{
   594  			{
   595  				entry: &dwarf.Entry{
   596  					Offset:   0xb,
   597  					Tag:      dwarf.TagCompileUnit,
   598  					Children: true,
   599  					Field: []dwarf.Field{
   600  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString},
   601  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   602  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   603  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   604  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   605  						{Attr: dwarf.AttrHighpc, Val: int64(0x64), Class: dwarf.ClassConstant},
   606  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   607  					},
   608  				},
   609  				pcRanges: [][2]uint64{{0x0, 0x64}},
   610  			},
   611  		},
   612  	},
   613  	{
   614  		"testdata/go-relocation-test-gcc720-riscv64.obj",
   615  		[]relocationTestEntry{
   616  			{
   617  				entry: &dwarf.Entry{
   618  					Offset:   0xb,
   619  					Tag:      dwarf.TagCompileUnit,
   620  					Children: true,
   621  					Field: []dwarf.Field{
   622  						{Attr: dwarf.AttrProducer, Val: "GNU C11 7.2.0 -march=rv64imafdc -mabi=lp64d -g -gdwarf-2", Class: dwarf.ClassString},
   623  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   624  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   625  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   626  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   627  						{Attr: dwarf.AttrHighpc, Val: uint64(0x2c), Class: dwarf.ClassAddress},
   628  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   629  					},
   630  				},
   631  				pcRanges: [][2]uint64{{0x0, 0x2c}},
   632  			},
   633  		},
   634  	},
   635  	{
   636  		"testdata/go-relocation-test-clang-x86.obj",
   637  		[]relocationTestEntry{
   638  			{
   639  				entry: &dwarf.Entry{
   640  					Offset:   0xb,
   641  					Tag:      dwarf.TagCompileUnit,
   642  					Children: true,
   643  					Field: []dwarf.Field{
   644  						{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
   645  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   646  						{Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
   647  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   648  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   649  					},
   650  				},
   651  			},
   652  		},
   653  	},
   654  	{
   655  		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
   656  		[]relocationTestEntry{
   657  			{
   658  				entryNumber: 203,
   659  				entry: &dwarf.Entry{
   660  					Offset:   0xc62,
   661  					Tag:      dwarf.TagMember,
   662  					Children: false,
   663  					Field: []dwarf.Field{
   664  						{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
   665  						{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   666  						{Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
   667  						{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   668  						{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
   669  					},
   670  				},
   671  			},
   672  			{
   673  				entryNumber: 204,
   674  				entry: &dwarf.Entry{
   675  					Offset:   0xc70,
   676  					Tag:      dwarf.TagMember,
   677  					Children: false,
   678  					Field: []dwarf.Field{
   679  						{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
   680  						{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   681  						{Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
   682  						{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   683  						{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
   684  					},
   685  				},
   686  			},
   687  		},
   688  	},
   689  	{
   690  		"testdata/go-relocation-test-gcc930-ranges-no-rela-x86-64",
   691  		[]relocationTestEntry{
   692  			{
   693  				entry: &dwarf.Entry{
   694  					Offset:   0xb,
   695  					Tag:      dwarf.TagCompileUnit,
   696  					Children: true,
   697  					Field: []dwarf.Field{
   698  						{Attr: dwarf.AttrProducer, Val: "GNU C17 9.3.0 -mtune=generic -march=x86-64 -g -fno-asynchronous-unwind-tables", Class: dwarf.ClassString},
   699  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   700  						{Attr: dwarf.AttrName, Val: "multiple-code-sections.c", Class: dwarf.ClassString},
   701  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   702  						{Attr: dwarf.AttrRanges, Val: int64(0), Class: dwarf.ClassRangeListPtr},
   703  						{Attr: dwarf.AttrLowpc, Val: uint64(0), Class: dwarf.ClassAddress},
   704  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   705  					},
   706  				},
   707  				pcRanges: [][2]uint64{
   708  					{0x765, 0x777},
   709  					{0x7e1, 0x7ec},
   710  				},
   711  			},
   712  		},
   713  	},
   714  	{
   715  		"testdata/go-relocation-test-gcc930-ranges-with-rela-x86-64",
   716  		[]relocationTestEntry{
   717  			{
   718  				entry: &dwarf.Entry{
   719  					Offset:   0xb,
   720  					Tag:      dwarf.TagCompileUnit,
   721  					Children: true,
   722  					Field: []dwarf.Field{
   723  						{Attr: dwarf.AttrProducer, Val: "GNU C17 9.3.0 -mtune=generic -march=x86-64 -g -fno-asynchronous-unwind-tables", Class: dwarf.ClassString},
   724  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   725  						{Attr: dwarf.AttrName, Val: "multiple-code-sections.c", Class: dwarf.ClassString},
   726  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   727  						{Attr: dwarf.AttrRanges, Val: int64(0), Class: dwarf.ClassRangeListPtr},
   728  						{Attr: dwarf.AttrLowpc, Val: uint64(0), Class: dwarf.ClassAddress},
   729  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   730  					},
   731  				},
   732  				pcRanges: [][2]uint64{
   733  					{0x765, 0x777},
   734  					{0x7e1, 0x7ec},
   735  				},
   736  			},
   737  		},
   738  	},
   739  }
   740  
   741  func TestDWARFRelocations(t *testing.T) {
   742  	for _, test := range relocationTests {
   743  		test := test
   744  		t.Run(test.file, func(t *testing.T) {
   745  			t.Parallel()
   746  			f, err := Open(test.file)
   747  			if err != nil {
   748  				t.Fatal(err)
   749  			}
   750  			dwarf, err := f.DWARF()
   751  			if err != nil {
   752  				t.Fatal(err)
   753  			}
   754  			reader := dwarf.Reader()
   755  			idx := 0
   756  			for _, testEntry := range test.entries {
   757  				if testEntry.entryNumber < idx {
   758  					t.Fatalf("internal test error: %d < %d", testEntry.entryNumber, idx)
   759  				}
   760  				for ; idx < testEntry.entryNumber; idx++ {
   761  					entry, err := reader.Next()
   762  					if entry == nil || err != nil {
   763  						t.Fatalf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
   764  					}
   765  				}
   766  				entry, err := reader.Next()
   767  				idx++
   768  				if err != nil {
   769  					t.Fatal(err)
   770  				}
   771  				if !reflect.DeepEqual(testEntry.entry, entry) {
   772  					t.Errorf("entry %d mismatch: got:%#v want:%#v", testEntry.entryNumber, entry, testEntry.entry)
   773  				}
   774  				pcRanges, err := dwarf.Ranges(entry)
   775  				if err != nil {
   776  					t.Fatal(err)
   777  				}
   778  				if !reflect.DeepEqual(testEntry.pcRanges, pcRanges) {
   779  					t.Errorf("entry %d: PC range mismatch: got:%#v want:%#v", testEntry.entryNumber, pcRanges, testEntry.pcRanges)
   780  				}
   781  			}
   782  		})
   783  	}
   784  }
   785  
   786  func TestCompressedDWARF(t *testing.T) {
   787  	// Test file built with GCC 4.8.4 and as 2.24 using:
   788  	// gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
   789  	f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
   790  	if err != nil {
   791  		t.Fatal(err)
   792  	}
   793  	dwarf, err := f.DWARF()
   794  	if err != nil {
   795  		t.Fatal(err)
   796  	}
   797  	reader := dwarf.Reader()
   798  	n := 0
   799  	for {
   800  		entry, err := reader.Next()
   801  		if err != nil {
   802  			t.Fatal(err)
   803  		}
   804  		if entry == nil {
   805  			break
   806  		}
   807  		n++
   808  	}
   809  	if n != 18 {
   810  		t.Fatalf("want %d DWARF entries, got %d", 18, n)
   811  	}
   812  }
   813  
   814  func TestCompressedSection(t *testing.T) {
   815  	// Test files built with gcc -g -S hello.c and assembled with
   816  	// --compress-debug-sections=zlib-gabi.
   817  	f, err := Open("testdata/compressed-64.obj")
   818  	if err != nil {
   819  		t.Fatal(err)
   820  	}
   821  	sec := f.Section(".debug_info")
   822  	wantData := []byte{
   823  		182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
   824  		1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   825  		0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
   826  		0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
   827  		0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
   828  		2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
   829  		5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
   830  		0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
   831  		0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
   832  		1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
   833  		0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
   834  		145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
   835  	}
   836  
   837  	// Test Data method.
   838  	b, err := sec.Data()
   839  	if err != nil {
   840  		t.Fatal(err)
   841  	}
   842  	if !bytes.Equal(wantData, b) {
   843  		t.Fatalf("want data %x, got %x", wantData, b)
   844  	}
   845  
   846  	// Test Open method and seeking.
   847  	buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
   848  	sf := sec.Open()
   849  	if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
   850  		t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
   851  	}
   852  	if n, err := sf.Read(buf); n != 0 || err != io.EOF {
   853  		t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
   854  	}
   855  	pos := int64(len(buf))
   856  	for count < len(buf) {
   857  		// Construct random seek arguments.
   858  		whence := rand.Intn(3)
   859  		target := rand.Int63n(int64(len(buf)))
   860  		var offset int64
   861  		switch whence {
   862  		case io.SeekStart:
   863  			offset = target
   864  		case io.SeekCurrent:
   865  			offset = target - pos
   866  		case io.SeekEnd:
   867  			offset = target - int64(len(buf))
   868  		}
   869  		pos, err = sf.Seek(offset, whence)
   870  		if err != nil {
   871  			t.Fatal(err)
   872  		}
   873  		if pos != target {
   874  			t.Fatalf("want position %d, got %d", target, pos)
   875  		}
   876  
   877  		// Read data from the new position.
   878  		end := pos + 16
   879  		if end > int64(len(buf)) {
   880  			end = int64(len(buf))
   881  		}
   882  		n, err := io.ReadFull(sf, buf[pos:end])
   883  		if err != nil {
   884  			t.Fatal(err)
   885  		}
   886  		for i := 0; i < n; i++ {
   887  			if !have[pos] {
   888  				have[pos] = true
   889  				count++
   890  			}
   891  			pos++
   892  		}
   893  	}
   894  	if !bytes.Equal(wantData, buf) {
   895  		t.Fatalf("want data %x, got %x", wantData, buf)
   896  	}
   897  }
   898  
   899  func TestNoSectionOverlaps(t *testing.T) {
   900  	// Ensure cmd/link outputs sections without overlaps.
   901  	switch runtime.GOOS {
   902  	case "aix", "android", "darwin", "ios", "js", "plan9", "windows":
   903  		t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS)
   904  	}
   905  	_ = net.ResolveIPAddr // force dynamic linkage
   906  	f, err := Open(os.Args[0])
   907  	if err != nil {
   908  		t.Error(err)
   909  		return
   910  	}
   911  	for i, si := range f.Sections {
   912  		sih := si.SectionHeader
   913  		if sih.Type == SHT_NOBITS {
   914  			continue
   915  		}
   916  		for j, sj := range f.Sections {
   917  			sjh := sj.SectionHeader
   918  			if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
   919  				continue
   920  			}
   921  			if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
   922  				t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
   923  					sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
   924  			}
   925  		}
   926  	}
   927  }
   928  
   929  func TestIssue10996(t *testing.T) {
   930  	data := []byte("\u007fELF\x02\x01\x010000000000000" +
   931  		"\x010000000000000000000" +
   932  		"\x00\x00\x00\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00" +
   933  		"0000")
   934  	_, err := NewFile(bytes.NewReader(data))
   935  	if err == nil {
   936  		t.Fatalf("opening invalid ELF file unexpectedly succeeded")
   937  	}
   938  }
   939  

View as plain text