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