Home | History | Annotate | Download | only in 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-clang-x86.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: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
    579 					{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
    580 					{Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
    581 					{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
    582 					{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
    583 				},
    584 			}},
    585 		},
    586 	},
    587 	{
    588 		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
    589 		[]relocationTestEntry{
    590 			{203, &dwarf.Entry{
    591 				Offset:   0xc62,
    592 				Tag:      dwarf.TagMember,
    593 				Children: false,
    594 				Field: []dwarf.Field{
    595 					{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
    596 					{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
    597 					{Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
    598 					{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
    599 					{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
    600 				},
    601 			}},
    602 			{204, &dwarf.Entry{
    603 				Offset:   0xc70,
    604 				Tag:      dwarf.TagMember,
    605 				Children: false,
    606 				Field: []dwarf.Field{
    607 					{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
    608 					{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
    609 					{Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
    610 					{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
    611 					{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
    612 				},
    613 			}},
    614 		},
    615 	},
    616 }
    617 
    618 func TestDWARFRelocations(t *testing.T) {
    619 	for i, test := range relocationTests {
    620 		f, err := Open(test.file)
    621 		if err != nil {
    622 			t.Error(err)
    623 			continue
    624 		}
    625 		dwarf, err := f.DWARF()
    626 		if err != nil {
    627 			t.Error(err)
    628 			continue
    629 		}
    630 		for _, testEntry := range test.entries {
    631 			reader := dwarf.Reader()
    632 			for j := 0; j < testEntry.entryNumber; j++ {
    633 				entry, err := reader.Next()
    634 				if entry == nil || err != nil {
    635 					t.Errorf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
    636 					continue
    637 				}
    638 			}
    639 			entry, err := reader.Next()
    640 			if err != nil {
    641 				t.Error(err)
    642 				continue
    643 			}
    644 			if !reflect.DeepEqual(testEntry.entry, entry) {
    645 				t.Errorf("#%d/%d: mismatch: got:%#v want:%#v", i, testEntry.entryNumber, entry, testEntry.entry)
    646 				continue
    647 			}
    648 		}
    649 	}
    650 }
    651 
    652 func TestCompressedDWARF(t *testing.T) {
    653 	// Test file built with GCC 4.8.4 and as 2.24 using:
    654 	// gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
    655 	f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
    656 	if err != nil {
    657 		t.Fatal(err)
    658 	}
    659 	dwarf, err := f.DWARF()
    660 	if err != nil {
    661 		t.Fatal(err)
    662 	}
    663 	reader := dwarf.Reader()
    664 	n := 0
    665 	for {
    666 		entry, err := reader.Next()
    667 		if err != nil {
    668 			t.Fatal(err)
    669 		}
    670 		if entry == nil {
    671 			break
    672 		}
    673 		n++
    674 	}
    675 	if n != 18 {
    676 		t.Fatalf("want %d DWARF entries, got %d", 18, n)
    677 	}
    678 }
    679 
    680 func TestCompressedSection(t *testing.T) {
    681 	// Test files built with gcc -g -S hello.c and assembled with
    682 	// --compress-debug-sections=zlib-gabi.
    683 	f, err := Open("testdata/compressed-64.obj")
    684 	if err != nil {
    685 		t.Fatal(err)
    686 	}
    687 	sec := f.Section(".debug_info")
    688 	wantData := []byte{
    689 		182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
    690 		1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    691 		0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
    692 		0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
    693 		0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
    694 		2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
    695 		5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
    696 		0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
    697 		0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
    698 		1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
    699 		0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
    700 		145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
    701 	}
    702 
    703 	// Test Data method.
    704 	b, err := sec.Data()
    705 	if err != nil {
    706 		t.Fatal(err)
    707 	}
    708 	if !bytes.Equal(wantData, b) {
    709 		t.Fatalf("want data %x, got %x", wantData, b)
    710 	}
    711 
    712 	// Test Open method and seeking.
    713 	buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
    714 	sf := sec.Open()
    715 	if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
    716 		t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
    717 	}
    718 	if n, err := sf.Read(buf); n != 0 || err != io.EOF {
    719 		t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
    720 	}
    721 	pos := int64(len(buf))
    722 	for count < len(buf) {
    723 		// Construct random seek arguments.
    724 		whence := rand.Intn(3)
    725 		target := rand.Int63n(int64(len(buf)))
    726 		var offset int64
    727 		switch whence {
    728 		case io.SeekStart:
    729 			offset = target
    730 		case io.SeekCurrent:
    731 			offset = target - pos
    732 		case io.SeekEnd:
    733 			offset = target - int64(len(buf))
    734 		}
    735 		pos, err = sf.Seek(offset, whence)
    736 		if err != nil {
    737 			t.Fatal(err)
    738 		}
    739 		if pos != target {
    740 			t.Fatalf("want position %d, got %d", target, pos)
    741 		}
    742 
    743 		// Read data from the new position.
    744 		end := pos + 16
    745 		if end > int64(len(buf)) {
    746 			end = int64(len(buf))
    747 		}
    748 		n, err := io.ReadFull(sf, buf[pos:end])
    749 		if err != nil {
    750 			t.Fatal(err)
    751 		}
    752 		for i := 0; i < n; i++ {
    753 			if !have[pos] {
    754 				have[pos] = true
    755 				count++
    756 			}
    757 			pos++
    758 		}
    759 	}
    760 	if !bytes.Equal(wantData, buf) {
    761 		t.Fatalf("want data %x, got %x", wantData, buf)
    762 	}
    763 }
    764 
    765 func TestNoSectionOverlaps(t *testing.T) {
    766 	// Ensure 6l outputs sections without overlaps.
    767 	if runtime.GOOS != "linux" && runtime.GOOS != "freebsd" {
    768 		return // not ELF
    769 	}
    770 	_ = net.ResolveIPAddr // force dynamic linkage
    771 	f, err := Open(os.Args[0])
    772 	if err != nil {
    773 		t.Error(err)
    774 		return
    775 	}
    776 	for i, si := range f.Sections {
    777 		sih := si.SectionHeader
    778 		if sih.Type == SHT_NOBITS {
    779 			continue
    780 		}
    781 		for j, sj := range f.Sections {
    782 			sjh := sj.SectionHeader
    783 			if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.Size == 0 {
    784 				continue
    785 			}
    786 			if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.Size {
    787 				t.Errorf("ld produced ELF with section %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
    788 					sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.Size, sjh.Offset+sjh.Size)
    789 			}
    790 		}
    791 	}
    792 }
    793