• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5package 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
12import (
13	"bytes"
14	"debug/elf"
15	"os"
16	"testing"
17)
18
19func 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
30sections:
31	for i, s := range f.Sections {
32		if s.Type != elf.SHT_NOTE {
33			continue
34		}
35
36		d, err := s.Data()
37		if err != nil {
38			t.Logf("reading data of note section %d: %v", i, err)
39			continue
40		}
41
42		for len(d) > 0 {
43
44			// ELF standards differ as to the sizes in
45			// note sections.  Both the GNU linker and
46			// gold always generate 32-bit sizes, so that
47			// is what we assume here.
48
49			if len(d) < 12 {
50				t.Logf("note section %d too short (%d < 12)", i, len(d))
51				continue sections
52			}
53
54			namesz := f.ByteOrder.Uint32(d)
55			descsz := f.ByteOrder.Uint32(d[4:])
56			typ := f.ByteOrder.Uint32(d[8:])
57
58			an := (namesz + 3) &^ 3
59			ad := (descsz + 3) &^ 3
60
61			if int(12+an+ad) > len(d) {
62				t.Logf("note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))", i, len(d), namesz, descsz)
63				continue sections
64			}
65
66			// 3 == NT_GNU_BUILD_ID
67			if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) {
68				c++
69			}
70
71			d = d[12+an+ad:]
72		}
73	}
74
75	if c > 1 {
76		t.Errorf("found %d build ID notes", c)
77	}
78}
79