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

View as plain text