1
2
3
4
5
6
7 package pkgpath
8
9 import (
10 "bytes"
11 "errors"
12 "fmt"
13 exec "internal/execabs"
14 "io/ioutil"
15 "os"
16 "strings"
17 )
18
19
20
21
22
23
24
25
26
27 func ToSymbolFunc(cmd, tmpdir string) (func(string) string, error) {
28
29
30
31
32
33
34 const filepat = "*_gccgo_manglechck.go"
35 f, err := ioutil.TempFile(tmpdir, filepat)
36 if err != nil {
37 return nil, err
38 }
39 gofilename := f.Name()
40 f.Close()
41 defer os.Remove(gofilename)
42
43 if err := ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0644); err != nil {
44 return nil, err
45 }
46
47 command := exec.Command(cmd, "-S", "-o", "-", gofilename)
48 buf, err := command.Output()
49 if err != nil {
50 return nil, err
51 }
52
53
54
55
56 if bytes.Contains(buf, []byte("go_0l_u00e4ufer.Run")) {
57 return toSymbolV3, nil
58 } else if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) {
59 return toSymbolV2, nil
60 } else if bytes.Contains(buf, []byte("go.l__ufer.Run")) {
61 return toSymbolV1, nil
62 } else {
63 return nil, errors.New(cmd + ": unrecognized mangling scheme")
64 }
65 }
66
67
68 const mangleCheckCode = `
69 package läufer
70 func Run(x int) int {
71 return 1
72 }
73 `
74
75
76 func toSymbolV1(ppath string) string {
77 clean := func(r rune) rune {
78 switch {
79 case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
80 '0' <= r && r <= '9':
81 return r
82 }
83 return '_'
84 }
85 return strings.Map(clean, ppath)
86 }
87
88
89 func toSymbolV2(ppath string) string {
90
91
92 bsl := make([]byte, 0, len(ppath))
93 changed := false
94 for _, c := range ppath {
95 if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' {
96 bsl = append(bsl, byte(c))
97 continue
98 }
99 var enc string
100 switch {
101 case c == '.':
102 enc = ".x2e"
103 case c < 0x80:
104 enc = fmt.Sprintf("..z%02x", c)
105 case c < 0x10000:
106 enc = fmt.Sprintf("..u%04x", c)
107 default:
108 enc = fmt.Sprintf("..U%08x", c)
109 }
110 bsl = append(bsl, enc...)
111 changed = true
112 }
113 if !changed {
114 return ppath
115 }
116 return string(bsl)
117 }
118
119
120
121 var v3UnderscoreCodes = map[byte]byte{
122 '_': '_',
123 '.': '0',
124 '/': '1',
125 '*': '2',
126 ',': '3',
127 '{': '4',
128 '}': '5',
129 '[': '6',
130 ']': '7',
131 '(': '8',
132 ')': '9',
133 '"': 'a',
134 ' ': 'b',
135 ';': 'c',
136 }
137
138
139 func toSymbolV3(ppath string) string {
140
141
142 bsl := make([]byte, 0, len(ppath))
143 changed := false
144 for _, c := range ppath {
145 if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') {
146 bsl = append(bsl, byte(c))
147 continue
148 }
149
150 if c < 0x80 {
151 if u, ok := v3UnderscoreCodes[byte(c)]; ok {
152 bsl = append(bsl, '_', u)
153 changed = true
154 continue
155 }
156 }
157
158 var enc string
159 switch {
160 case c < 0x80:
161 enc = fmt.Sprintf("_x%02x", c)
162 case c < 0x10000:
163 enc = fmt.Sprintf("_u%04x", c)
164 default:
165 enc = fmt.Sprintf("_U%08x", c)
166 }
167 bsl = append(bsl, enc...)
168 changed = true
169 }
170 if !changed {
171 return ppath
172 }
173 return string(bsl)
174 }
175
View as plain text