aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/newlink/dead_test.go
blob: eb34d0580d1889e486ee29c220d01b4f7c1b5c2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// 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 main

import (
	"cmd/internal/goobj"
	"reflect"
	"strings"
	"testing"
)

// Each test case is an object file, generated from a corresponding .s file.
// The symbols in the object file with a dead_ prefix are the ones that
// should be removed from the program.
var deadTests = []string{
	"testdata/dead.6",
}

func TestDead(t *testing.T) {
	for _, obj := range deadTests {
		p := Prog{GOOS: "darwin", GOARCH: "amd64", StartSym: "start"}
		p.omitRuntime = true
		p.Error = func(s string) { t.Error(s) }
		p.init()
		p.scan(obj)
		if p.NumError > 0 {
			continue // already reported
		}
		origSyms := copyMap(p.Syms)
		origMissing := copyMap(p.Missing)
		origSymOrder := copySlice(p.SymOrder)
		origPkgSyms := copySlice(p.Packages["main"].Syms)
		p.dead()
		checkDeadMap(t, obj, "p.Syms", origSyms, p.Syms)
		checkDeadMap(t, obj, "p.Missing", origMissing, p.Missing)
		checkDeadSlice(t, obj, "p.SymOrder", origSymOrder, p.SymOrder)
		checkDeadSlice(t, obj, `p.Packages["main"].Syms`, origPkgSyms, p.Packages["main"].Syms)
	}
}

func copyMap(m interface{}) interface{} {
	v := reflect.ValueOf(m)
	out := reflect.MakeMap(v.Type())
	for _, key := range v.MapKeys() {
		out.SetMapIndex(key, v.MapIndex(key))
	}
	return out.Interface()
}

func checkDeadMap(t *testing.T, obj, name string, old, new interface{}) {
	vold := reflect.ValueOf(old)
	vnew := reflect.ValueOf(new)
	for _, vid := range vold.MapKeys() {
		id := vid.Interface().(goobj.SymID)
		if strings.HasPrefix(id.Name, "dead_") {
			if vnew.MapIndex(vid).IsValid() {
				t.Errorf("%s: %s contains unnecessary symbol %s", obj, name, id)
			}
		} else {
			if !vnew.MapIndex(vid).IsValid() {
				t.Errorf("%s: %s is missing symbol %s", obj, name, id)
			}
		}
	}
	for _, vid := range vnew.MapKeys() {
		id := vid.Interface().(goobj.SymID)
		if !vold.MapIndex(vid).IsValid() {
			t.Errorf("%s: %s contains unexpected symbol %s", obj, name, id)
		}
	}
}

func copySlice(x []*Sym) (out []*Sym) {
	return append(out, x...)
}

func checkDeadSlice(t *testing.T, obj, name string, old, new []*Sym) {
	for i, s := range old {
		if strings.HasPrefix(s.Name, "dead_") {
			continue
		}
		if len(new) == 0 {
			t.Errorf("%s: %s is missing symbol %s\nhave%v\nwant%v", obj, name, s, new, old[i:])
			return
		}
		if new[0].SymID != s.SymID {
			t.Errorf("%s: %s is incorrect: have %s, want %s\nhave%v\nwant%v", obj, name, new[0].SymID, s.SymID, new, old[i:])
			return
		}
		new = new[1:]
	}
	if len(new) > 0 {
		t.Errorf("%s: %s has unexpected symbols: %v", obj, name, new)
	}
}