// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package cgotest // Test that we have no more than one build ID. In the past we used // to generate a separate build ID for each package using cgo, and the // linker concatenated them all. We don't want that--we only want // one. import ( "bytes" "debug/elf" "os" "testing" ) func testBuildID(t *testing.T) { f, err := elf.Open("/proc/self/exe") if err != nil { if os.IsNotExist(err) { t.Skip("no /proc/self/exe") } t.Fatal("opening /proc/self/exe: ", err) } defer f.Close() c := 0 sections: for i, s := range f.Sections { if s.Type != elf.SHT_NOTE { continue } d, err := s.Data() if err != nil { t.Logf("reading data of note section %d: %v", i, err) continue } for len(d) > 0 { // ELF standards differ as to the sizes in // note sections. Both the GNU linker and // gold always generate 32-bit sizes, so that // is what we assume here. if len(d) < 12 { t.Logf("note section %d too short (%d < 12)", i, len(d)) continue sections } namesz := f.ByteOrder.Uint32(d) descsz := f.ByteOrder.Uint32(d[4:]) typ := f.ByteOrder.Uint32(d[8:]) an := (namesz + 3) &^ 3 ad := (descsz + 3) &^ 3 if int(12+an+ad) > len(d) { t.Logf("note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))", i, len(d), namesz, descsz) continue sections } // 3 == NT_GNU_BUILD_ID if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) { c++ } d = d[12+an+ad:] } } if c > 1 { t.Errorf("found %d build ID notes", c) } }