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 goTypes[t.Name] != nil {
1125 return false
1126 }
1127
1128
1129 return true
1130 case *ast.SelectorExpr:
1131 if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" {
1132
1133
1134
1135 return true
1136 }
1137 if f == nil {
1138
1139 return true
1140 }
1141 name := f.Name[t.Sel.Name]
1142 if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
1143 return p.hasPointer(f, name.Type.Go, top)
1144 }
1145
1146
1147 return true
1148 default:
1149 error_(t.Pos(), "could not understand type %s", gofmt(t))
1150 return true
1151 }
1152 }
1153
1154
1155
1156
1157
1158
1159 func (p *Package) mangle(f *File, arg *ast.Expr, addPosition bool) (ast.Expr, bool) {
1160 needsUnsafe := false
1161 f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
1162 px, ok := arg.(*ast.Expr)
1163 if !ok {
1164 return
1165 }
1166 sel, ok := (*px).(*ast.SelectorExpr)
1167 if ok {
1168 if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
1169 return
1170 }
1171
1172 for _, r := range f.Ref {
1173 if r.Expr == px {
1174 *px = p.rewriteName(f, r, addPosition)
1175 r.Done = true
1176 break
1177 }
1178 }
1179
1180 return
1181 }
1182
1183 call, ok := (*px).(*ast.CallExpr)
1184 if !ok {
1185 return
1186 }
1187
1188 for _, c := range f.Calls {
1189 if !c.Done && c.Call.Lparen == call.Lparen {
1190 cstr, nu := p.rewriteCall(f, c)
1191 if cstr != "" {
1192
1193 *px = ast.NewIdent(cstr)
1194 if nu {
1195 needsUnsafe = true
1196 }
1197 c.Done = true
1198 }
1199 }
1200 }
1201 })
1202 return *arg, needsUnsafe
1203 }
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225 func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
1226
1227 x := arg
1228 for {
1229 c, ok := x.(*ast.CallExpr)
1230 if !ok || len(c.Args) != 1 {
1231 break
1232 }
1233 if !p.isType(c.Fun) && !p.isUnsafeData(c.Fun, false) {
1234 break
1235 }
1236 x = c.Args[0]
1237 }
1238 u, ok := x.(*ast.UnaryExpr)
1239 if !ok || u.Op != token.AND {
1240 return false
1241 }
1242 index, ok := u.X.(*ast.IndexExpr)
1243 if !ok {
1244 return false
1245 }
1246
1247 addr := ""
1248 deref := ""
1249 if p.isVariable(index.X) {
1250 addr = "&"
1251 deref = "*"
1252 }
1253
1254 fmt.Fprintf(sb, "_cgoIndex%d := %s%s; ", i, addr, gofmtPos(index.X, index.X.Pos()))
1255 origX := index.X
1256 index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i))
1257 if deref == "*" {
1258 index.X = &ast.StarExpr{X: index.X}
1259 }
1260 fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
1261 index.X = origX
1262
1263 fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, %s_cgoIndex%d); ", i, deref, i)
1264
1265 return true
1266 }
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282 func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
1283
1284 px := &arg
1285 for {
1286 c, ok := (*px).(*ast.CallExpr)
1287 if !ok || len(c.Args) != 1 {
1288 break
1289 }
1290 if !p.isType(c.Fun) && !p.isUnsafeData(c.Fun, false) {
1291 break
1292 }
1293 px = &c.Args[0]
1294 }
1295 if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND {
1296 return false
1297 }
1298
1299 fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
1300
1301 origX := *px
1302 *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i))
1303 fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
1304 *px = origX
1305
1306
1307
1308 fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i)
1309
1310 return true
1311 }
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326 func (p *Package) checkSlice(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
1327
1328 px := &arg
1329 for {
1330 c, ok := (*px).(*ast.CallExpr)
1331 if !ok || len(c.Args) != 1 {
1332 break
1333 }
1334 if !p.isType(c.Fun) && !p.isUnsafeData(c.Fun, false) {
1335 break
1336 }
1337 px = &c.Args[0]
1338 }
1339 if _, ok := (*px).(*ast.SliceExpr); !ok {
1340 return false
1341 }
1342
1343 fmt.Fprintf(sb, "_cgoSlice%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
1344
1345 origX := *px
1346 *px = ast.NewIdent(fmt.Sprintf("_cgoSlice%d", i))
1347 fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
1348 *px = origX
1349
1350
1351
1352 fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoSlice%d, 0 == 0); ", i)
1353
1354 return true
1355 }
1356
1357
1358
1359
1360 func (p *Package) checkUnsafeStringData(arg ast.Expr) bool {
1361 x := arg
1362 for {
1363 c, ok := x.(*ast.CallExpr)
1364 if !ok || len(c.Args) != 1 {
1365 break
1366 }
1367 if p.isUnsafeData(c.Fun, true) {
1368 return true
1369 }
1370 if !p.isType(c.Fun) {
1371 break
1372 }
1373 x = c.Args[0]
1374 }
1375 return false
1376 }
1377
1378
1379
1380 func (p *Package) isType(t ast.Expr) bool {
1381 switch t := t.(type) {
1382 case *ast.SelectorExpr:
1383 id, ok := t.X.(*ast.Ident)
1384 if !ok {
1385 return false
1386 }
1387 if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
1388 return true
1389 }
1390 if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
1391 return true
1392 }
1393 return false
1394 case *ast.Ident:
1395
1396 switch t.Name {
1397 case "unsafe.Pointer", "bool", "byte",
1398 "complex64", "complex128",
1399 "error",
1400 "float32", "float64",
1401 "int", "int8", "int16", "int32", "int64",
1402 "rune", "string",
1403 "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
1404
1405 return true
1406 }
1407 if strings.HasPrefix(t.Name, "_Ctype_") {
1408 return true
1409 }
1410 case *ast.ParenExpr:
1411 return p.isType(t.X)
1412 case *ast.StarExpr:
1413 return p.isType(t.X)
1414 case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
1415 *ast.MapType, *ast.ChanType:
1416
1417 return true
1418 }
1419 return false
1420 }
1421
1422
1423
1424
1425
1426 func (p *Package) isUnsafeData(x ast.Expr, onlyStringData bool) bool {
1427 st, ok := x.(*ast.SelectorExpr)
1428 if !ok {
1429 return false
1430 }
1431 id, ok := st.X.(*ast.Ident)
1432 if !ok {
1433 return false
1434 }
1435 if id.Name != "unsafe" {
1436 return false
1437 }
1438 if !onlyStringData && st.Sel.Name == "SliceData" {
1439 return true
1440 }
1441 return st.Sel.Name == "StringData"
1442 }
1443
1444
1445 func (p *Package) isVariable(x ast.Expr) bool {
1446 switch x := x.(type) {
1447 case *ast.Ident:
1448 return true
1449 case *ast.SelectorExpr:
1450 return p.isVariable(x.X)
1451 case *ast.IndexExpr:
1452 return true
1453 }
1454 return false
1455 }
1456
1457
1458
1459 func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
1460 switch t := t.(type) {
1461 case *ast.Ident:
1462
1463
1464 if t.Name == "unsafe.Pointer" {
1465 return ast.NewIdent("_cgo_unsafe.Pointer")
1466 }
1467 case *ast.ArrayType:
1468 t1 := p.rewriteUnsafe(t.Elt)
1469 if t1 != t.Elt {
1470 r := *t
1471 r.Elt = t1
1472 return &r
1473 }
1474 case *ast.StructType:
1475 changed := false
1476 fields := *t.Fields
1477 fields.List = nil
1478 for _, f := range t.Fields.List {
1479 ft := p.rewriteUnsafe(f.Type)
1480 if ft == f.Type {
1481 fields.List = append(fields.List, f)
1482 } else {
1483 fn := *f
1484 fn.Type = ft
1485 fields.List = append(fields.List, &fn)
1486 changed = true
1487 }
1488 }
1489 if changed {
1490 r := *t
1491 r.Fields = &fields
1492 return &r
1493 }
1494 case *ast.StarExpr:
1495 x1 := p.rewriteUnsafe(t.X)
1496 if x1 != t.X {
1497 r := *t
1498 r.X = x1
1499 return &r
1500 }
1501 }
1502 return t
1503 }
1504
1505
1506
1507
1508
1509 func (p *Package) rewriteRef(f *File) {
1510
1511
1512
1513 functions := make(map[string]bool)
1514
1515 for _, n := range f.Name {
1516 if n.Kind == "func" {
1517 functions[n.Go] = false
1518 }
1519 }
1520
1521
1522
1523
1524
1525 for _, r := range f.Ref {
1526 if r.Name.IsConst() && r.Name.Const == "" {
1527 error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
1528 }
1529
1530 if r.Name.Kind == "func" {
1531 switch r.Context {
1532 case ctxCall, ctxCall2:
1533 functions[r.Name.Go] = true
1534 }
1535 }
1536
1537 expr := p.rewriteName(f, r, false)
1538
1539 if *godefs {
1540
1541 if r.Name.Type != nil && r.Name.Kind == "type" {
1542 expr = r.Name.Type.Go
1543 }
1544 if id, ok := expr.(*ast.Ident); ok {
1545 if t := typedef[id.Name]; t != nil {
1546 expr = t.Go
1547 }
1548 if id.Name == r.Name.Mangle && r.Name.Const != "" {
1549 expr = ast.NewIdent(r.Name.Const)
1550 }
1551 }
1552 }
1553
1554
1555
1556
1557 pos := (*r.Expr).Pos()
1558 if x, ok := expr.(*ast.Ident); ok {
1559 expr = &ast.Ident{NamePos: pos, Name: x.Name}
1560 }
1561
1562
1563
1564 old := *r.Expr
1565 *r.Expr = expr
1566
1567
1568 if !r.Done {
1569
1570
1571 repl := " " + gofmtPos(expr, old.Pos())
1572 end := fset.Position(old.End())
1573
1574
1575
1576 sub := 0
1577 if r.Name.Kind != "type" {
1578 sub = 1
1579 }
1580 if end.Column > sub {
1581 repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub)
1582 }
1583 if r.Name.Kind != "type" {
1584 repl = "(" + repl + ")"
1585 }
1586 f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
1587 }
1588 }
1589
1590
1591
1592 for name, used := range functions {
1593 if !used {
1594 delete(f.Name, name)
1595 }
1596 }
1597 }
1598
1599
1600
1601 func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
1602 getNewIdent := ast.NewIdent
1603 if addPosition {
1604 getNewIdent = func(newName string) *ast.Ident {
1605 mangledIdent := ast.NewIdent(newName)
1606 if len(newName) == len(r.Name.Go) {
1607 return mangledIdent
1608 }
1609 p := fset.Position((*r.Expr).End())
1610 if p.Column == 0 {
1611 return mangledIdent
1612 }
1613 return ast.NewIdent(fmt.Sprintf("%s /*line :%d:%d*/", newName, p.Line, p.Column))
1614 }
1615 }
1616 var expr ast.Expr = getNewIdent(r.Name.Mangle)
1617 switch r.Context {
1618 case ctxCall, ctxCall2:
1619 if r.Name.Kind != "func" {
1620 if r.Name.Kind == "type" {
1621 r.Context = ctxType
1622 if r.Name.Type == nil {
1623 error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
1624 }
1625 break
1626 }
1627 error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
1628 break
1629 }
1630 if r.Context == ctxCall2 {
1631 if builtinDefs[r.Name.Go] != "" {
1632 error_(r.Pos(), "no two-result form for C.%s", r.Name.Go)
1633 break
1634 }
1635
1636 n := f.Name["2"+r.Name.Go]
1637 if n == nil {
1638 n = new(Name)
1639 *n = *r.Name
1640 n.AddError = true
1641 n.Mangle = "_C2func_" + n.Go
1642 f.Name["2"+r.Name.Go] = n
1643 }
1644 expr = getNewIdent(n.Mangle)
1645 r.Name = n
1646 break
1647 }
1648 case ctxExpr:
1649 switch r.Name.Kind {
1650 case "func":
1651 if builtinDefs[r.Name.C] != "" {
1652 error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
1653 }
1654
1655
1656
1657 fpName := "fp_" + r.Name.Go
1658 name := f.Name[fpName]
1659 if name == nil {
1660 name = &Name{
1661 Go: fpName,
1662 C: r.Name.C,
1663 Kind: "fpvar",
1664 Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
1665 }
1666 p.mangleName(name)
1667 f.Name[fpName] = name
1668 }
1669 r.Name = name
1670
1671
1672
1673 expr = &ast.CallExpr{
1674 Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
1675 Args: []ast.Expr{getNewIdent(name.Mangle)},
1676 }
1677 case "type":
1678
1679 if r.Name.Type == nil {
1680 error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
1681 }
1682 case "var":
1683 expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
1684 case "macro":
1685 expr = &ast.CallExpr{Fun: expr}
1686 }
1687 case ctxSelector:
1688 if r.Name.Kind == "var" {
1689 expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
1690 } else {
1691 error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
1692 }
1693 case ctxType:
1694 if r.Name.Kind != "type" {
1695 error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
1696 } else if r.Name.Type == nil {
1697
1698
1699 error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
1700 }
1701 default:
1702 if r.Name.Kind == "func" {
1703 error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
1704 }
1705 }
1706 return expr
1707 }
1708
1709
1710
1711 func gofmtPos(n ast.Expr, pos token.Pos) string {
1712 s := gofmt(n)
1713 p := fset.Position(pos)
1714 if p.Column == 0 {
1715 return s
1716 }
1717 return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
1718 }
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730 func checkGCCBaseCmd() ([]string, error) {
1731
1732 value := os.Getenv("CC")
1733 if value == "" {
1734
1735 value = os.Getenv("GCC")
1736 }
1737 if value == "" {
1738 value = defaultCC(goos, goarch)
1739 }
1740 args, err := quoted.Split(value)
1741 if err != nil {
1742 return nil, err
1743 }
1744 if len(args) == 0 {
1745 return nil, errors.New("CC not set and no default found")
1746 }
1747 if _, err := exec.LookPath(args[0]); err != nil {
1748 return nil, fmt.Errorf("C compiler %q not found: %v", args[0], err)
1749 }
1750 return args[:len(args):len(args)], nil
1751 }
1752
1753
1754 func gccMachine() []string {
1755 switch goarch {
1756 case "amd64":
1757 if goos == "darwin" {
1758 return []string{"-arch", "x86_64", "-m64"}
1759 }
1760 return []string{"-m64"}
1761 case "arm64":
1762 if goos == "darwin" {
1763 return []string{"-arch", "arm64"}
1764 }
1765 case "386":
1766 return []string{"-m32"}
1767 case "arm":
1768 return []string{"-marm"}
1769 case "s390":
1770 return []string{"-m31"}
1771 case "s390x":
1772 return []string{"-m64"}
1773 case "mips64", "mips64le":
1774 if gomips64 == "hardfloat" {
1775 return []string{"-mabi=64", "-mhard-float"}
1776 } else if gomips64 == "softfloat" {
1777 return []string{"-mabi=64", "-msoft-float"}
1778 }
1779 case "mips", "mipsle":
1780 if gomips == "hardfloat" {
1781 return []string{"-mabi=32", "-mfp32", "-mhard-float", "-mno-odd-spreg"}
1782 } else if gomips == "softfloat" {
1783 return []string{"-mabi=32", "-msoft-float"}
1784 }
1785 case "loong64":
1786 return []string{"-mabi=lp64d"}
1787 }
1788 return nil
1789 }
1790
1791 var n atomic.Int64
1792
1793 func gccTmp() string {
1794 c := strconv.Itoa(int(n.Add(1)))
1795 return *objDir + "_cgo_" + c + ".o"
1796 }
1797
1798
1799
1800
1801 func (p *Package) gccCmd(ofile string) []string {
1802 c := append(gccBaseCmd,
1803 "-w",
1804 "-Wno-error",
1805 "-o"+ofile,
1806 "-gdwarf-2",
1807 "-c",
1808 "-xc",
1809 )
1810 if p.GccIsClang {
1811 c = append(c,
1812 "-ferror-limit=0",
1813
1814
1815
1816 "-Wno-unknown-warning-option",
1817 "-Wno-unneeded-internal-declaration",
1818 "-Wno-unused-function",
1819 "-Qunused-arguments",
1820
1821
1822
1823
1824
1825
1826 "-fno-builtin",
1827 )
1828 }
1829
1830 c = append(c, p.GccOptions...)
1831 c = append(c, gccMachine()...)
1832 if goos == "aix" {
1833 c = append(c, "-maix64")
1834 c = append(c, "-mcmodel=large")
1835 }
1836
1837 c = append(c, "-fno-lto")
1838 c = append(c, "-")
1839 return c
1840 }
1841
1842
1843
1844
1845 func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
1846 ofile := gccTmp()
1847 runGcc(stdin, p.gccCmd(ofile))
1848
1849 isDebugInts := func(s string) bool {
1850
1851 return s == "__cgodebug_ints" || s == "___cgodebug_ints"
1852 }
1853 isDebugFloats := func(s string) bool {
1854
1855 return s == "__cgodebug_floats" || s == "___cgodebug_floats"
1856 }
1857 indexOfDebugStr := func(s string) int {
1858
1859 if strings.HasPrefix(s, "___") {
1860 s = s[1:]
1861 }
1862 if strings.HasPrefix(s, "__cgodebug_str__") {
1863 if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil {
1864 return n
1865 }
1866 }
1867 return -1
1868 }
1869 indexOfDebugStrlen := func(s string) int {
1870
1871 if strings.HasPrefix(s, "___") {
1872 s = s[1:]
1873 }
1874 if t, ok := strings.CutPrefix(s, "__cgodebug_strlen__"); ok {
1875 if n, err := strconv.Atoi(t); err == nil {
1876 return n
1877 }
1878 }
1879 return -1
1880 }
1881
1882 strs = make([]string, nnames)
1883
1884 strdata := make(map[int]string, nnames)
1885 strlens := make(map[int]int, nnames)
1886
1887 buildStrings := func() {
1888 for n, strlen := range strlens {
1889 data := strdata[n]
1890 if len(data) <= strlen {
1891 fatalf("invalid string literal")
1892 }
1893 strs[n] = data[:strlen]
1894 }
1895 }
1896
1897 if f, err := macho.Open(ofile); err == nil {
1898 defer f.Close()
1899 d, err := f.DWARF()
1900 if err != nil {
1901 fatalf("cannot load DWARF output from %s: %v", ofile, err)
1902 }
1903 bo := f.ByteOrder
1904 if f.Symtab != nil {
1905 for i := range f.Symtab.Syms {
1906 s := &f.Symtab.Syms[i]
1907 switch {
1908 case isDebugInts(s.Name):
1909
1910 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1911 sect := f.Sections[i]
1912 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1913 if sdat, err := sect.Data(); err == nil {
1914 data := sdat[s.Value-sect.Addr:]
1915 ints = make([]int64, len(data)/8)
1916 for i := range ints {
1917 ints[i] = int64(bo.Uint64(data[i*8:]))
1918 }
1919 }
1920 }
1921 }
1922 case isDebugFloats(s.Name):
1923
1924 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1925 sect := f.Sections[i]
1926 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1927 if sdat, err := sect.Data(); err == nil {
1928 data := sdat[s.Value-sect.Addr:]
1929 floats = make([]float64, len(data)/8)
1930 for i := range floats {
1931 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
1932 }
1933 }
1934 }
1935 }
1936 default:
1937 if n := indexOfDebugStr(s.Name); n != -1 {
1938
1939 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1940 sect := f.Sections[i]
1941 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1942 if sdat, err := sect.Data(); err == nil {
1943 data := sdat[s.Value-sect.Addr:]
1944 strdata[n] = string(data)
1945 }
1946 }
1947 }
1948 break
1949 }
1950 if n := indexOfDebugStrlen(s.Name); n != -1 {
1951
1952 if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
1953 sect := f.Sections[i]
1954 if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
1955 if sdat, err := sect.Data(); err == nil {
1956 data := sdat[s.Value-sect.Addr:]
1957 strlen := bo.Uint64(data[:8])
1958 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
1959 fatalf("string literal too big")
1960 }
1961 strlens[n] = int(strlen)
1962 }
1963 }
1964 }
1965 break
1966 }
1967 }
1968 }
1969
1970 buildStrings()
1971 }
1972 return d, ints, floats, strs
1973 }
1974
1975 if f, err := elf.Open(ofile); err == nil {
1976 defer f.Close()
1977 d, err := f.DWARF()
1978 if err != nil {
1979 fatalf("cannot load DWARF output from %s: %v", ofile, err)
1980 }
1981 bo := f.ByteOrder
1982 symtab, err := f.Symbols()
1983 if err == nil {
1984
1985 removeTag := func(v uint64) uint64 { return v }
1986 if goarch == "arm64" {
1987 for i := range symtab {
1988 if symtab[i].Name == "__hwasan_init" {
1989
1990
1991
1992
1993
1994
1995 removeTag = func(v uint64) uint64 { return v &^ (0xff << (64 - 8)) }
1996 break
1997 }
1998 }
1999 }
2000
2001 for i := range symtab {
2002 s := &symtab[i]
2003 switch {
2004 case isDebugInts(s.Name):
2005
2006 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
2007 sect := f.Sections[i]
2008 val := removeTag(s.Value)
2009 if sect.Addr <= val && val < sect.Addr+sect.Size {
2010 if sdat, err := sect.Data(); err == nil {
2011 data := sdat[val-sect.Addr:]
2012 ints = make([]int64, len(data)/8)
2013 for i := range ints {
2014 ints[i] = int64(bo.Uint64(data[i*8:]))
2015 }
2016 }
2017 }
2018 }
2019 case isDebugFloats(s.Name):
2020
2021 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
2022 sect := f.Sections[i]
2023 val := removeTag(s.Value)
2024 if sect.Addr <= val && val < sect.Addr+sect.Size {
2025 if sdat, err := sect.Data(); err == nil {
2026 data := sdat[val-sect.Addr:]
2027 floats = make([]float64, len(data)/8)
2028 for i := range floats {
2029 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
2030 }
2031 }
2032 }
2033 }
2034 default:
2035 if n := indexOfDebugStr(s.Name); n != -1 {
2036
2037 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
2038 sect := f.Sections[i]
2039 val := removeTag(s.Value)
2040 if sect.Addr <= val && val < sect.Addr+sect.Size {
2041 if sdat, err := sect.Data(); err == nil {
2042 data := sdat[val-sect.Addr:]
2043 strdata[n] = string(data)
2044 }
2045 }
2046 }
2047 break
2048 }
2049 if n := indexOfDebugStrlen(s.Name); n != -1 {
2050
2051 if i := int(s.Section); 0 <= i && i < len(f.Sections) {
2052 sect := f.Sections[i]
2053 val := removeTag(s.Value)
2054 if sect.Addr <= val && val < sect.Addr+sect.Size {
2055 if sdat, err := sect.Data(); err == nil {
2056 data := sdat[val-sect.Addr:]
2057 strlen := bo.Uint64(data[:8])
2058 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
2059 fatalf("string literal too big")
2060 }
2061 strlens[n] = int(strlen)
2062 }
2063 }
2064 }
2065 break
2066 }
2067 }
2068 }
2069
2070 buildStrings()
2071 }
2072 return d, ints, floats, strs
2073 }
2074
2075 if f, err := pe.Open(ofile); err == nil {
2076 defer f.Close()
2077 d, err := f.DWARF()
2078 if err != nil {
2079 fatalf("cannot load DWARF output from %s: %v", ofile, err)
2080 }
2081 bo := binary.LittleEndian
2082 for _, s := range f.Symbols {
2083 switch {
2084 case isDebugInts(s.Name):
2085 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2086 sect := f.Sections[i]
2087 if s.Value < sect.Size {
2088 if sdat, err := sect.Data(); err == nil {
2089 data := sdat[s.Value:]
2090 ints = make([]int64, len(data)/8)
2091 for i := range ints {
2092 ints[i] = int64(bo.Uint64(data[i*8:]))
2093 }
2094 }
2095 }
2096 }
2097 case isDebugFloats(s.Name):
2098 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2099 sect := f.Sections[i]
2100 if s.Value < sect.Size {
2101 if sdat, err := sect.Data(); err == nil {
2102 data := sdat[s.Value:]
2103 floats = make([]float64, len(data)/8)
2104 for i := range floats {
2105 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
2106 }
2107 }
2108 }
2109 }
2110 default:
2111 if n := indexOfDebugStr(s.Name); n != -1 {
2112 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2113 sect := f.Sections[i]
2114 if s.Value < sect.Size {
2115 if sdat, err := sect.Data(); err == nil {
2116 data := sdat[s.Value:]
2117 strdata[n] = string(data)
2118 }
2119 }
2120 }
2121 break
2122 }
2123 if n := indexOfDebugStrlen(s.Name); n != -1 {
2124 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2125 sect := f.Sections[i]
2126 if s.Value < sect.Size {
2127 if sdat, err := sect.Data(); err == nil {
2128 data := sdat[s.Value:]
2129 strlen := bo.Uint64(data[:8])
2130 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
2131 fatalf("string literal too big")
2132 }
2133 strlens[n] = int(strlen)
2134 }
2135 }
2136 }
2137 break
2138 }
2139 }
2140 }
2141
2142 buildStrings()
2143
2144 return d, ints, floats, strs
2145 }
2146
2147 if f, err := xcoff.Open(ofile); err == nil {
2148 defer f.Close()
2149 d, err := f.DWARF()
2150 if err != nil {
2151 fatalf("cannot load DWARF output from %s: %v", ofile, err)
2152 }
2153 bo := binary.BigEndian
2154 for _, s := range f.Symbols {
2155 switch {
2156 case isDebugInts(s.Name):
2157 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2158 sect := f.Sections[i]
2159 if s.Value < sect.Size {
2160 if sdat, err := sect.Data(); err == nil {
2161 data := sdat[s.Value:]
2162 ints = make([]int64, len(data)/8)
2163 for i := range ints {
2164 ints[i] = int64(bo.Uint64(data[i*8:]))
2165 }
2166 }
2167 }
2168 }
2169 case isDebugFloats(s.Name):
2170 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2171 sect := f.Sections[i]
2172 if s.Value < sect.Size {
2173 if sdat, err := sect.Data(); err == nil {
2174 data := sdat[s.Value:]
2175 floats = make([]float64, len(data)/8)
2176 for i := range floats {
2177 floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
2178 }
2179 }
2180 }
2181 }
2182 default:
2183 if n := indexOfDebugStr(s.Name); n != -1 {
2184 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2185 sect := f.Sections[i]
2186 if s.Value < sect.Size {
2187 if sdat, err := sect.Data(); err == nil {
2188 data := sdat[s.Value:]
2189 strdata[n] = string(data)
2190 }
2191 }
2192 }
2193 break
2194 }
2195 if n := indexOfDebugStrlen(s.Name); n != -1 {
2196 if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
2197 sect := f.Sections[i]
2198 if s.Value < sect.Size {
2199 if sdat, err := sect.Data(); err == nil {
2200 data := sdat[s.Value:]
2201 strlen := bo.Uint64(data[:8])
2202 if strlen > (1<<(uint(p.IntSize*8)-1) - 1) {
2203 fatalf("string literal too big")
2204 }
2205 strlens[n] = int(strlen)
2206 }
2207 }
2208 }
2209 break
2210 }
2211 }
2212 }
2213
2214 buildStrings()
2215 return d, ints, floats, strs
2216 }
2217 fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", ofile)
2218 panic("not reached")
2219 }
2220
2221
2222
2223
2224
2225 func gccDefines(stdin []byte, gccOptions []string) string {
2226 base := append(gccBaseCmd, "-E", "-dM", "-xc")
2227 base = append(base, gccMachine()...)
2228 stdout, _ := runGcc(stdin, append(append(base, gccOptions...), "-"))
2229 return stdout
2230 }
2231
2232
2233
2234
2235
2236 func (p *Package) gccErrors(stdin []byte, extraArgs ...string) string {
2237
2238 args := p.gccCmd(gccTmp())
2239
2240
2241 nargs := make([]string, 0, len(args)+len(extraArgs))
2242 for _, arg := range args {
2243 if !strings.HasPrefix(arg, "-O") {
2244 nargs = append(nargs, arg)
2245 }
2246 }
2247
2248
2249
2250 li := len(nargs) - 1
2251 last := nargs[li]
2252 nargs[li] = "-O0"
2253 nargs = append(nargs, extraArgs...)
2254 nargs = append(nargs, last)
2255
2256 if *debugGcc {
2257 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
2258 os.Stderr.Write(stdin)
2259 fmt.Fprint(os.Stderr, "EOF\n")
2260 }
2261 stdout, stderr, _ := run(stdin, nargs)
2262 if *debugGcc {
2263 os.Stderr.Write(stdout)
2264 os.Stderr.Write(stderr)
2265 }
2266 return string(stderr)
2267 }
2268
2269
2270
2271
2272
2273
2274
2275 func runGcc(stdin []byte, args []string) (string, string) {
2276 if *debugGcc {
2277 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
2278 os.Stderr.Write(stdin)
2279 fmt.Fprint(os.Stderr, "EOF\n")
2280 }
2281 stdout, stderr, ok := run(stdin, args)
2282 if *debugGcc {
2283 os.Stderr.Write(stdout)
2284 os.Stderr.Write(stderr)
2285 }
2286 if !ok {
2287 os.Stderr.Write(stderr)
2288 os.Exit(2)
2289 }
2290 return string(stdout), string(stderr)
2291 }
2292
2293
2294
2295 type typeConv struct {
2296
2297 m map[string]*Type
2298
2299
2300 ptrs map[string][]*Type
2301
2302
2303 ptrKeys []dwarf.Type
2304
2305
2306 getTypeIDs map[string]bool
2307
2308
2309 incompleteStructs map[string]bool
2310
2311
2312 bool ast.Expr
2313 byte ast.Expr
2314 int8, int16, int32, int64 ast.Expr
2315 uint8, uint16, uint32, uint64, uintptr ast.Expr
2316 float32, float64 ast.Expr
2317 complex64, complex128 ast.Expr
2318 void ast.Expr
2319 string ast.Expr
2320 goVoid ast.Expr
2321 goVoidPtr ast.Expr
2322
2323 ptrSize int64
2324 intSize int64
2325 }
2326
2327 var tagGen int
2328 var typedef = make(map[string]*Type)
2329 var goIdent = make(map[string]*ast.Ident)
2330
2331
2332
2333 var unionWithPointer = make(map[ast.Expr]bool)
2334
2335
2336
2337 var anonymousStructTag = make(map[*dwarf.StructType]string)
2338
2339 func (c *typeConv) Init(ptrSize, intSize int64) {
2340 c.ptrSize = ptrSize
2341 c.intSize = intSize
2342 c.m = make(map[string]*Type)
2343 c.ptrs = make(map[string][]*Type)
2344 c.getTypeIDs = make(map[string]bool)
2345 c.incompleteStructs = make(map[string]bool)
2346 c.bool = c.Ident("bool")
2347 c.byte = c.Ident("byte")
2348 c.int8 = c.Ident("int8")
2349 c.int16 = c.Ident("int16")
2350 c.int32 = c.Ident("int32")
2351 c.int64 = c.Ident("int64")
2352 c.uint8 = c.Ident("uint8")
2353 c.uint16 = c.Ident("uint16")
2354 c.uint32 = c.Ident("uint32")
2355 c.uint64 = c.Ident("uint64")
2356 c.uintptr = c.Ident("uintptr")
2357 c.float32 = c.Ident("float32")
2358 c.float64 = c.Ident("float64")
2359 c.complex64 = c.Ident("complex64")
2360 c.complex128 = c.Ident("complex128")
2361 c.void = c.Ident("void")
2362 c.string = c.Ident("string")
2363 c.goVoid = c.Ident("_Ctype_void")
2364
2365
2366
2367 if *godefs {
2368 c.goVoidPtr = &ast.StarExpr{X: c.byte}
2369 } else {
2370 c.goVoidPtr = c.Ident("unsafe.Pointer")
2371 }
2372 }
2373
2374
2375 func base(dt dwarf.Type) dwarf.Type {
2376 for {
2377 if d, ok := dt.(*dwarf.QualType); ok {
2378 dt = d.Type
2379 continue
2380 }
2381 if d, ok := dt.(*dwarf.TypedefType); ok {
2382 dt = d.Type
2383 continue
2384 }
2385 break
2386 }
2387 return dt
2388 }
2389
2390
2391
2392 func unqual(dt dwarf.Type) dwarf.Type {
2393 for {
2394 if d, ok := dt.(*dwarf.QualType); ok {
2395 dt = d.Type
2396 } else {
2397 break
2398 }
2399 }
2400 return dt
2401 }
2402
2403
2404 var dwarfToName = map[string]string{
2405 "long int": "long",
2406 "long unsigned int": "ulong",
2407 "unsigned int": "uint",
2408 "short unsigned int": "ushort",
2409 "unsigned short": "ushort",
2410 "short int": "short",
2411 "long long int": "longlong",
2412 "long long unsigned int": "ulonglong",
2413 "signed char": "schar",
2414 "unsigned char": "uchar",
2415 "unsigned long": "ulong",
2416 "unsigned long long": "ulonglong",
2417 }
2418
2419 const signedDelta = 64
2420
2421
2422
2423
2424 func (tr *TypeRepr) String() string {
2425 if len(tr.Repr) == 0 {
2426 return ""
2427 }
2428 if len(tr.FormatArgs) == 0 {
2429 return tr.Repr
2430 }
2431 return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
2432 }
2433
2434
2435 func (tr *TypeRepr) Empty() bool {
2436 return len(tr.Repr) == 0
2437 }
2438
2439
2440
2441
2442 func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
2443 tr.Repr = repr
2444 tr.FormatArgs = fargs
2445 }
2446
2447
2448
2449 func (c *typeConv) FinishType(pos token.Pos) {
2450
2451
2452 for len(c.ptrKeys) > 0 {
2453 dtype := c.ptrKeys[0]
2454 dtypeKey := dtype.String()
2455 c.ptrKeys = c.ptrKeys[1:]
2456 ptrs := c.ptrs[dtypeKey]
2457 delete(c.ptrs, dtypeKey)
2458
2459
2460 t := c.Type(dtype, pos)
2461 for _, ptr := range ptrs {
2462 ptr.Go.(*ast.StarExpr).X = t.Go
2463 ptr.C.Set("%s*", t.C)
2464 }
2465 }
2466 }
2467
2468
2469
2470 func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
2471 return c.loadType(dtype, pos, "")
2472 }
2473
2474
2475 func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Type {
2476
2477
2478 checkCache := true
2479 if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
2480 checkCache = false
2481 }
2482
2483
2484
2485 key := parent + " > " + dtype.String()
2486
2487 if checkCache {
2488 if t, ok := c.m[key]; ok {
2489 if t.Go == nil {
2490 fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
2491 }
2492 return t
2493 }
2494 }
2495
2496 t := new(Type)
2497 t.Size = dtype.Size()
2498 t.Align = -1
2499 t.C = &TypeRepr{Repr: dtype.Common().Name}
2500 c.m[key] = t
2501
2502 switch dt := dtype.(type) {
2503 default:
2504 fatalf("%s: unexpected type: %s", lineno(pos), dtype)
2505
2506 case *dwarf.AddrType:
2507 if t.Size != c.ptrSize {
2508 fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
2509 }
2510 t.Go = c.uintptr
2511 t.Align = t.Size
2512
2513 case *dwarf.ArrayType:
2514 if dt.StrideBitSize > 0 {
2515
2516 t.Go = c.Opaque(t.Size)
2517 break
2518 }
2519 count := dt.Count
2520 if count == -1 {
2521
2522
2523 count = 0
2524 }
2525 sub := c.Type(dt.Type, pos)
2526 t.Align = sub.Align
2527 t.Go = &ast.ArrayType{
2528 Len: c.intExpr(count),
2529 Elt: sub.Go,
2530 }
2531
2532 t.Size = count * sub.Size
2533 t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
2534
2535 case *dwarf.BoolType:
2536 t.Go = c.bool
2537 t.Align = 1
2538
2539 case *dwarf.CharType:
2540 if t.Size != 1 {
2541 fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
2542 }
2543 t.Go = c.int8
2544 t.Align = 1
2545
2546 case *dwarf.EnumType:
2547 if t.Align = t.Size; t.Align >= c.ptrSize {
2548 t.Align = c.ptrSize
2549 }
2550 t.C.Set("enum " + dt.EnumName)
2551 signed := 0
2552 t.EnumValues = make(map[string]int64)
2553 for _, ev := range dt.Val {
2554 t.EnumValues[ev.Name] = ev.Val
2555 if ev.Val < 0 {
2556 signed = signedDelta
2557 }
2558 }
2559 switch t.Size + int64(signed) {
2560 default:
2561 fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
2562 case 1:
2563 t.Go = c.uint8
2564 case 2:
2565 t.Go = c.uint16
2566 case 4:
2567 t.Go = c.uint32
2568 case 8:
2569 t.Go = c.uint64
2570 case 1 + signedDelta:
2571 t.Go = c.int8
2572 case 2 + signedDelta:
2573 t.Go = c.int16
2574 case 4 + signedDelta:
2575 t.Go = c.int32
2576 case 8 + signedDelta:
2577 t.Go = c.int64
2578 }
2579
2580 case *dwarf.FloatType:
2581 switch t.Size {
2582 default:
2583 fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
2584 case 4:
2585 t.Go = c.float32
2586 case 8:
2587 t.Go = c.float64
2588 }
2589 if t.Align = t.Size; t.Align >= c.ptrSize {
2590 t.Align = c.ptrSize
2591 }
2592
2593 case *dwarf.ComplexType:
2594 switch t.Size {
2595 default:
2596 fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
2597 case 8:
2598 t.Go = c.complex64
2599 case 16:
2600 t.Go = c.complex128
2601 }
2602 if t.Align = t.Size / 2; t.Align >= c.ptrSize {
2603 t.Align = c.ptrSize
2604 }
2605
2606 case *dwarf.FuncType:
2607
2608
2609 t.Go = c.uintptr
2610 t.Align = c.ptrSize
2611
2612 case *dwarf.IntType:
2613 if dt.BitSize > 0 {
2614 fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
2615 }
2616
2617 if t.Align = t.Size; t.Align >= c.ptrSize {
2618 t.Align = c.ptrSize
2619 }
2620
2621 switch t.Size {
2622 default:
2623 fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
2624 case 1:
2625 t.Go = c.int8
2626 case 2:
2627 t.Go = c.int16
2628 case 4:
2629 t.Go = c.int32
2630 case 8:
2631 t.Go = c.int64
2632 case 16:
2633 t.Go = &ast.ArrayType{
2634 Len: c.intExpr(t.Size),
2635 Elt: c.uint8,
2636 }
2637
2638 t.Align = 1
2639 }
2640
2641 case *dwarf.PtrType:
2642
2643 if t.Size != c.ptrSize && t.Size != -1 {
2644 fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
2645 }
2646 t.Size = c.ptrSize
2647 t.Align = c.ptrSize
2648
2649 if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
2650 t.Go = c.goVoidPtr
2651 t.C.Set("void*")
2652 dq := dt.Type
2653 for {
2654 if d, ok := dq.(*dwarf.QualType); ok {
2655 t.C.Set(d.Qual + " " + t.C.String())
2656 dq = d.Type
2657 } else {
2658 break
2659 }
2660 }
2661 break
2662 }
2663
2664
2665 t.Go = &ast.StarExpr{}
2666 t.C.Set("<incomplete>*")
2667 key := dt.Type.String()
2668 if _, ok := c.ptrs[key]; !ok {
2669 c.ptrKeys = append(c.ptrKeys, dt.Type)
2670 }
2671 c.ptrs[key] = append(c.ptrs[key], t)
2672
2673 case *dwarf.QualType:
2674 t1 := c.Type(dt.Type, pos)
2675 t.Size = t1.Size
2676 t.Align = t1.Align
2677 t.Go = t1.Go
2678 if unionWithPointer[t1.Go] {
2679 unionWithPointer[t.Go] = true
2680 }
2681 t.EnumValues = nil
2682 t.Typedef = ""
2683 t.C.Set("%s "+dt.Qual, t1.C)
2684 return t
2685
2686 case *dwarf.StructType:
2687
2688
2689 tag := dt.StructName
2690 if dt.ByteSize < 0 && tag == "" {
2691 break
2692 }
2693 if tag == "" {
2694 tag = anonymousStructTag[dt]
2695 if tag == "" {
2696 tag = "__" + strconv.Itoa(tagGen)
2697 tagGen++
2698 anonymousStructTag[dt] = tag
2699 }
2700 } else if t.C.Empty() {
2701 t.C.Set(dt.Kind + " " + tag)
2702 }
2703 name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
2704 t.Go = name
2705 goIdent[name.Name] = name
2706 if dt.ByteSize < 0 {
2707
2708 if _, ok := typedef[name.Name]; ok {
2709 break
2710 }
2711
2712
2713
2714
2715 tt := *t
2716 tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}}
2717
2718
2719
2720
2721
2722
2723 tt.Go = c.Ident(incomplete)
2724 typedef[name.Name] = &tt
2725 break
2726 }
2727 switch dt.Kind {
2728 case "class", "union":
2729 t.Go = c.Opaque(t.Size)
2730 if c.dwarfHasPointer(dt, pos) {
2731 unionWithPointer[t.Go] = true
2732 }
2733 if t.C.Empty() {
2734 t.C.Set("__typeof__(unsigned char[%d])", t.Size)
2735 }
2736 t.Align = 1
2737 typedef[name.Name] = t
2738 case "struct":
2739 g, csyntax, align := c.Struct(dt, pos)
2740 if t.C.Empty() {
2741 t.C.Set(csyntax)
2742 }
2743 t.Align = align
2744 tt := *t
2745 if tag != "" {
2746 tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
2747 }
2748 tt.Go = g
2749 if c.incompleteStructs[tag] {
2750 tt.Go = c.Ident(incomplete)
2751 }
2752 typedef[name.Name] = &tt
2753 }
2754
2755 case *dwarf.TypedefType:
2756
2757 if dt.Name == "_GoString_" {
2758
2759
2760
2761 t.Go = c.string
2762 t.Size = c.ptrSize * 2
2763 t.Align = c.ptrSize
2764 break
2765 }
2766 if dt.Name == "_GoBytes_" {
2767
2768
2769 t.Go = c.Ident("[]byte")
2770 t.Size = c.ptrSize + 4 + 4
2771 t.Align = c.ptrSize
2772 break
2773 }
2774 name := c.Ident("_Ctype_" + dt.Name)
2775 goIdent[name.Name] = name
2776 akey := ""
2777 if c.anonymousStructTypedef(dt) {
2778
2779
2780 akey = key
2781 }
2782 sub := c.loadType(dt.Type, pos, akey)
2783 if c.badPointerTypedef(dt) {
2784
2785 s := *sub
2786 s.Go = c.uintptr
2787 s.BadPointer = true
2788 sub = &s
2789
2790 if oldType := typedef[name.Name]; oldType != nil {
2791 oldType.Go = sub.Go
2792 oldType.BadPointer = true
2793 }
2794 }
2795 if c.badVoidPointerTypedef(dt) {
2796
2797 s := *sub
2798 s.Go = c.Ident("*" + incomplete)
2799 sub = &s
2800
2801 if oldType := typedef[name.Name]; oldType != nil {
2802 oldType.Go = sub.Go
2803 }
2804 }
2805
2806
2807 if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
2808 if strct, ok := ptr.Type.(*dwarf.StructType); ok {
2809 if c.badStructPointerTypedef(dt.Name, strct) {
2810 c.incompleteStructs[strct.StructName] = true
2811
2812 name := "_Ctype_struct_" + strct.StructName
2813 if oldType := typedef[name]; oldType != nil {
2814 oldType.Go = c.Ident(incomplete)
2815 }
2816 }
2817 }
2818 }
2819 t.Go = name
2820 t.BadPointer = sub.BadPointer
2821 if unionWithPointer[sub.Go] {
2822 unionWithPointer[t.Go] = true
2823 }
2824 t.Size = sub.Size
2825 t.Align = sub.Align
2826 oldType := typedef[name.Name]
2827 if oldType == nil {
2828 tt := *t
2829 tt.Go = sub.Go
2830 tt.BadPointer = sub.BadPointer
2831 typedef[name.Name] = &tt
2832 }
2833
2834
2835
2836
2837
2838 if isStructUnionClass(sub.Go) || *godefs {
2839 t.Go = sub.Go
2840
2841 if isStructUnionClass(sub.Go) {
2842
2843 typedef[sub.Go.(*ast.Ident).Name].C = t.C
2844 }
2845
2846
2847
2848
2849
2850
2851 if oldType != nil && isStructUnionClass(oldType.Go) {
2852 t.Go = oldType.Go
2853 }
2854 }
2855
2856 case *dwarf.UcharType:
2857 if t.Size != 1 {
2858 fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
2859 }
2860 t.Go = c.uint8
2861 t.Align = 1
2862
2863 case *dwarf.UintType:
2864 if dt.BitSize > 0 {
2865 fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
2866 }
2867
2868 if t.Align = t.Size; t.Align >= c.ptrSize {
2869 t.Align = c.ptrSize
2870 }
2871
2872 switch t.Size {
2873 default:
2874 fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
2875 case 1:
2876 t.Go = c.uint8
2877 case 2:
2878 t.Go = c.uint16
2879 case 4:
2880 t.Go = c.uint32
2881 case 8:
2882 t.Go = c.uint64
2883 case 16:
2884 t.Go = &ast.ArrayType{
2885 Len: c.intExpr(t.Size),
2886 Elt: c.uint8,
2887 }
2888
2889 t.Align = 1
2890 }
2891
2892 case *dwarf.VoidType:
2893 t.Go = c.goVoid
2894 t.C.Set("void")
2895 t.Align = 1
2896 }
2897
2898 switch dtype.(type) {
2899 case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
2900 s := dtype.Common().Name
2901 if s != "" {
2902 if ss, ok := dwarfToName[s]; ok {
2903 s = ss
2904 }
2905 s = strings.ReplaceAll(s, " ", "")
2906 name := c.Ident("_Ctype_" + s)
2907 tt := *t
2908 typedef[name.Name] = &tt
2909 if !*godefs {
2910 t.Go = name
2911 }
2912 }
2913 }
2914
2915 if t.Size < 0 {
2916
2917
2918
2919 t.Size = 0
2920 switch dt := dtype.(type) {
2921 case *dwarf.TypedefType:
2922
2923 case *dwarf.StructType:
2924 if dt.StructName != "" {
2925 break
2926 }
2927 t.Go = c.Opaque(0)
2928 default:
2929 t.Go = c.Opaque(0)
2930 }
2931 if t.C.Empty() {
2932 t.C.Set("void")
2933 }
2934 }
2935
2936 if t.C.Empty() {
2937 fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
2938 }
2939
2940 return t
2941 }
2942
2943
2944
2945 func isStructUnionClass(x ast.Expr) bool {
2946 id, ok := x.(*ast.Ident)
2947 if !ok {
2948 return false
2949 }
2950 name := id.Name
2951 return strings.HasPrefix(name, "_Ctype_struct_") ||
2952 strings.HasPrefix(name, "_Ctype_union_") ||
2953 strings.HasPrefix(name, "_Ctype_class_")
2954 }
2955
2956
2957
2958 func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
2959 t := c.Type(unqual(dtype), pos)
2960 switch dt := dtype.(type) {
2961 case *dwarf.ArrayType:
2962
2963
2964 tr := &TypeRepr{}
2965 tr.Set("%s*", t.C)
2966 return &Type{
2967 Size: c.ptrSize,
2968 Align: c.ptrSize,
2969 Go: &ast.StarExpr{X: t.Go},
2970 C: tr,
2971 }
2972 case *dwarf.TypedefType:
2973
2974
2975
2976
2977 if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
2978
2979
2980 if _, void := base(ptr.Type).(*dwarf.VoidType); void {
2981 break
2982 }
2983
2984
2985 if c.baseBadPointerTypedef(dt) {
2986 break
2987 }
2988
2989 t = c.Type(ptr, pos)
2990 if t == nil {
2991 return nil
2992 }
2993
2994
2995
2996
2997 if isStructUnionClass(t.Go) {
2998 t.Typedef = dt.Name
2999 }
3000 }
3001 }
3002 return t
3003 }
3004
3005
3006
3007 func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
3008 p := make([]*Type, len(dtype.ParamType))
3009 gp := make([]*ast.Field, len(dtype.ParamType))
3010 for i, f := range dtype.ParamType {
3011
3012
3013
3014
3015
3016 if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
3017 p, gp = nil, nil
3018 break
3019 }
3020 p[i] = c.FuncArg(f, pos)
3021 gp[i] = &ast.Field{Type: p[i].Go}
3022 }
3023 var r *Type
3024 var gr []*ast.Field
3025 if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok {
3026 gr = []*ast.Field{{Type: c.goVoid}}
3027 } else if dtype.ReturnType != nil {
3028 r = c.Type(unqual(dtype.ReturnType), pos)
3029 gr = []*ast.Field{{Type: r.Go}}
3030 }
3031 return &FuncType{
3032 Params: p,
3033 Result: r,
3034 Go: &ast.FuncType{
3035 Params: &ast.FieldList{List: gp},
3036 Results: &ast.FieldList{List: gr},
3037 },
3038 }
3039 }
3040
3041
3042 func (c *typeConv) Ident(s string) *ast.Ident {
3043 return ast.NewIdent(s)
3044 }
3045
3046
3047 func (c *typeConv) Opaque(n int64) ast.Expr {
3048 return &ast.ArrayType{
3049 Len: c.intExpr(n),
3050 Elt: c.byte,
3051 }
3052 }
3053
3054
3055 func (c *typeConv) intExpr(n int64) ast.Expr {
3056 return &ast.BasicLit{
3057 Kind: token.INT,
3058 Value: strconv.FormatInt(n, 10),
3059 }
3060 }
3061
3062
3063 func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
3064 n := len(fld)
3065 fld = fld[0 : n+1]
3066 fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
3067 sizes = sizes[0 : n+1]
3068 sizes[n] = size
3069 return fld, sizes
3070 }
3071
3072
3073 func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
3074
3075 align = 1
3076
3077 var buf strings.Builder
3078 buf.WriteString("struct {")
3079 fld := make([]*ast.Field, 0, 2*len(dt.Field)+1)
3080 sizes := make([]int64, 0, 2*len(dt.Field)+1)
3081 off := int64(0)
3082
3083
3084
3085
3086
3087
3088
3089 ident := make(map[string]string)
3090 used := make(map[string]bool)
3091 for _, f := range dt.Field {
3092 ident[f.Name] = f.Name
3093 used[f.Name] = true
3094 }
3095
3096 if !*godefs {
3097 for cid, goid := range ident {
3098 if token.Lookup(goid).IsKeyword() {
3099
3100 goid = "_" + goid
3101
3102
3103 for _, exist := used[goid]; exist; _, exist = used[goid] {
3104 goid = "_" + goid
3105 }
3106
3107 used[goid] = true
3108 ident[cid] = goid
3109 }
3110 }
3111 }
3112
3113 anon := 0
3114 for _, f := range dt.Field {
3115 name := f.Name
3116 ft := f.Type
3117
3118
3119
3120
3121
3122
3123 if *godefs {
3124 if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
3125 name = st.Field[0].Name
3126 ident[name] = name
3127 ft = st.Field[0].Type
3128 }
3129 }
3130
3131
3132
3133
3134 t := c.Type(ft, pos)
3135 tgo := t.Go
3136 size := t.Size
3137 talign := t.Align
3138 if f.BitOffset > 0 || f.BitSize > 0 {
3139
3140
3141
3142 continue
3143 }
3144
3145 if talign > 0 && f.ByteOffset%talign != 0 {
3146
3147
3148
3149
3150
3151 continue
3152 }
3153
3154
3155 origOff := off
3156 off = (off + talign - 1) &^ (talign - 1)
3157
3158 if f.ByteOffset > off {
3159 fld, sizes = c.pad(fld, sizes, f.ByteOffset-origOff)
3160 off = f.ByteOffset
3161 }
3162 if f.ByteOffset < off {
3163
3164 continue
3165 }
3166
3167 n := len(fld)
3168 fld = fld[0 : n+1]
3169 if name == "" {
3170 name = fmt.Sprintf("anon%d", anon)
3171 anon++
3172 ident[name] = name
3173 }
3174 fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
3175 sizes = sizes[0 : n+1]
3176 sizes[n] = size
3177 off += size
3178 buf.WriteString(t.C.String())
3179 buf.WriteString(" ")
3180 buf.WriteString(name)
3181 buf.WriteString("; ")
3182 if talign > align {
3183 align = talign
3184 }
3185 }
3186 if off < dt.ByteSize {
3187 fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
3188 off = dt.ByteSize
3189 }
3190
3191
3192
3193
3194
3195
3196
3197 for off > 0 && sizes[len(sizes)-1] == 0 {
3198 n := len(sizes)
3199 fld = fld[0 : n-1]
3200 sizes = sizes[0 : n-1]
3201 }
3202
3203 if off != dt.ByteSize {
3204 fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
3205 }
3206 buf.WriteString("}")
3207 csyntax = buf.String()
3208
3209 if *godefs {
3210 godefsFields(fld)
3211 }
3212 expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
3213 return
3214 }
3215
3216
3217 func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
3218 switch dt := dt.(type) {
3219 default:
3220 fatalf("%s: unexpected type: %s", lineno(pos), dt)
3221 return false
3222
3223 case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
3224 *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
3225 *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
3226
3227 return false
3228
3229 case *dwarf.ArrayType:
3230 return c.dwarfHasPointer(dt.Type, pos)
3231
3232 case *dwarf.PtrType:
3233 return true
3234
3235 case *dwarf.QualType:
3236 return c.dwarfHasPointer(dt.Type, pos)
3237
3238 case *dwarf.StructType:
3239 return slices.ContainsFunc(dt.Field, func(f *dwarf.StructField) bool {
3240 return c.dwarfHasPointer(f.Type, pos)
3241 })
3242
3243 case *dwarf.TypedefType:
3244 if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
3245 return true
3246 }
3247 return c.dwarfHasPointer(dt.Type, pos)
3248 }
3249 }
3250
3251 func upper(s string) string {
3252 if s == "" {
3253 return ""
3254 }
3255 r, size := utf8.DecodeRuneInString(s)
3256 if r == '_' {
3257 return "X" + s
3258 }
3259 return string(unicode.ToUpper(r)) + s[size:]
3260 }
3261
3262
3263
3264
3265
3266 func godefsFields(fld []*ast.Field) {
3267 prefix := fieldPrefix(fld)
3268
3269
3270 if prefix != "" {
3271 names := make(map[string]bool)
3272 fldLoop:
3273 for _, f := range fld {
3274 for _, n := range f.Names {
3275 name := n.Name
3276 if name == "_" {
3277 continue
3278 }
3279 if name != prefix {
3280 name = strings.TrimPrefix(n.Name, prefix)
3281 }
3282 name = upper(name)
3283 if names[name] {
3284
3285 prefix = ""
3286 break fldLoop
3287 }
3288 names[name] = true
3289 }
3290 }
3291 }
3292
3293 npad := 0
3294 for _, f := range fld {
3295 for _, n := range f.Names {
3296 if n.Name != prefix {
3297 n.Name = strings.TrimPrefix(n.Name, prefix)
3298 }
3299 if n.Name == "_" {
3300
3301 n.Name = "Pad_cgo_" + strconv.Itoa(npad)
3302 npad++
3303 }
3304 n.Name = upper(n.Name)
3305 }
3306 }
3307 }
3308
3309
3310
3311
3312
3313
3314
3315 func fieldPrefix(fld []*ast.Field) string {
3316 prefix := ""
3317 for _, f := range fld {
3318 for _, n := range f.Names {
3319
3320
3321
3322
3323
3324
3325
3326
3327 if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
3328 continue
3329 }
3330 i := strings.Index(n.Name, "_")
3331 if i < 0 {
3332 continue
3333 }
3334 if prefix == "" {
3335 prefix = n.Name[:i+1]
3336 } else if prefix != n.Name[:i+1] {
3337 return ""
3338 }
3339 }
3340 }
3341 return prefix
3342 }
3343
3344
3345
3346 func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
3347 st, ok := dt.Type.(*dwarf.StructType)
3348 return ok && st.StructName == ""
3349 }
3350
3351
3352
3353
3354
3355
3356
3357 func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
3358 if c.badCFType(dt) {
3359 return true
3360 }
3361 if c.badJNI(dt) {
3362 return true
3363 }
3364 if c.badEGLType(dt) {
3365 return true
3366 }
3367 return false
3368 }
3369
3370
3371 func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
3372
3373 if goos != "windows" || dt.Name != "HANDLE" {
3374 return false
3375 }
3376
3377 if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
3378 if _, ok := ptr.Type.(*dwarf.VoidType); ok {
3379 return true
3380 }
3381 }
3382 return false
3383 }
3384
3385
3386 func (c *typeConv) badStructPointerTypedef(name string, dt *dwarf.StructType) bool {
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397 if goos != "windows" {
3398 return false
3399 }
3400 if len(dt.Field) != 1 {
3401 return false
3402 }
3403 if dt.StructName != name+"__" {
3404 return false
3405 }
3406 if f := dt.Field[0]; f.Name != "unused" || f.Type.Common().Name != "int" {
3407 return false
3408 }
3409 return true
3410 }
3411
3412
3413
3414 func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
3415 for {
3416 if t, ok := dt.Type.(*dwarf.TypedefType); ok {
3417 dt = t
3418 continue
3419 }
3420 break
3421 }
3422 return c.badPointerTypedef(dt)
3423 }
3424
3425 func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
3426
3427
3428
3429
3430
3431
3432
3433 if goos != "darwin" && goos != "ios" {
3434 return false
3435 }
3436 s := dt.Name
3437 if !strings.HasSuffix(s, "Ref") {
3438 return false
3439 }
3440 s = s[:len(s)-3]
3441 if s == "CFType" {
3442 return true
3443 }
3444 if c.getTypeIDs[s] {
3445 return true
3446 }
3447 if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
3448
3449 return true
3450 }
3451 return false
3452 }
3453
3454
3455
3488
3489 func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
3490
3491
3492
3493
3494 if parent, ok := jniTypes[dt.Name]; ok {
3495
3496
3497
3498
3499
3500 w := dt
3501 for parent != "" {
3502 t, ok := w.Type.(*dwarf.TypedefType)
3503 if !ok || t.Name != parent {
3504 return false
3505 }
3506 w = t
3507 parent, ok = jniTypes[w.Name]
3508 if !ok {
3509 return false
3510 }
3511 }
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522 if ptr, ok := w.Type.(*dwarf.PtrType); ok {
3523 switch v := ptr.Type.(type) {
3524 case *dwarf.VoidType:
3525 return true
3526 case *dwarf.StructType:
3527 if v.StructName == "_jobject" && len(v.Field) == 0 {
3528 switch v.Kind {
3529 case "struct":
3530 if v.Incomplete {
3531 return true
3532 }
3533 case "class":
3534 if !v.Incomplete {
3535 return true
3536 }
3537 }
3538 }
3539 }
3540 }
3541 }
3542 return false
3543 }
3544
3545 func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
3546 if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
3547 return false
3548 }
3549
3550 if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
3551 if _, ok := ptr.Type.(*dwarf.VoidType); ok {
3552 return true
3553 }
3554 }
3555 return false
3556 }
3557
3558
3559
3560 var jniTypes = map[string]string{
3561 "jobject": "",
3562 "jclass": "jobject",
3563 "jthrowable": "jobject",
3564 "jstring": "jobject",
3565 "jarray": "jobject",
3566 "jbooleanArray": "jarray",
3567 "jbyteArray": "jarray",
3568 "jcharArray": "jarray",
3569 "jshortArray": "jarray",
3570 "jintArray": "jarray",
3571 "jlongArray": "jarray",
3572 "jfloatArray": "jarray",
3573 "jdoubleArray": "jarray",
3574 "jobjectArray": "jarray",
3575 "jweak": "jobject",
3576 }
3577
View as plain text