]> Cypherpunks.ru repositories - gostls13.git/blob - src/debug/elf/file_test.go
debug/elf: retrieve values for dynamic section tags
[gostls13.git] / 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         "fmt"
13         "io"
14         "math/rand"
15         "net"
16         "os"
17         "path"
18         "reflect"
19         "runtime"
20         "testing"
21 )
22
23 type fileTest struct {
24         file     string
25         hdr      FileHeader
26         sections []SectionHeader
27         progs    []ProgHeader
28         needed   []string
29 }
30
31 var fileTests = []fileTest{
32         {
33                 "testdata/gcc-386-freebsd-exec",
34                 FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
35                 []SectionHeader{
36                         {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
37                         {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15},
38                         {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90},
39                         {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110},
40                         {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb},
41                         {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20},
42                         {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
43                         {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50},
44                         {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180},
45                         {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
46                         {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3},
47                         {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
48                         {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
49                         {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98},
50                         {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
51                         {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
52                         {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
53                         {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c},
54                         {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
55                         {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d},
56                         {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
57                         {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
58                         {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d},
59                         {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41},
60                         {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35},
61                         {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30},
62                         {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
63                         {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8},
64                         {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0},
65                         {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206},
66                 },
67                 []ProgHeader{
68                         {PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
69                         {PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
70                         {PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
71                         {PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
72                         {PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
73                 },
74                 []string{"libc.so.6"},
75         },
76         {
77                 "testdata/gcc-amd64-linux-exec",
78                 FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
79                 []SectionHeader{
80                         {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
81                         {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c},
82                         {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
83                         {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24},
84                         {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c},
85                         {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
86                         {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d},
87                         {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
88                         {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20},
89                         {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18},
90                         {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30},
91                         {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18},
92                         {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30},
93                         {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4},
94                         {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe},
95                         {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
96                         {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
97                         {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4},
98                         {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
99                         {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
100                         {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
101                         {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0},
102                         {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
103                         {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28},
104                         {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18},
105                         {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
106                         {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126},
107                         {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
108                         {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25},
109                         {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7},
110                         {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f},
111                         {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f},
112                         {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1},
113                         {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
114                         {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149},
115                         {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0},
116                         {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc},
117                 },
118                 []ProgHeader{
119                         {PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
120                         {PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
121                         {PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
122                         {PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
123                         {PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
124                         {PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
125                         {PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
126                         {PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
127                 },
128                 []string{"libc.so.6"},
129         },
130         {
131                 "testdata/hello-world-core.gz",
132                 FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
133                 []SectionHeader{},
134                 []ProgHeader{
135                         {Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
136                         {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
137                         {Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
138                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
139                         {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
140                         {Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
141                         {Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
142                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
143                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
144                         {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
145                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
146                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
147                         {Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
148                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
149                         {Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
150                         {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
151                         {Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
152                 },
153                 nil,
154         },
155         {
156                 "testdata/compressed-32.obj",
157                 FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0},
158                 []SectionHeader{
159                         {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
160                         {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17},
161                         {".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10},
162                         {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
163                         {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
164                         {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
165                         {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84},
166                         {".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0},
167                         {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a},
168                         {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
169                         {".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10},
170                         {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
171                         {".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8},
172                         {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3},
173                         {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
174                         {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
175                         {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38},
176                         {".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8},
177                         {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab},
178                         {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100},
179                         {".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
180                 },
181                 []ProgHeader{},
182                 nil,
183         },
184         {
185                 "testdata/compressed-64.obj",
186                 FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0},
187                 []SectionHeader{
188                         {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
189                         {".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
190                         {".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30},
191                         {".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
192                         {".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
193                         {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
194                         {".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72},
195                         {".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8},
196                         {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
197                         {".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f},
198                         {".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
199                         {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60},
200                         {".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
201                         {".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3},
202                         {".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
203                         {".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
204                         {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
205                         {".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18},
206                         {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0},
207                         {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
208                         {".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
209                 },
210                 []ProgHeader{},
211                 nil,
212         },
213 }
214
215 func TestOpen(t *testing.T) {
216         for i := range fileTests {
217                 tt := &fileTests[i]
218
219                 var f *File
220                 var err error
221                 if path.Ext(tt.file) == ".gz" {
222                         var r io.ReaderAt
223                         if r, err = decompress(tt.file); err == nil {
224                                 f, err = NewFile(r)
225                         }
226                 } else {
227                         f, err = Open(tt.file)
228                 }
229                 if err != nil {
230                         t.Errorf("cannot open file %s: %v", tt.file, err)
231                         continue
232                 }
233                 defer f.Close()
234                 if f.FileHeader != tt.hdr {
235                         t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
236                         continue
237                 }
238                 for i, s := range f.Sections {
239                         if i >= len(tt.sections) {
240                                 break
241                         }
242                         sh := tt.sections[i]
243                         if s.SectionHeader != sh {
244                                 t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, s.SectionHeader, sh)
245                         }
246                 }
247                 for i, p := range f.Progs {
248                         if i >= len(tt.progs) {
249                                 break
250                         }
251                         ph := tt.progs[i]
252                         if p.ProgHeader != ph {
253                                 t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, p.ProgHeader, ph)
254                         }
255                 }
256                 tn := len(tt.sections)
257                 fn := len(f.Sections)
258                 if tn != fn {
259                         t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
260                 }
261                 tn = len(tt.progs)
262                 fn = len(f.Progs)
263                 if tn != fn {
264                         t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
265                 }
266                 tl := tt.needed
267                 fl, err := f.ImportedLibraries()
268                 if err != nil {
269                         t.Error(err)
270                 }
271                 if !reflect.DeepEqual(tl, fl) {
272                         t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
273                 }
274         }
275 }
276
277 // elf.NewFile requires io.ReaderAt, which compress/gzip cannot
278 // provide. Decompress the file to a bytes.Reader.
279 func decompress(gz string) (io.ReaderAt, error) {
280         in, err := os.Open(gz)
281         if err != nil {
282                 return nil, err
283         }
284         defer in.Close()
285         r, err := gzip.NewReader(in)
286         if err != nil {
287                 return nil, err
288         }
289         var out bytes.Buffer
290         _, err = io.Copy(&out, r)
291         return bytes.NewReader(out.Bytes()), err
292 }
293
294 type relocationTestEntry struct {
295         entryNumber int
296         entry       *dwarf.Entry
297         pcRanges    [][2]uint64
298 }
299
300 type relocationTest struct {
301         file    string
302         entries []relocationTestEntry
303 }
304
305 var relocationTests = []relocationTest{
306         {
307                 "testdata/go-relocation-test-gcc441-x86-64.obj",
308                 []relocationTestEntry{
309                         {
310                                 entry: &dwarf.Entry{
311                                         Offset:   0xb,
312                                         Tag:      dwarf.TagCompileUnit,
313                                         Children: true,
314                                         Field: []dwarf.Field{
315                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
316                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
317                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString},
318                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
319                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
320                                                 {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
321                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
322                                         },
323                                 },
324                                 pcRanges: [][2]uint64{{0x0, 0x6}},
325                         },
326                 },
327         },
328         {
329                 "testdata/go-relocation-test-gcc441-x86.obj",
330                 []relocationTestEntry{
331                         {
332                                 entry: &dwarf.Entry{
333                                         Offset:   0xb,
334                                         Tag:      dwarf.TagCompileUnit,
335                                         Children: true,
336                                         Field: []dwarf.Field{
337                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
338                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
339                                                 {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString},
340                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
341                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
342                                                 {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress},
343                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
344                                         },
345                                 },
346                                 pcRanges: [][2]uint64{{0x0, 0x5}},
347                         },
348                 },
349         },
350         {
351                 "testdata/go-relocation-test-gcc424-x86-64.obj",
352                 []relocationTestEntry{
353                         {
354                                 entry: &dwarf.Entry{
355                                         Offset:   0xb,
356                                         Tag:      dwarf.TagCompileUnit,
357                                         Children: true,
358                                         Field: []dwarf.Field{
359                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString},
360                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
361                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString},
362                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
363                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
364                                                 {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
365                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
366                                         },
367                                 },
368                                 pcRanges: [][2]uint64{{0x0, 0x6}},
369                         },
370                 },
371         },
372         {
373                 "testdata/go-relocation-test-gcc482-aarch64.obj",
374                 []relocationTestEntry{
375                         {
376                                 entry: &dwarf.Entry{
377                                         Offset:   0xb,
378                                         Tag:      dwarf.TagCompileUnit,
379                                         Children: true,
380                                         Field: []dwarf.Field{
381                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString},
382                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
383                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString},
384                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
385                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
386                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant},
387                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
388                                         },
389                                 },
390                                 pcRanges: [][2]uint64{{0x0, 0x24}},
391                         },
392                 },
393         },
394         {
395                 "testdata/go-relocation-test-gcc492-arm.obj",
396                 []relocationTestEntry{
397                         {
398                                 entry: &dwarf.Entry{
399                                         Offset:   0xb,
400                                         Tag:      dwarf.TagCompileUnit,
401                                         Children: true,
402                                         Field: []dwarf.Field{
403                                                 {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},
404                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
405                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString},
406                                                 {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString},
407                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
408                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant},
409                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
410                                         },
411                                 },
412                                 pcRanges: [][2]uint64{{0x0, 0x28}},
413                         },
414                 },
415         },
416         {
417                 "testdata/go-relocation-test-clang-arm.obj",
418                 []relocationTestEntry{
419                         {
420                                 entry: &dwarf.Entry{
421                                         Offset:   0xb,
422                                         Tag:      dwarf.TagCompileUnit,
423                                         Children: true,
424                                         Field: []dwarf.Field{
425                                                 {Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString},
426                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
427                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
428                                                 {Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr},
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(0x30), Class: dwarf.ClassConstant},
432                                         },
433                                 },
434                                 pcRanges: [][2]uint64{{0x0, 0x30}},
435                         },
436                 },
437         },
438         {
439                 "testdata/go-relocation-test-gcc5-ppc.obj",
440                 []relocationTestEntry{
441                         {
442                                 entry: &dwarf.Entry{
443                                         Offset:   0xb,
444                                         Tag:      dwarf.TagCompileUnit,
445                                         Children: true,
446                                         Field: []dwarf.Field{
447                                                 {Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString},
448                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
449                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString},
450                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
451                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
452                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant},
453                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
454                                         },
455                                 },
456                                 pcRanges: [][2]uint64{{0x0, 0x44}},
457                         },
458                 },
459         },
460         {
461                 "testdata/go-relocation-test-gcc482-ppc64le.obj",
462                 []relocationTestEntry{
463                         {
464                                 entry: &dwarf.Entry{
465                                         Offset:   0xb,
466                                         Tag:      dwarf.TagCompileUnit,
467                                         Children: true,
468                                         Field: []dwarf.Field{
469                                                 {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},
470                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
471                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString},
472                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
473                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
474                                                 {Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress},
475                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
476                                         },
477                                 },
478                                 pcRanges: [][2]uint64{{0x0, 0x24}},
479                         },
480                 },
481         },
482         {
483                 "testdata/go-relocation-test-gcc492-mips64.obj",
484                 []relocationTestEntry{
485                         {
486                                 entry: &dwarf.Entry{
487                                         Offset:   0xb,
488                                         Tag:      dwarf.TagCompileUnit,
489                                         Children: true,
490                                         Field: []dwarf.Field{
491                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString},
492                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
493                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
494                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
495                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
496                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x64), Class: dwarf.ClassConstant},
497                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
498                                         },
499                                 },
500                                 pcRanges: [][2]uint64{{0x0, 0x64}},
501                         },
502                 },
503         },
504         {
505                 "testdata/go-relocation-test-gcc531-s390x.obj",
506                 []relocationTestEntry{
507                         {
508                                 entry: &dwarf.Entry{
509                                         Offset:   0xb,
510                                         Tag:      dwarf.TagCompileUnit,
511                                         Children: true,
512                                         Field: []dwarf.Field{
513                                                 {Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong", Class: dwarf.ClassString},
514                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
515                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
516                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
517                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
518                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x3a), Class: dwarf.ClassConstant},
519                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
520                                         },
521                                 },
522                                 pcRanges: [][2]uint64{{0x0, 0x3a}},
523                         },
524                 },
525         },
526         {
527                 "testdata/go-relocation-test-gcc620-sparc64.obj",
528                 []relocationTestEntry{
529                         {
530                                 entry: &dwarf.Entry{
531                                         Offset:   0xb,
532                                         Tag:      dwarf.TagCompileUnit,
533                                         Children: true,
534                                         Field: []dwarf.Field{
535                                                 {Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong", Class: dwarf.ClassString},
536                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
537                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
538                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
539                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
540                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x2c), Class: dwarf.ClassConstant},
541                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
542                                         },
543                                 },
544                                 pcRanges: [][2]uint64{{0x0, 0x2c}},
545                         },
546                 },
547         },
548         {
549                 "testdata/go-relocation-test-gcc492-mipsle.obj",
550                 []relocationTestEntry{
551                         {
552                                 entry: &dwarf.Entry{
553                                         Offset:   0xb,
554                                         Tag:      dwarf.TagCompileUnit,
555                                         Children: true,
556                                         Field: []dwarf.Field{
557                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g", Class: dwarf.ClassString},
558                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
559                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
560                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
561                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
562                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x58), Class: dwarf.ClassConstant},
563                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
564                                         },
565                                 },
566                                 pcRanges: [][2]uint64{{0x0, 0x58}},
567                         },
568                 },
569         },
570         {
571                 "testdata/go-relocation-test-gcc540-mips.obj",
572                 []relocationTestEntry{
573                         {
574                                 entry: &dwarf.Entry{
575                                         Offset:   0xb,
576                                         Tag:      dwarf.TagCompileUnit,
577                                         Children: true,
578                                         Field: []dwarf.Field{
579                                                 {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},
580                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
581                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
582                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
583                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
584                                                 {Attr: dwarf.AttrHighpc, Val: uint64(0x5c), Class: dwarf.ClassAddress},
585                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
586                                         },
587                                 },
588                                 pcRanges: [][2]uint64{{0x0, 0x5c}},
589                         },
590                 },
591         },
592         {
593                 "testdata/go-relocation-test-gcc493-mips64le.obj",
594                 []relocationTestEntry{
595                         {
596                                 entry: &dwarf.Entry{
597                                         Offset:   0xb,
598                                         Tag:      dwarf.TagCompileUnit,
599                                         Children: true,
600                                         Field: []dwarf.Field{
601                                                 {Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString},
602                                                 {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
603                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
604                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
605                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
606                                                 {Attr: dwarf.AttrHighpc, Val: int64(0x64), Class: dwarf.ClassConstant},
607                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
608                                         },
609                                 },
610                                 pcRanges: [][2]uint64{{0x0, 0x64}},
611                         },
612                 },
613         },
614         {
615                 "testdata/go-relocation-test-gcc720-riscv64.obj",
616                 []relocationTestEntry{
617                         {
618                                 entry: &dwarf.Entry{
619                                         Offset:   0xb,
620                                         Tag:      dwarf.TagCompileUnit,
621                                         Children: true,
622                                         Field: []dwarf.Field{
623                                                 {Attr: dwarf.AttrProducer, Val: "GNU C11 7.2.0 -march=rv64imafdc -mabi=lp64d -g -gdwarf-2", Class: dwarf.ClassString},
624                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
625                                                 {Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
626                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
627                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
628                                                 {Attr: dwarf.AttrHighpc, Val: uint64(0x2c), Class: dwarf.ClassAddress},
629                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
630                                         },
631                                 },
632                                 pcRanges: [][2]uint64{{0x0, 0x2c}},
633                         },
634                 },
635         },
636         {
637                 "testdata/go-relocation-test-clang-x86.obj",
638                 []relocationTestEntry{
639                         {
640                                 entry: &dwarf.Entry{
641                                         Offset:   0xb,
642                                         Tag:      dwarf.TagCompileUnit,
643                                         Children: true,
644                                         Field: []dwarf.Field{
645                                                 {Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
646                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
647                                                 {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
648                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
649                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
650                                         },
651                                 },
652                         },
653                 },
654         },
655         {
656                 "testdata/gcc-amd64-openbsd-debug-with-rela.obj",
657                 []relocationTestEntry{
658                         {
659                                 entryNumber: 203,
660                                 entry: &dwarf.Entry{
661                                         Offset:   0xc62,
662                                         Tag:      dwarf.TagMember,
663                                         Children: false,
664                                         Field: []dwarf.Field{
665                                                 {Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
666                                                 {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
667                                                 {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
668                                                 {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
669                                                 {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
670                                         },
671                                 },
672                         },
673                         {
674                                 entryNumber: 204,
675                                 entry: &dwarf.Entry{
676                                         Offset:   0xc70,
677                                         Tag:      dwarf.TagMember,
678                                         Children: false,
679                                         Field: []dwarf.Field{
680                                                 {Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
681                                                 {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
682                                                 {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
683                                                 {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
684                                                 {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
685                                         },
686                                 },
687                         },
688                 },
689         },
690         {
691                 "testdata/go-relocation-test-gcc930-ranges-no-rela-x86-64",
692                 []relocationTestEntry{
693                         {
694                                 entry: &dwarf.Entry{
695                                         Offset:   0xb,
696                                         Tag:      dwarf.TagCompileUnit,
697                                         Children: true,
698                                         Field: []dwarf.Field{
699                                                 {Attr: dwarf.AttrProducer, Val: "GNU C17 9.3.0 -mtune=generic -march=x86-64 -g -fno-asynchronous-unwind-tables", Class: dwarf.ClassString},
700                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
701                                                 {Attr: dwarf.AttrName, Val: "multiple-code-sections.c", Class: dwarf.ClassString},
702                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
703                                                 {Attr: dwarf.AttrRanges, Val: int64(0), Class: dwarf.ClassRangeListPtr},
704                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0), Class: dwarf.ClassAddress},
705                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
706                                         },
707                                 },
708                                 pcRanges: [][2]uint64{
709                                         {0x765, 0x777},
710                                         {0x7e1, 0x7ec},
711                                 },
712                         },
713                 },
714         },
715         {
716                 "testdata/go-relocation-test-gcc930-ranges-with-rela-x86-64",
717                 []relocationTestEntry{
718                         {
719                                 entry: &dwarf.Entry{
720                                         Offset:   0xb,
721                                         Tag:      dwarf.TagCompileUnit,
722                                         Children: true,
723                                         Field: []dwarf.Field{
724                                                 {Attr: dwarf.AttrProducer, Val: "GNU C17 9.3.0 -mtune=generic -march=x86-64 -g -fno-asynchronous-unwind-tables", Class: dwarf.ClassString},
725                                                 {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
726                                                 {Attr: dwarf.AttrName, Val: "multiple-code-sections.c", Class: dwarf.ClassString},
727                                                 {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
728                                                 {Attr: dwarf.AttrRanges, Val: int64(0), Class: dwarf.ClassRangeListPtr},
729                                                 {Attr: dwarf.AttrLowpc, Val: uint64(0), Class: dwarf.ClassAddress},
730                                                 {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
731                                         },
732                                 },
733                                 pcRanges: [][2]uint64{
734                                         {0x765, 0x777},
735                                         {0x7e1, 0x7ec},
736                                 },
737                         },
738                 },
739         },
740 }
741
742 func TestDWARFRelocations(t *testing.T) {
743         for _, test := range relocationTests {
744                 test := test
745                 t.Run(test.file, func(t *testing.T) {
746                         t.Parallel()
747                         f, err := Open(test.file)
748                         if err != nil {
749                                 t.Fatal(err)
750                         }
751                         dwarf, err := f.DWARF()
752                         if err != nil {
753                                 t.Fatal(err)
754                         }
755                         reader := dwarf.Reader()
756                         idx := 0
757                         for _, testEntry := range test.entries {
758                                 if testEntry.entryNumber < idx {
759                                         t.Fatalf("internal test error: %d < %d", testEntry.entryNumber, idx)
760                                 }
761                                 for ; idx < testEntry.entryNumber; idx++ {
762                                         entry, err := reader.Next()
763                                         if entry == nil || err != nil {
764                                                 t.Fatalf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
765                                         }
766                                 }
767                                 entry, err := reader.Next()
768                                 idx++
769                                 if err != nil {
770                                         t.Fatal(err)
771                                 }
772                                 if !reflect.DeepEqual(testEntry.entry, entry) {
773                                         t.Errorf("entry %d mismatch: got:%#v want:%#v", testEntry.entryNumber, entry, testEntry.entry)
774                                 }
775                                 pcRanges, err := dwarf.Ranges(entry)
776                                 if err != nil {
777                                         t.Fatal(err)
778                                 }
779                                 if !reflect.DeepEqual(testEntry.pcRanges, pcRanges) {
780                                         t.Errorf("entry %d: PC range mismatch: got:%#v want:%#v", testEntry.entryNumber, pcRanges, testEntry.pcRanges)
781                                 }
782                         }
783                 })
784         }
785 }
786
787 func TestCompressedDWARF(t *testing.T) {
788         // Test file built with GCC 4.8.4 and as 2.24 using:
789         // gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
790         f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
791         if err != nil {
792                 t.Fatal(err)
793         }
794         dwarf, err := f.DWARF()
795         if err != nil {
796                 t.Fatal(err)
797         }
798         reader := dwarf.Reader()
799         n := 0
800         for {
801                 entry, err := reader.Next()
802                 if err != nil {
803                         t.Fatal(err)
804                 }
805                 if entry == nil {
806                         break
807                 }
808                 n++
809         }
810         if n != 18 {
811                 t.Fatalf("want %d DWARF entries, got %d", 18, n)
812         }
813 }
814
815 func TestCompressedSection(t *testing.T) {
816         // Test files built with gcc -g -S hello.c and assembled with
817         // --compress-debug-sections=zlib-gabi.
818         f, err := Open("testdata/compressed-64.obj")
819         if err != nil {
820                 t.Fatal(err)
821         }
822         sec := f.Section(".debug_info")
823         wantData := []byte{
824                 182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
825                 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
826                 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
827                 0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
828                 0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
829                 2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
830                 5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
831                 0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
832                 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
833                 1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
834                 0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
835                 145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
836         }
837
838         // Test Data method.
839         b, err := sec.Data()
840         if err != nil {
841                 t.Fatal(err)
842         }
843         if !bytes.Equal(wantData, b) {
844                 t.Fatalf("want data %x, got %x", wantData, b)
845         }
846
847         // Test Open method and seeking.
848         buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
849         sf := sec.Open()
850         if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
851                 t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
852         }
853         if n, err := sf.Read(buf); n != 0 || err != io.EOF {
854                 t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
855         }
856         pos := int64(len(buf))
857         for count < len(buf) {
858                 // Construct random seek arguments.
859                 whence := rand.Intn(3)
860                 target := rand.Int63n(int64(len(buf)))
861                 var offset int64
862                 switch whence {
863                 case io.SeekStart:
864                         offset = target
865                 case io.SeekCurrent:
866                         offset = target - pos
867                 case io.SeekEnd:
868                         offset = target - int64(len(buf))
869                 }
870                 pos, err = sf.Seek(offset, whence)
871                 if err != nil {
872                         t.Fatal(err)
873                 }
874                 if pos != target {
875                         t.Fatalf("want position %d, got %d", target, pos)
876                 }
877
878                 // Read data from the new position.
879                 end := pos + 16
880                 if end > int64(len(buf)) {
881                         end = int64(len(buf))
882                 }
883                 n, err := io.ReadFull(sf, buf[pos:end])
884                 if err != nil {
885                         t.Fatal(err)
886                 }
887                 for i := 0; i < n; i++ {
888                         if !have[pos] {
889                                 have[pos] = true
890                                 count++
891                         }
892                         pos++
893                 }
894         }
895         if !bytes.Equal(wantData, buf) {
896                 t.Fatalf("want data %x, got %x", wantData, buf)
897         }
898 }
899
900 func TestNoSectionOverlaps(t *testing.T) {
901         // Ensure cmd/link outputs sections without overlaps.
902         switch runtime.GOOS {
903         case "aix", "android", "darwin", "ios", "js", "plan9", "windows":
904                 t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS)
905         }
906         _ = net.ResolveIPAddr // force dynamic linkage
907         f, err := Open(os.Args[0])
908         if err != nil {
909                 t.Error(err)
910                 return
911         }
912         for i, si := range f.Sections {
913                 sih := si.SectionHeader
914                 if sih.Type == SHT_NOBITS {
915                         continue
916                 }
917                 // checking for overlap in file
918                 for j, sj := range f.Sections {
919                         sjh := sj.SectionHeader
920                         if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.FileSize == 0 {
921                                 continue
922                         }
923                         if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.FileSize {
924                                 t.Errorf("ld produced ELF with section offset %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
925                                         sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.FileSize, sjh.Offset+sjh.FileSize)
926                         }
927                 }
928
929                 if sih.Flags&SHF_ALLOC == 0 {
930                         continue
931                 }
932
933                 // checking for overlap in address space
934                 for j, sj := range f.Sections {
935                         sjh := sj.SectionHeader
936                         if i == j || sjh.Flags&SHF_ALLOC == 0 || sjh.Type == SHT_NOBITS ||
937                                 sih.Addr == sjh.Addr && sih.Size == 0 {
938                                 continue
939                         }
940                         if sih.Addr >= sjh.Addr && sih.Addr < sjh.Addr+sjh.Size {
941                                 t.Errorf("ld produced ELF with section address %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
942                                         sih.Name, sjh.Name, sjh.Addr, sih.Addr, sih.Addr+sih.Size, sjh.Addr+sjh.Size)
943                         }
944                 }
945         }
946 }
947
948 func TestNobitsSection(t *testing.T) {
949         const testdata = "testdata/gcc-amd64-linux-exec"
950         f, err := Open(testdata)
951         if err != nil {
952                 t.Fatalf("could not read %s: %v", testdata, err)
953         }
954         defer f.Close()
955
956         wantError := "unexpected read from SHT_NOBITS section"
957         bss := f.Section(".bss")
958
959         _, err = bss.Data()
960         if err == nil || err.Error() != wantError {
961                 t.Fatalf("bss.Data() got error %q, want error %q", err, wantError)
962         }
963
964         r := bss.Open()
965         p := make([]byte, 1)
966         _, err = r.Read(p)
967         if err == nil || err.Error() != wantError {
968                 t.Fatalf("r.Read(p) got error %q, want error %q", err, wantError)
969         }
970 }
971
972 // TestLargeNumberOfSections tests the case that a file has greater than or
973 // equal to 65280 (0xff00) sections.
974 func TestLargeNumberOfSections(t *testing.T) {
975         // A file with >= 0xff00 sections is too big, so we will construct it on the
976         // fly. The original file "y.o" is generated by these commands:
977         // 1. generate "y.c":
978         //   for i in `seq 1 65288`; do
979         //     printf -v x "%04x" i;
980         //     echo "int var_$x __attribute__((section(\"section_$x\"))) = $i;"
981         //   done > y.c
982         // 2. compile: gcc -c y.c -m32
983         //
984         // $readelf -h y.o
985         // ELF Header:
986         //   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
987         //   Class:                             ELF32
988         //   Data:                              2's complement, little endian
989         //   Version:                           1 (current)
990         //   OS/ABI:                            UNIX - System V
991         //   ABI Version:                       0
992         //   Type:                              REL (Relocatable file)
993         //   Machine:                           Intel 80386
994         //   Version:                           0x1
995         //   Entry point address:               0x0
996         //   Start of program headers:          0 (bytes into file)
997         //   Start of section headers:          3003468 (bytes into file)
998         //   Flags:                             0x0
999         //   Size of this header:               52 (bytes)
1000         //   Size of program headers:           0 (bytes)
1001         //   Number of program headers:         0
1002         //   Size of section headers:           40 (bytes)
1003         //   Number of section headers:         0 (65298)
1004         //   Section header string table index: 65535 (65297)
1005         //
1006         // $readelf -S y.o
1007         // There are 65298 section headers, starting at offset 0x2dd44c:
1008         // Section Headers:
1009         //   [Nr]    Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
1010         //   [    0]                   NULL            00000000 000000 00ff12 00     65297   0  0
1011         //   [    1] .text             PROGBITS        00000000 000034 000000 00  AX  0   0  1
1012         //   [    2] .data             PROGBITS        00000000 000034 000000 00  WA  0   0  1
1013         //   [    3] .bss              NOBITS          00000000 000034 000000 00  WA  0   0  1
1014         //   [    4] section_0001      PROGBITS        00000000 000034 000004 00  WA  0   0  4
1015         //   [    5] section_0002      PROGBITS        00000000 000038 000004 00  WA  0   0  4
1016         //   [ section_0003 ~ section_ff06 truncated ]
1017         //   [65290] section_ff07      PROGBITS        00000000 03fc4c 000004 00  WA  0   0  4
1018         //   [65291] section_ff08      PROGBITS        00000000 03fc50 000004 00  WA  0   0  4
1019         //   [65292] .comment          PROGBITS        00000000 03fc54 000027 01  MS  0   0  1
1020         //   [65293] .note.GNU-stack   PROGBITS        00000000 03fc7b 000000 00      0   0  1
1021         //   [65294] .symtab           SYMTAB          00000000 03fc7c 0ff0a0 10     65296   2  4
1022         //   [65295] .symtab_shndx     SYMTAB SECTION  00000000 13ed1c 03fc28 04     65294   0  4
1023         //   [65296] .strtab           STRTAB          00000000 17e944 08f74d 00      0   0  1
1024         //   [65297] .shstrtab         STRTAB          00000000 20e091 0cf3bb 00      0   0  1
1025
1026         var buf bytes.Buffer
1027
1028         {
1029                 buf.Grow(0x55AF1C) // 3003468 + 40 * 65298
1030
1031                 h := Header32{
1032                         Ident:     [16]byte{0x7F, 'E', 'L', 'F', 0x01, 0x01, 0x01},
1033                         Type:      1,
1034                         Machine:   3,
1035                         Version:   1,
1036                         Shoff:     0x2DD44C,
1037                         Ehsize:    0x34,
1038                         Shentsize: 0x28,
1039                         Shnum:     0,
1040                         Shstrndx:  0xFFFF,
1041                 }
1042                 binary.Write(&buf, binary.LittleEndian, h)
1043
1044                 // Zero out sections [1]~[65294].
1045                 buf.Write(bytes.Repeat([]byte{0}, 0x13ED1C-binary.Size(h)))
1046
1047                 // Write section [65295]. Section [65295] are all zeros except for the
1048                 // last 48 bytes.
1049                 buf.Write(bytes.Repeat([]byte{0}, 0x03FC28-12*4))
1050                 for i := 0; i < 12; i++ {
1051                         binary.Write(&buf, binary.LittleEndian, uint32(0xFF00|i))
1052                 }
1053
1054                 // Write section [65296].
1055                 buf.Write([]byte{0})
1056                 buf.Write([]byte("y.c\x00"))
1057                 for i := 1; i <= 65288; i++ {
1058                         // var_0001 ~ var_ff08
1059                         name := fmt.Sprintf("var_%04x", i)
1060                         buf.Write([]byte(name))
1061                         buf.Write([]byte{0})
1062                 }
1063
1064                 // Write section [65297].
1065                 buf.Write([]byte{0})
1066                 buf.Write([]byte(".symtab\x00"))
1067                 buf.Write([]byte(".strtab\x00"))
1068                 buf.Write([]byte(".shstrtab\x00"))
1069                 buf.Write([]byte(".text\x00"))
1070                 buf.Write([]byte(".data\x00"))
1071                 buf.Write([]byte(".bss\x00"))
1072                 for i := 1; i <= 65288; i++ {
1073                         // s_0001 ~ s_ff08
1074                         name := fmt.Sprintf("section_%04x", i)
1075                         buf.Write([]byte(name))
1076                         buf.Write([]byte{0})
1077                 }
1078                 buf.Write([]byte(".comment\x00"))
1079                 buf.Write([]byte(".note.GNU-stack\x00"))
1080                 buf.Write([]byte(".symtab_shndx\x00"))
1081
1082                 // Write section header table.
1083                 // NULL
1084                 binary.Write(&buf, binary.LittleEndian, Section32{Name: 0, Size: 0xFF12, Link: 0xFF11})
1085                 // .text
1086                 binary.Write(&buf, binary.LittleEndian, Section32{
1087                         Name:      0x1B,
1088                         Type:      uint32(SHT_PROGBITS),
1089                         Flags:     uint32(uint32(SHF_ALLOC | SHF_EXECINSTR)),
1090                         Off:       0x34,
1091                         Addralign: 0x01,
1092                 })
1093                 // .data
1094                 binary.Write(&buf, binary.LittleEndian, Section32{
1095                         Name:      0x21,
1096                         Type:      uint32(SHT_PROGBITS),
1097                         Flags:     uint32(SHF_WRITE | SHF_ALLOC),
1098                         Off:       0x34,
1099                         Addralign: 0x01,
1100                 })
1101                 // .bss
1102                 binary.Write(&buf, binary.LittleEndian, Section32{
1103                         Name:      0x27,
1104                         Type:      uint32(SHT_NOBITS),
1105                         Flags:     uint32(SHF_WRITE | SHF_ALLOC),
1106                         Off:       0x34,
1107                         Addralign: 0x01,
1108                 })
1109                 // s_1 ~ s_65537
1110                 for i := 0; i < 65288; i++ {
1111                         s := Section32{
1112                                 Name:      uint32(0x2C + i*13),
1113                                 Type:      uint32(SHT_PROGBITS),
1114                                 Flags:     uint32(SHF_WRITE | SHF_ALLOC),
1115                                 Off:       uint32(0x34 + i*4),
1116                                 Size:      0x04,
1117                                 Addralign: 0x04,
1118                         }
1119                         binary.Write(&buf, binary.LittleEndian, s)
1120                 }
1121                 // .comment
1122                 binary.Write(&buf, binary.LittleEndian, Section32{
1123                         Name:      0x0CF394,
1124                         Type:      uint32(SHT_PROGBITS),
1125                         Flags:     uint32(SHF_MERGE | SHF_STRINGS),
1126                         Off:       0x03FC54,
1127                         Size:      0x27,
1128                         Addralign: 0x01,
1129                         Entsize:   0x01,
1130                 })
1131                 // .note.GNU-stack
1132                 binary.Write(&buf, binary.LittleEndian, Section32{
1133                         Name:      0x0CF39D,
1134                         Type:      uint32(SHT_PROGBITS),
1135                         Off:       0x03FC7B,
1136                         Addralign: 0x01,
1137                 })
1138                 // .symtab
1139                 binary.Write(&buf, binary.LittleEndian, Section32{
1140                         Name:      0x01,
1141                         Type:      uint32(SHT_SYMTAB),
1142                         Off:       0x03FC7C,
1143                         Size:      0x0FF0A0,
1144                         Link:      0xFF10,
1145                         Info:      0x02,
1146                         Addralign: 0x04,
1147                         Entsize:   0x10,
1148                 })
1149                 // .symtab_shndx
1150                 binary.Write(&buf, binary.LittleEndian, Section32{
1151                         Name:      0x0CF3AD,
1152                         Type:      uint32(SHT_SYMTAB_SHNDX),
1153                         Off:       0x13ED1C,
1154                         Size:      0x03FC28,
1155                         Link:      0xFF0E,
1156                         Addralign: 0x04,
1157                         Entsize:   0x04,
1158                 })
1159                 // .strtab
1160                 binary.Write(&buf, binary.LittleEndian, Section32{
1161                         Name:      0x09,
1162                         Type:      uint32(SHT_STRTAB),
1163                         Off:       0x17E944,
1164                         Size:      0x08F74D,
1165                         Addralign: 0x01,
1166                 })
1167                 // .shstrtab
1168                 binary.Write(&buf, binary.LittleEndian, Section32{
1169                         Name:      0x11,
1170                         Type:      uint32(SHT_STRTAB),
1171                         Off:       0x20E091,
1172                         Size:      0x0CF3BB,
1173                         Addralign: 0x01,
1174                 })
1175         }
1176
1177         data := buf.Bytes()
1178
1179         f, err := NewFile(bytes.NewReader(data))
1180         if err != nil {
1181                 t.Errorf("cannot create file from data: %v", err)
1182         }
1183         defer f.Close()
1184
1185         wantFileHeader := FileHeader{
1186                 Class:     ELFCLASS32,
1187                 Data:      ELFDATA2LSB,
1188                 Version:   EV_CURRENT,
1189                 OSABI:     ELFOSABI_NONE,
1190                 ByteOrder: binary.LittleEndian,
1191                 Type:      ET_REL,
1192                 Machine:   EM_386,
1193         }
1194         if f.FileHeader != wantFileHeader {
1195                 t.Errorf("\nhave %#v\nwant %#v\n", f.FileHeader, wantFileHeader)
1196         }
1197
1198         wantSectionNum := 65298
1199         if len(f.Sections) != wantSectionNum {
1200                 t.Errorf("len(Sections) = %d, want %d", len(f.Sections), wantSectionNum)
1201         }
1202
1203         wantSectionHeader := SectionHeader{
1204                 Name:      "section_0007",
1205                 Type:      SHT_PROGBITS,
1206                 Flags:     SHF_WRITE + SHF_ALLOC,
1207                 Offset:    0x4c,
1208                 Size:      0x4,
1209                 Addralign: 0x4,
1210                 FileSize:  0x4,
1211         }
1212         if f.Sections[10].SectionHeader != wantSectionHeader {
1213                 t.Errorf("\nhave %#v\nwant %#v\n", f.Sections[10].SectionHeader, wantSectionHeader)
1214         }
1215 }
1216
1217 func TestIssue10996(t *testing.T) {
1218         data := []byte("\u007fELF\x02\x01\x010000000000000" +
1219                 "\x010000000000000000000" +
1220                 "\x00\x00\x00\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00" +
1221                 "0000")
1222         _, err := NewFile(bytes.NewReader(data))
1223         if err == nil {
1224                 t.Fatalf("opening invalid ELF file unexpectedly succeeded")
1225         }
1226 }
1227
1228 func TestDynValue(t *testing.T) {
1229         const testdata = "testdata/gcc-amd64-linux-exec"
1230         f, err := Open(testdata)
1231         if err != nil {
1232                 t.Fatalf("could not read %s: %v", testdata, err)
1233         }
1234         defer f.Close()
1235
1236         vals, err := f.DynValue(DT_VERNEEDNUM)
1237         if err != nil {
1238                 t.Fatalf("DynValue(DT_VERNEEDNUM): got unexpected error %v", err)
1239         }
1240
1241         if len(vals) != 1 || vals[0] != 1 {
1242                 t.Errorf("DynValue(DT_VERNEEDNUM): got %v, want [1]", vals)
1243         }
1244 }