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

View as plain text