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