| // names-1 is a change detector for Go symbol names. We don't want |
| // the name mangling to change silently. |
| package main |
| |
| import ( |
| "bytes" |
| "debug/elf" |
| "debug/macho" |
| "debug/pe" |
| "fmt" |
| "os" |
| "runtime" |
| "strings" |
| ) |
| |
| type Type int |
| type Alias = int |
| |
| //go:noinline |
| func Function1(out *bytes.Buffer) int { |
| var f2 func(int) int |
| f1 := func(i int) int { |
| if i == 0 { |
| return 0 |
| } |
| type NestedType struct { a int } |
| t := NestedType{f2(i-1)} |
| fmt.Fprint(out, t) |
| return t.a |
| } |
| f2 = func(i int) int { |
| if i == 0 { |
| return 0 |
| } |
| type NestedType struct { a int } |
| t := NestedType{f1(i-1)} |
| fmt.Fprint(out, t) |
| return t.a |
| } |
| return f1(10) + f2(10) |
| } |
| |
| //go:noinline |
| func Function2(out *bytes.Buffer) { |
| { |
| type T struct { b int } |
| fmt.Fprint(out, T{1}) |
| } |
| { |
| type T struct { b int } |
| fmt.Fprint(out, T{2}) |
| } |
| } |
| |
| func (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) { |
| } |
| |
| //go:noinline |
| func Function3(out *bytes.Buffer) { |
| fmt.Fprintf(out, "%T", Type(0)) |
| } |
| |
| func main() { |
| if runtime.GOOS == "aix" { |
| // Not supported on AIX until there is an externally |
| // visible version of internal/xcoff. |
| return |
| } |
| |
| var b bytes.Buffer |
| Function1(&b) |
| Function2(&b) |
| Function3(&b) |
| _ = len(b.String()) |
| |
| for _, n := range []string{"/proc/self/exe", os.Args[0]} { |
| if f, err := os.Open(n); err == nil { |
| checkFile(f) |
| return |
| } |
| } |
| fmt.Println("checksyms: could not find executable") |
| fmt.Println("UNSUPPORTED: checksyms") |
| } |
| |
| func checkFile(f *os.File) { |
| var syms []string |
| if ef, err := elf.NewFile(f); err == nil { |
| esyms, err := ef.Symbols() |
| if err != nil { |
| panic(err) |
| } |
| for _, esym := range esyms { |
| syms = append(syms, esym.Name) |
| } |
| } else if mf, err := macho.NewFile(f); err == nil { |
| for _, msym := range mf.Symtab.Syms { |
| syms = append(syms, msym.Name) |
| } |
| } else if pf, err := pe.NewFile(f); err == nil { |
| for _, psym := range pf.Symbols { |
| syms = append(syms, psym.Name) |
| } |
| } else { |
| fmt.Println("checksyms: could not parse executable") |
| fmt.Println("UNSUPPORTED: checksyms") |
| return |
| } |
| checkSyms(syms) |
| } |
| |
| var want = []string{ |
| "main.Function1", |
| "main.Function1..f", |
| "main.Function1..func1", |
| "main.Function1..func1.main.NestedType..d", |
| "main.Function1..func2", |
| "main.Function1..func2.main.NestedType..d", |
| "main.Function2", |
| "main.Function2..f", |
| "main.Function2.main.T..d", |
| "main.Function2.main.T..i1..d", |
| "main.Function3", |
| "main.Function3..f", |
| "main.Type..d", |
| "main.Type.M", |
| "main.main", |
| "main.want", |
| "type...1.1main.Type", // Why is this here? |
| "type...1main.Function1..func1.NestedType", |
| "type...1main.Function1..func2.NestedType", |
| "type...1main.Function2.T", |
| "type...1main.Function2.T..i1", |
| "type...1main.Type", |
| "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", |
| "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", |
| "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", |
| "type..struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5", |
| } |
| |
| func checkSyms(syms []string) { |
| m := make(map[string]bool) |
| for _, sym := range syms { |
| if strings.Contains(sym, ".") { |
| m[sym] = true |
| } |
| } |
| |
| ok := true |
| for _, w := range want { |
| if m[w] { |
| delete(m, w) |
| } else { |
| fmt.Printf("checksyms: missing expected symbol %q\n", w) |
| ok = false |
| } |
| } |
| |
| for sym := range m { |
| if !strings.Contains(sym, "main") { |
| continue |
| } |
| |
| // Skip some symbols we may see but know are unimportant. |
| if sym == "go-main.c" { |
| continue |
| } |
| if strings.HasPrefix(sym, "runtime.") { |
| continue |
| } |
| |
| // We can see a lot of spurious .eq and .hash |
| // functions for types defined in other packages. |
| // This is a bug but skip them for now. |
| if strings.Contains(sym, "..eq") || strings.Contains(sym, "..hash") { |
| continue |
| } |
| |
| // Skip closure types by skipping incomparable structs. |
| // This may be a bug, not sure. |
| if strings.Contains(sym, ".4x.5") { |
| continue |
| } |
| |
| // These functions may be inlined. |
| if sym == "main.checkFile" || sym == "main.checkSyms" { |
| continue |
| } |
| |
| fmt.Printf("checksyms: found unexpected symbol %q\n", sym) |
| ok = false |
| } |
| |
| if !ok { |
| fmt.Println("FAIL: checksyms") |
| } |
| } |