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