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