github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/misc/cgo/test/buildid_linux.go (about)

     1  // Copyright 2014 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 cgotest
     6  
     7  // Test that we have no more than one build ID.  In the past we used
     8  // to generate a separate build ID for each package using cgo, and the
     9  // linker concatenated them all.  We don't want that--we only want
    10  // one.
    11  
    12  import (
    13  	"bytes"
    14  	"debug/elf"
    15  	"os"
    16  	"testing"
    17  )
    18  
    19  func testBuildID(t *testing.T) {
    20  	f, err := elf.Open("/proc/self/exe")
    21  	if err != nil {
    22  		if os.IsNotExist(err) {
    23  			t.Skip("no /proc/self/exe")
    24  		}
    25  		t.Fatal("opening /proc/self/exe: ", err)
    26  	}
    27  	defer f.Close()
    28  
    29  	c := 0
    30  	for i, s := range f.Sections {
    31  		if s.Type != elf.SHT_NOTE {
    32  			continue
    33  		}
    34  
    35  		d, err := s.Data()
    36  		if err != nil {
    37  			t.Logf("reading data of note section %d: %v", i, err)
    38  			continue
    39  		}
    40  
    41  		for len(d) > 0 {
    42  
    43  			// ELF standards differ as to the sizes in
    44  			// note sections.  Both the GNU linker and
    45  			// gold always generate 32-bit sizes, so that
    46  			// is what we assume here.
    47  
    48  			if len(d) < 12 {
    49  				t.Logf("note section %d too short (%d < 12)", i, len(d))
    50  				continue
    51  			}
    52  
    53  			namesz := f.ByteOrder.Uint32(d)
    54  			descsz := f.ByteOrder.Uint32(d[4:])
    55  			typ := f.ByteOrder.Uint32(d[8:])
    56  
    57  			an := (namesz + 3) &^ 3
    58  			ad := (descsz + 3) &^ 3
    59  
    60  			if int(12+an+ad) > len(d) {
    61  				t.Logf("note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))", i, len(d), namesz, descsz)
    62  				continue
    63  			}
    64  
    65  			// 3 == NT_GNU_BUILD_ID
    66  			if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) {
    67  				c++
    68  			}
    69  
    70  			d = d[12+an+ad:]
    71  		}
    72  	}
    73  
    74  	if c > 1 {
    75  		t.Errorf("found %d build ID notes", c)
    76  	}
    77  }