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  	"compress/zlib"
    11  	"debug/dwarf"
    12  	"encoding/binary"
    13  	"errors"
    14  	"fmt"
    15  	"io"
    16  	"math/rand"
    17  	"net"
    18  	"os"
    19  	"path"
    20  	"path/filepath"
    21  	"reflect"
    22  	"runtime"
    23  	"slices"
    24  	"strings"
    25  	"testing"
    26  )
    27  
    28  type fileTest struct {
    29  	file     string
    30  	hdr      FileHeader
    31  	sections []SectionHeader
    32  	progs    []ProgHeader
    33  	needed   []string
    34  	symbols  []Symbol
    35  }
    36  
    37  var fileTests = []fileTest{
    38  	{
    39  		"testdata/gcc-386-freebsd-exec",
    40  		FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386, 0x80483cc},
    41  		[]SectionHeader{
    42  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
    43  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0, 0x15},
    44  			{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4, 0x90},
    45  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10, 0x110},
    46  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0, 0xbb},
    47  			{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8, 0x20},
    48  			{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
    49  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4, 0x50},
    50  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0, 0x180},
    51  			{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
    52  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0, 0xa3},
    53  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0, 0xc},
    54  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
    55  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8, 0x98},
    56  			{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
    57  			{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
    58  			{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0, 0x4},
    59  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4, 0x1c},
    60  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
    61  			{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0, 0x12d},
    62  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
    63  			{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
    64  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0, 0x11d},
    65  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0, 0x41},
    66  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0, 0x35},
    67  			{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0, 0x30},
    68  			{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
    69  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0, 0xf8},
    70  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10, 0x4b0},
    71  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0, 0x206},
    72  		},
    73  		[]ProgHeader{
    74  			{PT_PHDR, PF_R + PF_X, 0x34, 0x8048034, 0x8048034, 0xa0, 0xa0, 0x4},
    75  			{PT_INTERP, PF_R, 0xd4, 0x80480d4, 0x80480d4, 0x15, 0x15, 0x1},
    76  			{PT_LOAD, PF_R + PF_X, 0x0, 0x8048000, 0x8048000, 0x5fb, 0x5fb, 0x1000},
    77  			{PT_LOAD, PF_R + PF_W, 0x5fc, 0x80495fc, 0x80495fc, 0xd8, 0xf8, 0x1000},
    78  			{PT_DYNAMIC, PF_R + PF_W, 0x60c, 0x804960c, 0x804960c, 0x98, 0x98, 0x4},
    79  		},
    80  		[]string{"libc.so.6"},
    81  		[]Symbol{
    82  			{"", 3, 0, false, 0, 1, 134512852, 0, "", ""},
    83  			{"", 3, 0, false, 0, 2, 134512876, 0, "", ""},
    84  			{"", 3, 0, false, 0, 3, 134513020, 0, "", ""},
    85  			{"", 3, 0, false, 0, 4, 134513292, 0, "", ""},
    86  			{"", 3, 0, false, 0, 5, 134513480, 0, "", ""},
    87  			{"", 3, 0, false, 0, 6, 134513512, 0, "", ""},
    88  			{"", 3, 0, false, 0, 7, 134513532, 0, "", ""},
    89  			{"", 3, 0, false, 0, 8, 134513612, 0, "", ""},
    90  			{"", 3, 0, false, 0, 9, 134513996, 0, "", ""},
    91  			{"", 3, 0, false, 0, 10, 134514008, 0, "", ""},
    92  			{"", 3, 0, false, 0, 11, 134518268, 0, "", ""},
    93  			{"", 3, 0, false, 0, 12, 134518280, 0, "", ""},
    94  			{"", 3, 0, false, 0, 13, 134518284, 0, "", ""},
    95  			{"", 3, 0, false, 0, 14, 134518436, 0, "", ""},
    96  			{"", 3, 0, false, 0, 15, 134518444, 0, "", ""},
    97  			{"", 3, 0, false, 0, 16, 134518452, 0, "", ""},
    98  			{"", 3, 0, false, 0, 17, 134518456, 0, "", ""},
    99  			{"", 3, 0, false, 0, 18, 134518484, 0, "", ""},
   100  			{"", 3, 0, false, 0, 19, 0, 0, "", ""},
   101  			{"", 3, 0, false, 0, 20, 0, 0, "", ""},
   102  			{"", 3, 0, false, 0, 21, 0, 0, "", ""},
   103  			{"", 3, 0, false, 0, 22, 0, 0, "", ""},
   104  			{"", 3, 0, false, 0, 23, 0, 0, "", ""},
   105  			{"", 3, 0, false, 0, 24, 0, 0, "", ""},
   106  			{"", 3, 0, false, 0, 25, 0, 0, "", ""},
   107  			{"", 3, 0, false, 0, 26, 0, 0, "", ""},
   108  			{"", 3, 0, false, 0, 27, 0, 0, "", ""},
   109  			{"", 3, 0, false, 0, 28, 0, 0, "", ""},
   110  			{"", 3, 0, false, 0, 29, 0, 0, "", ""},
   111  			{"crt1.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   112  			{"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, false, 0, 65521, 0, 0, "", ""},
   113  			{"<command line>", 4, 0, false, 0, 65521, 0, 0, "", ""},
   114  			{"<built-in>", 4, 0, false, 0, 65521, 0, 0, "", ""},
   115  			{"/usr/src/lib/csu/i386-elf/crti.S", 4, 0, false, 0, 65521, 0, 0, "", ""},
   116  			{"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   117  			{"__CTOR_LIST__", 1, 0, false, 0, 14, 134518436, 0, "", ""},
   118  			{"__DTOR_LIST__", 1, 0, false, 0, 15, 134518444, 0, "", ""},
   119  			{"__EH_FRAME_BEGIN__", 1, 0, false, 0, 12, 134518280, 0, "", ""},
   120  			{"__JCR_LIST__", 1, 0, false, 0, 16, 134518452, 0, "", ""},
   121  			{"p.0", 1, 0, false, 0, 11, 134518276, 0, "", ""},
   122  			{"completed.1", 1, 0, false, 0, 18, 134518484, 1, "", ""},
   123  			{"__do_global_dtors_aux", 2, 0, false, 0, 8, 134513760, 0, "", ""},
   124  			{"object.2", 1, 0, false, 0, 18, 134518488, 24, "", ""},
   125  			{"frame_dummy", 2, 0, false, 0, 8, 134513836, 0, "", ""},
   126  			{"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   127  			{"__CTOR_END__", 1, 0, false, 0, 14, 134518440, 0, "", ""},
   128  			{"__DTOR_END__", 1, 0, false, 0, 15, 134518448, 0, "", ""},
   129  			{"__FRAME_END__", 1, 0, false, 0, 12, 134518280, 0, "", ""},
   130  			{"__JCR_END__", 1, 0, false, 0, 16, 134518452, 0, "", ""},
   131  			{"__do_global_ctors_aux", 2, 0, false, 0, 8, 134513960, 0, "", ""},
   132  			{"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, false, 0, 65521, 0, 0, "", ""},
   133  			{"<command line>", 4, 0, false, 0, 65521, 0, 0, "", ""},
   134  			{"<built-in>", 4, 0, false, 0, 65521, 0, 0, "", ""},
   135  			{"/usr/src/lib/csu/i386-elf/crtn.S", 4, 0, false, 0, 65521, 0, 0, "", ""},
   136  			{"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   137  			{"printf", 18, 0, false, 0, 0, 0, 44, "", ""},
   138  			{"_DYNAMIC", 17, 0, false, 0, 65521, 134518284, 0, "", ""},
   139  			{"__dso_handle", 17, 2, false, 0, 11, 134518272, 0, "", ""},
   140  			{"_init", 18, 0, false, 0, 6, 134513512, 0, "", ""},
   141  			{"environ", 17, 0, false, 0, 18, 134518512, 4, "", ""},
   142  			{"__deregister_frame_info", 32, 0, false, 0, 0, 0, 0, "", ""},
   143  			{"__progname", 17, 0, false, 0, 11, 134518268, 4, "", ""},
   144  			{"_start", 18, 0, false, 0, 8, 134513612, 145, "", ""},
   145  			{"__bss_start", 16, 0, false, 0, 65521, 134518484, 0, "", ""},
   146  			{"main", 18, 0, false, 0, 8, 134513912, 46, "", ""},
   147  			{"_init_tls", 18, 0, false, 0, 0, 0, 5, "", ""},
   148  			{"_fini", 18, 0, false, 0, 9, 134513996, 0, "", ""},
   149  			{"atexit", 18, 0, false, 0, 0, 0, 43, "", ""},
   150  			{"_edata", 16, 0, false, 0, 65521, 134518484, 0, "", ""},
   151  			{"_GLOBAL_OFFSET_TABLE_", 17, 0, false, 0, 65521, 134518456, 0, "", ""},
   152  			{"_end", 16, 0, false, 0, 65521, 134518516, 0, "", ""},
   153  			{"exit", 18, 0, false, 0, 0, 0, 68, "", ""},
   154  			{"_Jv_RegisterClasses", 32, 0, false, 0, 0, 0, 0, "", ""},
   155  			{"__register_frame_info", 32, 0, false, 0, 0, 0, 0, "", ""},
   156  		},
   157  	},
   158  	{
   159  		"testdata/gcc-amd64-linux-exec",
   160  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64, 0x4003e0},
   161  		[]SectionHeader{
   162  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   163  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0, 0x1c},
   164  			{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
   165  			{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4, 0x24},
   166  			{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0, 0x1c},
   167  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
   168  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0, 0x3d},
   169  			{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
   170  			{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0, 0x20},
   171  			{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18, 0x18},
   172  			{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18, 0x30},
   173  			{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0, 0x18},
   174  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10, 0x30},
   175  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0, 0x1b4},
   176  			{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0, 0xe},
   177  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0, 0x11},
   178  			{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
   179  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0, 0xa4},
   180  			{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
   181  			{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0, 0x10},
   182  			{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
   183  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10, 0x1a0},
   184  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
   185  			{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8, 0x28},
   186  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0, 0x18},
   187  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0, 0x8},
   188  			{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0, 0x126},
   189  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
   190  			{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0, 0x25},
   191  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0, 0x1a7},
   192  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0, 0x6f},
   193  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0, 0x13f},
   194  			{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1, 0xb1},
   195  			{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0, 0x90},
   196  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0, 0x149},
   197  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18, 0x6f0},
   198  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0, 0x1fc},
   199  		},
   200  		[]ProgHeader{
   201  			{PT_PHDR, PF_R + PF_X, 0x40, 0x400040, 0x400040, 0x1c0, 0x1c0, 0x8},
   202  			{PT_INTERP, PF_R, 0x200, 0x400200, 0x400200, 0x1c, 0x1c, 1},
   203  			{PT_LOAD, PF_R + PF_X, 0x0, 0x400000, 0x400000, 0x684, 0x684, 0x200000},
   204  			{PT_LOAD, PF_R + PF_W, 0x688, 0x600688, 0x600688, 0x210, 0x218, 0x200000},
   205  			{PT_DYNAMIC, PF_R + PF_W, 0x6b0, 0x6006b0, 0x6006b0, 0x1a0, 0x1a0, 0x8},
   206  			{PT_NOTE, PF_R, 0x21c, 0x40021c, 0x40021c, 0x20, 0x20, 0x4},
   207  			{PT_LOOS + 0x474E550, PF_R, 0x5b8, 0x4005b8, 0x4005b8, 0x24, 0x24, 0x4},
   208  			{PT_LOOS + 0x474E551, PF_R + PF_W, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8},
   209  		},
   210  		[]string{"libc.so.6"},
   211  		[]Symbol{
   212  			{"", 3, 0, false, 0, 1, 4194816, 0, "", ""},
   213  			{"", 3, 0, false, 0, 2, 4194844, 0, "", ""},
   214  			{"", 3, 0, false, 0, 3, 4194880, 0, "", ""},
   215  			{"", 3, 0, false, 0, 4, 4194920, 0, "", ""},
   216  			{"", 3, 0, false, 0, 5, 4194952, 0, "", ""},
   217  			{"", 3, 0, false, 0, 6, 4195048, 0, "", ""},
   218  			{"", 3, 0, false, 0, 7, 4195110, 0, "", ""},
   219  			{"", 3, 0, false, 0, 8, 4195120, 0, "", ""},
   220  			{"", 3, 0, false, 0, 9, 4195152, 0, "", ""},
   221  			{"", 3, 0, false, 0, 10, 4195176, 0, "", ""},
   222  			{"", 3, 0, false, 0, 11, 4195224, 0, "", ""},
   223  			{"", 3, 0, false, 0, 12, 4195248, 0, "", ""},
   224  			{"", 3, 0, false, 0, 13, 4195296, 0, "", ""},
   225  			{"", 3, 0, false, 0, 14, 4195732, 0, "", ""},
   226  			{"", 3, 0, false, 0, 15, 4195748, 0, "", ""},
   227  			{"", 3, 0, false, 0, 16, 4195768, 0, "", ""},
   228  			{"", 3, 0, false, 0, 17, 4195808, 0, "", ""},
   229  			{"", 3, 0, false, 0, 18, 6293128, 0, "", ""},
   230  			{"", 3, 0, false, 0, 19, 6293144, 0, "", ""},
   231  			{"", 3, 0, false, 0, 20, 6293160, 0, "", ""},
   232  			{"", 3, 0, false, 0, 21, 6293168, 0, "", ""},
   233  			{"", 3, 0, false, 0, 22, 6293584, 0, "", ""},
   234  			{"", 3, 0, false, 0, 23, 6293592, 0, "", ""},
   235  			{"", 3, 0, false, 0, 24, 6293632, 0, "", ""},
   236  			{"", 3, 0, false, 0, 25, 6293656, 0, "", ""},
   237  			{"", 3, 0, false, 0, 26, 0, 0, "", ""},
   238  			{"", 3, 0, false, 0, 27, 0, 0, "", ""},
   239  			{"", 3, 0, false, 0, 28, 0, 0, "", ""},
   240  			{"", 3, 0, false, 0, 29, 0, 0, "", ""},
   241  			{"", 3, 0, false, 0, 30, 0, 0, "", ""},
   242  			{"", 3, 0, false, 0, 31, 0, 0, "", ""},
   243  			{"", 3, 0, false, 0, 32, 0, 0, "", ""},
   244  			{"", 3, 0, false, 0, 33, 0, 0, "", ""},
   245  			{"init.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   246  			{"initfini.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   247  			{"call_gmon_start", 2, 0, false, 0, 13, 4195340, 0, "", ""},
   248  			{"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   249  			{"__CTOR_LIST__", 1, 0, false, 0, 18, 6293128, 0, "", ""},
   250  			{"__DTOR_LIST__", 1, 0, false, 0, 19, 6293144, 0, "", ""},
   251  			{"__JCR_LIST__", 1, 0, false, 0, 20, 6293160, 0, "", ""},
   252  			{"__do_global_dtors_aux", 2, 0, false, 0, 13, 4195376, 0, "", ""},
   253  			{"completed.6183", 1, 0, false, 0, 25, 6293656, 1, "", ""},
   254  			{"p.6181", 1, 0, false, 0, 24, 6293648, 0, "", ""},
   255  			{"frame_dummy", 2, 0, false, 0, 13, 4195440, 0, "", ""},
   256  			{"crtstuff.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   257  			{"__CTOR_END__", 1, 0, false, 0, 18, 6293136, 0, "", ""},
   258  			{"__DTOR_END__", 1, 0, false, 0, 19, 6293152, 0, "", ""},
   259  			{"__FRAME_END__", 1, 0, false, 0, 17, 4195968, 0, "", ""},
   260  			{"__JCR_END__", 1, 0, false, 0, 20, 6293160, 0, "", ""},
   261  			{"__do_global_ctors_aux", 2, 0, false, 0, 13, 4195680, 0, "", ""},
   262  			{"initfini.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   263  			{"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   264  			{"_GLOBAL_OFFSET_TABLE_", 1, 2, false, 0, 23, 6293592, 0, "", ""},
   265  			{"__init_array_end", 0, 2, false, 0, 18, 6293124, 0, "", ""},
   266  			{"__init_array_start", 0, 2, false, 0, 18, 6293124, 0, "", ""},
   267  			{"_DYNAMIC", 1, 2, false, 0, 21, 6293168, 0, "", ""},
   268  			{"data_start", 32, 0, false, 0, 24, 6293632, 0, "", ""},
   269  			{"__libc_csu_fini", 18, 0, false, 0, 13, 4195520, 2, "", ""},
   270  			{"_start", 18, 0, false, 0, 13, 4195296, 0, "", ""},
   271  			{"__gmon_start__", 32, 0, false, 0, 0, 0, 0, "", ""},
   272  			{"_Jv_RegisterClasses", 32, 0, false, 0, 0, 0, 0, "", ""},
   273  			{"puts@@GLIBC_2.2.5", 18, 0, false, 0, 0, 0, 396, "", ""},
   274  			{"_fini", 18, 0, false, 0, 14, 4195732, 0, "", ""},
   275  			{"__libc_start_main@@GLIBC_2.2.5", 18, 0, false, 0, 0, 0, 450, "", ""},
   276  			{"_IO_stdin_used", 17, 0, false, 0, 15, 4195748, 4, "", ""},
   277  			{"__data_start", 16, 0, false, 0, 24, 6293632, 0, "", ""},
   278  			{"__dso_handle", 17, 2, false, 0, 24, 6293640, 0, "", ""},
   279  			{"__libc_csu_init", 18, 0, false, 0, 13, 4195536, 137, "", ""},
   280  			{"__bss_start", 16, 0, false, 0, 65521, 6293656, 0, "", ""},
   281  			{"_end", 16, 0, false, 0, 65521, 6293664, 0, "", ""},
   282  			{"_edata", 16, 0, false, 0, 65521, 6293656, 0, "", ""},
   283  			{"main", 18, 0, false, 0, 13, 4195480, 27, "", ""},
   284  			{"_init", 18, 0, false, 0, 11, 4195224, 0, "", ""},
   285  		},
   286  	},
   287  	{
   288  		"testdata/hello-world-core.gz",
   289  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_CORE, EM_X86_64, 0x0},
   290  		[]SectionHeader{},
   291  		[]ProgHeader{
   292  			{Type: PT_NOTE, Flags: 0x0, Off: 0x3f8, Vaddr: 0x0, Paddr: 0x0, Filesz: 0x8ac, Memsz: 0x0, Align: 0x0},
   293  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x1000, Vaddr: 0x400000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1000, Align: 0x1000},
   294  			{Type: PT_LOAD, Flags: PF_R, Off: 0x1000, Vaddr: 0x401000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   295  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x2000, Vaddr: 0x402000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   296  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3000, Vaddr: 0x7f54078b8000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1b5000, Align: 0x1000},
   297  			{Type: PT_LOAD, Flags: 0x0, Off: 0x3000, Vaddr: 0x7f5407a6d000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x1ff000, Align: 0x1000},
   298  			{Type: PT_LOAD, Flags: PF_R, Off: 0x3000, Vaddr: 0x7f5407c6c000, Paddr: 0x0, Filesz: 0x4000, Memsz: 0x4000, Align: 0x1000},
   299  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x7000, Vaddr: 0x7f5407c70000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
   300  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x9000, Vaddr: 0x7f5407c72000, Paddr: 0x0, Filesz: 0x5000, Memsz: 0x5000, Align: 0x1000},
   301  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0xe000, Vaddr: 0x7f5407c77000, Paddr: 0x0, Filesz: 0x0, Memsz: 0x22000, Align: 0x1000},
   302  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0xe000, Vaddr: 0x7f5407e81000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
   303  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x11000, Vaddr: 0x7f5407e96000, Paddr: 0x0, Filesz: 0x3000, Memsz: 0x3000, Align: 0x1000},
   304  			{Type: PT_LOAD, Flags: PF_R, Off: 0x14000, Vaddr: 0x7f5407e99000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   305  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x15000, Vaddr: 0x7f5407e9a000, Paddr: 0x0, Filesz: 0x2000, Memsz: 0x2000, Align: 0x1000},
   306  			{Type: PT_LOAD, Flags: PF_W + PF_R, Off: 0x17000, Vaddr: 0x7fff79972000, Paddr: 0x0, Filesz: 0x23000, Memsz: 0x23000, Align: 0x1000},
   307  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3a000, Vaddr: 0x7fff799f8000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   308  			{Type: PT_LOAD, Flags: PF_X + PF_R, Off: 0x3b000, Vaddr: 0xffffffffff600000, Paddr: 0x0, Filesz: 0x1000, Memsz: 0x1000, Align: 0x1000},
   309  		},
   310  		nil,
   311  		nil,
   312  	},
   313  	{
   314  		"testdata/compressed-32.obj",
   315  		FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_386, 0x0},
   316  		[]SectionHeader{
   317  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   318  			{".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x34, 0x17, 0x0, 0x0, 0x1, 0x0, 0x17},
   319  			{".rel.text", SHT_REL, SHF_INFO_LINK, 0x0, 0x3dc, 0x10, 0x13, 0x1, 0x4, 0x8, 0x10},
   320  			{".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   321  			{".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x4b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   322  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x4b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
   323  			{".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x58, 0xb4, 0x0, 0x0, 0x1, 0x0, 0x84},
   324  			{".rel.debug_info", SHT_REL, SHF_INFO_LINK, 0x0, 0x3ec, 0xa0, 0x13, 0x6, 0x4, 0x8, 0xa0},
   325  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xdc, 0x5a, 0x0, 0x0, 0x1, 0x0, 0x5a},
   326  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x136, 0x20, 0x0, 0x0, 0x1, 0x0, 0x20},
   327  			{".rel.debug_aranges", SHT_REL, SHF_INFO_LINK, 0x0, 0x48c, 0x10, 0x13, 0x9, 0x4, 0x8, 0x10},
   328  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x156, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
   329  			{".rel.debug_line", SHT_REL, SHF_INFO_LINK, 0x0, 0x49c, 0x8, 0x13, 0xb, 0x4, 0x8, 0x8},
   330  			{".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1b2, 0x10f, 0x0, 0x0, 0x1, 0x1, 0xb3},
   331  			{".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x265, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
   332  			{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x28f, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   333  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x290, 0x38, 0x0, 0x0, 0x4, 0x0, 0x38},
   334  			{".rel.eh_frame", SHT_REL, SHF_INFO_LINK, 0x0, 0x4a4, 0x8, 0x13, 0x10, 0x4, 0x8, 0x8},
   335  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x4ac, 0xab, 0x0, 0x0, 0x1, 0x0, 0xab},
   336  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2c8, 0x100, 0x14, 0xe, 0x4, 0x10, 0x100},
   337  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x3c8, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
   338  		},
   339  		[]ProgHeader{},
   340  		nil,
   341  		[]Symbol{
   342  			{"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   343  			{"", 3, 0, false, 0, 1, 0, 0, "", ""},
   344  			{"", 3, 0, false, 0, 3, 0, 0, "", ""},
   345  			{"", 3, 0, false, 0, 4, 0, 0, "", ""},
   346  			{"", 3, 0, false, 0, 5, 0, 0, "", ""},
   347  			{"", 3, 0, false, 0, 6, 0, 0, "", ""},
   348  			{"", 3, 0, false, 0, 8, 0, 0, "", ""},
   349  			{"", 3, 0, false, 0, 9, 0, 0, "", ""},
   350  			{"", 3, 0, false, 0, 11, 0, 0, "", ""},
   351  			{"", 3, 0, false, 0, 13, 0, 0, "", ""},
   352  			{"", 3, 0, false, 0, 15, 0, 0, "", ""},
   353  			{"", 3, 0, false, 0, 16, 0, 0, "", ""},
   354  			{"", 3, 0, false, 0, 14, 0, 0, "", ""},
   355  			{"main", 18, 0, false, 0, 1, 0, 23, "", ""},
   356  			{"puts", 16, 0, false, 0, 0, 0, 0, "", ""},
   357  		},
   358  	},
   359  	{
   360  		"testdata/compressed-64.obj",
   361  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0x0, binary.LittleEndian, ET_REL, EM_X86_64, 0x0},
   362  		[]SectionHeader{
   363  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   364  			{".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, 0x0, 0x40, 0x1b, 0x0, 0x0, 0x1, 0x0, 0x1b},
   365  			{".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0x488, 0x30, 0x13, 0x1, 0x8, 0x18, 0x30},
   366  			{".data", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   367  			{".bss", SHT_NOBITS, SHF_WRITE | SHF_ALLOC, 0x0, 0x5b, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   368  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x5b, 0xd, 0x0, 0x0, 0x1, 0x0, 0xd},
   369  			{".debug_info", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x68, 0xba, 0x0, 0x0, 0x1, 0x0, 0x72},
   370  			{".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0x4b8, 0x1c8, 0x13, 0x6, 0x8, 0x18, 0x1c8},
   371  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xda, 0x5c, 0x0, 0x0, 0x1, 0x0, 0x5c},
   372  			{".debug_aranges", SHT_PROGBITS, SHF_COMPRESSED, 0x0, 0x136, 0x30, 0x0, 0x0, 0x1, 0x0, 0x2f},
   373  			{".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x680, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
   374  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x165, 0x60, 0x0, 0x0, 0x1, 0x0, 0x60},
   375  			{".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6b0, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
   376  			{".debug_str", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS | SHF_COMPRESSED, 0x0, 0x1c5, 0x104, 0x0, 0x0, 0x1, 0x1, 0xc3},
   377  			{".comment", SHT_PROGBITS, SHF_MERGE | SHF_STRINGS, 0x0, 0x288, 0x2a, 0x0, 0x0, 0x1, 0x1, 0x2a},
   378  			{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x2b2, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   379  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x2b8, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
   380  			{".rela.eh_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x6c8, 0x18, 0x13, 0x10, 0x8, 0x18, 0x18},
   381  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x6e0, 0xb0, 0x0, 0x0, 0x1, 0x0, 0xb0},
   382  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x2f0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
   383  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0x470, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
   384  		},
   385  		[]ProgHeader{},
   386  		nil,
   387  		[]Symbol{
   388  			{"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   389  			{"", 3, 0, false, 0, 1, 0, 0, "", ""},
   390  			{"", 3, 0, false, 0, 3, 0, 0, "", ""},
   391  			{"", 3, 0, false, 0, 4, 0, 0, "", ""},
   392  			{"", 3, 0, false, 0, 5, 0, 0, "", ""},
   393  			{"", 3, 0, false, 0, 6, 0, 0, "", ""},
   394  			{"", 3, 0, false, 0, 8, 0, 0, "", ""},
   395  			{"", 3, 0, false, 0, 9, 0, 0, "", ""},
   396  			{"", 3, 0, false, 0, 11, 0, 0, "", ""},
   397  			{"", 3, 0, false, 0, 13, 0, 0, "", ""},
   398  			{"", 3, 0, false, 0, 15, 0, 0, "", ""},
   399  			{"", 3, 0, false, 0, 16, 0, 0, "", ""},
   400  			{"", 3, 0, false, 0, 14, 0, 0, "", ""},
   401  			{"main", 18, 0, false, 0, 1, 0, 27, "", ""},
   402  			{"puts", 16, 0, false, 0, 0, 0, 0, "", ""},
   403  		},
   404  	},
   405  	{
   406  		"testdata/go-relocation-test-gcc620-sparc64.obj",
   407  		FileHeader{Class: ELFCLASS64, Data: ELFDATA2MSB, Version: EV_CURRENT, OSABI: ELFOSABI_NONE, ABIVersion: 0x0, ByteOrder: binary.BigEndian, Type: ET_REL, Machine: EM_SPARCV9, Entry: 0x0},
   408  		[]SectionHeader{
   409  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   410  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x0, 0x40, 0x2c, 0x0, 0x0, 0x4, 0x0, 0x2c},
   411  			{".rela.text", SHT_RELA, SHF_INFO_LINK, 0x0, 0xa58, 0x48, 0x13, 0x1, 0x8, 0x18, 0x48},
   412  			{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   413  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x0, 0x6c, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   414  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x0, 0x70, 0xd, 0x0, 0x0, 0x8, 0x0, 0xd},
   415  			{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x7d, 0x346, 0x0, 0x0, 0x1, 0x0, 0x346},
   416  			{".rela.debug_info", SHT_RELA, SHF_INFO_LINK, 0x0, 0xaa0, 0x630, 0x13, 0x6, 0x8, 0x18, 0x630},
   417  			{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x3c3, 0xf1, 0x0, 0x0, 0x1, 0x0, 0xf1},
   418  			{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x4b4, 0x30, 0x0, 0x0, 0x1, 0x0, 0x30},
   419  			{".rela.debug_aranges", SHT_RELA, SHF_INFO_LINK, 0x0, 0x10d0, 0x30, 0x13, 0x9, 0x8, 0x18, 0x30},
   420  			{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x4e4, 0xd3, 0x0, 0x0, 0x1, 0x0, 0xd3},
   421  			{".rela.debug_line", SHT_RELA, SHF_INFO_LINK, 0x0, 0x1100, 0x18, 0x13, 0xb, 0x8, 0x18, 0x18},
   422  			{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0x5b7, 0x2a3, 0x0, 0x0, 0x1, 0x1, 0x2a3},
   423  			{".comment", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0x85a, 0x2e, 0x0, 0x0, 0x1, 0x1, 0x2e},
   424  			{".note.GNU-stack", SHT_PROGBITS, 0x0, 0x0, 0x888, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0},
   425  			{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x888, 0x38, 0x0, 0x0, 0x8, 0x0, 0x38},
   426  			{".rela.debug_frame", SHT_RELA, SHF_INFO_LINK, 0x0, 0x1118, 0x30, 0x13, 0x10, 0x8, 0x18, 0x30},
   427  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x1148, 0xb3, 0x0, 0x0, 0x1, 0x0, 0xb3},
   428  			{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x8c0, 0x180, 0x14, 0xe, 0x8, 0x18, 0x180},
   429  			{".strtab", SHT_STRTAB, 0x0, 0x0, 0xa40, 0x13, 0x0, 0x0, 0x1, 0x0, 0x13},
   430  		},
   431  		[]ProgHeader{},
   432  		nil,
   433  		[]Symbol{
   434  			{"hello.c", 4, 0, false, 0, 65521, 0, 0, "", ""},
   435  			{"", 3, 0, false, 0, 1, 0, 0, "", ""},
   436  			{"", 3, 0, false, 0, 3, 0, 0, "", ""},
   437  			{"", 3, 0, false, 0, 4, 0, 0, "", ""},
   438  			{"", 3, 0, false, 0, 5, 0, 0, "", ""},
   439  			{"", 3, 0, false, 0, 6, 0, 0, "", ""},
   440  			{"", 3, 0, false, 0, 8, 0, 0, "", ""},
   441  			{"", 3, 0, false, 0, 9, 0, 0, "", ""},
   442  			{"", 3, 0, false, 0, 11, 0, 0, "", ""},
   443  			{"", 3, 0, false, 0, 13, 0, 0, "", ""},
   444  			{"", 3, 0, false, 0, 15, 0, 0, "", ""},
   445  			{"", 3, 0, false, 0, 16, 0, 0, "", ""},
   446  			{"", 3, 0, false, 0, 14, 0, 0, "", ""},
   447  			{"main", 18, 0, false, 0, 1, 0, 44, "", ""},
   448  			{"puts", 16, 0, false, 0, 0, 0, 0, "", ""},
   449  		},
   450  	},
   451  	{
   452  		"testdata/gcc-riscv64-linux-exec",
   453  		FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_RISCV, 0x10460},
   454  		[]SectionHeader{
   455  			{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
   456  			{".interp", SHT_PROGBITS, SHF_ALLOC, 0x10270, 0x270, 0x21, 0x0, 0x0, 0x1, 0x0, 0x21},
   457  			{".note.gnu.build-id", SHT_NOTE, SHF_ALLOC, 0x10294, 0x294, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
   458  			{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x102b8, 0x2b8, 0x20, 0x0, 0x0, 0x4, 0x0, 0x20},
   459  			{".gnu.hash", SHT_GNU_HASH, SHF_ALLOC, 0x102d8, 0x2d8, 0x30, 0x5, 0x0, 0x8, 0x0, 0x30},
   460  			{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x10308, 0x308, 0x60, 0x6, 0x1, 0x8, 0x18, 0x60},
   461  			{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x10368, 0x368, 0x4a, 0x0, 0x0, 0x1, 0x0, 0x4a},
   462  			{".gnu.version", SHT_GNU_VERSYM, SHF_ALLOC, 0x103b2, 0x3b2, 0x8, 0x5, 0x0, 0x2, 0x2, 0x8},
   463  			{".gnu.version_r", SHT_GNU_VERNEED, SHF_ALLOC, 0x103c0, 0x3c0, 0x30, 0x6, 0x1, 0x8, 0x0, 0x30},
   464  			{".rela.plt", SHT_RELA, SHF_ALLOC + SHF_INFO_LINK, 0x103f0, 0x3f0, 0x30, 0x5, 0x14, 0x8, 0x18, 0x30},
   465  			{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x10420, 0x420, 0x40, 0x0, 0x0, 0x10, 0x10, 0x40},
   466  			{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x10460, 0x460, 0xd8, 0x0, 0x0, 0x4, 0x0, 0xd8},
   467  			{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x10538, 0x538, 0x15, 0x0, 0x0, 0x8, 0x0, 0x15},
   468  			{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x10550, 0x550, 0x24, 0x0, 0x0, 0x4, 0x0, 0x24},
   469  			{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x10578, 0x578, 0x6c, 0x0, 0x0, 0x8, 0x0, 0x6c},
   470  			{".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE + SHF_ALLOC, 0x11e00, 0xe00, 0x8, 0x0, 0x0, 0x1, 0x8, 0x8},
   471  			{".init_array", SHT_INIT_ARRAY, SHF_WRITE + SHF_ALLOC, 0x11e08, 0xe08, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
   472  			{".fini_array", SHT_FINI_ARRAY, SHF_WRITE + SHF_ALLOC, 0x11e10, 0xe10, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
   473  			{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x11e18, 0xe18, 0x1d0, 0x6, 0x0, 0x8, 0x10, 0x1d0},
   474  			{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x11fe8, 0xfe8, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8},
   475  			{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x11ff0, 0xff0, 0x20, 0x0, 0x0, 0x8, 0x8, 0x20},
   476  			{".sdata", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x12010, 0x1010, 0x8, 0x0, 0x0, 0x8, 0x0, 0x8},
   477  			{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x12018, 0x1018, 0x8, 0x0, 0x0, 0x1, 0x0, 0x8},
   478  			{".comment", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0x1018, 0x26, 0x0, 0x0, 0x1, 0x1, 0x26},
   479  			{".riscv.attributes", SHT_RISCV_ATTRIBUTES, 0x0, 0x0, 0x103e, 0x66, 0x0, 0x0, 0x1, 0x0, 0x66},
   480  			{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0x10a4, 0xff, 0x0, 0x0, 0x1, 0x0, 0xff},
   481  		},
   482  		[]ProgHeader{
   483  			{PT_PHDR, PF_R, 0x40, 0x10040, 0x10040, 0x230, 0x230, 0x8},
   484  			{PT_INTERP, PF_R, 0x270, 0x10270, 0x10270, 0x21, 0x21, 0x1},
   485  			{PT_RISCV_ATTRIBUTES, PF_R, 0x103e, 0x0, 0x0, 0x66, 0x0, 0x1},
   486  			{PT_LOAD, PF_X + PF_R, 0x0, 0x10000, 0x10000, 0x5e4, 0x5e4, 0x1000},
   487  			{PT_LOAD, PF_W + PF_R, 0xe00, 0x11e00, 0x11e00, 0x218, 0x220, 0x1000},
   488  			{PT_DYNAMIC, PF_W + PF_R, 0xe18, 0x11e18, 0x11e18, 0x1d0, 0x1d0, 0x8},
   489  			{PT_NOTE, PF_R, 0x294, 0x10294, 0x10294, 0x44, 0x44, 0x4},
   490  			{PT_GNU_EH_FRAME, PF_R, 0x550, 0x10550, 0x10550, 0x24, 0x24, 0x4},
   491  			{PT_GNU_STACK, PF_W + PF_R, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10},
   492  			{PT_GNU_RELRO, PF_R, 0xe00, 0x11e00, 0x11e00, 0x200, 0x200, 0x1},
   493  		},
   494  		[]string{"libc.so.6"},
   495  		nil,
   496  	},
   497  }
   498  
   499  func TestOpen(t *testing.T) {
   500  	for i := range fileTests {
   501  		tt := &fileTests[i]
   502  
   503  		var f *File
   504  		var err error
   505  		if path.Ext(tt.file) == ".gz" {
   506  			var r io.ReaderAt
   507  			if r, err = decompress(tt.file); err == nil {
   508  				f, err = NewFile(r)
   509  			}
   510  		} else {
   511  			f, err = Open(tt.file)
   512  		}
   513  		if err != nil {
   514  			t.Errorf("cannot open file %s: %v", tt.file, err)
   515  			continue
   516  		}
   517  		defer f.Close()
   518  		if f.FileHeader != tt.hdr {
   519  			t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
   520  			continue
   521  		}
   522  		for i, s := range f.Sections {
   523  			if i >= len(tt.sections) {
   524  				break
   525  			}
   526  			sh := tt.sections[i]
   527  			if s.SectionHeader != sh {
   528  				t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, s.SectionHeader, sh)
   529  			}
   530  		}
   531  		for i, p := range f.Progs {
   532  			if i >= len(tt.progs) {
   533  				break
   534  			}
   535  			ph := tt.progs[i]
   536  			if p.ProgHeader != ph {
   537  				t.Errorf("open %s, program %d:\n\thave %#v\n\twant %#v\n", tt.file, i, p.ProgHeader, ph)
   538  			}
   539  		}
   540  		tn := len(tt.sections)
   541  		fn := len(f.Sections)
   542  		if tn != fn {
   543  			t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
   544  		}
   545  		tn = len(tt.progs)
   546  		fn = len(f.Progs)
   547  		if tn != fn {
   548  			t.Errorf("open %s: len(Progs) = %d, want %d", tt.file, fn, tn)
   549  		}
   550  		tl := tt.needed
   551  		fl, err := f.ImportedLibraries()
   552  		if err != nil {
   553  			t.Error(err)
   554  		}
   555  		if !reflect.DeepEqual(tl, fl) {
   556  			t.Errorf("open %s: DT_NEEDED = %v, want %v", tt.file, tl, fl)
   557  		}
   558  		symbols, err := f.Symbols()
   559  		if tt.symbols == nil {
   560  			if !errors.Is(err, ErrNoSymbols) {
   561  				t.Errorf("open %s: Symbols() expected ErrNoSymbols, have nil", tt.file)
   562  			}
   563  			if symbols != nil {
   564  				t.Errorf("open %s: Symbols() expected no symbols, have %v", tt.file, symbols)
   565  			}
   566  		} else {
   567  			if err != nil {
   568  				t.Errorf("open %s: Symbols() unexpected error %v", tt.file, err)
   569  			}
   570  			if !slices.Equal(symbols, tt.symbols) {
   571  				t.Errorf("open %s: Symbols() = %v, want %v", tt.file, symbols, tt.symbols)
   572  			}
   573  		}
   574  	}
   575  }
   576  
   577  // elf.NewFile requires io.ReaderAt, which compress/gzip cannot
   578  // provide. Decompress the file to a bytes.Reader.
   579  func decompress(gz string) (io.ReaderAt, error) {
   580  	in, err := os.Open(gz)
   581  	if err != nil {
   582  		return nil, err
   583  	}
   584  	defer in.Close()
   585  	r, err := gzip.NewReader(in)
   586  	if err != nil {
   587  		return nil, err
   588  	}
   589  	var out bytes.Buffer
   590  	_, err = io.Copy(&out, r)
   591  	return bytes.NewReader(out.Bytes()), err
   592  }
   593  
   594  type relocationTestEntry struct {
   595  	entryNumber int
   596  	entry       *dwarf.Entry
   597  	pcRanges    [][2]uint64
   598  }
   599  
   600  type relocationTest struct {
   601  	file    string
   602  	entries []relocationTestEntry
   603  }
   604  
   605  var relocationTests = []relocationTest{
   606  	{
   607  		"testdata/go-relocation-test-gcc441-x86-64.obj",
   608  		[]relocationTestEntry{
   609  			{
   610  				entry: &dwarf.Entry{
   611  					Offset:   0xb,
   612  					Tag:      dwarf.TagCompileUnit,
   613  					Children: true,
   614  					Field: []dwarf.Field{
   615  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   616  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   617  						{Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString},
   618  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   619  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   620  						{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   621  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   622  					},
   623  				},
   624  				pcRanges: [][2]uint64{{0x0, 0x6}},
   625  			},
   626  		},
   627  	},
   628  	{
   629  		"testdata/go-relocation-test-gcc441-x86.obj",
   630  		[]relocationTestEntry{
   631  			{
   632  				entry: &dwarf.Entry{
   633  					Offset:   0xb,
   634  					Tag:      dwarf.TagCompileUnit,
   635  					Children: true,
   636  					Field: []dwarf.Field{
   637  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString},
   638  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   639  						{Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString},
   640  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   641  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   642  						{Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress},
   643  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   644  					},
   645  				},
   646  				pcRanges: [][2]uint64{{0x0, 0x5}},
   647  			},
   648  		},
   649  	},
   650  	{
   651  		"testdata/go-relocation-test-gcc424-x86-64.obj",
   652  		[]relocationTestEntry{
   653  			{
   654  				entry: &dwarf.Entry{
   655  					Offset:   0xb,
   656  					Tag:      dwarf.TagCompileUnit,
   657  					Children: true,
   658  					Field: []dwarf.Field{
   659  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString},
   660  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   661  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString},
   662  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   663  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   664  						{Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress},
   665  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   666  					},
   667  				},
   668  				pcRanges: [][2]uint64{{0x0, 0x6}},
   669  			},
   670  		},
   671  	},
   672  	{
   673  		"testdata/go-relocation-test-gcc482-aarch64.obj",
   674  		[]relocationTestEntry{
   675  			{
   676  				entry: &dwarf.Entry{
   677  					Offset:   0xb,
   678  					Tag:      dwarf.TagCompileUnit,
   679  					Children: true,
   680  					Field: []dwarf.Field{
   681  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString},
   682  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   683  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString},
   684  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   685  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   686  						{Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant},
   687  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   688  					},
   689  				},
   690  				pcRanges: [][2]uint64{{0x0, 0x24}},
   691  			},
   692  		},
   693  	},
   694  	{
   695  		"testdata/go-relocation-test-gcc492-arm.obj",
   696  		[]relocationTestEntry{
   697  			{
   698  				entry: &dwarf.Entry{
   699  					Offset:   0xb,
   700  					Tag:      dwarf.TagCompileUnit,
   701  					Children: true,
   702  					Field: []dwarf.Field{
   703  						{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},
   704  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   705  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString},
   706  						{Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString},
   707  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   708  						{Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant},
   709  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   710  					},
   711  				},
   712  				pcRanges: [][2]uint64{{0x0, 0x28}},
   713  			},
   714  		},
   715  	},
   716  	{
   717  		"testdata/go-relocation-test-clang-arm.obj",
   718  		[]relocationTestEntry{
   719  			{
   720  				entry: &dwarf.Entry{
   721  					Offset:   0xb,
   722  					Tag:      dwarf.TagCompileUnit,
   723  					Children: true,
   724  					Field: []dwarf.Field{
   725  						{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString},
   726  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   727  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   728  						{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr},
   729  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   730  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   731  						{Attr: dwarf.AttrHighpc, Val: int64(0x30), Class: dwarf.ClassConstant},
   732  					},
   733  				},
   734  				pcRanges: [][2]uint64{{0x0, 0x30}},
   735  			},
   736  		},
   737  	},
   738  	{
   739  		"testdata/go-relocation-test-gcc5-ppc.obj",
   740  		[]relocationTestEntry{
   741  			{
   742  				entry: &dwarf.Entry{
   743  					Offset:   0xb,
   744  					Tag:      dwarf.TagCompileUnit,
   745  					Children: true,
   746  					Field: []dwarf.Field{
   747  						{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString},
   748  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   749  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString},
   750  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   751  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   752  						{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant},
   753  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   754  					},
   755  				},
   756  				pcRanges: [][2]uint64{{0x0, 0x44}},
   757  			},
   758  		},
   759  	},
   760  	{
   761  		"testdata/go-relocation-test-gcc482-ppc64le.obj",
   762  		[]relocationTestEntry{
   763  			{
   764  				entry: &dwarf.Entry{
   765  					Offset:   0xb,
   766  					Tag:      dwarf.TagCompileUnit,
   767  					Children: true,
   768  					Field: []dwarf.Field{
   769  						{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},
   770  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   771  						{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString},
   772  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   773  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   774  						{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress},
   775  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   776  					},
   777  				},
   778  				pcRanges: [][2]uint64{{0x0, 0x24}},
   779  			},
   780  		},
   781  	},
   782  	{
   783  		"testdata/go-relocation-test-gcc492-mips64.obj",
   784  		[]relocationTestEntry{
   785  			{
   786  				entry: &dwarf.Entry{
   787  					Offset:   0xb,
   788  					Tag:      dwarf.TagCompileUnit,
   789  					Children: true,
   790  					Field: []dwarf.Field{
   791  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -meb -mabi=64 -march=mips3 -mtune=mips64 -mllsc -mno-shared -g", Class: dwarf.ClassString},
   792  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   793  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   794  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   795  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   796  						{Attr: dwarf.AttrHighpc, Val: int64(0x64), Class: dwarf.ClassConstant},
   797  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   798  					},
   799  				},
   800  				pcRanges: [][2]uint64{{0x0, 0x64}},
   801  			},
   802  		},
   803  	},
   804  	{
   805  		"testdata/go-relocation-test-gcc531-s390x.obj",
   806  		[]relocationTestEntry{
   807  			{
   808  				entry: &dwarf.Entry{
   809  					Offset:   0xb,
   810  					Tag:      dwarf.TagCompileUnit,
   811  					Children: true,
   812  					Field: []dwarf.Field{
   813  						{Attr: dwarf.AttrProducer, Val: "GNU C11 5.3.1 20160316 -march=zEC12 -m64 -mzarch -g -fstack-protector-strong", Class: dwarf.ClassString},
   814  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   815  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   816  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   817  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   818  						{Attr: dwarf.AttrHighpc, Val: int64(0x3a), Class: dwarf.ClassConstant},
   819  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   820  					},
   821  				},
   822  				pcRanges: [][2]uint64{{0x0, 0x3a}},
   823  			},
   824  		},
   825  	},
   826  	{
   827  		"testdata/go-relocation-test-gcc620-sparc64.obj",
   828  		[]relocationTestEntry{
   829  			{
   830  				entry: &dwarf.Entry{
   831  					Offset:   0xb,
   832  					Tag:      dwarf.TagCompileUnit,
   833  					Children: true,
   834  					Field: []dwarf.Field{
   835  						{Attr: dwarf.AttrProducer, Val: "GNU C11 6.2.0 20160914 -mcpu=v9 -g -fstack-protector-strong", Class: dwarf.ClassString},
   836  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   837  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   838  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   839  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   840  						{Attr: dwarf.AttrHighpc, Val: int64(0x2c), Class: dwarf.ClassConstant},
   841  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   842  					},
   843  				},
   844  				pcRanges: [][2]uint64{{0x0, 0x2c}},
   845  			},
   846  		},
   847  	},
   848  	{
   849  		"testdata/go-relocation-test-gcc492-mipsle.obj",
   850  		[]relocationTestEntry{
   851  			{
   852  				entry: &dwarf.Entry{
   853  					Offset:   0xb,
   854  					Tag:      dwarf.TagCompileUnit,
   855  					Children: true,
   856  					Field: []dwarf.Field{
   857  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 -mel -march=mips2 -mtune=mips32 -mllsc -mno-shared -mabi=32 -g", Class: dwarf.ClassString},
   858  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   859  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   860  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   861  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   862  						{Attr: dwarf.AttrHighpc, Val: int64(0x58), Class: dwarf.ClassConstant},
   863  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   864  					},
   865  				},
   866  				pcRanges: [][2]uint64{{0x0, 0x58}},
   867  			},
   868  		},
   869  	},
   870  	{
   871  		"testdata/go-relocation-test-gcc540-mips.obj",
   872  		[]relocationTestEntry{
   873  			{
   874  				entry: &dwarf.Entry{
   875  					Offset:   0xb,
   876  					Tag:      dwarf.TagCompileUnit,
   877  					Children: true,
   878  					Field: []dwarf.Field{
   879  						{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},
   880  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   881  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   882  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   883  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   884  						{Attr: dwarf.AttrHighpc, Val: uint64(0x5c), Class: dwarf.ClassAddress},
   885  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   886  					},
   887  				},
   888  				pcRanges: [][2]uint64{{0x0, 0x5c}},
   889  			},
   890  		},
   891  	},
   892  	{
   893  		"testdata/go-relocation-test-gcc493-mips64le.obj",
   894  		[]relocationTestEntry{
   895  			{
   896  				entry: &dwarf.Entry{
   897  					Offset:   0xb,
   898  					Tag:      dwarf.TagCompileUnit,
   899  					Children: true,
   900  					Field: []dwarf.Field{
   901  						{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.3 -mel -mabi=64 -mllsc -mno-shared -g -fstack-protector-strong", Class: dwarf.ClassString},
   902  						{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant},
   903  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   904  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   905  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   906  						{Attr: dwarf.AttrHighpc, Val: int64(0x64), Class: dwarf.ClassConstant},
   907  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   908  					},
   909  				},
   910  				pcRanges: [][2]uint64{{0x0, 0x64}},
   911  			},
   912  		},
   913  	},
   914  	{
   915  		"testdata/go-relocation-test-gcc720-riscv64.obj",
   916  		[]relocationTestEntry{
   917  			{
   918  				entry: &dwarf.Entry{
   919  					Offset:   0xb,
   920  					Tag:      dwarf.TagCompileUnit,
   921  					Children: true,
   922  					Field: []dwarf.Field{
   923  						{Attr: dwarf.AttrProducer, Val: "GNU C11 7.2.0 -march=rv64imafdc -mabi=lp64d -g -gdwarf-2", Class: dwarf.ClassString},
   924  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   925  						{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString},
   926  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   927  						{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress},
   928  						{Attr: dwarf.AttrHighpc, Val: uint64(0x2c), Class: dwarf.ClassAddress},
   929  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   930  					},
   931  				},
   932  				pcRanges: [][2]uint64{{0x0, 0x2c}},
   933  			},
   934  		},
   935  	},
   936  	{
   937  		"testdata/go-relocation-test-clang-x86.obj",
   938  		[]relocationTestEntry{
   939  			{
   940  				entry: &dwarf.Entry{
   941  					Offset:   0xb,
   942  					Tag:      dwarf.TagCompileUnit,
   943  					Children: true,
   944  					Field: []dwarf.Field{
   945  						{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString},
   946  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
   947  						{Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString},
   948  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
   949  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
   950  					},
   951  				},
   952  			},
   953  		},
   954  	},
   955  	{
   956  		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
   957  		[]relocationTestEntry{
   958  			{
   959  				entryNumber: 203,
   960  				entry: &dwarf.Entry{
   961  					Offset:   0xc62,
   962  					Tag:      dwarf.TagMember,
   963  					Children: false,
   964  					Field: []dwarf.Field{
   965  						{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString},
   966  						{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   967  						{Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant},
   968  						{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   969  						{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc},
   970  					},
   971  				},
   972  			},
   973  			{
   974  				entryNumber: 204,
   975  				entry: &dwarf.Entry{
   976  					Offset:   0xc70,
   977  					Tag:      dwarf.TagMember,
   978  					Children: false,
   979  					Field: []dwarf.Field{
   980  						{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString},
   981  						{Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant},
   982  						{Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant},
   983  						{Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference},
   984  						{Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc},
   985  					},
   986  				},
   987  			},
   988  		},
   989  	},
   990  	{
   991  		"testdata/go-relocation-test-gcc930-ranges-no-rela-x86-64",
   992  		[]relocationTestEntry{
   993  			{
   994  				entry: &dwarf.Entry{
   995  					Offset:   0xb,
   996  					Tag:      dwarf.TagCompileUnit,
   997  					Children: true,
   998  					Field: []dwarf.Field{
   999  						{Attr: dwarf.AttrProducer, Val: "GNU C17 9.3.0 -mtune=generic -march=x86-64 -g -fno-asynchronous-unwind-tables", Class: dwarf.ClassString},
  1000  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
  1001  						{Attr: dwarf.AttrName, Val: "multiple-code-sections.c", Class: dwarf.ClassString},
  1002  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
  1003  						{Attr: dwarf.AttrRanges, Val: int64(0), Class: dwarf.ClassRangeListPtr},
  1004  						{Attr: dwarf.AttrLowpc, Val: uint64(0), Class: dwarf.ClassAddress},
  1005  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
  1006  					},
  1007  				},
  1008  				pcRanges: [][2]uint64{
  1009  					{0x765, 0x777},
  1010  					{0x7e1, 0x7ec},
  1011  				},
  1012  			},
  1013  		},
  1014  	},
  1015  	{
  1016  		"testdata/go-relocation-test-gcc930-ranges-with-rela-x86-64",
  1017  		[]relocationTestEntry{
  1018  			{
  1019  				entry: &dwarf.Entry{
  1020  					Offset:   0xb,
  1021  					Tag:      dwarf.TagCompileUnit,
  1022  					Children: true,
  1023  					Field: []dwarf.Field{
  1024  						{Attr: dwarf.AttrProducer, Val: "GNU C17 9.3.0 -mtune=generic -march=x86-64 -g -fno-asynchronous-unwind-tables", Class: dwarf.ClassString},
  1025  						{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant},
  1026  						{Attr: dwarf.AttrName, Val: "multiple-code-sections.c", Class: dwarf.ClassString},
  1027  						{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString},
  1028  						{Attr: dwarf.AttrRanges, Val: int64(0), Class: dwarf.ClassRangeListPtr},
  1029  						{Attr: dwarf.AttrLowpc, Val: uint64(0), Class: dwarf.ClassAddress},
  1030  						{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr},
  1031  					},
  1032  				},
  1033  				pcRanges: [][2]uint64{
  1034  					{0x765, 0x777},
  1035  					{0x7e1, 0x7ec},
  1036  				},
  1037  			},
  1038  		},
  1039  	},
  1040  }
  1041  
  1042  func TestDWARFRelocations(t *testing.T) {
  1043  	for _, test := range relocationTests {
  1044  		t.Run(test.file, func(t *testing.T) {
  1045  			t.Parallel()
  1046  			f, err := Open(test.file)
  1047  			if err != nil {
  1048  				t.Fatal(err)
  1049  			}
  1050  			dwarf, err := f.DWARF()
  1051  			if err != nil {
  1052  				t.Fatal(err)
  1053  			}
  1054  			reader := dwarf.Reader()
  1055  			idx := 0
  1056  			for _, testEntry := range test.entries {
  1057  				if testEntry.entryNumber < idx {
  1058  					t.Fatalf("internal test error: %d < %d", testEntry.entryNumber, idx)
  1059  				}
  1060  				for ; idx < testEntry.entryNumber; idx++ {
  1061  					entry, err := reader.Next()
  1062  					if entry == nil || err != nil {
  1063  						t.Fatalf("Failed to skip to entry %d: %v", testEntry.entryNumber, err)
  1064  					}
  1065  				}
  1066  				entry, err := reader.Next()
  1067  				idx++
  1068  				if err != nil {
  1069  					t.Fatal(err)
  1070  				}
  1071  				if !reflect.DeepEqual(testEntry.entry, entry) {
  1072  					t.Errorf("entry %d mismatch: got:%#v want:%#v", testEntry.entryNumber, entry, testEntry.entry)
  1073  				}
  1074  				pcRanges, err := dwarf.Ranges(entry)
  1075  				if err != nil {
  1076  					t.Fatal(err)
  1077  				}
  1078  				if !reflect.DeepEqual(testEntry.pcRanges, pcRanges) {
  1079  					t.Errorf("entry %d: PC range mismatch: got:%#v want:%#v", testEntry.entryNumber, pcRanges, testEntry.pcRanges)
  1080  				}
  1081  			}
  1082  		})
  1083  	}
  1084  }
  1085  
  1086  func TestCompressedDWARF(t *testing.T) {
  1087  	// Test file built with GCC 4.8.4 and as 2.24 using:
  1088  	// gcc -Wa,--compress-debug-sections -g -c -o zdebug-test-gcc484-x86-64.obj hello.c
  1089  	f, err := Open("testdata/zdebug-test-gcc484-x86-64.obj")
  1090  	if err != nil {
  1091  		t.Fatal(err)
  1092  	}
  1093  	dwarf, err := f.DWARF()
  1094  	if err != nil {
  1095  		t.Fatal(err)
  1096  	}
  1097  	reader := dwarf.Reader()
  1098  	n := 0
  1099  	for {
  1100  		entry, err := reader.Next()
  1101  		if err != nil {
  1102  			t.Fatal(err)
  1103  		}
  1104  		if entry == nil {
  1105  			break
  1106  		}
  1107  		n++
  1108  	}
  1109  	if n != 18 {
  1110  		t.Fatalf("want %d DWARF entries, got %d", 18, n)
  1111  	}
  1112  }
  1113  
  1114  func TestCompressedSection(t *testing.T) {
  1115  	// Test files built with gcc -g -S hello.c and assembled with
  1116  	// --compress-debug-sections=zlib-gabi.
  1117  	f, err := Open("testdata/compressed-64.obj")
  1118  	if err != nil {
  1119  		t.Fatal(err)
  1120  	}
  1121  	sec := f.Section(".debug_info")
  1122  	wantData := []byte{
  1123  		182, 0, 0, 0, 4, 0, 0, 0, 0, 0, 8, 1, 0, 0, 0, 0,
  1124  		1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1125  		0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 7,
  1126  		0, 0, 0, 0, 2, 1, 8, 0, 0, 0, 0, 2, 2, 7, 0, 0,
  1127  		0, 0, 2, 4, 7, 0, 0, 0, 0, 2, 1, 6, 0, 0, 0, 0,
  1128  		2, 2, 5, 0, 0, 0, 0, 3, 4, 5, 105, 110, 116, 0, 2, 8,
  1129  		5, 0, 0, 0, 0, 2, 8, 7, 0, 0, 0, 0, 4, 8, 114, 0,
  1130  		0, 0, 2, 1, 6, 0, 0, 0, 0, 5, 0, 0, 0, 0, 1, 4,
  1131  		0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0,
  1132  		1, 156, 179, 0, 0, 0, 6, 0, 0, 0, 0, 1, 4, 87, 0, 0,
  1133  		0, 2, 145, 108, 6, 0, 0, 0, 0, 1, 4, 179, 0, 0, 0, 2,
  1134  		145, 96, 0, 4, 8, 108, 0, 0, 0, 0,
  1135  	}
  1136  
  1137  	// Test Data method.
  1138  	b, err := sec.Data()
  1139  	if err != nil {
  1140  		t.Fatal(err)
  1141  	}
  1142  	if !bytes.Equal(wantData, b) {
  1143  		t.Fatalf("want data %x, got %x", wantData, b)
  1144  	}
  1145  
  1146  	// Test Open method and seeking.
  1147  	buf, have, count := make([]byte, len(b)), make([]bool, len(b)), 0
  1148  	sf := sec.Open()
  1149  	if got, err := sf.Seek(0, io.SeekEnd); got != int64(len(b)) || err != nil {
  1150  		t.Fatalf("want seek end %d, got %d error %v", len(b), got, err)
  1151  	}
  1152  	if n, err := sf.Read(buf); n != 0 || err != io.EOF {
  1153  		t.Fatalf("want EOF with 0 bytes, got %v with %d bytes", err, n)
  1154  	}
  1155  	pos := int64(len(buf))
  1156  	for count < len(buf) {
  1157  		// Construct random seek arguments.
  1158  		whence := rand.Intn(3)
  1159  		target := rand.Int63n(int64(len(buf)))
  1160  		var offset int64
  1161  		switch whence {
  1162  		case io.SeekStart:
  1163  			offset = target
  1164  		case io.SeekCurrent:
  1165  			offset = target - pos
  1166  		case io.SeekEnd:
  1167  			offset = target - int64(len(buf))
  1168  		}
  1169  		pos, err = sf.Seek(offset, whence)
  1170  		if err != nil {
  1171  			t.Fatal(err)
  1172  		}
  1173  		if pos != target {
  1174  			t.Fatalf("want position %d, got %d", target, pos)
  1175  		}
  1176  
  1177  		// Read data from the new position.
  1178  		end := pos + 16
  1179  		if end > int64(len(buf)) {
  1180  			end = int64(len(buf))
  1181  		}
  1182  		n, err := io.ReadFull(sf, buf[pos:end])
  1183  		if err != nil {
  1184  			t.Fatal(err)
  1185  		}
  1186  		for i := 0; i < n; i++ {
  1187  			if !have[pos] {
  1188  				have[pos] = true
  1189  				count++
  1190  			}
  1191  			pos++
  1192  		}
  1193  	}
  1194  	if !bytes.Equal(wantData, buf) {
  1195  		t.Fatalf("want data %x, got %x", wantData, buf)
  1196  	}
  1197  }
  1198  
  1199  func TestNoSectionOverlaps(t *testing.T) {
  1200  	// Ensure cmd/link outputs sections without overlaps.
  1201  	switch runtime.GOOS {
  1202  	case "aix", "android", "darwin", "ios", "js", "plan9", "windows", "wasip1":
  1203  		t.Skipf("cmd/link doesn't produce ELF binaries on %s", runtime.GOOS)
  1204  	}
  1205  	_ = net.ResolveIPAddr // force dynamic linkage
  1206  	f, err := Open(os.Args[0])
  1207  	if err != nil {
  1208  		t.Error(err)
  1209  		return
  1210  	}
  1211  	for i, si := range f.Sections {
  1212  		sih := si.SectionHeader
  1213  		if sih.Type == SHT_NOBITS {
  1214  			continue
  1215  		}
  1216  		// checking for overlap in file
  1217  		for j, sj := range f.Sections {
  1218  			sjh := sj.SectionHeader
  1219  			if i == j || sjh.Type == SHT_NOBITS || sih.Offset == sjh.Offset && sih.FileSize == 0 {
  1220  				continue
  1221  			}
  1222  			if sih.Offset >= sjh.Offset && sih.Offset < sjh.Offset+sjh.FileSize {
  1223  				t.Errorf("ld produced ELF with section offset %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
  1224  					sih.Name, sjh.Name, sjh.Offset, sih.Offset, sih.Offset+sih.FileSize, sjh.Offset+sjh.FileSize)
  1225  			}
  1226  		}
  1227  
  1228  		if sih.Flags&SHF_ALLOC == 0 {
  1229  			continue
  1230  		}
  1231  
  1232  		// checking for overlap in address space
  1233  		for j, sj := range f.Sections {
  1234  			sjh := sj.SectionHeader
  1235  			if i == j || sjh.Flags&SHF_ALLOC == 0 || sjh.Type == SHT_NOBITS ||
  1236  				sih.Addr == sjh.Addr && sih.Size == 0 {
  1237  				continue
  1238  			}
  1239  			if sih.Addr >= sjh.Addr && sih.Addr < sjh.Addr+sjh.Size {
  1240  				t.Errorf("ld produced ELF with section address %s within %s: 0x%x <= 0x%x..0x%x < 0x%x",
  1241  					sih.Name, sjh.Name, sjh.Addr, sih.Addr, sih.Addr+sih.Size, sjh.Addr+sjh.Size)
  1242  			}
  1243  		}
  1244  	}
  1245  }
  1246  
  1247  func TestNobitsSection(t *testing.T) {
  1248  	const testdata = "testdata/gcc-amd64-linux-exec"
  1249  	f, err := Open(testdata)
  1250  	if err != nil {
  1251  		t.Fatalf("could not read %s: %v", testdata, err)
  1252  	}
  1253  	defer f.Close()
  1254  
  1255  	wantError := "unexpected read from SHT_NOBITS section"
  1256  	bss := f.Section(".bss")
  1257  
  1258  	_, err = bss.Data()
  1259  	if err == nil || err.Error() != wantError {
  1260  		t.Fatalf("bss.Data() got error %q, want error %q", err, wantError)
  1261  	}
  1262  
  1263  	r := bss.Open()
  1264  	p := make([]byte, 1)
  1265  	_, err = r.Read(p)
  1266  	if err == nil || err.Error() != wantError {
  1267  		t.Fatalf("r.Read(p) got error %q, want error %q", err, wantError)
  1268  	}
  1269  }
  1270  
  1271  // TestLargeNumberOfSections tests the case that a file has greater than or
  1272  // equal to 65280 (0xff00) sections.
  1273  func TestLargeNumberOfSections(t *testing.T) {
  1274  	// A file with >= 0xff00 sections is too big, so we will construct it on the
  1275  	// fly. The original file "y.o" is generated by these commands:
  1276  	// 1. generate "y.c":
  1277  	//   for i in `seq 1 65288`; do
  1278  	//     printf -v x "%04x" i;
  1279  	//     echo "int var_$x __attribute__((section(\"section_$x\"))) = $i;"
  1280  	//   done > y.c
  1281  	// 2. compile: gcc -c y.c -m32
  1282  	//
  1283  	// $readelf -h y.o
  1284  	// ELF Header:
  1285  	//   Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  1286  	//   Class:                             ELF32
  1287  	//   Data:                              2's complement, little endian
  1288  	//   Version:                           1 (current)
  1289  	//   OS/ABI:                            UNIX - System V
  1290  	//   ABI Version:                       0
  1291  	//   Type:                              REL (Relocatable file)
  1292  	//   Machine:                           Intel 80386
  1293  	//   Version:                           0x1
  1294  	//   Entry point address:               0x0
  1295  	//   Start of program headers:          0 (bytes into file)
  1296  	//   Start of section headers:          3003468 (bytes into file)
  1297  	//   Flags:                             0x0
  1298  	//   Size of this header:               52 (bytes)
  1299  	//   Size of program headers:           0 (bytes)
  1300  	//   Number of program headers:         0
  1301  	//   Size of section headers:           40 (bytes)
  1302  	//   Number of section headers:         0 (65298)
  1303  	//   Section header string table index: 65535 (65297)
  1304  	//
  1305  	// $readelf -S y.o
  1306  	// There are 65298 section headers, starting at offset 0x2dd44c:
  1307  	// Section Headers:
  1308  	//   [Nr]    Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  1309  	//   [    0]                   NULL            00000000 000000 00ff12 00     65297   0  0
  1310  	//   [    1] .text             PROGBITS        00000000 000034 000000 00  AX  0   0  1
  1311  	//   [    2] .data             PROGBITS        00000000 000034 000000 00  WA  0   0  1
  1312  	//   [    3] .bss              NOBITS          00000000 000034 000000 00  WA  0   0  1
  1313  	//   [    4] section_0001      PROGBITS        00000000 000034 000004 00  WA  0   0  4
  1314  	//   [    5] section_0002      PROGBITS        00000000 000038 000004 00  WA  0   0  4
  1315  	//   [ section_0003 ~ section_ff06 truncated ]
  1316  	//   [65290] section_ff07      PROGBITS        00000000 03fc4c 000004 00  WA  0   0  4
  1317  	//   [65291] section_ff08      PROGBITS        00000000 03fc50 000004 00  WA  0   0  4
  1318  	//   [65292] .comment          PROGBITS        00000000 03fc54 000027 01  MS  0   0  1
  1319  	//   [65293] .note.GNU-stack   PROGBITS        00000000 03fc7b 000000 00      0   0  1
  1320  	//   [65294] .symtab           SYMTAB          00000000 03fc7c 0ff0a0 10     65296   2  4
  1321  	//   [65295] .symtab_shndx     SYMTAB SECTION  00000000 13ed1c 03fc28 04     65294   0  4
  1322  	//   [65296] .strtab           STRTAB          00000000 17e944 08f74d 00      0   0  1
  1323  	//   [65297] .shstrtab         STRTAB          00000000 20e091 0cf3bb 00      0   0  1
  1324  
  1325  	var buf bytes.Buffer
  1326  
  1327  	{
  1328  		buf.Grow(0x55AF1C) // 3003468 + 40 * 65298
  1329  
  1330  		h := Header32{
  1331  			Ident:     [16]byte{0x7F, 'E', 'L', 'F', 0x01, 0x01, 0x01},
  1332  			Type:      1,
  1333  			Machine:   3,
  1334  			Version:   1,
  1335  			Shoff:     0x2DD44C,
  1336  			Ehsize:    0x34,
  1337  			Shentsize: 0x28,
  1338  			Shnum:     0,
  1339  			Shstrndx:  0xFFFF,
  1340  		}
  1341  		binary.Write(&buf, binary.LittleEndian, h)
  1342  
  1343  		// Zero out sections [1]~[65294].
  1344  		buf.Write(bytes.Repeat([]byte{0}, 0x13ED1C-binary.Size(h)))
  1345  
  1346  		// Write section [65295]. Section [65295] are all zeros except for the
  1347  		// last 48 bytes.
  1348  		buf.Write(bytes.Repeat([]byte{0}, 0x03FC28-12*4))
  1349  		for i := 0; i < 12; i++ {
  1350  			binary.Write(&buf, binary.LittleEndian, uint32(0xFF00|i))
  1351  		}
  1352  
  1353  		// Write section [65296].
  1354  		buf.Write([]byte{0})
  1355  		buf.Write([]byte("y.c\x00"))
  1356  		for i := 1; i <= 65288; i++ {
  1357  			// var_0001 ~ var_ff08
  1358  			name := fmt.Sprintf("var_%04x", i)
  1359  			buf.Write([]byte(name))
  1360  			buf.Write([]byte{0})
  1361  		}
  1362  
  1363  		// Write section [65297].
  1364  		buf.Write([]byte{0})
  1365  		buf.Write([]byte(".symtab\x00"))
  1366  		buf.Write([]byte(".strtab\x00"))
  1367  		buf.Write([]byte(".shstrtab\x00"))
  1368  		buf.Write([]byte(".text\x00"))
  1369  		buf.Write([]byte(".data\x00"))
  1370  		buf.Write([]byte(".bss\x00"))
  1371  		for i := 1; i <= 65288; i++ {
  1372  			// s_0001 ~ s_ff08
  1373  			name := fmt.Sprintf("section_%04x", i)
  1374  			buf.Write([]byte(name))
  1375  			buf.Write([]byte{0})
  1376  		}
  1377  		buf.Write([]byte(".comment\x00"))
  1378  		buf.Write([]byte(".note.GNU-stack\x00"))
  1379  		buf.Write([]byte(".symtab_shndx\x00"))
  1380  
  1381  		// Write section header table.
  1382  		// NULL
  1383  		binary.Write(&buf, binary.LittleEndian, Section32{Name: 0, Size: 0xFF12, Link: 0xFF11})
  1384  		// .text
  1385  		binary.Write(&buf, binary.LittleEndian, Section32{
  1386  			Name:      0x1B,
  1387  			Type:      uint32(SHT_PROGBITS),
  1388  			Flags:     uint32(SHF_ALLOC | SHF_EXECINSTR),
  1389  			Off:       0x34,
  1390  			Addralign: 0x01,
  1391  		})
  1392  		// .data
  1393  		binary.Write(&buf, binary.LittleEndian, Section32{
  1394  			Name:      0x21,
  1395  			Type:      uint32(SHT_PROGBITS),
  1396  			Flags:     uint32(SHF_WRITE | SHF_ALLOC),
  1397  			Off:       0x34,
  1398  			Addralign: 0x01,
  1399  		})
  1400  		// .bss
  1401  		binary.Write(&buf, binary.LittleEndian, Section32{
  1402  			Name:      0x27,
  1403  			Type:      uint32(SHT_NOBITS),
  1404  			Flags:     uint32(SHF_WRITE | SHF_ALLOC),
  1405  			Off:       0x34,
  1406  			Addralign: 0x01,
  1407  		})
  1408  		// s_1 ~ s_65537
  1409  		for i := 0; i < 65288; i++ {
  1410  			s := Section32{
  1411  				Name:      uint32(0x2C + i*13),
  1412  				Type:      uint32(SHT_PROGBITS),
  1413  				Flags:     uint32(SHF_WRITE | SHF_ALLOC),
  1414  				Off:       uint32(0x34 + i*4),
  1415  				Size:      0x04,
  1416  				Addralign: 0x04,
  1417  			}
  1418  			binary.Write(&buf, binary.LittleEndian, s)
  1419  		}
  1420  		// .comment
  1421  		binary.Write(&buf, binary.LittleEndian, Section32{
  1422  			Name:      0x0CF394,
  1423  			Type:      uint32(SHT_PROGBITS),
  1424  			Flags:     uint32(SHF_MERGE | SHF_STRINGS),
  1425  			Off:       0x03FC54,
  1426  			Size:      0x27,
  1427  			Addralign: 0x01,
  1428  			Entsize:   0x01,
  1429  		})
  1430  		// .note.GNU-stack
  1431  		binary.Write(&buf, binary.LittleEndian, Section32{
  1432  			Name:      0x0CF39D,
  1433  			Type:      uint32(SHT_PROGBITS),
  1434  			Off:       0x03FC7B,
  1435  			Addralign: 0x01,
  1436  		})
  1437  		// .symtab
  1438  		binary.Write(&buf, binary.LittleEndian, Section32{
  1439  			Name:      0x01,
  1440  			Type:      uint32(SHT_SYMTAB),
  1441  			Off:       0x03FC7C,
  1442  			Size:      0x0FF0A0,
  1443  			Link:      0xFF10,
  1444  			Info:      0x02,
  1445  			Addralign: 0x04,
  1446  			Entsize:   0x10,
  1447  		})
  1448  		// .symtab_shndx
  1449  		binary.Write(&buf, binary.LittleEndian, Section32{
  1450  			Name:      0x0CF3AD,
  1451  			Type:      uint32(SHT_SYMTAB_SHNDX),
  1452  			Off:       0x13ED1C,
  1453  			Size:      0x03FC28,
  1454  			Link:      0xFF0E,
  1455  			Addralign: 0x04,
  1456  			Entsize:   0x04,
  1457  		})
  1458  		// .strtab
  1459  		binary.Write(&buf, binary.LittleEndian, Section32{
  1460  			Name:      0x09,
  1461  			Type:      uint32(SHT_STRTAB),
  1462  			Off:       0x17E944,
  1463  			Size:      0x08F74D,
  1464  			Addralign: 0x01,
  1465  		})
  1466  		// .shstrtab
  1467  		binary.Write(&buf, binary.LittleEndian, Section32{
  1468  			Name:      0x11,
  1469  			Type:      uint32(SHT_STRTAB),
  1470  			Off:       0x20E091,
  1471  			Size:      0x0CF3BB,
  1472  			Addralign: 0x01,
  1473  		})
  1474  	}
  1475  
  1476  	data := buf.Bytes()
  1477  
  1478  	f, err := NewFile(bytes.NewReader(data))
  1479  	if err != nil {
  1480  		t.Errorf("cannot create file from data: %v", err)
  1481  	}
  1482  	defer f.Close()
  1483  
  1484  	wantFileHeader := FileHeader{
  1485  		Class:     ELFCLASS32,
  1486  		Data:      ELFDATA2LSB,
  1487  		Version:   EV_CURRENT,
  1488  		OSABI:     ELFOSABI_NONE,
  1489  		ByteOrder: binary.LittleEndian,
  1490  		Type:      ET_REL,
  1491  		Machine:   EM_386,
  1492  	}
  1493  	if f.FileHeader != wantFileHeader {
  1494  		t.Errorf("\nhave %#v\nwant %#v\n", f.FileHeader, wantFileHeader)
  1495  	}
  1496  
  1497  	wantSectionNum := 65298
  1498  	if len(f.Sections) != wantSectionNum {
  1499  		t.Errorf("len(Sections) = %d, want %d", len(f.Sections), wantSectionNum)
  1500  	}
  1501  
  1502  	wantSectionHeader := SectionHeader{
  1503  		Name:      "section_0007",
  1504  		Type:      SHT_PROGBITS,
  1505  		Flags:     SHF_WRITE + SHF_ALLOC,
  1506  		Offset:    0x4c,
  1507  		Size:      0x4,
  1508  		Addralign: 0x4,
  1509  		FileSize:  0x4,
  1510  	}
  1511  	if f.Sections[10].SectionHeader != wantSectionHeader {
  1512  		t.Errorf("\nhave %#v\nwant %#v\n", f.Sections[10].SectionHeader, wantSectionHeader)
  1513  	}
  1514  }
  1515  
  1516  func TestIssue10996(t *testing.T) {
  1517  	data := []byte("\u007fELF\x02\x01\x010000000000000" +
  1518  		"\x010000000000000000000" +
  1519  		"\x00\x00\x00\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00" +
  1520  		"0000")
  1521  	_, err := NewFile(bytes.NewReader(data))
  1522  	if err == nil {
  1523  		t.Fatalf("opening invalid ELF file unexpectedly succeeded")
  1524  	}
  1525  }
  1526  
  1527  func TestDynValue(t *testing.T) {
  1528  	const testdata = "testdata/gcc-amd64-linux-exec"
  1529  	f, err := Open(testdata)
  1530  	if err != nil {
  1531  		t.Fatalf("could not read %s: %v", testdata, err)
  1532  	}
  1533  	defer f.Close()
  1534  
  1535  	vals, err := f.DynValue(DT_VERNEEDNUM)
  1536  	if err != nil {
  1537  		t.Fatalf("DynValue(DT_VERNEEDNUM): got unexpected error %v", err)
  1538  	}
  1539  
  1540  	if len(vals) != 1 || vals[0] != 1 {
  1541  		t.Errorf("DynValue(DT_VERNEEDNUM): got %v, want [1]", vals)
  1542  	}
  1543  }
  1544  
  1545  func TestIssue59208(t *testing.T) {
  1546  	// corrupted dwarf data should raise invalid dwarf data instead of invalid zlib
  1547  	const orig = "testdata/compressed-64.obj"
  1548  	f, err := Open(orig)
  1549  	if err != nil {
  1550  		t.Fatal(err)
  1551  	}
  1552  	sec := f.Section(".debug_info")
  1553  
  1554  	data, err := os.ReadFile(orig)
  1555  	if err != nil {
  1556  		t.Fatal(err)
  1557  	}
  1558  
  1559  	dn := make([]byte, len(data))
  1560  	zoffset := sec.Offset + uint64(sec.compressionOffset)
  1561  	copy(dn, data[:zoffset])
  1562  
  1563  	ozd, err := sec.Data()
  1564  	if err != nil {
  1565  		t.Fatal(err)
  1566  	}
  1567  	buf := bytes.NewBuffer(nil)
  1568  	wr := zlib.NewWriter(buf)
  1569  	// corrupt origin data same as COMPRESS_ZLIB
  1570  	copy(ozd, []byte{1, 0, 0, 0})
  1571  	wr.Write(ozd)
  1572  	wr.Close()
  1573  
  1574  	copy(dn[zoffset:], buf.Bytes())
  1575  	copy(dn[sec.Offset+sec.FileSize:], data[sec.Offset+sec.FileSize:])
  1576  
  1577  	nf, err := NewFile(bytes.NewReader(dn))
  1578  	if err != nil {
  1579  		t.Error(err)
  1580  	}
  1581  
  1582  	const want = "decoding dwarf section info"
  1583  	_, err = nf.DWARF()
  1584  	if err == nil || !strings.Contains(err.Error(), want) {
  1585  		t.Errorf("DWARF = %v; want %q", err, want)
  1586  	}
  1587  }
  1588  
  1589  func BenchmarkSymbols64(b *testing.B) {
  1590  	const testdata = "testdata/gcc-amd64-linux-exec"
  1591  	f, err := Open(testdata)
  1592  	if err != nil {
  1593  		b.Fatalf("could not read %s: %v", testdata, err)
  1594  	}
  1595  	defer f.Close()
  1596  	b.ResetTimer()
  1597  	for i := 0; i < b.N; i++ {
  1598  		symbols, err := f.Symbols()
  1599  		if err != nil {
  1600  			b.Fatalf("Symbols(): got unexpected error %v", err)
  1601  		}
  1602  		if len(symbols) != 73 {
  1603  			b.Errorf("\nhave %d symbols\nwant %d symbols\n", len(symbols), 73)
  1604  		}
  1605  	}
  1606  }
  1607  
  1608  func BenchmarkSymbols32(b *testing.B) {
  1609  	const testdata = "testdata/gcc-386-freebsd-exec"
  1610  	f, err := Open(testdata)
  1611  	if err != nil {
  1612  		b.Fatalf("could not read %s: %v", testdata, err)
  1613  	}
  1614  	defer f.Close()
  1615  	b.ResetTimer()
  1616  	for i := 0; i < b.N; i++ {
  1617  		symbols, err := f.Symbols()
  1618  		if err != nil {
  1619  			b.Fatalf("Symbols(): got unexpected error %v", err)
  1620  		}
  1621  		if len(symbols) != 74 {
  1622  			b.Errorf("\nhave %d symbols\nwant %d symbols\n", len(symbols), 74)
  1623  		}
  1624  	}
  1625  }
  1626  
  1627  func TestOpenEmptyFile(t *testing.T) {
  1628  	name := filepath.Join(t.TempDir(), "empty")
  1629  	if err := os.WriteFile(name, nil, 0o644); err != nil {
  1630  		t.Fatal(err)
  1631  	}
  1632  
  1633  	_, err := Open(name)
  1634  	if err == nil {
  1635  		t.Fatal("Open on empty file: got nil error, want non-nil")
  1636  	}
  1637  
  1638  	var formatErr *FormatError
  1639  	if !errors.As(err, &formatErr) {
  1640  		t.Errorf("Open on empty file: got %T (%v), want *FormatError", err, err)
  1641  	}
  1642  }
  1643  
  1644  func TestNewFileShortReader(t *testing.T) {
  1645  	tests := []struct {
  1646  		name string
  1647  		data []byte
  1648  	}{
  1649  		{"empty", []byte{}},
  1650  		{"one byte", []byte{0x7f}},
  1651  		{"four bytes", []byte{0x7f, 'E', 'L', 'F'}},
  1652  		{"fifteen bytes", make([]byte, 15)},
  1653  	}
  1654  
  1655  	for _, tt := range tests {
  1656  		t.Run(tt.name, func(t *testing.T) {
  1657  			_, err := NewFile(bytes.NewReader(tt.data))
  1658  			if err == nil {
  1659  				t.Fatal("NewFile with short data: got nil error, want non-nil")
  1660  			}
  1661  
  1662  			var formatErr *FormatError
  1663  			if !errors.As(err, &formatErr) {
  1664  				t.Errorf("NewFile with short data: got %T (%v), want *FormatError", err, err)
  1665  			}
  1666  		})
  1667  	}
  1668  }
  1669  

View as plain text