Source file src/pkg/cmd/cgo/gcc.go
1
2
3
4
5
6
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 "internal/xcoff"
24 "math"
25 "os"
26 "strconv"
27 "strings"
28 "unicode"
29 "unicode/utf8"
30 )
31
32 var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
33 var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
34
35 var nameToC = map[string]string{
36 "schar": "signed char",
37 "uchar": "unsigned char",
38 "ushort": "unsigned short",
39 "uint": "unsigned int",
40 "ulong": "unsigned long",
41 "longlong": "long long",
42 "ulonglong": "unsigned long long",
43 "complexfloat": "float _Complex",
44 "complexdouble": "double _Complex",
45 }
46
47
48
49
50
51 func cname(s string) string {
52 if t, ok := nameToC[s]; ok {
53 return t
54 }
55
56 if strings.HasPrefix(s, "struct_") {
57 return "struct " + s[len("struct_"):]
58 }
59 if strings.HasPrefix(s, "union_") {
60 return "union " + s[len("union_"):]
61 }
62 if strings.HasPrefix(s, "enum_") {
63 return "enum " + s[len("enum_"):]
64 }
65 if strings.HasPrefix(s, "sizeof_") {
66 return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
67 }
68 return s
69 }
70
71
72
73
74 func (f *File) DiscardCgoDirectives() {
75 linesIn := strings.Split(f.Preamble, "\n")
76 linesOut := make([]string, 0, len(linesIn))
77 for _, line := range linesIn {
78 l := strings.TrimSpace(line)
79 if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
80 linesOut = append(linesOut, line)
81 } else {
82 linesOut = append(linesOut, "")
83 }
84 }
85 f.Preamble = strings.Join(linesOut, "\n")
86 }
87
88
89
90 func (p *Package) addToFlag(flag string, args []string) {
91 p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
92 if flag == "CFLAGS" {
93
94
95
96 for _, arg := range args {
97 if !strings.HasPrefix(arg, "-g") {
98 p.GccOptions = append(p.GccOptions, arg)
99 }
100 }
101 }
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 func splitQuoted(s string) (r []string, err error) {
121 var args []string
122 arg := make([]rune, len(s))
123 escaped := false
124 quoted := false
125 quote := '\x00'
126 i := 0
127 for _, r := range s {
128 switch {
129 case escaped:
130 escaped = false
131 case r == '\\':
132 escaped = true
133 continue
134 case quote != 0:
135 if r == quote {
136 quote = 0
137 continue
138 }
139 case r == '"' || r == '\'':
140 quoted = true
141 quote = r
142 continue
143 case unicode.IsSpace(r):
144 if quoted || i > 0 {
145 quoted = false
146 args = append(args, string(arg[:i]))
147 i = 0
148 }
149 continue
150 }
151 arg[i] = r
152 i++
153 }
154 if quoted || i > 0 {
155 args = append(args, string(arg[:i]))
156 }
157 if quote != 0 {
158 err = errors.New("unclosed quote")
159 } else if escaped {
160 err = errors.New("unfinished escaping")
161 }
162 return args, err
163 }
164
165
166
167
168 func (p *Package) Translate(f *File) {
169 for _, cref := range f.Ref {
170
171 cref.Name.C = cname(cref.Name.Go)
172 }
173
174 var conv typeConv
175 conv.Init(p.PtrSize, p.IntSize)
176
177 p.loadDefines(f)
178 p.typedefs = map[string]bool{}
179 p.typedefList = nil
180 numTypedefs := -1
181 for len(p.typedefs) > numTypedefs {
182 numTypedefs = len(p.typedefs)
183
184 for _, info := range p.typedefList {
185 n := &Name{
186 Go: info.typedef,
187 C: info.typedef,
188 }
189 f.Name[info.typedef] = n
190 f.NamePos[n] = info.pos
191 }
192 needType := p.guessKinds(f)
193 if len(needType) > 0 {
194 p.loadDWARF(f, &conv, needType)
195 }
196
197
198
199
200 if *godefs {
201 break
202 }
203 }
204 p.prepareNames(f)
205 if p.rewriteCalls(f) {
206
207 f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"")
208 }
209 p.rewriteRef(f)
210 }
211
212
213
214 func (p *Package) loadDefines(f *File) {
215 var b bytes.Buffer
216 b.WriteString(builtinProlog)
217 b.WriteString(f.Preamble)
218 stdout := p.gccDefines(b.Bytes())
219
220 for _, line := range strings.Split(stdout, "\n") {
221 if len(line) < 9 || line[0:7] != "#define" {
222 continue
223 }
224
225 line = strings.TrimSpace(line[8:])
226
227 var key, val string
228 spaceIndex := strings.Index(line, " ")
229 tabIndex := strings.Index(line, "\t")
230
231 if spaceIndex == -1 && tabIndex == -1 {
232 continue
233 } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
234 key = line[0:spaceIndex]
235 val = strings.TrimSpace(line[spaceIndex:])
236 } else {
237 key = line[0:tabIndex]
238 val = strings.TrimSpace(line[tabIndex:])
239 }
240
241 if key == "__clang__" {
242 p.GccIsClang = true
243 }
244
245 if n := f.Name[key]; n != nil {
246 if *debugDefine {
247 fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
248 }
249 n.Define = val
250 }
251 }
252 }
253
254
255
256
257 func (p *Package) guessKinds(f *File) []*Name {
258
259
260 var names, needType []*Name
261 optional := map[*Name]bool{}
262 for _, key := range nameKeys(f.Name) {
263 n := f.Name[key]
264
265
266 if n.Define != "" {
267 if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil {
268 n.Kind = "iconst"
269
270
271
272
273 n.Const = fmt.Sprintf("%#x", i)
274 } else if n.Define[0] == '\'' {
275 if _, err := parser.ParseExpr(n.Define); err == nil {
276 n.Kind = "iconst"
277 n.Const = n.Define
278 }
279 } else if n.Define[0] == '"' {
280 if _, err := parser.ParseExpr(n.Define); err == nil {
281 n.Kind = "sconst"
282 n.Const = n.Define
283 }
284 }
285
286 if n.IsConst() {
287 continue
288 }
289 }
290
291
292 if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
293 n.Kind = "type"
294 needType = append(needType, n)
295 continue
296 }
297
298 if goos == "darwin" && strings.HasSuffix(n.C, "Ref") {
299
300 s := n.C[:len(n.C)-3] + "GetTypeID"
301 n := &Name{Go: s, C: s}
302 names = append(names, n)
303 optional[n] = true
304 }
305
306
307 names = append(names, n)
308 }
309
310
311 if len(names) == 0 {
312 return needType
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344 var b bytes.Buffer
345 b.WriteString(builtinProlog)
346 b.WriteString(f.Preamble)
347
348 for i, n := range names {
349 fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
350 "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__1; }\n"+
351 "#line %d \"not-type\"\n"+
352 "void __cgo_f_%d_2(void) { %s *__cgo_undefined__2; }\n"+
353 "#line %d \"not-int-const\"\n"+
354 "void __cgo_f_%d_3(void) { enum { __cgo_undefined__3 = (%s)*1 }; }\n"+
355 "#line %d \"not-num-const\"\n"+
356 "void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+
357 "#line %d \"not-str-lit\"\n"+
358 "void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n",
359 i+1, i+1, n.C,
360 i+1, i+1, n.C,
361 i+1, i+1, n.C,
362 i+1, i+1, n.C,
363 i+1, i+1, n.C,
364 )
365 }
366 fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
367 "int __cgo__1 = __cgo__2;\n")
368
369 stderr := p.gccErrors(b.Bytes())
370 if stderr == "" {
371 fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes())
372 }
373
374 completed := false
375 sniff := make([]int, len(names))
376 const (
377 notType = 1 << iota
378 notIntConst
379 notNumConst
380 notStrLiteral
381 notDeclared
382 )
383 sawUnmatchedErrors := false
384 for _, line := range strings.Split(stderr, "\n") {
385
386
387
388
389
390
391 isError := strings.Contains(line, ": error:")
392 isErrorNote := strings.Contains(line, ": note:") && sawUnmatchedErrors
393 if !isError && !isErrorNote {
394 continue
395 }
396
397 c1 := strings.Index(line, ":")
398 if c1 < 0 {
399 continue
400 }
401 c2 := strings.Index(line[c1+1:], ":")
402 if c2 < 0 {
403 continue
404 }
405 c2 += c1 + 1
406
407 filename := line[:c1]
408 i, _ := strconv.Atoi(line[c1+1 : c2])
409 i--
410 if i < 0 || i >= len(names) {
411 if isError {
412 sawUnmatchedErrors = true
413 }
414 continue
415 }
416
417 switch filename {
418 case "completed":
419
420
421
422
423 completed = true
424
425 case "not-declared":
426 sniff[i] |= notDeclared
427 case "not-type":
428 sniff[i] |= notType
429 case "not-int-const":
430 sniff[i] |= notIntConst
431 case "not-num-const":
432 sniff[i] |= notNumConst
433 case "not-str-lit":
434 sniff[i] |= notStrLiteral
435 default:
436 if isError {
437 sawUnmatchedErrors = true
438 }
439 continue
440 }
441
442 sawUnmatchedErrors = false
443 }
444
445 if !completed {
446 fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr)
447 }
448
449 for i, n := range names {
450 switch sniff[i] {
451 default:
452 if sniff[i]¬Declared != 0 && optional[n] {
453
454
455 continue
456 }
457 error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
458 case notStrLiteral | notType:
459 n.Kind = "iconst"
460 case notIntConst | notStrLiteral | notType:
461 n.Kind = "fconst"
462 case notIntConst | notNumConst | notType:
463 n.Kind = "sconst"
464 case notIntConst | notNumConst | notStrLiteral:
465 n.Kind = "type"
466 case notIntConst | notNumConst | notStrLiteral | notType:
467 n.Kind = "not-type"
468 }
469 needType = append(needType, n)
470 }
471 if nerrors > 0 {
472
473
474
475 preambleErrors := p.gccErrors([]byte(f.Preamble))
476 if len(preambleErrors) > 0 {
477 error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors)
478 }
479
480 fatalf("unresolved names")
481 }
482
483 return needType
484 }
485
486
487
488
489 func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
490
491
492
493
494
495
496
497
498 var b bytes.Buffer
499 b.WriteString(builtinProlog)
500 b.WriteString(f.Preamble)
501 b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
502 for i, n := range names {
503 fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
504 if n.Kind == "iconst" {
505 fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
506 }
507 }
508
509
510
511 fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
512 for _, n := range names {
513 if n.Kind == "iconst" {
514 fmt.Fprintf(&b, "\t%s,\n", n.C)
515 } else {
516 fmt.Fprintf(&b, "\t0,\n")
517 }
518 }
519
520
521
522
523
524 fmt.Fprintf(&b, "\t1\n")
525 fmt.Fprintf(&b, "};\n")
526
527
528 fmt.Fprintf(&b, "double __cgodebug_floats[] = {\n")
529 for _, n := range names {
530 if n.Kind == "fconst" {
531 fmt.Fprintf(&b, "\t%s,\n", n.C)
532 } else {
533 fmt.Fprintf(&b, "\t0,\n")
534 }
535 }
536 fmt.Fprintf(&b, "\t1\n")
537 fmt.Fprintf(&b, "};\n")
538
539
540 for i, n := range names {
541 if n.Kind == "sconst" {
542 fmt.Fprintf(&b, "const char __cgodebug_str__%d[] = %s;\n", i, n.C)
543 fmt.Fprintf(&b, "const unsigned long long __cgodebug_strlen__%d = sizeof(%s)-1;\n", i, n.C)
544 }
545 }
546
547 d, ints, floats, strs := p.gccDebug(b.Bytes(), len(names))
548
549
550 types := make([]dwarf.Type, len(names))
551 r := d.Reader()
552 for {
553 e, err := r.Next()
554 if err != nil {
555 fatalf("reading DWARF entry: %s", err)
556 }
557 if e == nil {
558 break
559 }
560 switch e.Tag {
561 case dwarf.TagVariable:
562 name, _ := e.Val(dwarf.AttrName).(string)
563 typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
564 if name == "" || typOff == 0 {
565 if e.Val(dwarf.AttrSpecification) != nil {
566
567
568 break
569 }
570 fatalf("malformed DWARF TagVariable entry")
571 }
572 if !strings.HasPrefix(name, "__cgo__") {
573 break
574 }
575 typ, err := d.Type(typOff)
576 if err != nil {
577 fatalf("loading DWARF type: %s", err)
578 }
579 t, ok := typ.(*dwarf.PtrType)
580 if !ok || t == nil {
581 fatalf("internal error: %s has non-pointer type", name)
582 }
583 i, err := strconv.Atoi(name[7:])
584 if err != nil {
585 fatalf("malformed __cgo__ name: %s", name)
586 }
587 types[i] = t.Type
588 p.recordTypedefs(t.Type, f.NamePos[names[i]])
589 }
590 if e.Tag != dwarf.TagCompileUnit {
591 r.SkipChildren()
592 }
593 }
594
595
596 for i, n := range names {
597 if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
598 conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
599 }
600 }
601 for i, n := range names {
602 if types[i] == nil {
603 continue
604 }
605 pos := f.NamePos[n]
606 f, fok := types[i].(*dwarf.FuncType)
607 if n.Kind != "type" && fok {
608 n.Kind = "func"
609 n.FuncType = conv.FuncType(f, pos)
610 } else {
611 n.Type = conv.Type(types[i], pos)
612 switch n.Kind {
613 case "iconst":
614 if i < len(ints) {
615 if _, ok := types[i].(*dwarf.UintType); ok {
616 n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
617 } else {
618 n.Const = fmt.Sprintf("%#x", ints[i])
619 }
620 }
621 case "fconst":
622 if i >= len(floats) {
623 break
624 }
625 switch base(types[i]).(type) {
626 case *dwarf.IntType, *dwarf.UintType:
627
628
629
630
631
632
633
634
635
636
637
638
639 n.Kind = "var"
640 default:
641 n.Const = fmt.Sprintf("%f", floats[i])
642 }
643 case "sconst":
644 if i < len(strs) {
645 n.Const = fmt.Sprintf("%q", strs[i])
646 }
647 }
648 }
649 conv.FinishType(pos)
650 }
651 }
652
653
654 func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) {
655 p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{})
656 }
657
658 func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) {
659 if dtype == nil {
660 return
661 }
662 if visited[dtype] {
663 return
664 }
665 visited[dtype] = true
666 switch dt := dtype.(type) {
667 case *dwarf.TypedefType:
668 if strings.HasPrefix(dt.Name, "__builtin") {
669
670 return
671 }
672 if !p.typedefs[dt.Name] {
673 p.typedefs[dt.Name] = true
674 p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos})
675 p.recordTypedefs1(dt.Type, pos, visited)
676 }
677 case *dwarf.PtrType:
678 p.recordTypedefs1(dt.Type, pos, visited)
679 case *dwarf.ArrayType:
680 p.recordTypedefs1(dt.Type, pos, visited)
681 case *dwarf.QualType:
682 p.recordTypedefs1(dt.Type, pos, visited)
683 case *dwarf.FuncType:
684 p.recordTypedefs1(dt.ReturnType, pos, visited)
685 for _, a := range dt.ParamType {
686 p.recordTypedefs1(a, pos, visited)
687 }
688 case *dwarf.StructType:
689 for _, f := range dt.Field {
690 p.recordTypedefs1(f.Type, pos, visited)
691 }
692 }
693 }
694
695
696
697 func (p *Package) prepareNames(f *File) {
698 for _, n := range f.Name {
699 if n.Kind == "not-type" {
700 if n.Define == "" {
701 n.Kind = "var"
702 } else {
703 n.Kind = "macro"
704 n.FuncType = &FuncType{
705 Result: n.Type,
706 Go: &ast.FuncType{
707 Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
708 },
709 }
710 }
711 }
712 p.mangleName(n)
713 }
714 }
715
716
717
718
719 func (p *Package) mangleName(n *Name) {
720
721
722
723 prefix := "_C"
724 if *gccgo && n.IsVar() {
725 prefix = "C"
726 }
727 n.Mangle = prefix + n.Kind + "_" + n.Go
728 }
729
730 func (f *File) isMangledName(s string) bool {
731 prefix := "_C"
732 if strings.HasPrefix(s, prefix) {
733 t := s[len(prefix):]
734 for _, k := range nameKinds {
735 if strings.HasPrefix(t, k+"_") {
736 return true
737 }
738 }
739 }
740 return false
741 }
742
743
744
745
746 func (p *Package) rewriteCalls(f *File) bool {
747 needsUnsafe := false
748
749 for _, call := range f.Calls {
750 if call.Done {
751 continue
752 }
753 start := f.offset(call.Call.Pos())
754 end := f.offset(call.Call.End())
755 str, nu := p.rewriteCall(f, call)
756 if str != "" {
757 f.Edit.Replace(start, end, str)
758 if nu {
759 needsUnsafe = true
760 }
761 }
762 }
763 return needsUnsafe
764 }
765
766
767
768
769
770
771
772
773 func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
774
775
776 var goname string
777 switch fun := call.Call.Fun.(type) {
778 case *ast.SelectorExpr:
779 goname = fun.Sel.Name
780 case *ast.Ident:
781 goname = strings.TrimPrefix(fun.Name, "_C2func_")
782 goname = strings.TrimPrefix(goname, "_Cfunc_")
783 }
784 if goname == "" || goname == "malloc" {
785 return "", false
786 }
787 name := f.Name[goname]
788 if name == nil || name.Kind != "func" {
789
790 return "", false
791 }
792
793 params := name.FuncType.Params
794 args := call.Call.Args
795
796
797
798
799 if len(args) != len(params) {
800 return "", false
801 }
802
803 any := false
804 for i, param := range params {
805 if p.needsPointerCheck(f, param.Go, args[i]) {
806 any = true
807 break
808 }
809 }
810 if !any {
811 return "", false
812 }
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844 var sb bytes.Buffer
845 sb.WriteString("func() ")
846 if call.Deferred {
847 sb.WriteString("func() ")
848 }
849
850 needsUnsafe := false
851 result := false
852 twoResults := false
853 if !call.Deferred {
854
855 for _, ref := range f.Ref {
856 if ref.Expr != &call.Call.Fun {
857 continue
858 }
859 if ref.Context == ctxCall2 {
860 sb.WriteString("(")
861 result = true
862 twoResults = true
863 }
864 break
865 }
866
867
868 if name.FuncType.Result != nil {
869 rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
870 if rtype != name.FuncType.Result.Go {
871 needsUnsafe = true
872 }
873 sb.WriteString(gofmtLine(rtype))
874 result = true
875 }
876
877
878 if twoResults {
879 if name.FuncType.Result == nil {
880
881
882 sb.WriteString("_Ctype_void")
883 }
884 sb.WriteString(", error)")
885 }
886 }
887
888 sb.WriteString("{ ")
889
890
891
892 var sbCheck bytes.Buffer
893 for i, param := range params {
894 origArg := args[i]
895 arg, nu := p.mangle(f, &args[i])
896 if nu {
897 needsUnsafe = true
898 }
899
900
901
902 ptype := p.rewriteUnsafe(param.Go)
903
904 if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer {
905 if ptype != param.Go {
906 needsUnsafe = true
907 }
908 fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
909 gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
910 continue
911 }
912
913
914 if p.checkIndex(&sb, &sbCheck, arg, i) {
915 continue
916 }
917
918
919 if p.checkAddr(&sb, &sbCheck, arg, i) {
920 continue
921 }
922
923 fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
924 fmt.Fprintf(&sbCheck, "_cgoCheckPointer(_cgo%d); ", i)
925 }
926
927 if call.Deferred {
928 sb.WriteString("return func() { ")
929 }
930
931
932 sb.WriteString(sbCheck.String())
933
934 if result {
935 sb.WriteString("return ")
936 }
937
938 m, nu := p.mangle(f, &call.Call.Fun)
939 if nu {
940 needsUnsafe = true
941 }
942 sb.WriteString(gofmtLine(m))
943
944 sb.WriteString("(")
945 for i := range params {
946 if i > 0 {
947 sb.WriteString(", ")
948 }
949 fmt.Fprintf(&sb, "_cgo%d", i)
950 }
951 sb.WriteString("); ")
952 if call.Deferred {
953 sb.WriteString("}")
954 }
955 sb.WriteString("}")
956 if call.Deferred {
957 sb.WriteString("()")
958 }
959 sb.WriteString("()")
960
961 return sb.String(), needsUnsafe
962 }
963
964
965
966
967 func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
968
969
970
971
972 if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
973 return false
974 }
975
976 return p.hasPointer(f, t, true)
977 }
978
979
980
981
982
983 func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
984 switch t := t.(type) {
985 case *ast.ArrayType:
986 if t.Len == nil {
987 if !top {
988 return true
989 }
990 return p.hasPointer(f, t.Elt, false)
991 }
992 return p.hasPointer(f, t.Elt, top)
993 case *ast.StructType:
994 for _, field := range t.Fields.List {
995 if p.hasPointer(f, field.Type, top) {
996 return true
997 }
998 }
999 return false
1000 case *ast.StarExpr:
1001 if !top {
1002 return true
1003 }
1004
1005
1006 if unionWithPointer[t.X] {
1007 return true
1008 }
1009 return p.hasPointer(f, t.X, false)
1010 case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
1011 return true
1012 case *ast.Ident:
1013
1014 for _, d := range p.Decl {
1015 gd, ok := d.(*ast.GenDecl)
1016 if !ok || gd.Tok != token.TYPE {
1017 continue
1018 }
1019 for _, spec := range gd.Specs {
1020 ts, ok := spec.(*ast.TypeSpec)
1021 if !ok {
1022 continue
1023 }
1024 if ts.Name.Name == t.Name {
1025 return p.hasPointer(f, ts.Type, top)
1026 }
1027 }
1028 }
1029 if def := typedef[t.Name]; def != nil {
1030 return p.hasPointer(f, def.Go, top)
1031 }
1032 if t.Name == "string" {
1033 return !top
1034 }
1035 if t.Name == "error" {
1036 return true
1037 }
1038 if goTypes[t.Name] != nil {
1039 return false
1040 }
1041
1042
1043 return true
1044 case *ast.SelectorExpr:
1045 if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" {
1046
1047
1048
1049 return true
1050 }
1051 if f == nil {
1052
1053 return true
1054 }
1055 name := f.Name[t.Sel.Name]
1056 if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
1057 return p.hasPointer(f, name.Type.Go, top)
1058 }
1059
1060
1061 return true
1062 default:
1063 error_(t.Pos(), "could not understand type %s", gofmt(t))
1064 return true
1065 }
1066 }
1067
1068
1069
1070
1071
1072 func (p *Package) mangle(f *File, arg *ast.Expr) (ast.Expr, bool) {
1073 needsUnsafe := false
1074 f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
1075 px, ok := arg.(*ast.Expr)
1076 if !ok {
1077 return
1078 }
1079 sel, ok := (*px).(*ast.SelectorExpr)
1080 if ok {
1081 if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
1082 return
1083 }
1084
1085 for _, r := range f.Ref {
1086 if r.Expr == px {
1087 *px = p.rewriteName(f, r)
1088 r.Done = true
1089 break
1090 }
1091 }
1092
1093 return
1094 }
1095
1096 call, ok := (*px).(*ast.CallExpr)
1097 if !ok {
1098 return
1099 }
1100
1101 for _, c := range f.Calls {
1102 if !c.Done && c.Call.Lparen == call.Lparen {
1103 cstr, nu := p.rewriteCall(f, c)
1104 if cstr != "" {
1105
1106 *px = ast.NewIdent(cstr)
1107 if nu {
1108 needsUnsafe = true
1109 }
1110 c.Done = true
1111 }
1112 }
1113 }
1114 })
1115 return *arg, needsUnsafe
1116 }
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
1133
1134 x := arg
1135 for {
1136 c, ok := x.(*ast.CallExpr)
1137 if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
1138 break
1139 }
1140 x = c.Args[0]
1141 }
1142 u, ok := x.(*ast.UnaryExpr)
1143 if !ok || u.Op != token.AND {
1144 return false
1145 }
1146 index, ok := u.X.(*ast.IndexExpr)
1147 if !ok {
1148 return false
1149 }
1150
1151 addr := ""
1152 deref := ""
1153 if p.isVariable(index.X) {
1154 addr = "&"
1155 deref = "*"
1156 }
1157
1158 fmt.Fprintf(sb, "_cgoIndex%d := %s%s; ", i, addr, gofmtPos(index.X, index.X.Pos()))
1159 origX := index.X
1160 index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i))
1161 if deref == "*" {
1162 index.X = &ast.StarExpr{X: index.X}
1163 }
1164 fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
1165 index.X = origX
1166
1167 fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, %s_cgoIndex%d); ", i, deref, i)
1168
1169 return true
1170 }
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182 func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
1183
1184 px := &arg
1185 for {
1186 c, ok := (*px).(*ast.CallExpr)
1187 if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
1188 break
1189 }
1190 px = &c.Args[0]
1191 }
1192 if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND {
1193 return false
1194 }
1195
1196 fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
1197
1198 origX := *px
1199 *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i))
1200 fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
1201 *px = origX
1202
1203
1204
1205 fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i)
1206
1207 return true
1208 }
1209
1210
1211
1212 func (p *Package) isType(t ast.Expr) bool {
1213 switch t := t.(type) {
1214 case *ast.SelectorExpr:
1215 id, ok := t.X.(*ast.Ident)
1216 if !ok {
1217 return false
1218 }
1219 if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
1220 return true
1221 }
1222 if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
1223 return true
1224 }
1225 return false
1226 case *ast.Ident:
1227
1228 switch t.Name {
1229 case "unsafe.Pointer", "bool", "byte",
1230 "complex64", "complex128",
1231 "error",
1232 "float32", "float64",
1233 "int", "int8", "int16", "int32", "int64",
1234 "rune", "string",
1235 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
1236
1237 return true
1238 }
1239 if strings.HasPrefix(t.Name, "_Ctype_") {
1240 return true
1241 }
1242 case *ast.ParenExpr:
1243 return p.isType(t.X)
1244 case *ast.StarExpr:
1245 return p.isType(t.X)
1246 case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
1247 *ast.MapType, *ast.ChanType:
1248
1249 return true
1250 }
1251 return false
1252 }
1253
1254
1255 func (p *Package) isVariable(x ast.Expr) bool {
1256 switch x := x.(type) {
1257 case *ast.Ident:
1258 return true
1259 case *ast.SelectorExpr:
1260 return p.isVariable(x.X)
1261 case *ast.IndexExpr:
1262 return true
1263 }
1264 return false
1265 }
1266
1267
1268
1269 func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
1270 switch t := t.(type) {
1271 case *ast.Ident:
1272
1273
1274 if t.Name == "unsafe.Pointer" {
1275 return ast.NewIdent("_cgo_unsafe.Pointer")
1276 }
1277 case *ast.ArrayType:
1278 t1 := p.rewriteUnsafe(t.Elt)
1279 if t1 != t.Elt {
1280 r := *t
1281 r.Elt = t1
1282 return &r
1283 }
1284 case *ast.StructType:
1285 changed := false
1286 fields := *t.Fields
1287 fields.List = nil
1288 for _, f := range t.Fields.List {
1289 ft := p.rewriteUnsafe(f.Type)
1290 if ft == f.Type {
1291 fields.List = append(fields.List, f)
1292 } else {
1293 fn := *f
1294 fn.Type = ft
1295 fields.List = append(fields.List, &fn)
1296 changed = true
1297 }
1298 }
1299 if changed {
1300 r := *t
1301 r.Fields = &fields
1302 return &r
1303 }
1304 case *ast.StarExpr:
1305 x1 := p.rewriteUnsafe(t.X)
1306 if x1 != t.X {
1307 r := *t
1308 r.X = x1
1309 return &r
1310 }
1311 }
1312 return t
1313 }
1314
1315
1316
1317
1318
1319 func (p *Package) rewriteRef(f *File) {
1320
1321
1322
1323 functions := make(map[string]bool)
1324
1325 for _, n := range f.Name {
1326 if n.Kind == "func" {
1327 functions[n.Go] = false
1328 }
1329 }
1330
1331
1332
1333
1334
1335 for _, r := range f.Ref {
1336 if r.Name.IsConst() && r.Name.Const == "" {
1337 error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
1338 }
1339
1340 if r.Name.Kind == "func" {
1341 switch r.Context {
1342 case ctxCall, ctxCall2:
1343 functions[r.Name.Go] = true
1344 }
1345 }
1346
1347 expr := p.rewriteName(f, r)
1348
1349 if *godefs {
1350
1351 if id, ok := expr.(*ast.Ident); ok {
1352 if t := typedef[id.Name]; t != nil {
1353 expr = t.Go
1354 }
1355 if id.Name == r.Name.Mangle && r.Name.Const != "" {
1356 expr = ast.NewIdent(r.Name.Const)
1357 }
1358 }
1359 }
1360
1361
1362
1363
1364 pos := (*r.Expr).Pos()
1365 if x, ok := expr.(*ast.Ident); ok {
1366 expr = &ast.Ident{NamePos: pos, Name: x.Name}
1367 }
1368
1369
1370
1371 old := *r.Expr
1372 *r.Expr = expr
1373
1374
1375 if !r.Done {
1376
1377
1378 repl := " " + gofmtPos(expr, old.Pos())
1379 end := fset.Position(old.End())
1380
1381
1382
1383 sub := 0
1384 if r.Name.Kind != "type" {
1385 sub = 1
1386 }
1387 if end.Column > sub {
1388 repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub)
1389 }
1390 if r.Name.Kind != "type" {
1391 repl = "(" + repl + ")"
1392 }
1393 f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
1394 }
1395 }
1396
1397
1398
1399 for name, used := range functions {
1400 if !used {
1401 delete(f.Name, name)
1402 }
1403 }
1404 }
1405
1406
1407 func (p *Package) rewriteName(f *File, r *Ref) ast.Expr {
1408 var expr ast.Expr = ast.NewIdent(r.Name.Mangle)
1409 switch r.Context {
1410 case ctxCall, ctxCall2:
1411 if r.Name.Kind != "func" {
1412 if r.Name.Kind == "type" {
1413 r.Context = ctxType
1414 if r.Name.Type == nil {
1415 error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
1416 break
1417 }
1418 expr = r.Name.Type.Go
1419 break
1420 }
1421 error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
1422 break
1423 }
1424 if r.Context == ctxCall2 {
1425 if r.Name.Go == "_CMalloc" {
1426 error_(r.Pos(), "no two-result form for C.malloc")
1427 break
1428 }
1429
1430 n := f.Name["2"+r.Name.Go]
1431 if n == nil {
1432 n = new(Name)
1433 *n = *r.Name
1434 n.AddError = true
1435 n.Mangle = "_C2func_" + n.Go
1436 f.Name["2"+r.Name.Go] = n
1437 }
1438 expr = ast.NewIdent(n.Mangle)
1439 r.Name = n
1440 break
1441 }
1442 case ctxExpr:
1443 switch r.Name.Kind {
1444 case "func":
1445 if builtinDefs[r.Name.C] != "" {
1446 error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
1447 }
1448
1449
1450
1451 fpName := "fp_" + r.Name.Go
1452 name := f.Name[fpName]
1453 if name == nil {
1454 name = &Name{
1455 Go: fpName,
1456 C: r.Name.C,
1457 Kind: "fpvar",
1458 Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
1459 }
1460 p.mangleName(name)
1461 f.Name[fpName] = name
1462 }
1463 r.Name = name
1464
1465
1466
1467 expr = &ast.CallExpr{
1468 Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
1469 Args: []ast.Expr{ast.NewIdent(name.Mangle)},
1470 }
1471 case "type":
1472
1473 if r.Name.Type == nil {
1474 error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
1475 break
1476 }
1477 expr = r.Name.Type.Go
1478 case "var":
1479 expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
1480 case "macro":
1481 expr = &ast.CallExpr{Fun: expr}
1482 }
1483 case ctxSelector:
1484 if r.Name.Kind == "var" {
1485 expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
1486 } else {
1487 error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
1488 }
1489 case ctxType:
1490 if r.Name.Kind != "type" {
1491 error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
1492 } else if r.Name.Type == nil {
1493
1494
1495 error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
1496 } else {
1497 expr = r.Name.Type.Go
1498 }
1499 default:
1500 if r.Name.Kind == "func" {
1501 error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
1502 }
1503 }
1504 return expr
1505 }
1506
1507
1508
1509 func gofmtPos(n ast.Expr, pos token.Pos) string {
1510 s := gofmtLine(n)
1511 p := fset.Position(pos)
1512 if p.Column == 0 {
1513 return s
1514 }
1515 return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
1516 }
1517
1518
1519
1520
1521
1522 func (p *Package) gccBaseCmd() []string {
1523
1524 if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 {
1525 return ret
1526 }
1527
1528 if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 {
1529 return ret
1530 }
1531 return strings.Fields(defaultCC(goos, goarch))
1532 }
1533
1534
1535 func (p *Package) gccMachine() []string {
1536 switch goarch {
1537 case "amd64":
1538 return []string{"-m64"}
1539 case "386":
1540 return []string{"-m32"}
1541 case "arm":
1542 return []string{"-marm"}
1543 case "s390":
1544 return []string{"-m31"}
1545 case "s390x":
1546 return []string{"-m64"}
1547 case "mips64", "mips64le":
1548 return []string{"-mabi=64"}
1549 case "mips", "mipsle":
1550 return []string{"-mabi=32"}
1551 }
1552 return nil
1553 }
1554
1555 func gccTmp() string {
1556 return *objDir + "_cgo_.o"
1557 }
1558
1559
1560
1561 func (p *Package) gccCmd() []string {
1562 c := append(p.gccBaseCmd(),
1563 "-w",
1564 "-Wno-error",
1565 "-o"+gccTmp(),
1566 "-gdwarf-2",
1567 "-c",
1568 "-xc",
1569 )
1570 if p.GccIsClang {
1571 c = append(c,
1572 "-ferror-limit=0",
1573
1574
1575
1576 "-Wno-unknown-warning-option",
1577 "-Wno-unneeded-internal-declaration",
1578 "-Wno-unused-function",
1579 "-Qunused-arguments",
1580
1581
1582
1583
1584
1585
1586 "-fno-builtin",
1587 )
1588 }
1589
1590 c = append(c, p.GccOptions...)
1591 c = append(c, p.gccMachine()...)
1592 if goos == "aix" {
1593 c = append(c, "-maix64")
1594 c = append(c, "-mcmodel=large")
1595 }
1596 c = append(c, "-")
1597 return c
1598 }
1599
1600
1601
1602 func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
1603 runGcc(stdin, p.gccCmd())
1604
1605 isDebugInts := func(s string) bool {
1606
1607 return s == "__cgodebug_ints" || s == "___cgodebug_ints"
1608 }
1609 isDebugFloats := func(s string) bool {
1610
1611 return s == "__cgodebug_floats" || s == "___cgodebug_floats"
1612 }
1613 indexOfDebugStr := func(s string) int {
1614
1615 if strings.HasPrefix(s, "___") {
1616 s = s[1:]
1617 }
1618 if strings.HasPrefix(s, "__cgodebug_str__") {
1619 if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil {
1620 return n
1621 }
1622 }
1623 return -1
1624 }
1625 indexOfDebugStrlen := func(s string) int {
1626
1627 if strings.HasPrefix(s, "___") {
1628 s = s[1:]
1629 }
1630 if strings.HasPrefix(s, "__cgodebug_strlen__") {
1631 if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil {
1632 return n
1633 }
1634 }
1635 return -1
1636 }
1637
1638 strs = make([]string, nnames)
1639
1640 strdata := make(map[int]string, nnames)
1641 strlens := make(map[int]int, nnames)
1642
1643 buildStrings := func() {
1644 for n, strlen := range strlens {
1645 data := strdata[n]
1646 if len(data) <= strlen {
1647 fatalf("invalid string literal")
1648 }
1649 strs[n] = data[:strlen]
1650 }
1651 }
1652
1653 if f, err := macho.Open(gccTmp()); err == nil {
1654 defer f.Close()
1655 d, err := f.DWARF()
1656 if err != nil {
1657 fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
1658 }
1659 bo := f.ByteOrder
1660 if f.Symtab != nil {
1661 for i := range f.Symtab.Syms {
1662 s := &f.Symtab.Syms[i]
1663 switch {
1664 case isDebugInts(s.Name):
1665
1666 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1667 sect := f.Sections[i]
1668 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1669 if sdat, err := sect.Data(); err == nil {
1670 data := sdat[s.Value-sect.Addr:]
1671 ints = make([]int64, len(data)/8)
1672 for i := range ints {
1673 ints[i] = int64(bo.Uint64(data[i*8:]))
1674 }
1675 }
1676 }
1677 }
1678 case isDebugFloats(s.Name):
1679
1680 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1681 sect := f.Sections[i]
1682 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1683 if sdat, err := sect.Data(); err == nil {
1684 data := sdat[s.Value-sect.Addr:]
1685 floats = make([]float64, len(data)/8)
1686 for i := range floats {
1687 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
1688 }
1689 }
1690 }
1691 }
1692 default:
1693 if n := indexOfDebugStr(s.Name); n != -1 {
1694
1695 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1696 sect := f.Sections[i]
1697 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1698 if sdat, err := sect.Data(); err == nil {
1699 data := sdat[s.Value-sect.Addr:]
1700 strdata[n] = string(data)
1701 }
1702 }
1703 }
1704 break
1705 }
1706 if n := indexOfDebugStrlen(s.Name); n != -1 {
1707
1708 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1709 sect := f.Sections[i]
1710 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1711 if sdat, err := sect.Data(); err == nil {
1712 data := sdat[s.Value-sect.Addr:]
1713 strlen := bo.Uint64(data[:8])
1714 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
1715 fatalf("string literal too big")
1716 }
1717 strlens[n] = int(strlen)
1718 }
1719 }
1720 }
1721 break
1722 }
1723 }
1724 }
1725
1726 buildStrings()
1727 }
1728 return d, ints, floats, strs
1729 }
1730
1731 if f, err := elf.Open(gccTmp()); err == nil {
1732 defer f.Close()
1733 d, err := f.DWARF()
1734 if err != nil {
1735 fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
1736 }
1737 bo := f.ByteOrder
1738 symtab, err := f.Symbols()
1739 if err == nil {
1740 for i := range symtab {
1741 s := &symtab[i]
1742 switch {
1743 case isDebugInts(s.Name):
1744
1745 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
1746 sect := f.Sections[i]
1747 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1748 if sdat, err := sect.Data(); err == nil {
1749 data := sdat[s.Value-sect.Addr:]
1750 ints = make([]int64, len(data)/8)
1751 for i := range ints {
1752 ints[i] = int64(bo.Uint64(data[i*8:]))
1753 }
1754 }
1755 }
1756 }
1757 case isDebugFloats(s.Name):
1758
1759 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
1760 sect := f.Sections[i]
1761 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1762 if sdat, err := sect.Data(); err == nil {
1763 data := sdat[s.Value-sect.Addr:]
1764 floats = make([]float64, len(data)/8)
1765 for i := range floats {
1766 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
1767 }
1768 }
1769 }
1770 }
1771 default:
1772 if n := indexOfDebugStr(s.Name); n != -1 {
1773
1774 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
1775 sect := f.Sections[i]
1776 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1777 if sdat, err := sect.Data(); err == nil {
1778 data := sdat[s.Value-sect.Addr:]
1779 strdata[n] = string(data)
1780 }
1781 }
1782 }
1783 break
1784 }
1785 if n := indexOfDebugStrlen(s.Name); n != -1 {
1786
1787 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
1788 sect := f.Sections[i]
1789 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1790 if sdat, err := sect.Data(); err == nil {
1791 data := sdat[s.Value-sect.Addr:]
1792 strlen := bo.Uint64(data[:8])
1793 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
1794 fatalf("string literal too big")
1795 }
1796 strlens[n] = int(strlen)
1797 }
1798 }
1799 }
1800 break
1801 }
1802 }
1803 }
1804
1805 buildStrings()
1806 }
1807 return d, ints, floats, strs
1808 }
1809
1810 if f, err := pe.Open(gccTmp()); err == nil {
1811 defer f.Close()
1812 d, err := f.DWARF()
1813 if err != nil {
1814 fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
1815 }
1816 bo := binary.LittleEndian
1817 for _, s := range f.Symbols {
1818 switch {
1819 case isDebugInts(s.Name):
1820 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1821 sect := f.Sections[i]
1822 if s.Value < sect.Size {
1823 if sdat, err := sect.Data(); err == nil {
1824 data := sdat[s.Value:]
1825 ints = make([]int64, len(data)/8)
1826 for i := range ints {
1827 ints[i] = int64(bo.Uint64(data[i*8:]))
1828 }
1829 }
1830 }
1831 }
1832 case isDebugFloats(s.Name):
1833 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1834 sect := f.Sections[i]
1835 if s.Value < sect.Size {
1836 if sdat, err := sect.Data(); err == nil {
1837 data := sdat[s.Value:]
1838 floats = make([]float64, len(data)/8)
1839 for i := range floats {
1840 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
1841 }
1842 }
1843 }
1844 }
1845 default:
1846 if n := indexOfDebugStr(s.Name); n != -1 {
1847 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1848 sect := f.Sections[i]
1849 if s.Value < sect.Size {
1850 if sdat, err := sect.Data(); err == nil {
1851 data := sdat[s.Value:]
1852 strdata[n] = string(data)
1853 }
1854 }
1855 }
1856 break
1857 }
1858 if n := indexOfDebugStrlen(s.Name); n != -1 {
1859 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1860 sect := f.Sections[i]
1861 if s.Value < sect.Size {
1862 if sdat, err := sect.Data(); err == nil {
1863 data := sdat[s.Value:]
1864 strlen := bo.Uint64(data[:8])
1865 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
1866 fatalf("string literal too big")
1867 }
1868 strlens[n] = int(strlen)
1869 }
1870 }
1871 }
1872 break
1873 }
1874 }
1875 }
1876
1877 buildStrings()
1878
1879 return d, ints, floats, strs
1880 }
1881
1882 if f, err := xcoff.Open(gccTmp()); err == nil {
1883 defer f.Close()
1884 d, err := f.DWARF()
1885 if err != nil {
1886 fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
1887 }
1888 bo := binary.BigEndian
1889 for _, s := range f.Symbols {
1890 switch {
1891 case isDebugInts(s.Name):
1892 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1893 sect := f.Sections[i]
1894 if s.Value < sect.Size {
1895 if sdat, err := sect.Data(); err == nil {
1896 data := sdat[s.Value:]
1897 ints = make([]int64, len(data)/8)
1898 for i := range ints {
1899 ints[i] = int64(bo.Uint64(data[i*8:]))
1900 }
1901 }
1902 }
1903 }
1904 case isDebugFloats(s.Name):
1905 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1906 sect := f.Sections[i]
1907 if s.Value < sect.Size {
1908 if sdat, err := sect.Data(); err == nil {
1909 data := sdat[s.Value:]
1910 floats = make([]float64, len(data)/8)
1911 for i := range floats {
1912 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
1913 }
1914 }
1915 }
1916 }
1917 default:
1918 if n := indexOfDebugStr(s.Name); n != -1 {
1919 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1920 sect := f.Sections[i]
1921 if s.Value < sect.Size {
1922 if sdat, err := sect.Data(); err == nil {
1923 data := sdat[s.Value:]
1924 strdata[n] = string(data)
1925 }
1926 }
1927 }
1928 break
1929 }
1930 if n := indexOfDebugStrlen(s.Name); n != -1 {
1931 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
1932 sect := f.Sections[i]
1933 if s.Value < sect.Size {
1934 if sdat, err := sect.Data(); err == nil {
1935 data := sdat[s.Value:]
1936 strlen := bo.Uint64(data[:8])
1937 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
1938 fatalf("string literal too big")
1939 }
1940 strlens[n] = int(strlen)
1941 }
1942 }
1943 }
1944 break
1945 }
1946 }
1947 }
1948
1949 buildStrings()
1950 return d, ints, floats, strs
1951 }
1952 fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
1953 panic("not reached")
1954 }
1955
1956
1957
1958
1959
1960 func (p *Package) gccDefines(stdin []byte) string {
1961 base := append(p.gccBaseCmd(), "-E", "-dM", "-xc")
1962 base = append(base, p.gccMachine()...)
1963 stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
1964 return stdout
1965 }
1966
1967
1968
1969
1970 func (p *Package) gccErrors(stdin []byte) string {
1971
1972 args := p.gccCmd()
1973
1974
1975 nargs := make([]string, 0, len(args))
1976 for _, arg := range args {
1977 if !strings.HasPrefix(arg, "-O") {
1978 nargs = append(nargs, arg)
1979 }
1980 }
1981
1982
1983 nargs = append(nargs, "-O0")
1984 nl := len(nargs)
1985 nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2]
1986
1987 if *debugGcc {
1988 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
1989 os.Stderr.Write(stdin)
1990 fmt.Fprint(os.Stderr, "EOF\n")
1991 }
1992 stdout, stderr, _ := run(stdin, nargs)
1993 if *debugGcc {
1994 os.Stderr.Write(stdout)
1995 os.Stderr.Write(stderr)
1996 }
1997 return string(stderr)
1998 }
1999
2000
2001
2002
2003
2004
2005
2006 func runGcc(stdin []byte, args []string) (string, string) {
2007 if *debugGcc {
2008 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
2009 os.Stderr.Write(stdin)
2010 fmt.Fprint(os.Stderr, "EOF\n")
2011 }
2012 stdout, stderr, ok := run(stdin, args)
2013 if *debugGcc {
2014 os.Stderr.Write(stdout)
2015 os.Stderr.Write(stderr)
2016 }
2017 if !ok {
2018 os.Stderr.Write(stderr)
2019 os.Exit(2)
2020 }
2021 return string(stdout), string(stderr)
2022 }
2023
2024
2025
2026 type typeConv struct {
2027
2028 m map[string]*Type
2029
2030
2031 ptrs map[string][]*Type
2032
2033
2034 ptrKeys []dwarf.Type
2035
2036
2037 getTypeIDs map[string]bool
2038
2039
2040 bool ast.Expr
2041 byte ast.Expr
2042 int8, int16, int32, int64 ast.Expr
2043 uint8, uint16, uint32, uint64, uintptr ast.Expr
2044 float32, float64 ast.Expr
2045 complex64, complex128 ast.Expr
2046 void ast.Expr
2047 string ast.Expr
2048 goVoid ast.Expr
2049 goVoidPtr ast.Expr
2050
2051 ptrSize int64
2052 intSize int64
2053 }
2054
2055 var tagGen int
2056 var typedef = make(map[string]*Type)
2057 var goIdent = make(map[string]*ast.Ident)
2058
2059
2060
2061 var unionWithPointer = make(map[ast.Expr]bool)
2062
2063 func (c *typeConv) Init(ptrSize, intSize int64) {
2064 c.ptrSize = ptrSize
2065 c.intSize = intSize
2066 c.m = make(map[string]*Type)
2067 c.ptrs = make(map[string][]*Type)
2068 c.getTypeIDs = make(map[string]bool)
2069 c.bool = c.Ident("bool")
2070 c.byte = c.Ident("byte")
2071 c.int8 = c.Ident("int8")
2072 c.int16 = c.Ident("int16")
2073 c.int32 = c.Ident("int32")
2074 c.int64 = c.Ident("int64")
2075 c.uint8 = c.Ident("uint8")
2076 c.uint16 = c.Ident("uint16")
2077 c.uint32 = c.Ident("uint32")
2078 c.uint64 = c.Ident("uint64")
2079 c.uintptr = c.Ident("uintptr")
2080 c.float32 = c.Ident("float32")
2081 c.float64 = c.Ident("float64")
2082 c.complex64 = c.Ident("complex64")
2083 c.complex128 = c.Ident("complex128")
2084 c.void = c.Ident("void")
2085 c.string = c.Ident("string")
2086 c.goVoid = c.Ident("_Ctype_void")
2087
2088
2089
2090 if *godefs {
2091 c.goVoidPtr = &ast.StarExpr{X: c.byte}
2092 } else {
2093 c.goVoidPtr = c.Ident("unsafe.Pointer")
2094 }
2095 }
2096
2097
2098 func base(dt dwarf.Type) dwarf.Type {
2099 for {
2100 if d, ok := dt.(*dwarf.QualType); ok {
2101 dt = d.Type
2102 continue
2103 }
2104 if d, ok := dt.(*dwarf.TypedefType); ok {
2105 dt = d.Type
2106 continue
2107 }
2108 break
2109 }
2110 return dt
2111 }
2112
2113
2114
2115 func unqual(dt dwarf.Type) dwarf.Type {
2116 for {
2117 if d, ok := dt.(*dwarf.QualType); ok {
2118 dt = d.Type
2119 } else {
2120 break
2121 }
2122 }
2123 return dt
2124 }
2125
2126
2127 var dwarfToName = map[string]string{
2128 "long int": "long",
2129 "long unsigned int": "ulong",
2130 "unsigned int": "uint",
2131 "short unsigned int": "ushort",
2132 "unsigned short": "ushort",
2133 "short int": "short",
2134 "long long int": "longlong",
2135 "long long unsigned int": "ulonglong",
2136 "signed char": "schar",
2137 "unsigned char": "uchar",
2138 }
2139
2140 const signedDelta = 64
2141
2142
2143
2144
2145 func (tr *TypeRepr) String() string {
2146 if len(tr.Repr) == 0 {
2147 return ""
2148 }
2149 if len(tr.FormatArgs) == 0 {
2150 return tr.Repr
2151 }
2152 return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
2153 }
2154
2155
2156 func (tr *TypeRepr) Empty() bool {
2157 return len(tr.Repr) == 0
2158 }
2159
2160
2161
2162
2163 func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
2164 tr.Repr = repr
2165 tr.FormatArgs = fargs
2166 }
2167
2168
2169
2170 func (c *typeConv) FinishType(pos token.Pos) {
2171
2172
2173 for len(c.ptrKeys) > 0 {
2174 dtype := c.ptrKeys[0]
2175 dtypeKey := dtype.String()
2176 c.ptrKeys = c.ptrKeys[1:]
2177 ptrs := c.ptrs[dtypeKey]
2178 delete(c.ptrs, dtypeKey)
2179
2180
2181 t := c.Type(dtype, pos)
2182 for _, ptr := range ptrs {
2183 ptr.Go.(*ast.StarExpr).X = t.Go
2184 ptr.C.Set("%s*", t.C)
2185 }
2186 }
2187 }
2188
2189
2190
2191 func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
2192
2193
2194 checkCache := true
2195 if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
2196 checkCache = false
2197 }
2198
2199 key := dtype.String()
2200
2201 if checkCache {
2202 if t, ok := c.m[key]; ok {
2203 if t.Go == nil {
2204 fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
2205 }
2206 return t
2207 }
2208 }
2209
2210 t := new(Type)
2211 t.Size = dtype.Size()
2212 t.Align = -1
2213 t.C = &TypeRepr{Repr: dtype.Common().Name}
2214 c.m[key] = t
2215
2216 switch dt := dtype.(type) {
2217 default:
2218 fatalf("%s: unexpected type: %s", lineno(pos), dtype)
2219
2220 case *dwarf.AddrType:
2221 if t.Size != c.ptrSize {
2222 fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
2223 }
2224 t.Go = c.uintptr
2225 t.Align = t.Size
2226
2227 case *dwarf.ArrayType:
2228 if dt.StrideBitSize > 0 {
2229
2230 t.Go = c.Opaque(t.Size)
2231 break
2232 }
2233 count := dt.Count
2234 if count == -1 {
2235
2236
2237 count = 0
2238 }
2239 sub := c.Type(dt.Type, pos)
2240 t.Align = sub.Align
2241 t.Go = &ast.ArrayType{
2242 Len: c.intExpr(count),
2243 Elt: sub.Go,
2244 }
2245
2246 t.Size = count * sub.Size
2247 t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
2248
2249 case *dwarf.BoolType:
2250 t.Go = c.bool
2251 t.Align = 1
2252
2253 case *dwarf.CharType:
2254 if t.Size != 1 {
2255 fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
2256 }
2257 t.Go = c.int8
2258 t.Align = 1
2259
2260 case *dwarf.EnumType:
2261 if t.Align = t.Size; t.Align >= c.ptrSize {
2262 t.Align = c.ptrSize
2263 }
2264 t.C.Set("enum " + dt.EnumName)
2265 signed := 0
2266 t.EnumValues = make(map[string]int64)
2267 for _, ev := range dt.Val {
2268 t.EnumValues[ev.Name] = ev.Val
2269 if ev.Val < 0 {
2270 signed = signedDelta
2271 }
2272 }
2273 switch t.Size + int64(signed) {
2274 default:
2275 fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
2276 case 1:
2277 t.Go = c.uint8
2278 case 2:
2279 t.Go = c.uint16
2280 case 4:
2281 t.Go = c.uint32
2282 case 8:
2283 t.Go = c.uint64
2284 case 1 + signedDelta:
2285 t.Go = c.int8
2286 case 2 + signedDelta:
2287 t.Go = c.int16
2288 case 4 + signedDelta:
2289 t.Go = c.int32
2290 case 8 + signedDelta:
2291 t.Go = c.int64
2292 }
2293
2294 case *dwarf.FloatType:
2295 switch t.Size {
2296 default:
2297 fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
2298 case 4:
2299 t.Go = c.float32
2300 case 8:
2301 t.Go = c.float64
2302 }
2303 if t.Align = t.Size; t.Align >= c.ptrSize {
2304 t.Align = c.ptrSize
2305 }
2306
2307 case *dwarf.ComplexType:
2308 switch t.Size {
2309 default:
2310 fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
2311 case 8:
2312 t.Go = c.complex64
2313 case 16:
2314 t.Go = c.complex128
2315 }
2316 if t.Align = t.Size / 2; t.Align >= c.ptrSize {
2317 t.Align = c.ptrSize
2318 }
2319
2320 case *dwarf.FuncType:
2321
2322
2323 t.Go = c.uintptr
2324 t.Align = c.ptrSize
2325
2326 case *dwarf.IntType:
2327 if dt.BitSize > 0 {
2328 fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
2329 }
2330 switch t.Size {
2331 default:
2332 fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
2333 case 1:
2334 t.Go = c.int8
2335 case 2:
2336 t.Go = c.int16
2337 case 4:
2338 t.Go = c.int32
2339 case 8:
2340 t.Go = c.int64
2341 case 16:
2342 t.Go = &ast.ArrayType{
2343 Len: c.intExpr(t.Size),
2344 Elt: c.uint8,
2345 }
2346 }
2347 if t.Align = t.Size; t.Align >= c.ptrSize {
2348 t.Align = c.ptrSize
2349 }
2350
2351 case *dwarf.PtrType:
2352
2353 if t.Size != c.ptrSize && t.Size != -1 {
2354 fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
2355 }
2356 t.Size = c.ptrSize
2357 t.Align = c.ptrSize
2358
2359 if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
2360 t.Go = c.goVoidPtr
2361 t.C.Set("void*")
2362 dq := dt.Type
2363 for {
2364 if d, ok := dq.(*dwarf.QualType); ok {
2365 t.C.Set(d.Qual + " " + t.C.String())
2366 dq = d.Type
2367 } else {
2368 break
2369 }
2370 }
2371 break
2372 }
2373
2374
2375 t.Go = &ast.StarExpr{}
2376 t.C.Set("<incomplete>*")
2377 key := dt.Type.String()
2378 if _, ok := c.ptrs[key]; !ok {
2379 c.ptrKeys = append(c.ptrKeys, dt.Type)
2380 }
2381 c.ptrs[key] = append(c.ptrs[key], t)
2382
2383 case *dwarf.QualType:
2384 t1 := c.Type(dt.Type, pos)
2385 t.Size = t1.Size
2386 t.Align = t1.Align
2387 t.Go = t1.Go
2388 if unionWithPointer[t1.Go] {
2389 unionWithPointer[t.Go] = true
2390 }
2391 t.EnumValues = nil
2392 t.Typedef = ""
2393 t.C.Set("%s "+dt.Qual, t1.C)
2394 return t
2395
2396 case *dwarf.StructType:
2397
2398
2399 tag := dt.StructName
2400 if dt.ByteSize < 0 && tag == "" {
2401 break
2402 }
2403 if tag == "" {
2404 tag = "__" + strconv.Itoa(tagGen)
2405 tagGen++
2406 } else if t.C.Empty() {
2407 t.C.Set(dt.Kind + " " + tag)
2408 }
2409 name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
2410 t.Go = name
2411 goIdent[name.Name] = name
2412 if dt.ByteSize < 0 {
2413
2414
2415
2416 tt := *t
2417 tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
2418 tt.Go = c.Ident("struct{}")
2419 typedef[name.Name] = &tt
2420 break
2421 }
2422 switch dt.Kind {
2423 case "class", "union":
2424 t.Go = c.Opaque(t.Size)
2425 if c.dwarfHasPointer(dt, pos) {
2426 unionWithPointer[t.Go] = true
2427 }
2428 if t.C.Empty() {
2429 t.C.Set("__typeof__(unsigned char[%d])", t.Size)
2430 }
2431 t.Align = 1
2432 typedef[name.Name] = t
2433 case "struct":
2434 g, csyntax, align := c.Struct(dt, pos)
2435 if t.C.Empty() {
2436 t.C.Set(csyntax)
2437 }
2438 t.Align = align
2439 tt := *t
2440 if tag != "" {
2441 tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
2442 }
2443 tt.Go = g
2444 typedef[name.Name] = &tt
2445 }
2446
2447 case *dwarf.TypedefType:
2448
2449 if dt.Name == "_GoString_" {
2450
2451
2452
2453 t.Go = c.string
2454 t.Size = c.ptrSize * 2
2455 t.Align = c.ptrSize
2456 break
2457 }
2458 if dt.Name == "_GoBytes_" {
2459
2460
2461 t.Go = c.Ident("[]byte")
2462 t.Size = c.ptrSize + 4 + 4
2463 t.Align = c.ptrSize
2464 break
2465 }
2466 name := c.Ident("_Ctype_" + dt.Name)
2467 goIdent[name.Name] = name
2468 sub := c.Type(dt.Type, pos)
2469 if c.badPointerTypedef(dt) {
2470
2471 s := *sub
2472 s.Go = c.uintptr
2473 s.BadPointer = true
2474 sub = &s
2475
2476 if oldType := typedef[name.Name]; oldType != nil {
2477 oldType.Go = sub.Go
2478 oldType.BadPointer = true
2479 }
2480 }
2481 t.Go = name
2482 t.BadPointer = sub.BadPointer
2483 if unionWithPointer[sub.Go] {
2484 unionWithPointer[t.Go] = true
2485 }
2486 t.Size = sub.Size
2487 t.Align = sub.Align
2488 oldType := typedef[name.Name]
2489 if oldType == nil {
2490 tt := *t
2491 tt.Go = sub.Go
2492 tt.BadPointer = sub.BadPointer
2493 typedef[name.Name] = &tt
2494 }
2495
2496
2497
2498
2499
2500 if isStructUnionClass(sub.Go) || *godefs {
2501 t.Go = sub.Go
2502
2503 if isStructUnionClass(sub.Go) {
2504
2505 typedef[sub.Go.(*ast.Ident).Name].C = t.C
2506 }
2507
2508
2509
2510
2511
2512
2513 if oldType != nil && isStructUnionClass(oldType.Go) {
2514 t.Go = oldType.Go
2515 }
2516 }
2517
2518 case *dwarf.UcharType:
2519 if t.Size != 1 {
2520 fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
2521 }
2522 t.Go = c.uint8
2523 t.Align = 1
2524
2525 case *dwarf.UintType:
2526 if dt.BitSize > 0 {
2527 fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
2528 }
2529 switch t.Size {
2530 default:
2531 fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
2532 case 1:
2533 t.Go = c.uint8
2534 case 2:
2535 t.Go = c.uint16
2536 case 4:
2537 t.Go = c.uint32
2538 case 8:
2539 t.Go = c.uint64
2540 case 16:
2541 t.Go = &ast.ArrayType{
2542 Len: c.intExpr(t.Size),
2543 Elt: c.uint8,
2544 }
2545 }
2546 if t.Align = t.Size; t.Align >= c.ptrSize {
2547 t.Align = c.ptrSize
2548 }
2549
2550 case *dwarf.VoidType:
2551 t.Go = c.goVoid
2552 t.C.Set("void")
2553 t.Align = 1
2554 }
2555
2556 switch dtype.(type) {
2557 case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
2558 s := dtype.Common().Name
2559 if s != "" {
2560 if ss, ok := dwarfToName[s]; ok {
2561 s = ss
2562 }
2563 s = strings.Replace(s, " ", "", -1)
2564 name := c.Ident("_Ctype_" + s)
2565 tt := *t
2566 typedef[name.Name] = &tt
2567 if !*godefs {
2568 t.Go = name
2569 }
2570 }
2571 }
2572
2573 if t.Size < 0 {
2574
2575
2576
2577 t.Size = 0
2578 switch dt := dtype.(type) {
2579 case *dwarf.TypedefType:
2580
2581 case *dwarf.StructType:
2582 if dt.StructName != "" {
2583 break
2584 }
2585 t.Go = c.Opaque(0)
2586 default:
2587 t.Go = c.Opaque(0)
2588 }
2589 if t.C.Empty() {
2590 t.C.Set("void")
2591 }
2592 }
2593
2594 if t.C.Empty() {
2595 fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
2596 }
2597
2598 return t
2599 }
2600
2601
2602
2603 func isStructUnionClass(x ast.Expr) bool {
2604 id, ok := x.(*ast.Ident)
2605 if !ok {
2606 return false
2607 }
2608 name := id.Name
2609 return strings.HasPrefix(name, "_Ctype_struct_") ||
2610 strings.HasPrefix(name, "_Ctype_union_") ||
2611 strings.HasPrefix(name, "_Ctype_class_")
2612 }
2613
2614
2615
2616 func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
2617 t := c.Type(unqual(dtype), pos)
2618 switch dt := dtype.(type) {
2619 case *dwarf.ArrayType:
2620
2621
2622 tr := &TypeRepr{}
2623 tr.Set("%s*", t.C)
2624 return &Type{
2625 Size: c.ptrSize,
2626 Align: c.ptrSize,
2627 Go: &ast.StarExpr{X: t.Go},
2628 C: tr,
2629 }
2630 case *dwarf.TypedefType:
2631
2632
2633
2634
2635 if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
2636
2637
2638 if _, void := base(ptr.Type).(*dwarf.VoidType); void {
2639 break
2640 }
2641
2642
2643 if c.baseBadPointerTypedef(dt) {
2644 break
2645 }
2646
2647 t = c.Type(ptr, pos)
2648 if t == nil {
2649 return nil
2650 }
2651
2652
2653
2654
2655 if isStructUnionClass(t.Go) {
2656 t.Typedef = dt.Name
2657 }
2658 }
2659 }
2660 return t
2661 }
2662
2663
2664
2665 func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
2666 p := make([]*Type, len(dtype.ParamType))
2667 gp := make([]*ast.Field, len(dtype.ParamType))
2668 for i, f := range dtype.ParamType {
2669
2670
2671
2672
2673
2674 if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
2675 p, gp = nil, nil
2676 break
2677 }
2678 p[i] = c.FuncArg(f, pos)
2679 gp[i] = &ast.Field{Type: p[i].Go}
2680 }
2681 var r *Type
2682 var gr []*ast.Field
2683 if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok {
2684 gr = []*ast.Field{{Type: c.goVoid}}
2685 } else if dtype.ReturnType != nil {
2686 r = c.Type(unqual(dtype.ReturnType), pos)
2687 gr = []*ast.Field{{Type: r.Go}}
2688 }
2689 return &FuncType{
2690 Params: p,
2691 Result: r,
2692 Go: &ast.FuncType{
2693 Params: &ast.FieldList{List: gp},
2694 Results: &ast.FieldList{List: gr},
2695 },
2696 }
2697 }
2698
2699
2700 func (c *typeConv) Ident(s string) *ast.Ident {
2701 return ast.NewIdent(s)
2702 }
2703
2704
2705 func (c *typeConv) Opaque(n int64) ast.Expr {
2706 return &ast.ArrayType{
2707 Len: c.intExpr(n),
2708 Elt: c.byte,
2709 }
2710 }
2711
2712
2713 func (c *typeConv) intExpr(n int64) ast.Expr {
2714 return &ast.BasicLit{
2715 Kind: token.INT,
2716 Value: strconv.FormatInt(n, 10),
2717 }
2718 }
2719
2720
2721 func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
2722 n := len(fld)
2723 fld = fld[0 : n+1]
2724 fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
2725 sizes = sizes[0 : n+1]
2726 sizes[n] = size
2727 return fld, sizes
2728 }
2729
2730
2731 func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
2732
2733 align = 1
2734
2735 var buf bytes.Buffer
2736 buf.WriteString("struct {")
2737 fld := make([]*ast.Field, 0, 2*len(dt.Field)+1)
2738 sizes := make([]int64, 0, 2*len(dt.Field)+1)
2739 off := int64(0)
2740
2741
2742
2743
2744
2745
2746
2747 ident := make(map[string]string)
2748 used := make(map[string]bool)
2749 for _, f := range dt.Field {
2750 ident[f.Name] = f.Name
2751 used[f.Name] = true
2752 }
2753
2754 if !*godefs {
2755 for cid, goid := range ident {
2756 if token.Lookup(goid).IsKeyword() {
2757
2758 goid = "_" + goid
2759
2760
2761 for _, exist := used[goid]; exist; _, exist = used[goid] {
2762 goid = "_" + goid
2763 }
2764
2765 used[goid] = true
2766 ident[cid] = goid
2767 }
2768 }
2769 }
2770
2771 anon := 0
2772 for _, f := range dt.Field {
2773 name := f.Name
2774 ft := f.Type
2775
2776
2777
2778
2779
2780
2781 if *godefs {
2782 if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
2783 name = st.Field[0].Name
2784 ident[name] = name
2785 ft = st.Field[0].Type
2786 }
2787 }
2788
2789
2790
2791
2792 t := c.Type(ft, pos)
2793 tgo := t.Go
2794 size := t.Size
2795 talign := t.Align
2796 if f.BitSize > 0 {
2797 switch f.BitSize {
2798 case 8, 16, 32, 64:
2799 default:
2800 continue
2801 }
2802 size = f.BitSize / 8
2803 name := tgo.(*ast.Ident).String()
2804 if strings.HasPrefix(name, "int") {
2805 name = "int"
2806 } else {
2807 name = "uint"
2808 }
2809 tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize))
2810 talign = size
2811 }
2812
2813 if talign > 0 && f.ByteOffset%talign != 0 {
2814
2815
2816
2817
2818
2819 continue
2820 }
2821
2822
2823 off = (off + talign - 1) &^ (talign - 1)
2824
2825 if f.ByteOffset > off {
2826 fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
2827 off = f.ByteOffset
2828 }
2829 if f.ByteOffset < off {
2830
2831 continue
2832 }
2833
2834 n := len(fld)
2835 fld = fld[0 : n+1]
2836 if name == "" {
2837 name = fmt.Sprintf("anon%d", anon)
2838 anon++
2839 ident[name] = name
2840 }
2841 fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
2842 sizes = sizes[0 : n+1]
2843 sizes[n] = size
2844 off += size
2845 buf.WriteString(t.C.String())
2846 buf.WriteString(" ")
2847 buf.WriteString(name)
2848 buf.WriteString("; ")
2849 if talign > align {
2850 align = talign
2851 }
2852 }
2853 if off < dt.ByteSize {
2854 fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
2855 off = dt.ByteSize
2856 }
2857
2858
2859
2860
2861
2862
2863
2864 for off > 0 && sizes[len(sizes)-1] == 0 {
2865 n := len(sizes)
2866 fld = fld[0 : n-1]
2867 sizes = sizes[0 : n-1]
2868 }
2869
2870 if off != dt.ByteSize {
2871 fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
2872 }
2873 buf.WriteString("}")
2874 csyntax = buf.String()
2875
2876 if *godefs {
2877 godefsFields(fld)
2878 }
2879 expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
2880 return
2881 }
2882
2883
2884 func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
2885 switch dt := dt.(type) {
2886 default:
2887 fatalf("%s: unexpected type: %s", lineno(pos), dt)
2888 return false
2889
2890 case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
2891 *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
2892 *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
2893
2894 return false
2895
2896 case *dwarf.ArrayType:
2897 return c.dwarfHasPointer(dt.Type, pos)
2898
2899 case *dwarf.PtrType:
2900 return true
2901
2902 case *dwarf.QualType:
2903 return c.dwarfHasPointer(dt.Type, pos)
2904
2905 case *dwarf.StructType:
2906 for _, f := range dt.Field {
2907 if c.dwarfHasPointer(f.Type, pos) {
2908 return true
2909 }
2910 }
2911 return false
2912
2913 case *dwarf.TypedefType:
2914 if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
2915 return true
2916 }
2917 return c.dwarfHasPointer(dt.Type, pos)
2918 }
2919 }
2920
2921 func upper(s string) string {
2922 if s == "" {
2923 return ""
2924 }
2925 r, size := utf8.DecodeRuneInString(s)
2926 if r == '_' {
2927 return "X" + s
2928 }
2929 return string(unicode.ToUpper(r)) + s[size:]
2930 }
2931
2932
2933
2934
2935
2936 func godefsFields(fld []*ast.Field) {
2937 prefix := fieldPrefix(fld)
2938 npad := 0
2939 for _, f := range fld {
2940 for _, n := range f.Names {
2941 if n.Name != prefix {
2942 n.Name = strings.TrimPrefix(n.Name, prefix)
2943 }
2944 if n.Name == "_" {
2945
2946 n.Name = "Pad_cgo_" + strconv.Itoa(npad)
2947 npad++
2948 }
2949 n.Name = upper(n.Name)
2950 }
2951 }
2952 }
2953
2954
2955
2956
2957
2958
2959
2960 func fieldPrefix(fld []*ast.Field) string {
2961 prefix := ""
2962 for _, f := range fld {
2963 for _, n := range f.Names {
2964
2965
2966
2967
2968
2969
2970
2971
2972 if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
2973 continue
2974 }
2975 i := strings.Index(n.Name, "_")
2976 if i < 0 {
2977 continue
2978 }
2979 if prefix == "" {
2980 prefix = n.Name[:i+1]
2981 } else if prefix != n.Name[:i+1] {
2982 return ""
2983 }
2984 }
2985 }
2986 return prefix
2987 }
2988
2989
2990
2991
2992
2993 func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
2994 if c.badCFType(dt) {
2995 return true
2996 }
2997 if c.badJNI(dt) {
2998 return true
2999 }
3000 if c.badEGLDisplay(dt) {
3001 return true
3002 }
3003 return false
3004 }
3005
3006
3007
3008 func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
3009 for {
3010 if t, ok := dt.Type.(*dwarf.TypedefType); ok {
3011 dt = t
3012 continue
3013 }
3014 break
3015 }
3016 return c.badPointerTypedef(dt)
3017 }
3018
3019 func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
3020
3021
3022
3023
3024
3025
3026
3027 if goos != "darwin" {
3028 return false
3029 }
3030 s := dt.Name
3031 if !strings.HasSuffix(s, "Ref") {
3032 return false
3033 }
3034 s = s[:len(s)-3]
3035 if s == "CFType" {
3036 return true
3037 }
3038 if c.getTypeIDs[s] {
3039 return true
3040 }
3041 if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
3042
3043 return true
3044 }
3045 return false
3046 }
3047
3048
3049
3082
3083 func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
3084
3085
3086
3087
3088 if parent, ok := jniTypes[dt.Name]; ok {
3089
3090
3091
3092
3093
3094 w := dt
3095 for parent != "" {
3096 t, ok := w.Type.(*dwarf.TypedefType)
3097 if !ok || t.Name != parent {
3098 return false
3099 }
3100 w = t
3101 parent, ok = jniTypes[w.Name]
3102 if !ok {
3103 return false
3104 }
3105 }
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116 if ptr, ok := w.Type.(*dwarf.PtrType); ok {
3117 switch v := ptr.Type.(type) {
3118 case *dwarf.VoidType:
3119 return true
3120 case *dwarf.StructType:
3121 if v.StructName == "_jobject" && len(v.Field) == 0 {
3122 switch v.Kind {
3123 case "struct":
3124 if v.Incomplete {
3125 return true
3126 }
3127 case "class":
3128 if !v.Incomplete {
3129 return true
3130 }
3131 }
3132 }
3133 }
3134 }
3135 }
3136 return false
3137 }
3138
3139 func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
3140 if dt.Name != "EGLDisplay" {
3141 return false
3142 }
3143
3144 if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
3145 if _, ok := ptr.Type.(*dwarf.VoidType); ok {
3146 return true
3147 }
3148 }
3149 return false
3150 }
3151
3152
3153
3154 var jniTypes = map[string]string{
3155 "jobject": "",
3156 "jclass": "jobject",
3157 "jthrowable": "jobject",
3158 "jstring": "jobject",
3159 "jarray": "jobject",
3160 "jbooleanArray": "jarray",
3161 "jbyteArray": "jarray",
3162 "jcharArray": "jarray",
3163 "jshortArray": "jarray",
3164 "jintArray": "jarray",
3165 "jlongArray": "jarray",
3166 "jfloatArray": "jarray",
3167 "jdoubleArray": "jarray",
3168 "jobjectArray": "jarray",
3169 "jweak": "jobject",
3170 }
3171
View as plain text