Source file src/debug/elf/file_test.go

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

View as plain text