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