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