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