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