github.com/dorkamotorka/go/src@v0.0.0-20230614113921-187095f0e316/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  }