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