Merge lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo into lp:ubuntu/utopic/gccgo-go
- Utopic (14.10)
- build-cgo
- Merge into utopic
Proposed by
Michael Hudson-Doyle
Status: | Work in progress |
---|---|
Proposed branch: | lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo |
Merge into: | lp:ubuntu/utopic/gccgo-go |
Diff against target: |
1972 lines (+1870/-1) 12 files modified
.pc/applied-patches (+1/-0) .pc/build-cgo.diff/src/cmd/cgo/gcc.go (+1633/-0) .pc/build-cgo.diff/src/cmd/go/tool.go (+156/-0) debian/changelog (+6/-0) debian/install (+1/-0) debian/lintian-overrides (+1/-0) debian/patches/build-cgo.diff (+49/-0) debian/patches/series (+1/-0) debian/rules (+2/-0) src/cmd/cgo/Makefile (+16/-0) src/cmd/cgo/gcc.go (+1/-1) src/cmd/go/tool.go (+3/-0) |
To merge this branch: | bzr merge lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Pending | ||
Review via email: mp+230739@code.launchpad.net |
Commit message
Description of the change
This branch builds and installs cgo. It also makes things so that "go tool cgo" works. It's probably all horrible but it's a start :)
To post a comment you must log in.
Unmerged revisions
- 15. By Michael Hudson-Doyle <mwhudson@narsil>
-
lintian overrides
- 14. By Michael Hudson-Doyle <mwhudson@narsil>
-
install cgo
- 13. By Michael Hudson-Doyle <mwhudson@narsil>
-
updates
- 12. By Michael Hudson-Doyle <mwhudson@narsil>
-
quilt updates
- 11. By Michael Hudson-Doyle <mwhudson@narsil>
-
update version
- 10. By Michael Hudson-Doyle <mwhudson@narsil>
-
Build cgo too
- 9. By Michael Hudson-Doyle <mwhudson@narsil>
-
Add broken Makefile for cgo
- 8. By Michael Hudson-Doyle <mwhudson@narsil>
-
set ToolDir to something more sensible
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.pc/applied-patches' | |||
2 | --- .pc/applied-patches 2014-03-26 10:50:18 +0000 | |||
3 | +++ .pc/applied-patches 2014-08-14 02:29:21 +0000 | |||
4 | @@ -5,3 +5,4 @@ | |||
5 | 5 | issue28050043_60001_70001.diff | 5 | issue28050043_60001_70001.diff |
6 | 6 | issue61970044_80001.diff | 6 | issue61970044_80001.diff |
7 | 7 | issue80300043_60001.diff | 7 | issue80300043_60001.diff |
8 | 8 | build-cgo.diff | ||
9 | 8 | 9 | ||
10 | === added directory '.pc/build-cgo.diff' | |||
11 | === added file '.pc/build-cgo.diff/.timestamp' | |||
12 | === added directory '.pc/build-cgo.diff/src' | |||
13 | === added directory '.pc/build-cgo.diff/src/cmd' | |||
14 | === added directory '.pc/build-cgo.diff/src/cmd/cgo' | |||
15 | === added file '.pc/build-cgo.diff/src/cmd/cgo/Makefile' | |||
16 | === added file '.pc/build-cgo.diff/src/cmd/cgo/gcc.go' | |||
17 | --- .pc/build-cgo.diff/src/cmd/cgo/gcc.go 1970-01-01 00:00:00 +0000 | |||
18 | +++ .pc/build-cgo.diff/src/cmd/cgo/gcc.go 2014-08-14 02:29:21 +0000 | |||
19 | @@ -0,0 +1,1633 @@ | |||
20 | 1 | // Copyright 2009 The Go Authors. All rights reserved. | ||
21 | 2 | // Use of this source code is governed by a BSD-style | ||
22 | 3 | // license that can be found in the LICENSE file. | ||
23 | 4 | |||
24 | 5 | // Annotate Ref in Prog with C types by parsing gcc debug output. | ||
25 | 6 | // Conversion of debug output to Go types. | ||
26 | 7 | |||
27 | 8 | package main | ||
28 | 9 | |||
29 | 10 | import ( | ||
30 | 11 | "bytes" | ||
31 | 12 | "debug/dwarf" | ||
32 | 13 | "debug/elf" | ||
33 | 14 | "debug/macho" | ||
34 | 15 | "debug/pe" | ||
35 | 16 | "encoding/binary" | ||
36 | 17 | "errors" | ||
37 | 18 | "flag" | ||
38 | 19 | "fmt" | ||
39 | 20 | "go/ast" | ||
40 | 21 | "go/parser" | ||
41 | 22 | "go/token" | ||
42 | 23 | "os" | ||
43 | 24 | "strconv" | ||
44 | 25 | "strings" | ||
45 | 26 | "unicode" | ||
46 | 27 | "unicode/utf8" | ||
47 | 28 | ) | ||
48 | 29 | |||
49 | 30 | var debugDefine = flag.Bool("debug-define", false, "print relevant #defines") | ||
50 | 31 | var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations") | ||
51 | 32 | |||
52 | 33 | var nameToC = map[string]string{ | ||
53 | 34 | "schar": "signed char", | ||
54 | 35 | "uchar": "unsigned char", | ||
55 | 36 | "ushort": "unsigned short", | ||
56 | 37 | "uint": "unsigned int", | ||
57 | 38 | "ulong": "unsigned long", | ||
58 | 39 | "longlong": "long long", | ||
59 | 40 | "ulonglong": "unsigned long long", | ||
60 | 41 | "complexfloat": "float complex", | ||
61 | 42 | "complexdouble": "double complex", | ||
62 | 43 | } | ||
63 | 44 | |||
64 | 45 | // cname returns the C name to use for C.s. | ||
65 | 46 | // The expansions are listed in nameToC and also | ||
66 | 47 | // struct_foo becomes "struct foo", and similarly for | ||
67 | 48 | // union and enum. | ||
68 | 49 | func cname(s string) string { | ||
69 | 50 | if t, ok := nameToC[s]; ok { | ||
70 | 51 | return t | ||
71 | 52 | } | ||
72 | 53 | |||
73 | 54 | if strings.HasPrefix(s, "struct_") { | ||
74 | 55 | return "struct " + s[len("struct_"):] | ||
75 | 56 | } | ||
76 | 57 | if strings.HasPrefix(s, "union_") { | ||
77 | 58 | return "union " + s[len("union_"):] | ||
78 | 59 | } | ||
79 | 60 | if strings.HasPrefix(s, "enum_") { | ||
80 | 61 | return "enum " + s[len("enum_"):] | ||
81 | 62 | } | ||
82 | 63 | if strings.HasPrefix(s, "sizeof_") { | ||
83 | 64 | return "sizeof(" + cname(s[len("sizeof_"):]) + ")" | ||
84 | 65 | } | ||
85 | 66 | return s | ||
86 | 67 | } | ||
87 | 68 | |||
88 | 69 | // DiscardCgoDirectives processes the import C preamble, and discards | ||
89 | 70 | // all #cgo CFLAGS and LDFLAGS directives, so they don't make their | ||
90 | 71 | // way into _cgo_export.h. | ||
91 | 72 | func (f *File) DiscardCgoDirectives() { | ||
92 | 73 | linesIn := strings.Split(f.Preamble, "\n") | ||
93 | 74 | linesOut := make([]string, 0, len(linesIn)) | ||
94 | 75 | for _, line := range linesIn { | ||
95 | 76 | l := strings.TrimSpace(line) | ||
96 | 77 | if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) { | ||
97 | 78 | linesOut = append(linesOut, line) | ||
98 | 79 | } else { | ||
99 | 80 | linesOut = append(linesOut, "") | ||
100 | 81 | } | ||
101 | 82 | } | ||
102 | 83 | f.Preamble = strings.Join(linesOut, "\n") | ||
103 | 84 | } | ||
104 | 85 | |||
105 | 86 | // addToFlag appends args to flag. All flags are later written out onto the | ||
106 | 87 | // _cgo_flags file for the build system to use. | ||
107 | 88 | func (p *Package) addToFlag(flag string, args []string) { | ||
108 | 89 | p.CgoFlags[flag] = append(p.CgoFlags[flag], args...) | ||
109 | 90 | if flag == "CFLAGS" { | ||
110 | 91 | // We'll also need these when preprocessing for dwarf information. | ||
111 | 92 | p.GccOptions = append(p.GccOptions, args...) | ||
112 | 93 | } | ||
113 | 94 | } | ||
114 | 95 | |||
115 | 96 | // splitQuoted splits the string s around each instance of one or more consecutive | ||
116 | 97 | // white space characters while taking into account quotes and escaping, and | ||
117 | 98 | // returns an array of substrings of s or an empty list if s contains only white space. | ||
118 | 99 | // Single quotes and double quotes are recognized to prevent splitting within the | ||
119 | 100 | // quoted region, and are removed from the resulting substrings. If a quote in s | ||
120 | 101 | // isn't closed err will be set and r will have the unclosed argument as the | ||
121 | 102 | // last element. The backslash is used for escaping. | ||
122 | 103 | // | ||
123 | 104 | // For example, the following string: | ||
124 | 105 | // | ||
125 | 106 | // `a b:"c d" 'e''f' "g\""` | ||
126 | 107 | // | ||
127 | 108 | // Would be parsed as: | ||
128 | 109 | // | ||
129 | 110 | // []string{"a", "b:c d", "ef", `g"`} | ||
130 | 111 | // | ||
131 | 112 | func splitQuoted(s string) (r []string, err error) { | ||
132 | 113 | var args []string | ||
133 | 114 | arg := make([]rune, len(s)) | ||
134 | 115 | escaped := false | ||
135 | 116 | quoted := false | ||
136 | 117 | quote := '\x00' | ||
137 | 118 | i := 0 | ||
138 | 119 | for _, r := range s { | ||
139 | 120 | switch { | ||
140 | 121 | case escaped: | ||
141 | 122 | escaped = false | ||
142 | 123 | case r == '\\': | ||
143 | 124 | escaped = true | ||
144 | 125 | continue | ||
145 | 126 | case quote != 0: | ||
146 | 127 | if r == quote { | ||
147 | 128 | quote = 0 | ||
148 | 129 | continue | ||
149 | 130 | } | ||
150 | 131 | case r == '"' || r == '\'': | ||
151 | 132 | quoted = true | ||
152 | 133 | quote = r | ||
153 | 134 | continue | ||
154 | 135 | case unicode.IsSpace(r): | ||
155 | 136 | if quoted || i > 0 { | ||
156 | 137 | quoted = false | ||
157 | 138 | args = append(args, string(arg[:i])) | ||
158 | 139 | i = 0 | ||
159 | 140 | } | ||
160 | 141 | continue | ||
161 | 142 | } | ||
162 | 143 | arg[i] = r | ||
163 | 144 | i++ | ||
164 | 145 | } | ||
165 | 146 | if quoted || i > 0 { | ||
166 | 147 | args = append(args, string(arg[:i])) | ||
167 | 148 | } | ||
168 | 149 | if quote != 0 { | ||
169 | 150 | err = errors.New("unclosed quote") | ||
170 | 151 | } else if escaped { | ||
171 | 152 | err = errors.New("unfinished escaping") | ||
172 | 153 | } | ||
173 | 154 | return args, err | ||
174 | 155 | } | ||
175 | 156 | |||
176 | 157 | var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`) | ||
177 | 158 | |||
178 | 159 | func safeName(s string) bool { | ||
179 | 160 | if s == "" { | ||
180 | 161 | return false | ||
181 | 162 | } | ||
182 | 163 | for i := 0; i < len(s); i++ { | ||
183 | 164 | if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { | ||
184 | 165 | return false | ||
185 | 166 | } | ||
186 | 167 | } | ||
187 | 168 | return true | ||
188 | 169 | } | ||
189 | 170 | |||
190 | 171 | // Translate rewrites f.AST, the original Go input, to remove | ||
191 | 172 | // references to the imported package C, replacing them with | ||
192 | 173 | // references to the equivalent Go types, functions, and variables. | ||
193 | 174 | func (p *Package) Translate(f *File) { | ||
194 | 175 | for _, cref := range f.Ref { | ||
195 | 176 | // Convert C.ulong to C.unsigned long, etc. | ||
196 | 177 | cref.Name.C = cname(cref.Name.Go) | ||
197 | 178 | } | ||
198 | 179 | p.loadDefines(f) | ||
199 | 180 | needType := p.guessKinds(f) | ||
200 | 181 | if len(needType) > 0 { | ||
201 | 182 | p.loadDWARF(f, needType) | ||
202 | 183 | } | ||
203 | 184 | p.rewriteRef(f) | ||
204 | 185 | } | ||
205 | 186 | |||
206 | 187 | // loadDefines coerces gcc into spitting out the #defines in use | ||
207 | 188 | // in the file f and saves relevant renamings in f.Name[name].Define. | ||
208 | 189 | func (p *Package) loadDefines(f *File) { | ||
209 | 190 | var b bytes.Buffer | ||
210 | 191 | b.WriteString(f.Preamble) | ||
211 | 192 | b.WriteString(builtinProlog) | ||
212 | 193 | stdout := p.gccDefines(b.Bytes()) | ||
213 | 194 | |||
214 | 195 | for _, line := range strings.Split(stdout, "\n") { | ||
215 | 196 | if len(line) < 9 || line[0:7] != "#define" { | ||
216 | 197 | continue | ||
217 | 198 | } | ||
218 | 199 | |||
219 | 200 | line = strings.TrimSpace(line[8:]) | ||
220 | 201 | |||
221 | 202 | var key, val string | ||
222 | 203 | spaceIndex := strings.Index(line, " ") | ||
223 | 204 | tabIndex := strings.Index(line, "\t") | ||
224 | 205 | |||
225 | 206 | if spaceIndex == -1 && tabIndex == -1 { | ||
226 | 207 | continue | ||
227 | 208 | } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) { | ||
228 | 209 | key = line[0:spaceIndex] | ||
229 | 210 | val = strings.TrimSpace(line[spaceIndex:]) | ||
230 | 211 | } else { | ||
231 | 212 | key = line[0:tabIndex] | ||
232 | 213 | val = strings.TrimSpace(line[tabIndex:]) | ||
233 | 214 | } | ||
234 | 215 | |||
235 | 216 | if n := f.Name[key]; n != nil { | ||
236 | 217 | if *debugDefine { | ||
237 | 218 | fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val) | ||
238 | 219 | } | ||
239 | 220 | n.Define = val | ||
240 | 221 | } | ||
241 | 222 | } | ||
242 | 223 | } | ||
243 | 224 | |||
244 | 225 | // guessKinds tricks gcc into revealing the kind of each | ||
245 | 226 | // name xxx for the references C.xxx in the Go input. | ||
246 | 227 | // The kind is either a constant, type, or variable. | ||
247 | 228 | func (p *Package) guessKinds(f *File) []*Name { | ||
248 | 229 | // Determine kinds for names we already know about, | ||
249 | 230 | // like #defines or 'struct foo', before bothering with gcc. | ||
250 | 231 | var names, needType []*Name | ||
251 | 232 | for _, n := range f.Name { | ||
252 | 233 | // If we've already found this name as a #define | ||
253 | 234 | // and we can translate it as a constant value, do so. | ||
254 | 235 | if n.Define != "" { | ||
255 | 236 | isConst := false | ||
256 | 237 | if _, err := strconv.Atoi(n.Define); err == nil { | ||
257 | 238 | isConst = true | ||
258 | 239 | } else if n.Define[0] == '"' || n.Define[0] == '\'' { | ||
259 | 240 | if _, err := parser.ParseExpr(n.Define); err == nil { | ||
260 | 241 | isConst = true | ||
261 | 242 | } | ||
262 | 243 | } | ||
263 | 244 | if isConst { | ||
264 | 245 | n.Kind = "const" | ||
265 | 246 | // Turn decimal into hex, just for consistency | ||
266 | 247 | // with enum-derived constants. Otherwise | ||
267 | 248 | // in the cgo -godefs output half the constants | ||
268 | 249 | // are in hex and half are in whatever the #define used. | ||
269 | 250 | i, err := strconv.ParseInt(n.Define, 0, 64) | ||
270 | 251 | if err == nil { | ||
271 | 252 | n.Const = fmt.Sprintf("%#x", i) | ||
272 | 253 | } else { | ||
273 | 254 | n.Const = n.Define | ||
274 | 255 | } | ||
275 | 256 | continue | ||
276 | 257 | } | ||
277 | 258 | |||
278 | 259 | if isName(n.Define) { | ||
279 | 260 | n.C = n.Define | ||
280 | 261 | } | ||
281 | 262 | } | ||
282 | 263 | |||
283 | 264 | needType = append(needType, n) | ||
284 | 265 | |||
285 | 266 | // If this is a struct, union, or enum type name, no need to guess the kind. | ||
286 | 267 | if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") { | ||
287 | 268 | n.Kind = "type" | ||
288 | 269 | continue | ||
289 | 270 | } | ||
290 | 271 | |||
291 | 272 | // Otherwise, we'll need to find out from gcc. | ||
292 | 273 | names = append(names, n) | ||
293 | 274 | } | ||
294 | 275 | |||
295 | 276 | // Bypass gcc if there's nothing left to find out. | ||
296 | 277 | if len(names) == 0 { | ||
297 | 278 | return needType | ||
298 | 279 | } | ||
299 | 280 | |||
300 | 281 | // Coerce gcc into telling us whether each name is a type, a value, or undeclared. | ||
301 | 282 | // For names, find out whether they are integer constants. | ||
302 | 283 | // We used to look at specific warning or error messages here, but that tied the | ||
303 | 284 | // behavior too closely to specific versions of the compilers. | ||
304 | 285 | // Instead, arrange that we can infer what we need from only the presence or absence | ||
305 | 286 | // of an error on a specific line. | ||
306 | 287 | // | ||
307 | 288 | // For each name, we generate these lines, where xxx is the index in toSniff plus one. | ||
308 | 289 | // | ||
309 | 290 | // #line xxx "not-declared" | ||
310 | 291 | // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; } | ||
311 | 292 | // #line xxx "not-type" | ||
312 | 293 | // void __cgo_f_xxx_2(void) { name *__cgo_undefined__; } | ||
313 | 294 | // #line xxx "not-const" | ||
314 | 295 | // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; } | ||
315 | 296 | // | ||
316 | 297 | // If we see an error at not-declared:xxx, the corresponding name is not declared. | ||
317 | 298 | // If we see an error at not-type:xxx, the corresponding name is a type. | ||
318 | 299 | // If we see an error at not-const:xxx, the corresponding name is not an integer constant. | ||
319 | 300 | // If we see no errors, we assume the name is an expression but not a constant | ||
320 | 301 | // (so a variable or a function). | ||
321 | 302 | // | ||
322 | 303 | // The specific input forms are chosen so that they are valid C syntax regardless of | ||
323 | 304 | // whether name denotes a type or an expression. | ||
324 | 305 | |||
325 | 306 | var b bytes.Buffer | ||
326 | 307 | b.WriteString(f.Preamble) | ||
327 | 308 | b.WriteString(builtinProlog) | ||
328 | 309 | |||
329 | 310 | for i, n := range names { | ||
330 | 311 | fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+ | ||
331 | 312 | "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+ | ||
332 | 313 | "#line %d \"not-type\"\n"+ | ||
333 | 314 | "void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+ | ||
334 | 315 | "#line %d \"not-const\"\n"+ | ||
335 | 316 | "void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n", | ||
336 | 317 | i+1, i+1, n.C, | ||
337 | 318 | i+1, i+1, n.C, | ||
338 | 319 | i+1, i+1, n.C) | ||
339 | 320 | } | ||
340 | 321 | fmt.Fprintf(&b, "#line 1 \"completed\"\n"+ | ||
341 | 322 | "int __cgo__1 = __cgo__2;\n") | ||
342 | 323 | |||
343 | 324 | stderr := p.gccErrors(b.Bytes()) | ||
344 | 325 | if stderr == "" { | ||
345 | 326 | fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) | ||
346 | 327 | } | ||
347 | 328 | |||
348 | 329 | completed := false | ||
349 | 330 | sniff := make([]int, len(names)) | ||
350 | 331 | const ( | ||
351 | 332 | notType = 1 << iota | ||
352 | 333 | notConst | ||
353 | 334 | ) | ||
354 | 335 | for _, line := range strings.Split(stderr, "\n") { | ||
355 | 336 | if !strings.Contains(line, ": error:") { | ||
356 | 337 | // we only care about errors. | ||
357 | 338 | // we tried to turn off warnings on the command line, but one never knows. | ||
358 | 339 | continue | ||
359 | 340 | } | ||
360 | 341 | |||
361 | 342 | c1 := strings.Index(line, ":") | ||
362 | 343 | if c1 < 0 { | ||
363 | 344 | continue | ||
364 | 345 | } | ||
365 | 346 | c2 := strings.Index(line[c1+1:], ":") | ||
366 | 347 | if c2 < 0 { | ||
367 | 348 | continue | ||
368 | 349 | } | ||
369 | 350 | c2 += c1 + 1 | ||
370 | 351 | |||
371 | 352 | filename := line[:c1] | ||
372 | 353 | i, _ := strconv.Atoi(line[c1+1 : c2]) | ||
373 | 354 | i-- | ||
374 | 355 | if i < 0 || i >= len(names) { | ||
375 | 356 | continue | ||
376 | 357 | } | ||
377 | 358 | |||
378 | 359 | switch filename { | ||
379 | 360 | case "completed": | ||
380 | 361 | // Strictly speaking, there is no guarantee that seeing the error at completed:1 | ||
381 | 362 | // (at the end of the file) means we've seen all the errors from earlier in the file, | ||
382 | 363 | // but usually it does. Certainly if we don't see the completed:1 error, we did | ||
383 | 364 | // not get all the errors we expected. | ||
384 | 365 | completed = true | ||
385 | 366 | |||
386 | 367 | case "not-declared": | ||
387 | 368 | error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:])) | ||
388 | 369 | case "not-type": | ||
389 | 370 | sniff[i] |= notType | ||
390 | 371 | case "not-const": | ||
391 | 372 | sniff[i] |= notConst | ||
392 | 373 | } | ||
393 | 374 | } | ||
394 | 375 | |||
395 | 376 | if !completed { | ||
396 | 377 | fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) | ||
397 | 378 | } | ||
398 | 379 | |||
399 | 380 | for i, n := range names { | ||
400 | 381 | switch sniff[i] { | ||
401 | 382 | case 0: | ||
402 | 383 | error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go)) | ||
403 | 384 | case notType: | ||
404 | 385 | n.Kind = "const" | ||
405 | 386 | case notConst: | ||
406 | 387 | n.Kind = "type" | ||
407 | 388 | case notConst | notType: | ||
408 | 389 | n.Kind = "not-type" | ||
409 | 390 | } | ||
410 | 391 | } | ||
411 | 392 | if nerrors > 0 { | ||
412 | 393 | fatalf("unresolved names") | ||
413 | 394 | } | ||
414 | 395 | |||
415 | 396 | needType = append(needType, names...) | ||
416 | 397 | return needType | ||
417 | 398 | } | ||
418 | 399 | |||
419 | 400 | // loadDWARF parses the DWARF debug information generated | ||
420 | 401 | // by gcc to learn the details of the constants, variables, and types | ||
421 | 402 | // being referred to as C.xxx. | ||
422 | 403 | func (p *Package) loadDWARF(f *File, names []*Name) { | ||
423 | 404 | // Extract the types from the DWARF section of an object | ||
424 | 405 | // from a well-formed C program. Gcc only generates DWARF info | ||
425 | 406 | // for symbols in the object file, so it is not enough to print the | ||
426 | 407 | // preamble and hope the symbols we care about will be there. | ||
427 | 408 | // Instead, emit | ||
428 | 409 | // __typeof__(names[i]) *__cgo__i; | ||
429 | 410 | // for each entry in names and then dereference the type we | ||
430 | 411 | // learn for __cgo__i. | ||
431 | 412 | var b bytes.Buffer | ||
432 | 413 | b.WriteString(f.Preamble) | ||
433 | 414 | b.WriteString(builtinProlog) | ||
434 | 415 | for i, n := range names { | ||
435 | 416 | fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i) | ||
436 | 417 | if n.Kind == "const" { | ||
437 | 418 | fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C) | ||
438 | 419 | } | ||
439 | 420 | } | ||
440 | 421 | |||
441 | 422 | // Apple's LLVM-based gcc does not include the enumeration | ||
442 | 423 | // names and values in its DWARF debug output. In case we're | ||
443 | 424 | // using such a gcc, create a data block initialized with the values. | ||
444 | 425 | // We can read them out of the object file. | ||
445 | 426 | fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n") | ||
446 | 427 | for _, n := range names { | ||
447 | 428 | if n.Kind == "const" { | ||
448 | 429 | fmt.Fprintf(&b, "\t%s,\n", n.C) | ||
449 | 430 | } else { | ||
450 | 431 | fmt.Fprintf(&b, "\t0,\n") | ||
451 | 432 | } | ||
452 | 433 | } | ||
453 | 434 | // for the last entry, we can not use 0, otherwise | ||
454 | 435 | // in case all __cgodebug_data is zero initialized, | ||
455 | 436 | // LLVM-based gcc will place the it in the __DATA.__common | ||
456 | 437 | // zero-filled section (our debug/macho doesn't support | ||
457 | 438 | // this) | ||
458 | 439 | fmt.Fprintf(&b, "\t1\n") | ||
459 | 440 | fmt.Fprintf(&b, "};\n") | ||
460 | 441 | |||
461 | 442 | d, bo, debugData := p.gccDebug(b.Bytes()) | ||
462 | 443 | enumVal := make([]int64, len(debugData)/8) | ||
463 | 444 | for i := range enumVal { | ||
464 | 445 | enumVal[i] = int64(bo.Uint64(debugData[i*8:])) | ||
465 | 446 | } | ||
466 | 447 | |||
467 | 448 | // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i. | ||
468 | 449 | types := make([]dwarf.Type, len(names)) | ||
469 | 450 | enums := make([]dwarf.Offset, len(names)) | ||
470 | 451 | nameToIndex := make(map[*Name]int) | ||
471 | 452 | for i, n := range names { | ||
472 | 453 | nameToIndex[n] = i | ||
473 | 454 | } | ||
474 | 455 | nameToRef := make(map[*Name]*Ref) | ||
475 | 456 | for _, ref := range f.Ref { | ||
476 | 457 | nameToRef[ref.Name] = ref | ||
477 | 458 | } | ||
478 | 459 | r := d.Reader() | ||
479 | 460 | for { | ||
480 | 461 | e, err := r.Next() | ||
481 | 462 | if err != nil { | ||
482 | 463 | fatalf("reading DWARF entry: %s", err) | ||
483 | 464 | } | ||
484 | 465 | if e == nil { | ||
485 | 466 | break | ||
486 | 467 | } | ||
487 | 468 | switch e.Tag { | ||
488 | 469 | case dwarf.TagEnumerationType: | ||
489 | 470 | offset := e.Offset | ||
490 | 471 | for { | ||
491 | 472 | e, err := r.Next() | ||
492 | 473 | if err != nil { | ||
493 | 474 | fatalf("reading DWARF entry: %s", err) | ||
494 | 475 | } | ||
495 | 476 | if e.Tag == 0 { | ||
496 | 477 | break | ||
497 | 478 | } | ||
498 | 479 | if e.Tag == dwarf.TagEnumerator { | ||
499 | 480 | entryName := e.Val(dwarf.AttrName).(string) | ||
500 | 481 | if strings.HasPrefix(entryName, "__cgo_enum__") { | ||
501 | 482 | n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):]) | ||
502 | 483 | if 0 <= n && n < len(names) { | ||
503 | 484 | enums[n] = offset | ||
504 | 485 | } | ||
505 | 486 | } | ||
506 | 487 | } | ||
507 | 488 | } | ||
508 | 489 | case dwarf.TagVariable: | ||
509 | 490 | name, _ := e.Val(dwarf.AttrName).(string) | ||
510 | 491 | typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset) | ||
511 | 492 | if name == "" || typOff == 0 { | ||
512 | 493 | fatalf("malformed DWARF TagVariable entry") | ||
513 | 494 | } | ||
514 | 495 | if !strings.HasPrefix(name, "__cgo__") { | ||
515 | 496 | break | ||
516 | 497 | } | ||
517 | 498 | typ, err := d.Type(typOff) | ||
518 | 499 | if err != nil { | ||
519 | 500 | fatalf("loading DWARF type: %s", err) | ||
520 | 501 | } | ||
521 | 502 | t, ok := typ.(*dwarf.PtrType) | ||
522 | 503 | if !ok || t == nil { | ||
523 | 504 | fatalf("internal error: %s has non-pointer type", name) | ||
524 | 505 | } | ||
525 | 506 | i, err := strconv.Atoi(name[7:]) | ||
526 | 507 | if err != nil { | ||
527 | 508 | fatalf("malformed __cgo__ name: %s", name) | ||
528 | 509 | } | ||
529 | 510 | if enums[i] != 0 { | ||
530 | 511 | t, err := d.Type(enums[i]) | ||
531 | 512 | if err != nil { | ||
532 | 513 | fatalf("loading DWARF type: %s", err) | ||
533 | 514 | } | ||
534 | 515 | types[i] = t | ||
535 | 516 | } else { | ||
536 | 517 | types[i] = t.Type | ||
537 | 518 | } | ||
538 | 519 | } | ||
539 | 520 | if e.Tag != dwarf.TagCompileUnit { | ||
540 | 521 | r.SkipChildren() | ||
541 | 522 | } | ||
542 | 523 | } | ||
543 | 524 | |||
544 | 525 | // Record types and typedef information. | ||
545 | 526 | var conv typeConv | ||
546 | 527 | conv.Init(p.PtrSize, p.IntSize) | ||
547 | 528 | for i, n := range names { | ||
548 | 529 | if types[i] == nil { | ||
549 | 530 | continue | ||
550 | 531 | } | ||
551 | 532 | pos := token.NoPos | ||
552 | 533 | if ref, ok := nameToRef[n]; ok { | ||
553 | 534 | pos = ref.Pos() | ||
554 | 535 | } | ||
555 | 536 | f, fok := types[i].(*dwarf.FuncType) | ||
556 | 537 | if n.Kind != "type" && fok { | ||
557 | 538 | n.Kind = "func" | ||
558 | 539 | n.FuncType = conv.FuncType(f, pos) | ||
559 | 540 | } else { | ||
560 | 541 | n.Type = conv.Type(types[i], pos) | ||
561 | 542 | if enums[i] != 0 && n.Type.EnumValues != nil { | ||
562 | 543 | k := fmt.Sprintf("__cgo_enum__%d", i) | ||
563 | 544 | n.Kind = "const" | ||
564 | 545 | n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k]) | ||
565 | 546 | // Remove injected enum to ensure the value will deep-compare | ||
566 | 547 | // equally in future loads of the same constant. | ||
567 | 548 | delete(n.Type.EnumValues, k) | ||
568 | 549 | } | ||
569 | 550 | // Prefer debug data over DWARF debug output, if we have it. | ||
570 | 551 | if n.Kind == "const" && i < len(enumVal) { | ||
571 | 552 | n.Const = fmt.Sprintf("%#x", enumVal[i]) | ||
572 | 553 | } | ||
573 | 554 | } | ||
574 | 555 | } | ||
575 | 556 | |||
576 | 557 | } | ||
577 | 558 | |||
578 | 559 | // mangleName does name mangling to translate names | ||
579 | 560 | // from the original Go source files to the names | ||
580 | 561 | // used in the final Go files generated by cgo. | ||
581 | 562 | func (p *Package) mangleName(n *Name) { | ||
582 | 563 | // When using gccgo variables have to be | ||
583 | 564 | // exported so that they become global symbols | ||
584 | 565 | // that the C code can refer to. | ||
585 | 566 | prefix := "_C" | ||
586 | 567 | if *gccgo && n.IsVar() { | ||
587 | 568 | prefix = "C" | ||
588 | 569 | } | ||
589 | 570 | n.Mangle = prefix + n.Kind + "_" + n.Go | ||
590 | 571 | } | ||
591 | 572 | |||
592 | 573 | // rewriteRef rewrites all the C.xxx references in f.AST to refer to the | ||
593 | 574 | // Go equivalents, now that we have figured out the meaning of all | ||
594 | 575 | // the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names | ||
595 | 576 | // with full definitions instead of mangled names. | ||
596 | 577 | func (p *Package) rewriteRef(f *File) { | ||
597 | 578 | // Keep a list of all the functions, to remove the ones | ||
598 | 579 | // only used as expressions and avoid generating bridge | ||
599 | 580 | // code for them. | ||
600 | 581 | functions := make(map[string]bool) | ||
601 | 582 | |||
602 | 583 | // Assign mangled names. | ||
603 | 584 | for _, n := range f.Name { | ||
604 | 585 | if n.Kind == "not-type" { | ||
605 | 586 | n.Kind = "var" | ||
606 | 587 | } | ||
607 | 588 | if n.Mangle == "" { | ||
608 | 589 | p.mangleName(n) | ||
609 | 590 | } | ||
610 | 591 | if n.Kind == "func" { | ||
611 | 592 | functions[n.Go] = false | ||
612 | 593 | } | ||
613 | 594 | } | ||
614 | 595 | |||
615 | 596 | // Now that we have all the name types filled in, | ||
616 | 597 | // scan through the Refs to identify the ones that | ||
617 | 598 | // are trying to do a ,err call. Also check that | ||
618 | 599 | // functions are only used in calls. | ||
619 | 600 | for _, r := range f.Ref { | ||
620 | 601 | if r.Name.Kind == "const" && r.Name.Const == "" { | ||
621 | 602 | error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go)) | ||
622 | 603 | } | ||
623 | 604 | var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default | ||
624 | 605 | switch r.Context { | ||
625 | 606 | case "call", "call2": | ||
626 | 607 | if r.Name.Kind != "func" { | ||
627 | 608 | if r.Name.Kind == "type" { | ||
628 | 609 | r.Context = "type" | ||
629 | 610 | expr = r.Name.Type.Go | ||
630 | 611 | break | ||
631 | 612 | } | ||
632 | 613 | error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go)) | ||
633 | 614 | break | ||
634 | 615 | } | ||
635 | 616 | functions[r.Name.Go] = true | ||
636 | 617 | if r.Context == "call2" { | ||
637 | 618 | if r.Name.Go == "_CMalloc" { | ||
638 | 619 | error_(r.Pos(), "no two-result form for C.malloc") | ||
639 | 620 | break | ||
640 | 621 | } | ||
641 | 622 | // Invent new Name for the two-result function. | ||
642 | 623 | n := f.Name["2"+r.Name.Go] | ||
643 | 624 | if n == nil { | ||
644 | 625 | n = new(Name) | ||
645 | 626 | *n = *r.Name | ||
646 | 627 | n.AddError = true | ||
647 | 628 | n.Mangle = "_C2func_" + n.Go | ||
648 | 629 | f.Name["2"+r.Name.Go] = n | ||
649 | 630 | } | ||
650 | 631 | expr = ast.NewIdent(n.Mangle) | ||
651 | 632 | r.Name = n | ||
652 | 633 | break | ||
653 | 634 | } | ||
654 | 635 | case "expr": | ||
655 | 636 | if r.Name.Kind == "func" { | ||
656 | 637 | // Function is being used in an expression, to e.g. pass around a C function pointer. | ||
657 | 638 | // Create a new Name for this Ref which causes the variable to be declared in Go land. | ||
658 | 639 | fpName := "fp_" + r.Name.Go | ||
659 | 640 | name := f.Name[fpName] | ||
660 | 641 | if name == nil { | ||
661 | 642 | name = &Name{ | ||
662 | 643 | Go: fpName, | ||
663 | 644 | C: r.Name.C, | ||
664 | 645 | Kind: "fpvar", | ||
665 | 646 | Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")}, | ||
666 | 647 | } | ||
667 | 648 | p.mangleName(name) | ||
668 | 649 | f.Name[fpName] = name | ||
669 | 650 | } | ||
670 | 651 | r.Name = name | ||
671 | 652 | expr = ast.NewIdent(name.Mangle) | ||
672 | 653 | } else if r.Name.Kind == "type" { | ||
673 | 654 | // Okay - might be new(T) | ||
674 | 655 | expr = r.Name.Type.Go | ||
675 | 656 | } else if r.Name.Kind == "var" { | ||
676 | 657 | expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} | ||
677 | 658 | } | ||
678 | 659 | |||
679 | 660 | case "type": | ||
680 | 661 | if r.Name.Kind != "type" { | ||
681 | 662 | error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go)) | ||
682 | 663 | } else if r.Name.Type == nil { | ||
683 | 664 | // Use of C.enum_x, C.struct_x or C.union_x without C definition. | ||
684 | 665 | // GCC won't raise an error when using pointers to such unknown types. | ||
685 | 666 | error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) | ||
686 | 667 | } else { | ||
687 | 668 | expr = r.Name.Type.Go | ||
688 | 669 | } | ||
689 | 670 | default: | ||
690 | 671 | if r.Name.Kind == "func" { | ||
691 | 672 | error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go)) | ||
692 | 673 | } | ||
693 | 674 | } | ||
694 | 675 | if *godefs || *cdefs { | ||
695 | 676 | // Substitute definition for mangled type name. | ||
696 | 677 | if id, ok := expr.(*ast.Ident); ok { | ||
697 | 678 | if t := typedef[id.Name]; t != nil { | ||
698 | 679 | expr = t.Go | ||
699 | 680 | } | ||
700 | 681 | if id.Name == r.Name.Mangle && r.Name.Const != "" { | ||
701 | 682 | expr = ast.NewIdent(r.Name.Const) | ||
702 | 683 | } | ||
703 | 684 | } | ||
704 | 685 | } | ||
705 | 686 | |||
706 | 687 | // Copy position information from old expr into new expr, | ||
707 | 688 | // in case expression being replaced is first on line. | ||
708 | 689 | // See golang.org/issue/6563. | ||
709 | 690 | pos := (*r.Expr).Pos() | ||
710 | 691 | switch x := expr.(type) { | ||
711 | 692 | case *ast.Ident: | ||
712 | 693 | expr = &ast.Ident{NamePos: pos, Name: x.Name} | ||
713 | 694 | } | ||
714 | 695 | |||
715 | 696 | *r.Expr = expr | ||
716 | 697 | } | ||
717 | 698 | |||
718 | 699 | // Remove functions only used as expressions, so their respective | ||
719 | 700 | // bridge functions are not generated. | ||
720 | 701 | for name, used := range functions { | ||
721 | 702 | if !used { | ||
722 | 703 | delete(f.Name, name) | ||
723 | 704 | } | ||
724 | 705 | } | ||
725 | 706 | } | ||
726 | 707 | |||
727 | 708 | // gccBaseCmd returns the start of the compiler command line. | ||
728 | 709 | // It uses $CC if set, or else $GCC, or else the compiler recorded | ||
729 | 710 | // during the initial build as defaultCC. | ||
730 | 711 | // defaultCC is defined in zdefaultcc.go, written by cmd/dist. | ||
731 | 712 | func (p *Package) gccBaseCmd() []string { | ||
732 | 713 | // Use $CC if set, since that's what the build uses. | ||
733 | 714 | if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 { | ||
734 | 715 | return ret | ||
735 | 716 | } | ||
736 | 717 | // Try $GCC if set, since that's what we used to use. | ||
737 | 718 | if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { | ||
738 | 719 | return ret | ||
739 | 720 | } | ||
740 | 721 | return strings.Fields(defaultCC) | ||
741 | 722 | } | ||
742 | 723 | |||
743 | 724 | // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". | ||
744 | 725 | func (p *Package) gccMachine() []string { | ||
745 | 726 | switch goarch { | ||
746 | 727 | case "amd64": | ||
747 | 728 | return []string{"-m64"} | ||
748 | 729 | case "386": | ||
749 | 730 | return []string{"-m32"} | ||
750 | 731 | case "arm": | ||
751 | 732 | return []string{"-marm"} // not thumb | ||
752 | 733 | } | ||
753 | 734 | return nil | ||
754 | 735 | } | ||
755 | 736 | |||
756 | 737 | func gccTmp() string { | ||
757 | 738 | return *objDir + "_cgo_.o" | ||
758 | 739 | } | ||
759 | 740 | |||
760 | 741 | // gccCmd returns the gcc command line to use for compiling | ||
761 | 742 | // the input. | ||
762 | 743 | func (p *Package) gccCmd() []string { | ||
763 | 744 | c := append(p.gccBaseCmd(), | ||
764 | 745 | "-w", // no warnings | ||
765 | 746 | "-Wno-error", // warnings are not errors | ||
766 | 747 | "-o"+gccTmp(), // write object to tmp | ||
767 | 748 | "-gdwarf-2", // generate DWARF v2 debugging symbols | ||
768 | 749 | "-c", // do not link | ||
769 | 750 | "-xc", // input language is C | ||
770 | 751 | ) | ||
771 | 752 | if strings.Contains(c[0], "clang") { | ||
772 | 753 | c = append(c, | ||
773 | 754 | "-ferror-limit=0", | ||
774 | 755 | // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) | ||
775 | 756 | // doesn't have -Wno-unneeded-internal-declaration, so we need yet another | ||
776 | 757 | // flag to disable the warning. Yes, really good diagnostics, clang. | ||
777 | 758 | "-Wno-unknown-warning-option", | ||
778 | 759 | "-Wno-unneeded-internal-declaration", | ||
779 | 760 | "-Wno-unused-function", | ||
780 | 761 | "-Qunused-arguments", | ||
781 | 762 | // Clang embeds prototypes for some builtin functions, | ||
782 | 763 | // like malloc and calloc, but all size_t parameters are | ||
783 | 764 | // incorrectly typed unsigned long. We work around that | ||
784 | 765 | // by disabling the builtin functions (this is safe as | ||
785 | 766 | // it won't affect the actual compilation of the C code). | ||
786 | 767 | // See: http://golang.org/issue/6506. | ||
787 | 768 | "-fno-builtin", | ||
788 | 769 | ) | ||
789 | 770 | } | ||
790 | 771 | |||
791 | 772 | c = append(c, p.GccOptions...) | ||
792 | 773 | c = append(c, p.gccMachine()...) | ||
793 | 774 | c = append(c, "-") //read input from standard input | ||
794 | 775 | return c | ||
795 | 776 | } | ||
796 | 777 | |||
797 | 778 | // gccDebug runs gcc -gdwarf-2 over the C program stdin and | ||
798 | 779 | // returns the corresponding DWARF data and, if present, debug data block. | ||
799 | 780 | func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) { | ||
800 | 781 | runGcc(stdin, p.gccCmd()) | ||
801 | 782 | |||
802 | 783 | isDebugData := func(s string) bool { | ||
803 | 784 | // Some systems use leading _ to denote non-assembly symbols. | ||
804 | 785 | return s == "__cgodebug_data" || s == "___cgodebug_data" | ||
805 | 786 | } | ||
806 | 787 | |||
807 | 788 | if f, err := macho.Open(gccTmp()); err == nil { | ||
808 | 789 | defer f.Close() | ||
809 | 790 | d, err := f.DWARF() | ||
810 | 791 | if err != nil { | ||
811 | 792 | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | ||
812 | 793 | } | ||
813 | 794 | var data []byte | ||
814 | 795 | if f.Symtab != nil { | ||
815 | 796 | for i := range f.Symtab.Syms { | ||
816 | 797 | s := &f.Symtab.Syms[i] | ||
817 | 798 | if isDebugData(s.Name) { | ||
818 | 799 | // Found it. Now find data section. | ||
819 | 800 | if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { | ||
820 | 801 | sect := f.Sections[i] | ||
821 | 802 | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | ||
822 | 803 | if sdat, err := sect.Data(); err == nil { | ||
823 | 804 | data = sdat[s.Value-sect.Addr:] | ||
824 | 805 | } | ||
825 | 806 | } | ||
826 | 807 | } | ||
827 | 808 | } | ||
828 | 809 | } | ||
829 | 810 | } | ||
830 | 811 | return d, f.ByteOrder, data | ||
831 | 812 | } | ||
832 | 813 | |||
833 | 814 | if f, err := elf.Open(gccTmp()); err == nil { | ||
834 | 815 | defer f.Close() | ||
835 | 816 | d, err := f.DWARF() | ||
836 | 817 | if err != nil { | ||
837 | 818 | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | ||
838 | 819 | } | ||
839 | 820 | var data []byte | ||
840 | 821 | symtab, err := f.Symbols() | ||
841 | 822 | if err == nil { | ||
842 | 823 | for i := range symtab { | ||
843 | 824 | s := &symtab[i] | ||
844 | 825 | if isDebugData(s.Name) { | ||
845 | 826 | // Found it. Now find data section. | ||
846 | 827 | if i := int(s.Section); 0 <= i && i < len(f.Sections) { | ||
847 | 828 | sect := f.Sections[i] | ||
848 | 829 | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | ||
849 | 830 | if sdat, err := sect.Data(); err == nil { | ||
850 | 831 | data = sdat[s.Value-sect.Addr:] | ||
851 | 832 | } | ||
852 | 833 | } | ||
853 | 834 | } | ||
854 | 835 | } | ||
855 | 836 | } | ||
856 | 837 | } | ||
857 | 838 | return d, f.ByteOrder, data | ||
858 | 839 | } | ||
859 | 840 | |||
860 | 841 | if f, err := pe.Open(gccTmp()); err == nil { | ||
861 | 842 | defer f.Close() | ||
862 | 843 | d, err := f.DWARF() | ||
863 | 844 | if err != nil { | ||
864 | 845 | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | ||
865 | 846 | } | ||
866 | 847 | var data []byte | ||
867 | 848 | for _, s := range f.Symbols { | ||
868 | 849 | if isDebugData(s.Name) { | ||
869 | 850 | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | ||
870 | 851 | sect := f.Sections[i] | ||
871 | 852 | if s.Value < sect.Size { | ||
872 | 853 | if sdat, err := sect.Data(); err == nil { | ||
873 | 854 | data = sdat[s.Value:] | ||
874 | 855 | } | ||
875 | 856 | } | ||
876 | 857 | } | ||
877 | 858 | } | ||
878 | 859 | } | ||
879 | 860 | return d, binary.LittleEndian, data | ||
880 | 861 | } | ||
881 | 862 | |||
882 | 863 | fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp()) | ||
883 | 864 | panic("not reached") | ||
884 | 865 | } | ||
885 | 866 | |||
886 | 867 | // gccDefines runs gcc -E -dM -xc - over the C program stdin | ||
887 | 868 | // and returns the corresponding standard output, which is the | ||
888 | 869 | // #defines that gcc encountered while processing the input | ||
889 | 870 | // and its included files. | ||
890 | 871 | func (p *Package) gccDefines(stdin []byte) string { | ||
891 | 872 | base := append(p.gccBaseCmd(), "-E", "-dM", "-xc") | ||
892 | 873 | base = append(base, p.gccMachine()...) | ||
893 | 874 | stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) | ||
894 | 875 | return stdout | ||
895 | 876 | } | ||
896 | 877 | |||
897 | 878 | // gccErrors runs gcc over the C program stdin and returns | ||
898 | 879 | // the errors that gcc prints. That is, this function expects | ||
899 | 880 | // gcc to fail. | ||
900 | 881 | func (p *Package) gccErrors(stdin []byte) string { | ||
901 | 882 | // TODO(rsc): require failure | ||
902 | 883 | args := p.gccCmd() | ||
903 | 884 | |||
904 | 885 | if *debugGcc { | ||
905 | 886 | fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) | ||
906 | 887 | os.Stderr.Write(stdin) | ||
907 | 888 | fmt.Fprint(os.Stderr, "EOF\n") | ||
908 | 889 | } | ||
909 | 890 | stdout, stderr, _ := run(stdin, args) | ||
910 | 891 | if *debugGcc { | ||
911 | 892 | os.Stderr.Write(stdout) | ||
912 | 893 | os.Stderr.Write(stderr) | ||
913 | 894 | } | ||
914 | 895 | return string(stderr) | ||
915 | 896 | } | ||
916 | 897 | |||
917 | 898 | // runGcc runs the gcc command line args with stdin on standard input. | ||
918 | 899 | // If the command exits with a non-zero exit status, runGcc prints | ||
919 | 900 | // details about what was run and exits. | ||
920 | 901 | // Otherwise runGcc returns the data written to standard output and standard error. | ||
921 | 902 | // Note that for some of the uses we expect useful data back | ||
922 | 903 | // on standard error, but for those uses gcc must still exit 0. | ||
923 | 904 | func runGcc(stdin []byte, args []string) (string, string) { | ||
924 | 905 | if *debugGcc { | ||
925 | 906 | fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) | ||
926 | 907 | os.Stderr.Write(stdin) | ||
927 | 908 | fmt.Fprint(os.Stderr, "EOF\n") | ||
928 | 909 | } | ||
929 | 910 | stdout, stderr, ok := run(stdin, args) | ||
930 | 911 | if *debugGcc { | ||
931 | 912 | os.Stderr.Write(stdout) | ||
932 | 913 | os.Stderr.Write(stderr) | ||
933 | 914 | } | ||
934 | 915 | if !ok { | ||
935 | 916 | os.Stderr.Write(stderr) | ||
936 | 917 | os.Exit(2) | ||
937 | 918 | } | ||
938 | 919 | return string(stdout), string(stderr) | ||
939 | 920 | } | ||
940 | 921 | |||
941 | 922 | // A typeConv is a translator from dwarf types to Go types | ||
942 | 923 | // with equivalent memory layout. | ||
943 | 924 | type typeConv struct { | ||
944 | 925 | // Cache of already-translated or in-progress types. | ||
945 | 926 | m map[dwarf.Type]*Type | ||
946 | 927 | typedef map[string]ast.Expr | ||
947 | 928 | |||
948 | 929 | // Predeclared types. | ||
949 | 930 | bool ast.Expr | ||
950 | 931 | byte ast.Expr // denotes padding | ||
951 | 932 | int8, int16, int32, int64 ast.Expr | ||
952 | 933 | uint8, uint16, uint32, uint64, uintptr ast.Expr | ||
953 | 934 | float32, float64 ast.Expr | ||
954 | 935 | complex64, complex128 ast.Expr | ||
955 | 936 | void ast.Expr | ||
956 | 937 | unsafePointer ast.Expr | ||
957 | 938 | string ast.Expr | ||
958 | 939 | goVoid ast.Expr // _Ctype_void, denotes C's void | ||
959 | 940 | |||
960 | 941 | ptrSize int64 | ||
961 | 942 | intSize int64 | ||
962 | 943 | } | ||
963 | 944 | |||
964 | 945 | var tagGen int | ||
965 | 946 | var typedef = make(map[string]*Type) | ||
966 | 947 | var goIdent = make(map[string]*ast.Ident) | ||
967 | 948 | |||
968 | 949 | func (c *typeConv) Init(ptrSize, intSize int64) { | ||
969 | 950 | c.ptrSize = ptrSize | ||
970 | 951 | c.intSize = intSize | ||
971 | 952 | c.m = make(map[dwarf.Type]*Type) | ||
972 | 953 | c.bool = c.Ident("bool") | ||
973 | 954 | c.byte = c.Ident("byte") | ||
974 | 955 | c.int8 = c.Ident("int8") | ||
975 | 956 | c.int16 = c.Ident("int16") | ||
976 | 957 | c.int32 = c.Ident("int32") | ||
977 | 958 | c.int64 = c.Ident("int64") | ||
978 | 959 | c.uint8 = c.Ident("uint8") | ||
979 | 960 | c.uint16 = c.Ident("uint16") | ||
980 | 961 | c.uint32 = c.Ident("uint32") | ||
981 | 962 | c.uint64 = c.Ident("uint64") | ||
982 | 963 | c.uintptr = c.Ident("uintptr") | ||
983 | 964 | c.float32 = c.Ident("float32") | ||
984 | 965 | c.float64 = c.Ident("float64") | ||
985 | 966 | c.complex64 = c.Ident("complex64") | ||
986 | 967 | c.complex128 = c.Ident("complex128") | ||
987 | 968 | c.unsafePointer = c.Ident("unsafe.Pointer") | ||
988 | 969 | c.void = c.Ident("void") | ||
989 | 970 | c.string = c.Ident("string") | ||
990 | 971 | c.goVoid = c.Ident("_Ctype_void") | ||
991 | 972 | } | ||
992 | 973 | |||
993 | 974 | // base strips away qualifiers and typedefs to get the underlying type | ||
994 | 975 | func base(dt dwarf.Type) dwarf.Type { | ||
995 | 976 | for { | ||
996 | 977 | if d, ok := dt.(*dwarf.QualType); ok { | ||
997 | 978 | dt = d.Type | ||
998 | 979 | continue | ||
999 | 980 | } | ||
1000 | 981 | if d, ok := dt.(*dwarf.TypedefType); ok { | ||
1001 | 982 | dt = d.Type | ||
1002 | 983 | continue | ||
1003 | 984 | } | ||
1004 | 985 | break | ||
1005 | 986 | } | ||
1006 | 987 | return dt | ||
1007 | 988 | } | ||
1008 | 989 | |||
1009 | 990 | // Map from dwarf text names to aliases we use in package "C". | ||
1010 | 991 | var dwarfToName = map[string]string{ | ||
1011 | 992 | "long int": "long", | ||
1012 | 993 | "long unsigned int": "ulong", | ||
1013 | 994 | "unsigned int": "uint", | ||
1014 | 995 | "short unsigned int": "ushort", | ||
1015 | 996 | "short int": "short", | ||
1016 | 997 | "long long int": "longlong", | ||
1017 | 998 | "long long unsigned int": "ulonglong", | ||
1018 | 999 | "signed char": "schar", | ||
1019 | 1000 | "float complex": "complexfloat", | ||
1020 | 1001 | "double complex": "complexdouble", | ||
1021 | 1002 | } | ||
1022 | 1003 | |||
1023 | 1004 | const signedDelta = 64 | ||
1024 | 1005 | |||
1025 | 1006 | // String returns the current type representation. Format arguments | ||
1026 | 1007 | // are assembled within this method so that any changes in mutable | ||
1027 | 1008 | // values are taken into account. | ||
1028 | 1009 | func (tr *TypeRepr) String() string { | ||
1029 | 1010 | if len(tr.Repr) == 0 { | ||
1030 | 1011 | return "" | ||
1031 | 1012 | } | ||
1032 | 1013 | if len(tr.FormatArgs) == 0 { | ||
1033 | 1014 | return tr.Repr | ||
1034 | 1015 | } | ||
1035 | 1016 | return fmt.Sprintf(tr.Repr, tr.FormatArgs...) | ||
1036 | 1017 | } | ||
1037 | 1018 | |||
1038 | 1019 | // Empty returns true if the result of String would be "". | ||
1039 | 1020 | func (tr *TypeRepr) Empty() bool { | ||
1040 | 1021 | return len(tr.Repr) == 0 | ||
1041 | 1022 | } | ||
1042 | 1023 | |||
1043 | 1024 | // Set modifies the type representation. | ||
1044 | 1025 | // If fargs are provided, repr is used as a format for fmt.Sprintf. | ||
1045 | 1026 | // Otherwise, repr is used unprocessed as the type representation. | ||
1046 | 1027 | func (tr *TypeRepr) Set(repr string, fargs ...interface{}) { | ||
1047 | 1028 | tr.Repr = repr | ||
1048 | 1029 | tr.FormatArgs = fargs | ||
1049 | 1030 | } | ||
1050 | 1031 | |||
1051 | 1032 | // Type returns a *Type with the same memory layout as | ||
1052 | 1033 | // dtype when used as the type of a variable or a struct field. | ||
1053 | 1034 | func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { | ||
1054 | 1035 | if t, ok := c.m[dtype]; ok { | ||
1055 | 1036 | if t.Go == nil { | ||
1056 | 1037 | fatalf("%s: type conversion loop at %s", lineno(pos), dtype) | ||
1057 | 1038 | } | ||
1058 | 1039 | return t | ||
1059 | 1040 | } | ||
1060 | 1041 | |||
1061 | 1042 | // clang won't generate DW_AT_byte_size for pointer types, | ||
1062 | 1043 | // so we have to fix it here. | ||
1063 | 1044 | if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 { | ||
1064 | 1045 | dt.ByteSize = c.ptrSize | ||
1065 | 1046 | } | ||
1066 | 1047 | |||
1067 | 1048 | t := new(Type) | ||
1068 | 1049 | t.Size = dtype.Size() // note: wrong for array of pointers, corrected below | ||
1069 | 1050 | t.Align = -1 | ||
1070 | 1051 | t.C = &TypeRepr{Repr: dtype.Common().Name} | ||
1071 | 1052 | c.m[dtype] = t | ||
1072 | 1053 | |||
1073 | 1054 | switch dt := dtype.(type) { | ||
1074 | 1055 | default: | ||
1075 | 1056 | fatalf("%s: unexpected type: %s", lineno(pos), dtype) | ||
1076 | 1057 | |||
1077 | 1058 | case *dwarf.AddrType: | ||
1078 | 1059 | if t.Size != c.ptrSize { | ||
1079 | 1060 | fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype) | ||
1080 | 1061 | } | ||
1081 | 1062 | t.Go = c.uintptr | ||
1082 | 1063 | t.Align = t.Size | ||
1083 | 1064 | |||
1084 | 1065 | case *dwarf.ArrayType: | ||
1085 | 1066 | if dt.StrideBitSize > 0 { | ||
1086 | 1067 | // Cannot represent bit-sized elements in Go. | ||
1087 | 1068 | t.Go = c.Opaque(t.Size) | ||
1088 | 1069 | break | ||
1089 | 1070 | } | ||
1090 | 1071 | gt := &ast.ArrayType{ | ||
1091 | 1072 | Len: c.intExpr(dt.Count), | ||
1092 | 1073 | } | ||
1093 | 1074 | t.Go = gt // publish before recursive call | ||
1094 | 1075 | sub := c.Type(dt.Type, pos) | ||
1095 | 1076 | t.Align = sub.Align | ||
1096 | 1077 | gt.Elt = sub.Go | ||
1097 | 1078 | t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) | ||
1098 | 1079 | |||
1099 | 1080 | case *dwarf.BoolType: | ||
1100 | 1081 | t.Go = c.bool | ||
1101 | 1082 | t.Align = 1 | ||
1102 | 1083 | |||
1103 | 1084 | case *dwarf.CharType: | ||
1104 | 1085 | if t.Size != 1 { | ||
1105 | 1086 | fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype) | ||
1106 | 1087 | } | ||
1107 | 1088 | t.Go = c.int8 | ||
1108 | 1089 | t.Align = 1 | ||
1109 | 1090 | |||
1110 | 1091 | case *dwarf.EnumType: | ||
1111 | 1092 | if t.Align = t.Size; t.Align >= c.ptrSize { | ||
1112 | 1093 | t.Align = c.ptrSize | ||
1113 | 1094 | } | ||
1114 | 1095 | t.C.Set("enum " + dt.EnumName) | ||
1115 | 1096 | signed := 0 | ||
1116 | 1097 | t.EnumValues = make(map[string]int64) | ||
1117 | 1098 | for _, ev := range dt.Val { | ||
1118 | 1099 | t.EnumValues[ev.Name] = ev.Val | ||
1119 | 1100 | if ev.Val < 0 { | ||
1120 | 1101 | signed = signedDelta | ||
1121 | 1102 | } | ||
1122 | 1103 | } | ||
1123 | 1104 | switch t.Size + int64(signed) { | ||
1124 | 1105 | default: | ||
1125 | 1106 | fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype) | ||
1126 | 1107 | case 1: | ||
1127 | 1108 | t.Go = c.uint8 | ||
1128 | 1109 | case 2: | ||
1129 | 1110 | t.Go = c.uint16 | ||
1130 | 1111 | case 4: | ||
1131 | 1112 | t.Go = c.uint32 | ||
1132 | 1113 | case 8: | ||
1133 | 1114 | t.Go = c.uint64 | ||
1134 | 1115 | case 1 + signedDelta: | ||
1135 | 1116 | t.Go = c.int8 | ||
1136 | 1117 | case 2 + signedDelta: | ||
1137 | 1118 | t.Go = c.int16 | ||
1138 | 1119 | case 4 + signedDelta: | ||
1139 | 1120 | t.Go = c.int32 | ||
1140 | 1121 | case 8 + signedDelta: | ||
1141 | 1122 | t.Go = c.int64 | ||
1142 | 1123 | } | ||
1143 | 1124 | |||
1144 | 1125 | case *dwarf.FloatType: | ||
1145 | 1126 | switch t.Size { | ||
1146 | 1127 | default: | ||
1147 | 1128 | fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype) | ||
1148 | 1129 | case 4: | ||
1149 | 1130 | t.Go = c.float32 | ||
1150 | 1131 | case 8: | ||
1151 | 1132 | t.Go = c.float64 | ||
1152 | 1133 | } | ||
1153 | 1134 | if t.Align = t.Size; t.Align >= c.ptrSize { | ||
1154 | 1135 | t.Align = c.ptrSize | ||
1155 | 1136 | } | ||
1156 | 1137 | |||
1157 | 1138 | case *dwarf.ComplexType: | ||
1158 | 1139 | switch t.Size { | ||
1159 | 1140 | default: | ||
1160 | 1141 | fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype) | ||
1161 | 1142 | case 8: | ||
1162 | 1143 | t.Go = c.complex64 | ||
1163 | 1144 | case 16: | ||
1164 | 1145 | t.Go = c.complex128 | ||
1165 | 1146 | } | ||
1166 | 1147 | if t.Align = t.Size; t.Align >= c.ptrSize { | ||
1167 | 1148 | t.Align = c.ptrSize | ||
1168 | 1149 | } | ||
1169 | 1150 | |||
1170 | 1151 | case *dwarf.FuncType: | ||
1171 | 1152 | // No attempt at translation: would enable calls | ||
1172 | 1153 | // directly between worlds, but we need to moderate those. | ||
1173 | 1154 | t.Go = c.uintptr | ||
1174 | 1155 | t.Align = c.ptrSize | ||
1175 | 1156 | |||
1176 | 1157 | case *dwarf.IntType: | ||
1177 | 1158 | if dt.BitSize > 0 { | ||
1178 | 1159 | fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype) | ||
1179 | 1160 | } | ||
1180 | 1161 | switch t.Size { | ||
1181 | 1162 | default: | ||
1182 | 1163 | fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype) | ||
1183 | 1164 | case 1: | ||
1184 | 1165 | t.Go = c.int8 | ||
1185 | 1166 | case 2: | ||
1186 | 1167 | t.Go = c.int16 | ||
1187 | 1168 | case 4: | ||
1188 | 1169 | t.Go = c.int32 | ||
1189 | 1170 | case 8: | ||
1190 | 1171 | t.Go = c.int64 | ||
1191 | 1172 | } | ||
1192 | 1173 | if t.Align = t.Size; t.Align >= c.ptrSize { | ||
1193 | 1174 | t.Align = c.ptrSize | ||
1194 | 1175 | } | ||
1195 | 1176 | |||
1196 | 1177 | case *dwarf.PtrType: | ||
1197 | 1178 | t.Align = c.ptrSize | ||
1198 | 1179 | |||
1199 | 1180 | // Translate void* as unsafe.Pointer | ||
1200 | 1181 | if _, ok := base(dt.Type).(*dwarf.VoidType); ok { | ||
1201 | 1182 | t.Go = c.unsafePointer | ||
1202 | 1183 | t.C.Set("void*") | ||
1203 | 1184 | break | ||
1204 | 1185 | } | ||
1205 | 1186 | |||
1206 | 1187 | gt := &ast.StarExpr{} | ||
1207 | 1188 | t.Go = gt // publish before recursive call | ||
1208 | 1189 | sub := c.Type(dt.Type, pos) | ||
1209 | 1190 | gt.X = sub.Go | ||
1210 | 1191 | t.C.Set("%s*", sub.C) | ||
1211 | 1192 | |||
1212 | 1193 | case *dwarf.QualType: | ||
1213 | 1194 | // Ignore qualifier. | ||
1214 | 1195 | t = c.Type(dt.Type, pos) | ||
1215 | 1196 | c.m[dtype] = t | ||
1216 | 1197 | return t | ||
1217 | 1198 | |||
1218 | 1199 | case *dwarf.StructType: | ||
1219 | 1200 | if dt.ByteSize < 0 { // opaque struct | ||
1220 | 1201 | break | ||
1221 | 1202 | } | ||
1222 | 1203 | // Convert to Go struct, being careful about alignment. | ||
1223 | 1204 | // Have to give it a name to simulate C "struct foo" references. | ||
1224 | 1205 | tag := dt.StructName | ||
1225 | 1206 | if tag == "" { | ||
1226 | 1207 | tag = "__" + strconv.Itoa(tagGen) | ||
1227 | 1208 | tagGen++ | ||
1228 | 1209 | } else if t.C.Empty() { | ||
1229 | 1210 | t.C.Set(dt.Kind + " " + tag) | ||
1230 | 1211 | } | ||
1231 | 1212 | name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) | ||
1232 | 1213 | t.Go = name // publish before recursive calls | ||
1233 | 1214 | goIdent[name.Name] = name | ||
1234 | 1215 | switch dt.Kind { | ||
1235 | 1216 | case "class", "union": | ||
1236 | 1217 | t.Go = c.Opaque(t.Size) | ||
1237 | 1218 | if t.C.Empty() { | ||
1238 | 1219 | t.C.Set("__typeof__(unsigned char[%d])", t.Size) | ||
1239 | 1220 | } | ||
1240 | 1221 | t.Align = 1 // TODO: should probably base this on field alignment. | ||
1241 | 1222 | typedef[name.Name] = t | ||
1242 | 1223 | case "struct": | ||
1243 | 1224 | g, csyntax, align := c.Struct(dt, pos) | ||
1244 | 1225 | if t.C.Empty() { | ||
1245 | 1226 | t.C.Set(csyntax) | ||
1246 | 1227 | } | ||
1247 | 1228 | t.Align = align | ||
1248 | 1229 | tt := *t | ||
1249 | 1230 | if tag != "" { | ||
1250 | 1231 | tt.C = &TypeRepr{"struct %s", []interface{}{tag}} | ||
1251 | 1232 | } | ||
1252 | 1233 | tt.Go = g | ||
1253 | 1234 | typedef[name.Name] = &tt | ||
1254 | 1235 | } | ||
1255 | 1236 | |||
1256 | 1237 | case *dwarf.TypedefType: | ||
1257 | 1238 | // Record typedef for printing. | ||
1258 | 1239 | if dt.Name == "_GoString_" { | ||
1259 | 1240 | // Special C name for Go string type. | ||
1260 | 1241 | // Knows string layout used by compilers: pointer plus length, | ||
1261 | 1242 | // which rounds up to 2 pointers after alignment. | ||
1262 | 1243 | t.Go = c.string | ||
1263 | 1244 | t.Size = c.ptrSize * 2 | ||
1264 | 1245 | t.Align = c.ptrSize | ||
1265 | 1246 | break | ||
1266 | 1247 | } | ||
1267 | 1248 | if dt.Name == "_GoBytes_" { | ||
1268 | 1249 | // Special C name for Go []byte type. | ||
1269 | 1250 | // Knows slice layout used by compilers: pointer, length, cap. | ||
1270 | 1251 | t.Go = c.Ident("[]byte") | ||
1271 | 1252 | t.Size = c.ptrSize + 4 + 4 | ||
1272 | 1253 | t.Align = c.ptrSize | ||
1273 | 1254 | break | ||
1274 | 1255 | } | ||
1275 | 1256 | name := c.Ident("_Ctype_" + dt.Name) | ||
1276 | 1257 | goIdent[name.Name] = name | ||
1277 | 1258 | t.Go = name // publish before recursive call | ||
1278 | 1259 | sub := c.Type(dt.Type, pos) | ||
1279 | 1260 | t.Size = sub.Size | ||
1280 | 1261 | t.Align = sub.Align | ||
1281 | 1262 | if _, ok := typedef[name.Name]; !ok { | ||
1282 | 1263 | tt := *t | ||
1283 | 1264 | tt.Go = sub.Go | ||
1284 | 1265 | typedef[name.Name] = &tt | ||
1285 | 1266 | } | ||
1286 | 1267 | if *godefs || *cdefs { | ||
1287 | 1268 | t.Go = sub.Go | ||
1288 | 1269 | } | ||
1289 | 1270 | |||
1290 | 1271 | case *dwarf.UcharType: | ||
1291 | 1272 | if t.Size != 1 { | ||
1292 | 1273 | fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype) | ||
1293 | 1274 | } | ||
1294 | 1275 | t.Go = c.uint8 | ||
1295 | 1276 | t.Align = 1 | ||
1296 | 1277 | |||
1297 | 1278 | case *dwarf.UintType: | ||
1298 | 1279 | if dt.BitSize > 0 { | ||
1299 | 1280 | fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype) | ||
1300 | 1281 | } | ||
1301 | 1282 | switch t.Size { | ||
1302 | 1283 | default: | ||
1303 | 1284 | fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype) | ||
1304 | 1285 | case 1: | ||
1305 | 1286 | t.Go = c.uint8 | ||
1306 | 1287 | case 2: | ||
1307 | 1288 | t.Go = c.uint16 | ||
1308 | 1289 | case 4: | ||
1309 | 1290 | t.Go = c.uint32 | ||
1310 | 1291 | case 8: | ||
1311 | 1292 | t.Go = c.uint64 | ||
1312 | 1293 | } | ||
1313 | 1294 | if t.Align = t.Size; t.Align >= c.ptrSize { | ||
1314 | 1295 | t.Align = c.ptrSize | ||
1315 | 1296 | } | ||
1316 | 1297 | |||
1317 | 1298 | case *dwarf.VoidType: | ||
1318 | 1299 | t.Go = c.goVoid | ||
1319 | 1300 | t.C.Set("void") | ||
1320 | 1301 | t.Align = 1 | ||
1321 | 1302 | } | ||
1322 | 1303 | |||
1323 | 1304 | switch dtype.(type) { | ||
1324 | 1305 | case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: | ||
1325 | 1306 | s := dtype.Common().Name | ||
1326 | 1307 | if s != "" { | ||
1327 | 1308 | if ss, ok := dwarfToName[s]; ok { | ||
1328 | 1309 | s = ss | ||
1329 | 1310 | } | ||
1330 | 1311 | s = strings.Join(strings.Split(s, " "), "") // strip spaces | ||
1331 | 1312 | name := c.Ident("_Ctype_" + s) | ||
1332 | 1313 | tt := *t | ||
1333 | 1314 | typedef[name.Name] = &tt | ||
1334 | 1315 | if !*godefs && !*cdefs { | ||
1335 | 1316 | t.Go = name | ||
1336 | 1317 | } | ||
1337 | 1318 | } | ||
1338 | 1319 | } | ||
1339 | 1320 | |||
1340 | 1321 | if t.Size <= 0 { | ||
1341 | 1322 | // Clang does not record the size of a pointer in its DWARF entry, | ||
1342 | 1323 | // so if dtype is an array, the call to dtype.Size at the top of the function | ||
1343 | 1324 | // computed the size as the array length * 0 = 0. | ||
1344 | 1325 | // The type switch called Type (this function) recursively on the pointer | ||
1345 | 1326 | // entry, and the code near the top of the function updated the size to | ||
1346 | 1327 | // be correct, so calling dtype.Size again will produce the correct value. | ||
1347 | 1328 | t.Size = dtype.Size() | ||
1348 | 1329 | if t.Size < 0 { | ||
1349 | 1330 | // Unsized types are [0]byte | ||
1350 | 1331 | t.Size = 0 | ||
1351 | 1332 | t.Go = c.Opaque(0) | ||
1352 | 1333 | if t.C.Empty() { | ||
1353 | 1334 | t.C.Set("void") | ||
1354 | 1335 | } | ||
1355 | 1336 | return t | ||
1356 | 1337 | } | ||
1357 | 1338 | } | ||
1358 | 1339 | |||
1359 | 1340 | if t.C.Empty() { | ||
1360 | 1341 | fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype) | ||
1361 | 1342 | } | ||
1362 | 1343 | |||
1363 | 1344 | return t | ||
1364 | 1345 | } | ||
1365 | 1346 | |||
1366 | 1347 | // FuncArg returns a Go type with the same memory layout as | ||
1367 | 1348 | // dtype when used as the type of a C function argument. | ||
1368 | 1349 | func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { | ||
1369 | 1350 | t := c.Type(dtype, pos) | ||
1370 | 1351 | switch dt := dtype.(type) { | ||
1371 | 1352 | case *dwarf.ArrayType: | ||
1372 | 1353 | // Arrays are passed implicitly as pointers in C. | ||
1373 | 1354 | // In Go, we must be explicit. | ||
1374 | 1355 | tr := &TypeRepr{} | ||
1375 | 1356 | tr.Set("%s*", t.C) | ||
1376 | 1357 | return &Type{ | ||
1377 | 1358 | Size: c.ptrSize, | ||
1378 | 1359 | Align: c.ptrSize, | ||
1379 | 1360 | Go: &ast.StarExpr{X: t.Go}, | ||
1380 | 1361 | C: tr, | ||
1381 | 1362 | } | ||
1382 | 1363 | case *dwarf.TypedefType: | ||
1383 | 1364 | // C has much more relaxed rules than Go for | ||
1384 | 1365 | // implicit type conversions. When the parameter | ||
1385 | 1366 | // is type T defined as *X, simulate a little of the | ||
1386 | 1367 | // laxness of C by making the argument *X instead of T. | ||
1387 | 1368 | if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok { | ||
1388 | 1369 | // Unless the typedef happens to point to void* since | ||
1389 | 1370 | // Go has special rules around using unsafe.Pointer. | ||
1390 | 1371 | if _, void := base(ptr.Type).(*dwarf.VoidType); void { | ||
1391 | 1372 | break | ||
1392 | 1373 | } | ||
1393 | 1374 | |||
1394 | 1375 | t = c.Type(ptr, pos) | ||
1395 | 1376 | if t == nil { | ||
1396 | 1377 | return nil | ||
1397 | 1378 | } | ||
1398 | 1379 | |||
1399 | 1380 | // Remember the C spelling, in case the struct | ||
1400 | 1381 | // has __attribute__((unavailable)) on it. See issue 2888. | ||
1401 | 1382 | t.Typedef = dt.Name | ||
1402 | 1383 | } | ||
1403 | 1384 | } | ||
1404 | 1385 | return t | ||
1405 | 1386 | } | ||
1406 | 1387 | |||
1407 | 1388 | // FuncType returns the Go type analogous to dtype. | ||
1408 | 1389 | // There is no guarantee about matching memory layout. | ||
1409 | 1390 | func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType { | ||
1410 | 1391 | p := make([]*Type, len(dtype.ParamType)) | ||
1411 | 1392 | gp := make([]*ast.Field, len(dtype.ParamType)) | ||
1412 | 1393 | for i, f := range dtype.ParamType { | ||
1413 | 1394 | // gcc's DWARF generator outputs a single DotDotDotType parameter for | ||
1414 | 1395 | // function pointers that specify no parameters (e.g. void | ||
1415 | 1396 | // (*__cgo_0)()). Treat this special case as void. This case is | ||
1416 | 1397 | // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not | ||
1417 | 1398 | // legal). | ||
1418 | 1399 | if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 { | ||
1419 | 1400 | p, gp = nil, nil | ||
1420 | 1401 | break | ||
1421 | 1402 | } | ||
1422 | 1403 | p[i] = c.FuncArg(f, pos) | ||
1423 | 1404 | gp[i] = &ast.Field{Type: p[i].Go} | ||
1424 | 1405 | } | ||
1425 | 1406 | var r *Type | ||
1426 | 1407 | var gr []*ast.Field | ||
1427 | 1408 | if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok { | ||
1428 | 1409 | gr = []*ast.Field{{Type: c.goVoid}} | ||
1429 | 1410 | } else if dtype.ReturnType != nil { | ||
1430 | 1411 | r = c.Type(dtype.ReturnType, pos) | ||
1431 | 1412 | gr = []*ast.Field{{Type: r.Go}} | ||
1432 | 1413 | } | ||
1433 | 1414 | return &FuncType{ | ||
1434 | 1415 | Params: p, | ||
1435 | 1416 | Result: r, | ||
1436 | 1417 | Go: &ast.FuncType{ | ||
1437 | 1418 | Params: &ast.FieldList{List: gp}, | ||
1438 | 1419 | Results: &ast.FieldList{List: gr}, | ||
1439 | 1420 | }, | ||
1440 | 1421 | } | ||
1441 | 1422 | } | ||
1442 | 1423 | |||
1443 | 1424 | // Identifier | ||
1444 | 1425 | func (c *typeConv) Ident(s string) *ast.Ident { | ||
1445 | 1426 | return ast.NewIdent(s) | ||
1446 | 1427 | } | ||
1447 | 1428 | |||
1448 | 1429 | // Opaque type of n bytes. | ||
1449 | 1430 | func (c *typeConv) Opaque(n int64) ast.Expr { | ||
1450 | 1431 | return &ast.ArrayType{ | ||
1451 | 1432 | Len: c.intExpr(n), | ||
1452 | 1433 | Elt: c.byte, | ||
1453 | 1434 | } | ||
1454 | 1435 | } | ||
1455 | 1436 | |||
1456 | 1437 | // Expr for integer n. | ||
1457 | 1438 | func (c *typeConv) intExpr(n int64) ast.Expr { | ||
1458 | 1439 | return &ast.BasicLit{ | ||
1459 | 1440 | Kind: token.INT, | ||
1460 | 1441 | Value: strconv.FormatInt(n, 10), | ||
1461 | 1442 | } | ||
1462 | 1443 | } | ||
1463 | 1444 | |||
1464 | 1445 | // Add padding of given size to fld. | ||
1465 | 1446 | func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field { | ||
1466 | 1447 | n := len(fld) | ||
1467 | 1448 | fld = fld[0 : n+1] | ||
1468 | 1449 | fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)} | ||
1469 | 1450 | return fld | ||
1470 | 1451 | } | ||
1471 | 1452 | |||
1472 | 1453 | // Struct conversion: return Go and (6g) C syntax for type. | ||
1473 | 1454 | func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { | ||
1474 | 1455 | var buf bytes.Buffer | ||
1475 | 1456 | buf.WriteString("struct {") | ||
1476 | 1457 | fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field | ||
1477 | 1458 | off := int64(0) | ||
1478 | 1459 | |||
1479 | 1460 | // Rename struct fields that happen to be named Go keywords into | ||
1480 | 1461 | // _{keyword}. Create a map from C ident -> Go ident. The Go ident will | ||
1481 | 1462 | // be mangled. Any existing identifier that already has the same name on | ||
1482 | 1463 | // the C-side will cause the Go-mangled version to be prefixed with _. | ||
1483 | 1464 | // (e.g. in a struct with fields '_type' and 'type', the latter would be | ||
1484 | 1465 | // rendered as '__type' in Go). | ||
1485 | 1466 | ident := make(map[string]string) | ||
1486 | 1467 | used := make(map[string]bool) | ||
1487 | 1468 | for _, f := range dt.Field { | ||
1488 | 1469 | ident[f.Name] = f.Name | ||
1489 | 1470 | used[f.Name] = true | ||
1490 | 1471 | } | ||
1491 | 1472 | |||
1492 | 1473 | if !*godefs && !*cdefs { | ||
1493 | 1474 | for cid, goid := range ident { | ||
1494 | 1475 | if token.Lookup(goid).IsKeyword() { | ||
1495 | 1476 | // Avoid keyword | ||
1496 | 1477 | goid = "_" + goid | ||
1497 | 1478 | |||
1498 | 1479 | // Also avoid existing fields | ||
1499 | 1480 | for _, exist := used[goid]; exist; _, exist = used[goid] { | ||
1500 | 1481 | goid = "_" + goid | ||
1501 | 1482 | } | ||
1502 | 1483 | |||
1503 | 1484 | used[goid] = true | ||
1504 | 1485 | ident[cid] = goid | ||
1505 | 1486 | } | ||
1506 | 1487 | } | ||
1507 | 1488 | } | ||
1508 | 1489 | |||
1509 | 1490 | anon := 0 | ||
1510 | 1491 | for _, f := range dt.Field { | ||
1511 | 1492 | if f.ByteOffset > off { | ||
1512 | 1493 | fld = c.pad(fld, f.ByteOffset-off) | ||
1513 | 1494 | off = f.ByteOffset | ||
1514 | 1495 | } | ||
1515 | 1496 | t := c.Type(f.Type, pos) | ||
1516 | 1497 | tgo := t.Go | ||
1517 | 1498 | size := t.Size | ||
1518 | 1499 | |||
1519 | 1500 | if f.BitSize > 0 { | ||
1520 | 1501 | if f.BitSize%8 != 0 { | ||
1521 | 1502 | continue | ||
1522 | 1503 | } | ||
1523 | 1504 | size = f.BitSize / 8 | ||
1524 | 1505 | name := tgo.(*ast.Ident).String() | ||
1525 | 1506 | if strings.HasPrefix(name, "int") { | ||
1526 | 1507 | name = "int" | ||
1527 | 1508 | } else { | ||
1528 | 1509 | name = "uint" | ||
1529 | 1510 | } | ||
1530 | 1511 | tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize)) | ||
1531 | 1512 | } | ||
1532 | 1513 | |||
1533 | 1514 | n := len(fld) | ||
1534 | 1515 | fld = fld[0 : n+1] | ||
1535 | 1516 | name := f.Name | ||
1536 | 1517 | if name == "" { | ||
1537 | 1518 | name = fmt.Sprintf("anon%d", anon) | ||
1538 | 1519 | anon++ | ||
1539 | 1520 | ident[name] = name | ||
1540 | 1521 | } | ||
1541 | 1522 | fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo} | ||
1542 | 1523 | off += size | ||
1543 | 1524 | buf.WriteString(t.C.String()) | ||
1544 | 1525 | buf.WriteString(" ") | ||
1545 | 1526 | buf.WriteString(name) | ||
1546 | 1527 | buf.WriteString("; ") | ||
1547 | 1528 | if t.Align > align { | ||
1548 | 1529 | align = t.Align | ||
1549 | 1530 | } | ||
1550 | 1531 | } | ||
1551 | 1532 | if off < dt.ByteSize { | ||
1552 | 1533 | fld = c.pad(fld, dt.ByteSize-off) | ||
1553 | 1534 | off = dt.ByteSize | ||
1554 | 1535 | } | ||
1555 | 1536 | if off != dt.ByteSize { | ||
1556 | 1537 | fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize) | ||
1557 | 1538 | } | ||
1558 | 1539 | buf.WriteString("}") | ||
1559 | 1540 | csyntax = buf.String() | ||
1560 | 1541 | |||
1561 | 1542 | if *godefs || *cdefs { | ||
1562 | 1543 | godefsFields(fld) | ||
1563 | 1544 | } | ||
1564 | 1545 | expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} | ||
1565 | 1546 | return | ||
1566 | 1547 | } | ||
1567 | 1548 | |||
1568 | 1549 | func upper(s string) string { | ||
1569 | 1550 | if s == "" { | ||
1570 | 1551 | return "" | ||
1571 | 1552 | } | ||
1572 | 1553 | r, size := utf8.DecodeRuneInString(s) | ||
1573 | 1554 | if r == '_' { | ||
1574 | 1555 | return "X" + s | ||
1575 | 1556 | } | ||
1576 | 1557 | return string(unicode.ToUpper(r)) + s[size:] | ||
1577 | 1558 | } | ||
1578 | 1559 | |||
1579 | 1560 | // godefsFields rewrites field names for use in Go or C definitions. | ||
1580 | 1561 | // It strips leading common prefixes (like tv_ in tv_sec, tv_usec) | ||
1581 | 1562 | // converts names to upper case, and rewrites _ into Pad_godefs_n, | ||
1582 | 1563 | // so that all fields are exported. | ||
1583 | 1564 | func godefsFields(fld []*ast.Field) { | ||
1584 | 1565 | prefix := fieldPrefix(fld) | ||
1585 | 1566 | npad := 0 | ||
1586 | 1567 | for _, f := range fld { | ||
1587 | 1568 | for _, n := range f.Names { | ||
1588 | 1569 | if n.Name != prefix { | ||
1589 | 1570 | n.Name = strings.TrimPrefix(n.Name, prefix) | ||
1590 | 1571 | } | ||
1591 | 1572 | if n.Name == "_" { | ||
1592 | 1573 | // Use exported name instead. | ||
1593 | 1574 | n.Name = "Pad_cgo_" + strconv.Itoa(npad) | ||
1594 | 1575 | npad++ | ||
1595 | 1576 | } | ||
1596 | 1577 | if !*cdefs { | ||
1597 | 1578 | n.Name = upper(n.Name) | ||
1598 | 1579 | } | ||
1599 | 1580 | } | ||
1600 | 1581 | p := &f.Type | ||
1601 | 1582 | t := *p | ||
1602 | 1583 | if star, ok := t.(*ast.StarExpr); ok { | ||
1603 | 1584 | star = &ast.StarExpr{X: star.X} | ||
1604 | 1585 | *p = star | ||
1605 | 1586 | p = &star.X | ||
1606 | 1587 | t = *p | ||
1607 | 1588 | } | ||
1608 | 1589 | if id, ok := t.(*ast.Ident); ok { | ||
1609 | 1590 | if id.Name == "unsafe.Pointer" { | ||
1610 | 1591 | *p = ast.NewIdent("*byte") | ||
1611 | 1592 | } | ||
1612 | 1593 | } | ||
1613 | 1594 | } | ||
1614 | 1595 | } | ||
1615 | 1596 | |||
1616 | 1597 | // fieldPrefix returns the prefix that should be removed from all the | ||
1617 | 1598 | // field names when generating the C or Go code. For generated | ||
1618 | 1599 | // C, we leave the names as is (tv_sec, tv_usec), since that's what | ||
1619 | 1600 | // people are used to seeing in C. For generated Go code, such as | ||
1620 | 1601 | // package syscall's data structures, we drop a common prefix | ||
1621 | 1602 | // (so sec, usec, which will get turned into Sec, Usec for exporting). | ||
1622 | 1603 | func fieldPrefix(fld []*ast.Field) string { | ||
1623 | 1604 | if *cdefs { | ||
1624 | 1605 | return "" | ||
1625 | 1606 | } | ||
1626 | 1607 | prefix := "" | ||
1627 | 1608 | for _, f := range fld { | ||
1628 | 1609 | for _, n := range f.Names { | ||
1629 | 1610 | // Ignore field names that don't have the prefix we're | ||
1630 | 1611 | // looking for. It is common in C headers to have fields | ||
1631 | 1612 | // named, say, _pad in an otherwise prefixed header. | ||
1632 | 1613 | // If the struct has 3 fields tv_sec, tv_usec, _pad1, then we | ||
1633 | 1614 | // still want to remove the tv_ prefix. | ||
1634 | 1615 | // The check for "orig_" here handles orig_eax in the | ||
1635 | 1616 | // x86 ptrace register sets, which otherwise have all fields | ||
1636 | 1617 | // with reg_ prefixes. | ||
1637 | 1618 | if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") { | ||
1638 | 1619 | continue | ||
1639 | 1620 | } | ||
1640 | 1621 | i := strings.Index(n.Name, "_") | ||
1641 | 1622 | if i < 0 { | ||
1642 | 1623 | continue | ||
1643 | 1624 | } | ||
1644 | 1625 | if prefix == "" { | ||
1645 | 1626 | prefix = n.Name[:i+1] | ||
1646 | 1627 | } else if prefix != n.Name[:i+1] { | ||
1647 | 1628 | return "" | ||
1648 | 1629 | } | ||
1649 | 1630 | } | ||
1650 | 1631 | } | ||
1651 | 1632 | return prefix | ||
1652 | 1633 | } | ||
1653 | 0 | 1634 | ||
1654 | === added directory '.pc/build-cgo.diff/src/cmd/go' | |||
1655 | === added file '.pc/build-cgo.diff/src/cmd/go/tool.go' | |||
1656 | --- .pc/build-cgo.diff/src/cmd/go/tool.go 1970-01-01 00:00:00 +0000 | |||
1657 | +++ .pc/build-cgo.diff/src/cmd/go/tool.go 2014-08-14 02:29:21 +0000 | |||
1658 | @@ -0,0 +1,156 @@ | |||
1659 | 1 | // Copyright 2011 The Go Authors. All rights reserved. | ||
1660 | 2 | // Use of this source code is governed by a BSD-style | ||
1661 | 3 | // license that can be found in the LICENSE file. | ||
1662 | 4 | |||
1663 | 5 | package main | ||
1664 | 6 | |||
1665 | 7 | import ( | ||
1666 | 8 | "fmt" | ||
1667 | 9 | "go/build" | ||
1668 | 10 | "os" | ||
1669 | 11 | "os/exec" | ||
1670 | 12 | "path/filepath" | ||
1671 | 13 | "runtime" | ||
1672 | 14 | "sort" | ||
1673 | 15 | "strings" | ||
1674 | 16 | ) | ||
1675 | 17 | |||
1676 | 18 | var cmdTool = &Command{ | ||
1677 | 19 | Run: runTool, | ||
1678 | 20 | UsageLine: "tool [-n] command [args...]", | ||
1679 | 21 | Short: "run specified go tool", | ||
1680 | 22 | Long: ` | ||
1681 | 23 | Tool runs the go tool command identified by the arguments. | ||
1682 | 24 | With no arguments it prints the list of known tools. | ||
1683 | 25 | |||
1684 | 26 | The -n flag causes tool to print the command that would be | ||
1685 | 27 | executed but not execute it. | ||
1686 | 28 | |||
1687 | 29 | For more about each tool command, see 'go tool command -h'. | ||
1688 | 30 | `, | ||
1689 | 31 | } | ||
1690 | 32 | |||
1691 | 33 | var ( | ||
1692 | 34 | toolGOOS = runtime.GOOS | ||
1693 | 35 | toolGOARCH = runtime.GOARCH | ||
1694 | 36 | toolIsWindows = toolGOOS == "windows" | ||
1695 | 37 | toolDir = build.ToolDir | ||
1696 | 38 | |||
1697 | 39 | toolN bool | ||
1698 | 40 | ) | ||
1699 | 41 | |||
1700 | 42 | func init() { | ||
1701 | 43 | cmdTool.Flag.BoolVar(&toolN, "n", false, "") | ||
1702 | 44 | } | ||
1703 | 45 | |||
1704 | 46 | const toolWindowsExtension = ".exe" | ||
1705 | 47 | |||
1706 | 48 | func tool(toolName string) string { | ||
1707 | 49 | toolPath := filepath.Join(toolDir, toolName) | ||
1708 | 50 | if toolIsWindows && toolName != "pprof" { | ||
1709 | 51 | toolPath += toolWindowsExtension | ||
1710 | 52 | } | ||
1711 | 53 | // Give a nice message if there is no tool with that name. | ||
1712 | 54 | if _, err := os.Stat(toolPath); err != nil { | ||
1713 | 55 | if isInGoToolsRepo(toolName) { | ||
1714 | 56 | fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName) | ||
1715 | 57 | } else { | ||
1716 | 58 | fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName) | ||
1717 | 59 | } | ||
1718 | 60 | setExitStatus(3) | ||
1719 | 61 | exit() | ||
1720 | 62 | } | ||
1721 | 63 | return toolPath | ||
1722 | 64 | } | ||
1723 | 65 | |||
1724 | 66 | func isInGoToolsRepo(toolName string) bool { | ||
1725 | 67 | switch toolName { | ||
1726 | 68 | case "cover", "vet": | ||
1727 | 69 | return true | ||
1728 | 70 | } | ||
1729 | 71 | return false | ||
1730 | 72 | } | ||
1731 | 73 | |||
1732 | 74 | func runTool(cmd *Command, args []string) { | ||
1733 | 75 | if len(args) == 0 { | ||
1734 | 76 | listTools() | ||
1735 | 77 | return | ||
1736 | 78 | } | ||
1737 | 79 | toolName := args[0] | ||
1738 | 80 | // The tool name must be lower-case letters, numbers or underscores. | ||
1739 | 81 | for _, c := range toolName { | ||
1740 | 82 | switch { | ||
1741 | 83 | case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_': | ||
1742 | 84 | default: | ||
1743 | 85 | fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName) | ||
1744 | 86 | setExitStatus(2) | ||
1745 | 87 | return | ||
1746 | 88 | } | ||
1747 | 89 | } | ||
1748 | 90 | toolPath := tool(toolName) | ||
1749 | 91 | if toolPath == "" { | ||
1750 | 92 | return | ||
1751 | 93 | } | ||
1752 | 94 | if toolIsWindows && toolName == "pprof" { | ||
1753 | 95 | args = append([]string{"perl", toolPath}, args[1:]...) | ||
1754 | 96 | var err error | ||
1755 | 97 | toolPath, err = exec.LookPath("perl") | ||
1756 | 98 | if err != nil { | ||
1757 | 99 | fmt.Fprintf(os.Stderr, "go tool: perl not found\n") | ||
1758 | 100 | setExitStatus(3) | ||
1759 | 101 | return | ||
1760 | 102 | } | ||
1761 | 103 | } | ||
1762 | 104 | if toolN { | ||
1763 | 105 | fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " ")) | ||
1764 | 106 | return | ||
1765 | 107 | } | ||
1766 | 108 | toolCmd := &exec.Cmd{ | ||
1767 | 109 | Path: toolPath, | ||
1768 | 110 | Args: args, | ||
1769 | 111 | Stdin: os.Stdin, | ||
1770 | 112 | Stdout: os.Stdout, | ||
1771 | 113 | Stderr: os.Stderr, | ||
1772 | 114 | } | ||
1773 | 115 | err := toolCmd.Run() | ||
1774 | 116 | if err != nil { | ||
1775 | 117 | // Only print about the exit status if the command | ||
1776 | 118 | // didn't even run (not an ExitError) or it didn't exit cleanly | ||
1777 | 119 | // or we're printing command lines too (-x mode). | ||
1778 | 120 | // Assume if command exited cleanly (even with non-zero status) | ||
1779 | 121 | // it printed any messages it wanted to print. | ||
1780 | 122 | if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX { | ||
1781 | 123 | fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err) | ||
1782 | 124 | } | ||
1783 | 125 | setExitStatus(1) | ||
1784 | 126 | return | ||
1785 | 127 | } | ||
1786 | 128 | } | ||
1787 | 129 | |||
1788 | 130 | // listTools prints a list of the available tools in the tools directory. | ||
1789 | 131 | func listTools() { | ||
1790 | 132 | f, err := os.Open(toolDir) | ||
1791 | 133 | if err != nil { | ||
1792 | 134 | fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err) | ||
1793 | 135 | setExitStatus(2) | ||
1794 | 136 | return | ||
1795 | 137 | } | ||
1796 | 138 | defer f.Close() | ||
1797 | 139 | names, err := f.Readdirnames(-1) | ||
1798 | 140 | if err != nil { | ||
1799 | 141 | fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err) | ||
1800 | 142 | setExitStatus(2) | ||
1801 | 143 | return | ||
1802 | 144 | } | ||
1803 | 145 | |||
1804 | 146 | sort.Strings(names) | ||
1805 | 147 | for _, name := range names { | ||
1806 | 148 | // Unify presentation by going to lower case. | ||
1807 | 149 | name = strings.ToLower(name) | ||
1808 | 150 | // If it's windows, don't show the .exe suffix. | ||
1809 | 151 | if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) { | ||
1810 | 152 | name = name[:len(name)-len(toolWindowsExtension)] | ||
1811 | 153 | } | ||
1812 | 154 | fmt.Println(name) | ||
1813 | 155 | } | ||
1814 | 156 | } | ||
1815 | 0 | 157 | ||
1816 | === modified file 'debian/changelog' | |||
1817 | --- debian/changelog 2014-03-26 10:50:18 +0000 | |||
1818 | +++ debian/changelog 2014-08-14 02:29:21 +0000 | |||
1819 | @@ -1,3 +1,9 @@ | |||
1820 | 1 | gccgo-go (1.2.1-0ubuntu2) UNRELEASED; urgency=medium | ||
1821 | 2 | |||
1822 | 3 | * Build and install cgo too. | ||
1823 | 4 | |||
1824 | 5 | -- Michael Hudson-Doyle <michael.hudson@linaro.org> Thu, 14 Aug 2014 14:01:51 +1200 | ||
1825 | 6 | |||
1826 | 1 | gccgo-go (1.2.1-0ubuntu1) trusty; urgency=medium | 7 | gccgo-go (1.2.1-0ubuntu1) trusty; urgency=medium |
1827 | 2 | 8 | ||
1828 | 3 | * New upstream point release. | 9 | * New upstream point release. |
1829 | 4 | 10 | ||
1830 | === modified file 'debian/install' | |||
1831 | --- debian/install 2014-01-28 12:32:46 +0000 | |||
1832 | +++ debian/install 2014-08-14 02:29:21 +0000 | |||
1833 | @@ -1,1 +1,2 @@ | |||
1834 | 1 | src/cmd/go/gccgo-go /usr/bin | 1 | src/cmd/go/gccgo-go /usr/bin |
1835 | 2 | src/cmd/cgo/cgo /usr/lib/gccgo/tool | ||
1836 | 2 | \ No newline at end of file | 3 | \ No newline at end of file |
1837 | 3 | 4 | ||
1838 | === modified file 'debian/lintian-overrides' | |||
1839 | --- debian/lintian-overrides 2014-01-27 09:18:55 +0000 | |||
1840 | +++ debian/lintian-overrides 2014-08-14 02:29:21 +0000 | |||
1841 | @@ -1,2 +1,3 @@ | |||
1842 | 1 | # go binaries should never be stripped | 1 | # go binaries should never be stripped |
1843 | 2 | gccgo-go: unstripped-binary-or-object usr/bin/gccgo-go | 2 | gccgo-go: unstripped-binary-or-object usr/bin/gccgo-go |
1844 | 3 | gccgo-go: unstripped-binary-or-object usr/lib/gccgo/tool/cgo | ||
1845 | 3 | 4 | ||
1846 | === added file 'debian/patches/build-cgo.diff' | |||
1847 | --- debian/patches/build-cgo.diff 1970-01-01 00:00:00 +0000 | |||
1848 | +++ debian/patches/build-cgo.diff 2014-08-14 02:29:21 +0000 | |||
1849 | @@ -0,0 +1,49 @@ | |||
1850 | 1 | === added file 'src/cmd/cgo/Makefile' | ||
1851 | 2 | Index: gccgo-go/src/cmd/cgo/Makefile | ||
1852 | 3 | =================================================================== | ||
1853 | 4 | --- /dev/null 1970-01-01 00:00:00.000000000 +0000 | ||
1854 | 5 | +++ gccgo-go/src/cmd/cgo/Makefile 2014-08-14 14:13:14.620783230 +1200 | ||
1855 | 6 | @@ -0,0 +1,16 @@ | ||
1856 | 7 | +TARG=cgo | ||
1857 | 8 | +GOFILES=\ | ||
1858 | 9 | + ast.go\ | ||
1859 | 10 | + doc.go\ | ||
1860 | 11 | + gcc.go\ | ||
1861 | 12 | + godefs.go\ | ||
1862 | 13 | + main.go\ | ||
1863 | 14 | + out.go\ | ||
1864 | 15 | + util.go | ||
1865 | 16 | + | ||
1866 | 17 | +build: | ||
1867 | 18 | + gccgo -o _$(TARG)_ -c $(GOFLAGS) $(GOFILES) | ||
1868 | 19 | + gccgo -o $(TARG) _$(TARG)_ $(LDFLAGS) | ||
1869 | 20 | + | ||
1870 | 21 | +clean: | ||
1871 | 22 | + rm -f _$(TARG)_ $(TARG) | ||
1872 | 23 | Index: gccgo-go/src/cmd/go/tool.go | ||
1873 | 24 | =================================================================== | ||
1874 | 25 | --- gccgo-go.orig/src/cmd/go/tool.go 2014-08-14 14:11:25.772787121 +1200 | ||
1875 | 26 | +++ gccgo-go/src/cmd/go/tool.go 2014-08-14 14:20:57.504766684 +1200 | ||
1876 | 27 | @@ -41,6 +41,9 @@ | ||
1877 | 28 | |||
1878 | 29 | func init() { | ||
1879 | 30 | cmdTool.Flag.BoolVar(&toolN, "n", false, "") | ||
1880 | 31 | + if (runtime.Compiler == "gccgo") { | ||
1881 | 32 | + toolDir = filepath.Join(runtime.GOROOT(), "lib/gccgo/tool") | ||
1882 | 33 | + } | ||
1883 | 34 | } | ||
1884 | 35 | |||
1885 | 36 | const toolWindowsExtension = ".exe" | ||
1886 | 37 | Index: gccgo-go/src/cmd/cgo/gcc.go | ||
1887 | 38 | =================================================================== | ||
1888 | 39 | --- gccgo-go.orig/src/cmd/cgo/gcc.go 2014-08-12 15:34:03.612461000 +1200 | ||
1889 | 40 | +++ gccgo-go/src/cmd/cgo/gcc.go 2014-08-14 14:14:30.380780522 +1200 | ||
1890 | 41 | @@ -718,7 +718,7 @@ | ||
1891 | 42 | if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { | ||
1892 | 43 | return ret | ||
1893 | 44 | } | ||
1894 | 45 | - return strings.Fields(defaultCC) | ||
1895 | 46 | + return strings.Fields("gcc") | ||
1896 | 47 | } | ||
1897 | 48 | |||
1898 | 49 | // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". | ||
1899 | 0 | 50 | ||
1900 | === modified file 'debian/patches/series' | |||
1901 | --- debian/patches/series 2014-03-26 10:50:18 +0000 | |||
1902 | +++ debian/patches/series 2014-08-14 02:29:21 +0000 | |||
1903 | @@ -5,3 +5,4 @@ | |||
1904 | 5 | issue28050043_60001_70001.diff | 5 | issue28050043_60001_70001.diff |
1905 | 6 | issue61970044_80001.diff | 6 | issue61970044_80001.diff |
1906 | 7 | issue80300043_60001.diff | 7 | issue80300043_60001.diff |
1907 | 8 | build-cgo.diff | ||
1908 | 8 | 9 | ||
1909 | === modified file 'debian/rules' | |||
1910 | --- debian/rules 2014-02-15 22:18:45 +0000 | |||
1911 | +++ debian/rules 2014-08-14 02:29:21 +0000 | |||
1912 | @@ -10,6 +10,7 @@ | |||
1913 | 10 | 10 | ||
1914 | 11 | override_dh_auto_clean: | 11 | override_dh_auto_clean: |
1915 | 12 | dh_auto_clean -D src/cmd/go | 12 | dh_auto_clean -D src/cmd/go |
1916 | 13 | dh_auto_clean -D src/cmd/cgo | ||
1917 | 13 | 14 | ||
1918 | 14 | override_dh_strip: | 15 | override_dh_strip: |
1919 | 15 | # strip disabled as golang upstream doesn't support it and it makes go | 16 | # strip disabled as golang upstream doesn't support it and it makes go |
1920 | @@ -20,3 +21,4 @@ | |||
1921 | 20 | 21 | ||
1922 | 21 | override_dh_auto_build: | 22 | override_dh_auto_build: |
1923 | 22 | dh_auto_build -D src/cmd/go | 23 | dh_auto_build -D src/cmd/go |
1924 | 24 | dh_auto_build -D src/cmd/cgo | ||
1925 | 23 | 25 | ||
1926 | === added file 'src/cmd/cgo/Makefile' | |||
1927 | --- src/cmd/cgo/Makefile 1970-01-01 00:00:00 +0000 | |||
1928 | +++ src/cmd/cgo/Makefile 2014-08-14 02:29:21 +0000 | |||
1929 | @@ -0,0 +1,16 @@ | |||
1930 | 1 | TARG=cgo | ||
1931 | 2 | GOFILES=\ | ||
1932 | 3 | ast.go\ | ||
1933 | 4 | doc.go\ | ||
1934 | 5 | gcc.go\ | ||
1935 | 6 | godefs.go\ | ||
1936 | 7 | main.go\ | ||
1937 | 8 | out.go\ | ||
1938 | 9 | util.go | ||
1939 | 10 | |||
1940 | 11 | build: | ||
1941 | 12 | gccgo -o _$(TARG)_ -c $(GOFLAGS) $(GOFILES) | ||
1942 | 13 | gccgo -o $(TARG) _$(TARG)_ $(LDFLAGS) | ||
1943 | 14 | |||
1944 | 15 | clean: | ||
1945 | 16 | rm -f _$(TARG)_ $(TARG) | ||
1946 | 0 | 17 | ||
1947 | === modified file 'src/cmd/cgo/gcc.go' | |||
1948 | --- src/cmd/cgo/gcc.go 2014-01-27 09:18:55 +0000 | |||
1949 | +++ src/cmd/cgo/gcc.go 2014-08-14 02:29:21 +0000 | |||
1950 | @@ -718,7 +718,7 @@ | |||
1951 | 718 | if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { | 718 | if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { |
1952 | 719 | return ret | 719 | return ret |
1953 | 720 | } | 720 | } |
1955 | 721 | return strings.Fields(defaultCC) | 721 | return strings.Fields("gcc") |
1956 | 722 | } | 722 | } |
1957 | 723 | 723 | ||
1958 | 724 | // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". | 724 | // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". |
1959 | 725 | 725 | ||
1960 | === modified file 'src/cmd/go/tool.go' | |||
1961 | --- src/cmd/go/tool.go 2014-01-27 09:18:55 +0000 | |||
1962 | +++ src/cmd/go/tool.go 2014-08-14 02:29:21 +0000 | |||
1963 | @@ -41,6 +41,9 @@ | |||
1964 | 41 | 41 | ||
1965 | 42 | func init() { | 42 | func init() { |
1966 | 43 | cmdTool.Flag.BoolVar(&toolN, "n", false, "") | 43 | cmdTool.Flag.BoolVar(&toolN, "n", false, "") |
1967 | 44 | if (runtime.Compiler == "gccgo") { | ||
1968 | 45 | toolDir = filepath.Join(runtime.GOROOT(), "lib/gccgo/tool") | ||
1969 | 46 | } | ||
1970 | 44 | } | 47 | } |
1971 | 45 | 48 | ||
1972 | 46 | const toolWindowsExtension = ".exe" | 49 | const toolWindowsExtension = ".exe" |
Bah the diff is certainly horrible. Here's a debdiff: http:// paste.ubuntu. com/8041422/