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