LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Annotate Ref in Prog with C types by parsing gcc debug output. | 5 // Annotate Ref in Prog with C types by parsing gcc debug output. |
6 // Conversion of debug output to Go types. | 6 // Conversion of debug output to Go types. |
7 | 7 |
8 package main | 8 package main |
9 | 9 |
10 import ( | 10 import ( |
(...skipping 10 matching lines...) Expand all Loading... |
21 "os" | 21 "os" |
22 "strconv" | 22 "strconv" |
23 "strings" | 23 "strings" |
24 "unicode" | 24 "unicode" |
25 ) | 25 ) |
26 | 26 |
27 var debugDefine = flag.Bool("debug-define", false, "print relevant #defines") | 27 var debugDefine = flag.Bool("debug-define", false, "print relevant #defines") |
28 var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations") | 28 var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations") |
29 | 29 |
30 var nameToC = map[string]string{ | 30 var nameToC = map[string]string{ |
31 » "schar": "signed char", | 31 » "schar": "signed char", |
32 » "uchar": "unsigned char", | 32 » "uchar": "unsigned char", |
33 » "ushort": "unsigned short", | 33 » "ushort": "unsigned short", |
34 » "uint": "unsigned int", | 34 » "uint": "unsigned int", |
35 » "ulong": "unsigned long", | 35 » "ulong": "unsigned long", |
36 » "longlong": "long long", | 36 » "longlong": "long long", |
37 » "ulonglong": "unsigned long long", | 37 » "ulonglong": "unsigned long long", |
| 38 » "complexfloat": "float complex", |
| 39 » "complexdouble": "double complex", |
38 } | 40 } |
39 | 41 |
40 // cname returns the C name to use for C.s. | 42 // cname returns the C name to use for C.s. |
41 // The expansions are listed in nameToC and also | 43 // The expansions are listed in nameToC and also |
42 // struct_foo becomes "struct foo", and similarly for | 44 // struct_foo becomes "struct foo", and similarly for |
43 // union and enum. | 45 // union and enum. |
44 func cname(s string) string { | 46 func cname(s string) string { |
45 if t, ok := nameToC[s]; ok { | 47 if t, ok := nameToC[s]; ok { |
46 return t | 48 return t |
47 } | 49 } |
(...skipping 27 matching lines...) Expand all Loading... |
75 fields := strings.Split(l, ":", 2) | 77 fields := strings.Split(l, ":", 2) |
76 if len(fields) != 2 { | 78 if len(fields) != 2 { |
77 fatal("%s: bad #cgo line: %s", srcfile, line) | 79 fatal("%s: bad #cgo line: %s", srcfile, line) |
78 } | 80 } |
79 | 81 |
80 k := fields[0] | 82 k := fields[0] |
81 v := strings.TrimSpace(fields[1]) | 83 v := strings.TrimSpace(fields[1]) |
82 if k != "CFLAGS" && k != "LDFLAGS" { | 84 if k != "CFLAGS" && k != "LDFLAGS" { |
83 fatal("%s: unsupported #cgo option %s", srcfile, k) | 85 fatal("%s: unsupported #cgo option %s", srcfile, k) |
84 } | 86 } |
| 87 args, err := splitQuoted(v) |
| 88 if err != nil { |
| 89 fatal("%s: bad #cgo option %s: %s", srcfile, k, err.Stri
ng()) |
| 90 } |
85 if oldv, ok := p.CgoFlags[k]; ok { | 91 if oldv, ok := p.CgoFlags[k]; ok { |
86 p.CgoFlags[k] = oldv + " " + v | 92 p.CgoFlags[k] = oldv + " " + v |
87 } else { | 93 } else { |
88 p.CgoFlags[k] = v | 94 p.CgoFlags[k] = v |
89 } | 95 } |
90 if k == "CFLAGS" { | 96 if k == "CFLAGS" { |
91 » » » p.GccOptions = append(p.GccOptions, splitArgs(v)...) | 97 » » » p.GccOptions = append(p.GccOptions, args...) |
92 } | 98 } |
93 } | 99 } |
94 f.Preamble = strings.Join(linesOut, "\n") | 100 f.Preamble = strings.Join(linesOut, "\n") |
95 } | 101 } |
96 | 102 |
97 // splitArgs returns the string splitted in the same way | 103 // splitQuoted splits the string s around each instance of one or more consecuti
ve |
98 // a shell splits arguments in the command line. | 104 // white space characters while taking into account quotes and escaping, and |
| 105 // returns an array of substrings of s or an empty list if s contains only white
space. |
| 106 // Single quotes and double quotes are recognized to prevent splitting within th
e |
| 107 // quoted region, and are removed from the resulting substrings. If a quote in s |
| 108 // isn't closed err will be set and r will have the unclosed argument as the |
| 109 // last element. The backslash is used for escaping. |
99 // | 110 // |
100 // TODO(niemeyer): This looks like a handy function to have | 111 // For example, the following string: |
101 // available, and should probably be moved into the stdlib. | 112 // |
102 func splitArgs(s string) []string { | 113 // `a b:"c d" 'e''f' "g\""` |
103 » args := make([]string, 0, len(s)) | 114 // |
| 115 // Would be parsed as: |
| 116 // |
| 117 // []string{"a", "b:c d", "ef", `g"`} |
| 118 // |
| 119 func splitQuoted(s string) (r []string, err os.Error) { |
| 120 » var args []string |
104 arg := make([]int, len(s)) | 121 arg := make([]int, len(s)) |
105 escaped := false | 122 escaped := false |
| 123 quoted := false |
106 quote := 0 | 124 quote := 0 |
107 i := 0 | 125 i := 0 |
108 for _, rune := range s { | 126 for _, rune := range s { |
109 switch { | 127 switch { |
110 case escaped: | 128 case escaped: |
111 escaped = false | 129 escaped = false |
112 » » case rune == int('\\'): | 130 » » case rune == '\\': |
113 escaped = true | 131 escaped = true |
114 continue | 132 continue |
115 case quote != 0: | 133 case quote != 0: |
116 if rune == quote { | 134 if rune == quote { |
117 quote = 0 | 135 quote = 0 |
118 continue | 136 continue |
119 } | 137 } |
120 » » case rune == int('"') || rune == int('\''): | 138 » » case rune == '"' || rune == '\'': |
| 139 » » » quoted = true |
121 quote = rune | 140 quote = rune |
122 continue | 141 continue |
123 case unicode.IsSpace(rune): | 142 case unicode.IsSpace(rune): |
124 » » » if i > 0 { | 143 » » » if quoted || i > 0 { |
| 144 » » » » quoted = false |
125 args = append(args, string(arg[:i])) | 145 args = append(args, string(arg[:i])) |
126 i = 0 | 146 i = 0 |
127 } | 147 } |
128 continue | 148 continue |
129 } | 149 } |
130 arg[i] = rune | 150 arg[i] = rune |
131 i++ | 151 i++ |
132 } | 152 } |
133 » if i > 0 { | 153 » if quoted || i > 0 { |
134 args = append(args, string(arg[:i])) | 154 args = append(args, string(arg[:i])) |
135 } | 155 } |
136 » return args | 156 » if quote != 0 { |
| 157 » » err = os.ErrorString("unclosed quote") |
| 158 » } else if escaped { |
| 159 » » err = os.ErrorString("unfinished escaping") |
| 160 » } |
| 161 » return args, err |
137 } | 162 } |
138 | 163 |
139 // Translate rewrites f.AST, the original Go input, to remove | 164 // Translate rewrites f.AST, the original Go input, to remove |
140 // references to the imported package C, replacing them with | 165 // references to the imported package C, replacing them with |
141 // references to the equivalent Go types, functions, and variables. | 166 // references to the equivalent Go types, functions, and variables. |
142 func (p *Package) Translate(f *File) { | 167 func (p *Package) Translate(f *File) { |
143 for _, cref := range f.Ref { | 168 for _, cref := range f.Ref { |
144 // Convert C.ulong to C.unsigned long, etc. | 169 // Convert C.ulong to C.unsigned long, etc. |
145 cref.Name.C = cname(cref.Name.Go) | 170 cref.Name.C = cname(cref.Name.Go) |
146 } | 171 } |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 names := make([]*Name, len(toSniff)) | 302 names := make([]*Name, len(toSniff)) |
278 copy(names, toSniff) | 303 copy(names, toSniff) |
279 | 304 |
280 isConst := make([]bool, len(toSniff)) | 305 isConst := make([]bool, len(toSniff)) |
281 for i := range isConst { | 306 for i := range isConst { |
282 isConst[i] = true // until proven otherwise | 307 isConst[i] = true // until proven otherwise |
283 } | 308 } |
284 | 309 |
285 for _, line := range strings.Split(stderr, "\n", -1) { | 310 for _, line := range strings.Split(stderr, "\n", -1) { |
286 if len(line) < 9 || line[0:9] != "cgo-test:" { | 311 if len(line) < 9 || line[0:9] != "cgo-test:" { |
287 » » » if len(line) > 8 && line[0:8] == "<stdin>:" { | 312 » » » // the user will see any compiler errors when the code i
s compiled later. |
288 » » » » fatal("gcc produced unexpected output:\n%s\non i
nput:\n%s", line, b.Bytes()) | |
289 » » » } | |
290 continue | 313 continue |
291 } | 314 } |
292 line = line[9:] | 315 line = line[9:] |
293 colon := strings.Index(line, ":") | 316 colon := strings.Index(line, ":") |
294 if colon < 0 { | 317 if colon < 0 { |
295 continue | 318 continue |
296 } | 319 } |
297 i, err := strconv.Atoi(line[0:colon]) | 320 i, err := strconv.Atoi(line[0:colon]) |
298 if err != nil { | 321 if err != nil { |
299 continue | 322 continue |
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) | 663 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) |
641 os.Stderr.Write(stdin) | 664 os.Stderr.Write(stdin) |
642 fmt.Fprint(os.Stderr, "EOF\n") | 665 fmt.Fprint(os.Stderr, "EOF\n") |
643 } | 666 } |
644 stdout, stderr, ok := run(stdin, args) | 667 stdout, stderr, ok := run(stdin, args) |
645 if *debugGcc { | 668 if *debugGcc { |
646 os.Stderr.Write(stdout) | 669 os.Stderr.Write(stdout) |
647 os.Stderr.Write(stderr) | 670 os.Stderr.Write(stderr) |
648 } | 671 } |
649 if !ok { | 672 if !ok { |
650 fmt.Fprint(os.Stderr, "Error running gcc:\n") | |
651 fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) | |
652 os.Stderr.Write(stdin) | |
653 fmt.Fprint(os.Stderr, "EOF\n") | |
654 os.Stderr.Write(stderr) | 673 os.Stderr.Write(stderr) |
655 os.Exit(2) | 674 os.Exit(2) |
656 } | 675 } |
657 return string(stdout), string(stderr) | 676 return string(stdout), string(stderr) |
658 } | 677 } |
659 | 678 |
660 // A typeConv is a translator from dwarf types to Go types | 679 // A typeConv is a translator from dwarf types to Go types |
661 // with equivalent memory layout. | 680 // with equivalent memory layout. |
662 type typeConv struct { | 681 type typeConv struct { |
663 // Cache of already-translated or in-progress types. | 682 // Cache of already-translated or in-progress types. |
664 m map[dwarf.Type]*Type | 683 m map[dwarf.Type]*Type |
665 typedef map[string]ast.Expr | 684 typedef map[string]ast.Expr |
666 | 685 |
667 // Predeclared types. | 686 // Predeclared types. |
668 bool ast.Expr | 687 bool ast.Expr |
669 byte ast.Expr // denotes padding | 688 byte ast.Expr // denotes padding |
670 int8, int16, int32, int64 ast.Expr | 689 int8, int16, int32, int64 ast.Expr |
671 uint8, uint16, uint32, uint64, uintptr ast.Expr | 690 uint8, uint16, uint32, uint64, uintptr ast.Expr |
672 float32, float64 ast.Expr | 691 float32, float64 ast.Expr |
| 692 complex64, complex128 ast.Expr |
673 void ast.Expr | 693 void ast.Expr |
674 unsafePointer ast.Expr | 694 unsafePointer ast.Expr |
675 string ast.Expr | 695 string ast.Expr |
676 | 696 |
677 ptrSize int64 | 697 ptrSize int64 |
678 } | 698 } |
679 | 699 |
680 var tagGen int | 700 var tagGen int |
681 var typedef = make(map[string]ast.Expr) | 701 var typedef = make(map[string]ast.Expr) |
682 | 702 |
683 func (c *typeConv) Init(ptrSize int64) { | 703 func (c *typeConv) Init(ptrSize int64) { |
684 c.ptrSize = ptrSize | 704 c.ptrSize = ptrSize |
685 c.m = make(map[dwarf.Type]*Type) | 705 c.m = make(map[dwarf.Type]*Type) |
686 c.bool = c.Ident("bool") | 706 c.bool = c.Ident("bool") |
687 c.byte = c.Ident("byte") | 707 c.byte = c.Ident("byte") |
688 c.int8 = c.Ident("int8") | 708 c.int8 = c.Ident("int8") |
689 c.int16 = c.Ident("int16") | 709 c.int16 = c.Ident("int16") |
690 c.int32 = c.Ident("int32") | 710 c.int32 = c.Ident("int32") |
691 c.int64 = c.Ident("int64") | 711 c.int64 = c.Ident("int64") |
692 c.uint8 = c.Ident("uint8") | 712 c.uint8 = c.Ident("uint8") |
693 c.uint16 = c.Ident("uint16") | 713 c.uint16 = c.Ident("uint16") |
694 c.uint32 = c.Ident("uint32") | 714 c.uint32 = c.Ident("uint32") |
695 c.uint64 = c.Ident("uint64") | 715 c.uint64 = c.Ident("uint64") |
696 c.uintptr = c.Ident("uintptr") | 716 c.uintptr = c.Ident("uintptr") |
697 c.float32 = c.Ident("float32") | 717 c.float32 = c.Ident("float32") |
698 c.float64 = c.Ident("float64") | 718 c.float64 = c.Ident("float64") |
| 719 c.complex64 = c.Ident("complex64") |
| 720 c.complex128 = c.Ident("complex128") |
699 c.unsafePointer = c.Ident("unsafe.Pointer") | 721 c.unsafePointer = c.Ident("unsafe.Pointer") |
700 c.void = c.Ident("void") | 722 c.void = c.Ident("void") |
701 c.string = c.Ident("string") | 723 c.string = c.Ident("string") |
702 } | 724 } |
703 | 725 |
704 // base strips away qualifiers and typedefs to get the underlying type | 726 // base strips away qualifiers and typedefs to get the underlying type |
705 func base(dt dwarf.Type) dwarf.Type { | 727 func base(dt dwarf.Type) dwarf.Type { |
706 for { | 728 for { |
707 if d, ok := dt.(*dwarf.QualType); ok { | 729 if d, ok := dt.(*dwarf.QualType); ok { |
708 dt = d.Type | 730 dt = d.Type |
(...skipping 11 matching lines...) Expand all Loading... |
720 // Map from dwarf text names to aliases we use in package "C". | 742 // Map from dwarf text names to aliases we use in package "C". |
721 var dwarfToName = map[string]string{ | 743 var dwarfToName = map[string]string{ |
722 "long int": "long", | 744 "long int": "long", |
723 "long unsigned int": "ulong", | 745 "long unsigned int": "ulong", |
724 "unsigned int": "uint", | 746 "unsigned int": "uint", |
725 "short unsigned int": "ushort", | 747 "short unsigned int": "ushort", |
726 "short int": "short", | 748 "short int": "short", |
727 "long long int": "longlong", | 749 "long long int": "longlong", |
728 "long long unsigned int": "ulonglong", | 750 "long long unsigned int": "ulonglong", |
729 "signed char": "schar", | 751 "signed char": "schar", |
| 752 "float complex": "complexfloat", |
| 753 "double complex": "complexdouble", |
730 } | 754 } |
731 | 755 |
732 // Type returns a *Type with the same memory layout as | 756 // Type returns a *Type with the same memory layout as |
733 // dtype when used as the type of a variable or a struct field. | 757 // dtype when used as the type of a variable or a struct field. |
734 func (c *typeConv) Type(dtype dwarf.Type) *Type { | 758 func (c *typeConv) Type(dtype dwarf.Type) *Type { |
735 if t, ok := c.m[dtype]; ok { | 759 if t, ok := c.m[dtype]; ok { |
736 if t.Go == nil { | 760 if t.Go == nil { |
737 fatal("type conversion loop at %s", dtype) | 761 fatal("type conversion loop at %s", dtype) |
738 } | 762 } |
739 return t | 763 return t |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
816 } | 840 } |
817 | 841 |
818 case *dwarf.FloatType: | 842 case *dwarf.FloatType: |
819 switch t.Size { | 843 switch t.Size { |
820 default: | 844 default: |
821 fatal("unexpected: %d-byte float type - %s", t.Size, dty
pe) | 845 fatal("unexpected: %d-byte float type - %s", t.Size, dty
pe) |
822 case 4: | 846 case 4: |
823 t.Go = c.float32 | 847 t.Go = c.float32 |
824 case 8: | 848 case 8: |
825 t.Go = c.float64 | 849 t.Go = c.float64 |
| 850 } |
| 851 if t.Align = t.Size; t.Align >= c.ptrSize { |
| 852 t.Align = c.ptrSize |
| 853 } |
| 854 |
| 855 case *dwarf.ComplexType: |
| 856 switch t.Size { |
| 857 default: |
| 858 fatal("unexpected: %d-byte complex type - %s", t.Size, d
type) |
| 859 case 8: |
| 860 t.Go = c.complex64 |
| 861 case 16: |
| 862 t.Go = c.complex128 |
826 } | 863 } |
827 if t.Align = t.Size; t.Align >= c.ptrSize { | 864 if t.Align = t.Size; t.Align >= c.ptrSize { |
828 t.Align = c.ptrSize | 865 t.Align = c.ptrSize |
829 } | 866 } |
830 | 867 |
831 case *dwarf.FuncType: | 868 case *dwarf.FuncType: |
832 // No attempt at translation: would enable calls | 869 // No attempt at translation: would enable calls |
833 // directly between worlds, but we need to moderate those. | 870 // directly between worlds, but we need to moderate those. |
834 t.Go = c.uintptr | 871 t.Go = c.uintptr |
835 t.Align = c.ptrSize | 872 t.Align = c.ptrSize |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1130 off = dt.ByteSize | 1167 off = dt.ByteSize |
1131 } | 1168 } |
1132 if off != dt.ByteSize { | 1169 if off != dt.ByteSize { |
1133 fatal("struct size calculation error") | 1170 fatal("struct size calculation error") |
1134 } | 1171 } |
1135 buf.WriteString("}") | 1172 buf.WriteString("}") |
1136 csyntax = buf.String() | 1173 csyntax = buf.String() |
1137 expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} | 1174 expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} |
1138 return | 1175 return |
1139 } | 1176 } |
LEFT | RIGHT |