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