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