1// names-1 is a change detector for Go symbol names. We don't want 2// the name mangling to change silently. 3package main 4 5import ( 6 "bytes" 7 "debug/elf" 8 "debug/macho" 9 "debug/pe" 10 "fmt" 11 "os" 12 "runtime" 13 "strings" 14) 15 16type Type int 17type Alias = int 18 19//go:noinline 20func Function1(out *bytes.Buffer) int { 21 var f2 func(int) int 22 f1 := func(i int) int { 23 if i == 0 { 24 return 0 25 } 26 type NestedType struct { a int } 27 t := NestedType{f2(i-1)} 28 fmt.Fprint(out, t) 29 return t.a 30 } 31 f2 = func(i int) int { 32 if i == 0 { 33 return 0 34 } 35 type NestedType struct { a int } 36 t := NestedType{f1(i-1)} 37 fmt.Fprint(out, t) 38 return t.a 39 } 40 return f1(10) + f2(10) 41} 42 43//go:noinline 44func Function2(out *bytes.Buffer) { 45 { 46 type T struct { b int } 47 fmt.Fprint(out, T{1}) 48 } 49 { 50 type T struct { b int } 51 fmt.Fprint(out, T{2}) 52 } 53} 54 55func (t Type) M(bool, int8, float32, complex64, string, func(), func(int16) (float64, complex128), *byte, struct { f int "tag #$%^&{}: 世界" }, []int32, [24]int64, map[uint8]uint16, chan uint32, <-chan uint64, chan <- uintptr, Type, Alias) { 56} 57 58//go:noinline 59func Function3(out *bytes.Buffer) { 60 fmt.Fprintf(out, "%T", Type(0)) 61} 62 63func main() { 64 if runtime.GOOS == "aix" { 65 // Not supported on AIX until there is an externally 66 // visible version of internal/xcoff. 67 return 68 } 69 70 var b bytes.Buffer 71 Function1(&b) 72 Function2(&b) 73 Function3(&b) 74 _ = len(b.String()) 75 76 for _, n := range []string{"/proc/self/exe", os.Args[0]} { 77 if f, err := os.Open(n); err == nil { 78 checkFile(f) 79 return 80 } 81 } 82 fmt.Println("checksyms: could not find executable") 83 fmt.Println("UNSUPPORTED: checksyms") 84} 85 86func checkFile(f *os.File) { 87 var syms []string 88 if ef, err := elf.NewFile(f); err == nil { 89 esyms, err := ef.Symbols() 90 if err != nil { 91 panic(err) 92 } 93 for _, esym := range esyms { 94 syms = append(syms, esym.Name) 95 } 96 } else if mf, err := macho.NewFile(f); err == nil { 97 for _, msym := range mf.Symtab.Syms { 98 syms = append(syms, msym.Name) 99 } 100 } else if pf, err := pe.NewFile(f); err == nil { 101 for _, psym := range pf.Symbols { 102 syms = append(syms, psym.Name) 103 } 104 } else { 105 fmt.Println("checksyms: could not parse executable") 106 fmt.Println("UNSUPPORTED: checksyms") 107 return 108 } 109 checkSyms(syms) 110} 111 112var want = []string{ 113 "main.Function1", 114 "main.Function1..f", 115 "main.Function1..func1", 116 "main.Function1..func1.main.NestedType..d", 117 "main.Function1..func2", 118 "main.Function1..func2.main.NestedType..d", 119 "main.Function2", 120 "main.Function2..f", 121 "main.Function2.main.T..d", 122 "main.Function2.main.T..i1..d", 123 "main.Function3", 124 "main.Function3..f", 125 "main.Type..d", 126 "main.Type.M", 127 "main.main", 128 "main.want", 129 "type...1.1main.Type", // Why is this here? 130 "type...1main.Function1..func1.NestedType", 131 "type...1main.Function1..func2.NestedType", 132 "type...1main.Function2.T", 133 "type...1main.Function2.T..i1", 134 "type...1main.Type", 135 "type..func.8.1main.Type.3bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9", 136 "type..func.8bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9", 137 "type..func.8main.Type.3bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9", 138 "type..struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5", 139} 140 141func checkSyms(syms []string) { 142 m := make(map[string]bool) 143 for _, sym := range syms { 144 if strings.Contains(sym, ".") { 145 m[sym] = true 146 } 147 } 148 149 ok := true 150 for _, w := range want { 151 if m[w] { 152 delete(m, w) 153 } else { 154 fmt.Printf("checksyms: missing expected symbol %q\n", w) 155 ok = false 156 } 157 } 158 159 for sym := range m { 160 if !strings.Contains(sym, "main") { 161 continue 162 } 163 164 // Skip some symbols we may see but know are unimportant. 165 if sym == "go-main.c" { 166 continue 167 } 168 if strings.HasPrefix(sym, "runtime.") { 169 continue 170 } 171 172 // We can see a lot of spurious .eq and .hash 173 // functions for types defined in other packages. 174 // This is a bug but skip them for now. 175 if strings.Contains(sym, "..eq") || strings.Contains(sym, "..hash") { 176 continue 177 } 178 179 // Skip closure types by skipping incomparable structs. 180 // This may be a bug, not sure. 181 if strings.Contains(sym, ".4x.5") { 182 continue 183 } 184 185 // These functions may be inlined. 186 if sym == "main.checkFile" || sym == "main.checkSyms" { 187 continue 188 } 189 190 fmt.Printf("checksyms: found unexpected symbol %q\n", sym) 191 ok = false 192 } 193 194 if !ok { 195 fmt.Println("FAIL: checksyms") 196 } 197} 198