|  | // Copyright 2009 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // Annotate Ref in Prog with C types by parsing gcc debug output. | 
|  | // Conversion of debug output to Go types. | 
|  |  | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "debug/dwarf" | 
|  | "debug/elf" | 
|  | "debug/macho" | 
|  | "debug/pe" | 
|  | "encoding/binary" | 
|  | "errors" | 
|  | "flag" | 
|  | "fmt" | 
|  | "go/ast" | 
|  | "go/parser" | 
|  | "go/token" | 
|  | "internal/xcoff" | 
|  | "math" | 
|  | "os" | 
|  | "strconv" | 
|  | "strings" | 
|  | "unicode" | 
|  | "unicode/utf8" | 
|  | ) | 
|  |  | 
|  | var debugDefine = flag.Bool("debug-define", false, "print relevant #defines") | 
|  | var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations") | 
|  |  | 
|  | var nameToC = map[string]string{ | 
|  | "schar":         "signed char", | 
|  | "uchar":         "unsigned char", | 
|  | "ushort":        "unsigned short", | 
|  | "uint":          "unsigned int", | 
|  | "ulong":         "unsigned long", | 
|  | "longlong":      "long long", | 
|  | "ulonglong":     "unsigned long long", | 
|  | "complexfloat":  "float _Complex", | 
|  | "complexdouble": "double _Complex", | 
|  | } | 
|  |  | 
|  | // cname returns the C name to use for C.s. | 
|  | // The expansions are listed in nameToC and also | 
|  | // struct_foo becomes "struct foo", and similarly for | 
|  | // union and enum. | 
|  | func cname(s string) string { | 
|  | if t, ok := nameToC[s]; ok { | 
|  | return t | 
|  | } | 
|  |  | 
|  | if strings.HasPrefix(s, "struct_") { | 
|  | return "struct " + s[len("struct_"):] | 
|  | } | 
|  | if strings.HasPrefix(s, "union_") { | 
|  | return "union " + s[len("union_"):] | 
|  | } | 
|  | if strings.HasPrefix(s, "enum_") { | 
|  | return "enum " + s[len("enum_"):] | 
|  | } | 
|  | if strings.HasPrefix(s, "sizeof_") { | 
|  | return "sizeof(" + cname(s[len("sizeof_"):]) + ")" | 
|  | } | 
|  | return s | 
|  | } | 
|  |  | 
|  | // DiscardCgoDirectives processes the import C preamble, and discards | 
|  | // all #cgo CFLAGS and LDFLAGS directives, so they don't make their | 
|  | // way into _cgo_export.h. | 
|  | func (f *File) DiscardCgoDirectives() { | 
|  | linesIn := strings.Split(f.Preamble, "\n") | 
|  | linesOut := make([]string, 0, len(linesIn)) | 
|  | for _, line := range linesIn { | 
|  | l := strings.TrimSpace(line) | 
|  | if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) { | 
|  | linesOut = append(linesOut, line) | 
|  | } else { | 
|  | linesOut = append(linesOut, "") | 
|  | } | 
|  | } | 
|  | f.Preamble = strings.Join(linesOut, "\n") | 
|  | } | 
|  |  | 
|  | // addToFlag appends args to flag. All flags are later written out onto the | 
|  | // _cgo_flags file for the build system to use. | 
|  | func (p *Package) addToFlag(flag string, args []string) { | 
|  | p.CgoFlags[flag] = append(p.CgoFlags[flag], args...) | 
|  | if flag == "CFLAGS" { | 
|  | // We'll also need these when preprocessing for dwarf information. | 
|  | // However, discard any -g options: we need to be able | 
|  | // to parse the debug info, so stick to what we expect. | 
|  | for _, arg := range args { | 
|  | if !strings.HasPrefix(arg, "-g") { | 
|  | p.GccOptions = append(p.GccOptions, arg) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // splitQuoted splits the string s around each instance of one or more consecutive | 
|  | // white space characters while taking into account quotes and escaping, and | 
|  | // returns an array of substrings of s or an empty list if s contains only white space. | 
|  | // Single quotes and double quotes are recognized to prevent splitting within the | 
|  | // quoted region, and are removed from the resulting substrings. If a quote in s | 
|  | // isn't closed err will be set and r will have the unclosed argument as the | 
|  | // last element. The backslash is used for escaping. | 
|  | // | 
|  | // For example, the following string: | 
|  | // | 
|  | //     `a b:"c d" 'e''f'  "g\""` | 
|  | // | 
|  | // Would be parsed as: | 
|  | // | 
|  | //     []string{"a", "b:c d", "ef", `g"`} | 
|  | // | 
|  | func splitQuoted(s string) (r []string, err error) { | 
|  | var args []string | 
|  | arg := make([]rune, len(s)) | 
|  | escaped := false | 
|  | quoted := false | 
|  | quote := '\x00' | 
|  | i := 0 | 
|  | for _, r := range s { | 
|  | switch { | 
|  | case escaped: | 
|  | escaped = false | 
|  | case r == '\\': | 
|  | escaped = true | 
|  | continue | 
|  | case quote != 0: | 
|  | if r == quote { | 
|  | quote = 0 | 
|  | continue | 
|  | } | 
|  | case r == '"' || r == '\'': | 
|  | quoted = true | 
|  | quote = r | 
|  | continue | 
|  | case unicode.IsSpace(r): | 
|  | if quoted || i > 0 { | 
|  | quoted = false | 
|  | args = append(args, string(arg[:i])) | 
|  | i = 0 | 
|  | } | 
|  | continue | 
|  | } | 
|  | arg[i] = r | 
|  | i++ | 
|  | } | 
|  | if quoted || i > 0 { | 
|  | args = append(args, string(arg[:i])) | 
|  | } | 
|  | if quote != 0 { | 
|  | err = errors.New("unclosed quote") | 
|  | } else if escaped { | 
|  | err = errors.New("unfinished escaping") | 
|  | } | 
|  | return args, err | 
|  | } | 
|  |  | 
|  | // Translate rewrites f.AST, the original Go input, to remove | 
|  | // references to the imported package C, replacing them with | 
|  | // references to the equivalent Go types, functions, and variables. | 
|  | func (p *Package) Translate(f *File) { | 
|  | for _, cref := range f.Ref { | 
|  | // Convert C.ulong to C.unsigned long, etc. | 
|  | cref.Name.C = cname(cref.Name.Go) | 
|  | } | 
|  |  | 
|  | var conv typeConv | 
|  | conv.Init(p.PtrSize, p.IntSize) | 
|  |  | 
|  | p.loadDefines(f) | 
|  | p.typedefs = map[string]bool{} | 
|  | p.typedefList = nil | 
|  | numTypedefs := -1 | 
|  | for len(p.typedefs) > numTypedefs { | 
|  | numTypedefs = len(p.typedefs) | 
|  | // Also ask about any typedefs we've seen so far. | 
|  | for _, info := range p.typedefList { | 
|  | n := &Name{ | 
|  | Go: info.typedef, | 
|  | C:  info.typedef, | 
|  | } | 
|  | f.Name[info.typedef] = n | 
|  | f.NamePos[n] = info.pos | 
|  | } | 
|  | needType := p.guessKinds(f) | 
|  | if len(needType) > 0 { | 
|  | p.loadDWARF(f, &conv, needType) | 
|  | } | 
|  |  | 
|  | // In godefs mode we're OK with the typedefs, which | 
|  | // will presumably also be defined in the file, we | 
|  | // don't want to resolve them to their base types. | 
|  | if *godefs { | 
|  | break | 
|  | } | 
|  | } | 
|  | p.prepareNames(f) | 
|  | if p.rewriteCalls(f) { | 
|  | // Add `import _cgo_unsafe "unsafe"` after the package statement. | 
|  | f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"") | 
|  | } | 
|  | p.rewriteRef(f) | 
|  | } | 
|  |  | 
|  | // loadDefines coerces gcc into spitting out the #defines in use | 
|  | // in the file f and saves relevant renamings in f.Name[name].Define. | 
|  | func (p *Package) loadDefines(f *File) { | 
|  | var b bytes.Buffer | 
|  | b.WriteString(builtinProlog) | 
|  | b.WriteString(f.Preamble) | 
|  | stdout := p.gccDefines(b.Bytes()) | 
|  |  | 
|  | for _, line := range strings.Split(stdout, "\n") { | 
|  | if len(line) < 9 || line[0:7] != "#define" { | 
|  | continue | 
|  | } | 
|  |  | 
|  | line = strings.TrimSpace(line[8:]) | 
|  |  | 
|  | var key, val string | 
|  | spaceIndex := strings.Index(line, " ") | 
|  | tabIndex := strings.Index(line, "\t") | 
|  |  | 
|  | if spaceIndex == -1 && tabIndex == -1 { | 
|  | continue | 
|  | } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) { | 
|  | key = line[0:spaceIndex] | 
|  | val = strings.TrimSpace(line[spaceIndex:]) | 
|  | } else { | 
|  | key = line[0:tabIndex] | 
|  | val = strings.TrimSpace(line[tabIndex:]) | 
|  | } | 
|  |  | 
|  | if key == "__clang__" { | 
|  | p.GccIsClang = true | 
|  | } | 
|  |  | 
|  | if n := f.Name[key]; n != nil { | 
|  | if *debugDefine { | 
|  | fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val) | 
|  | } | 
|  | n.Define = val | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // guessKinds tricks gcc into revealing the kind of each | 
|  | // name xxx for the references C.xxx in the Go input. | 
|  | // The kind is either a constant, type, or variable. | 
|  | func (p *Package) guessKinds(f *File) []*Name { | 
|  | // Determine kinds for names we already know about, | 
|  | // like #defines or 'struct foo', before bothering with gcc. | 
|  | var names, needType []*Name | 
|  | optional := map[*Name]bool{} | 
|  | for _, key := range nameKeys(f.Name) { | 
|  | n := f.Name[key] | 
|  | // If we've already found this name as a #define | 
|  | // and we can translate it as a constant value, do so. | 
|  | if n.Define != "" { | 
|  | if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil { | 
|  | n.Kind = "iconst" | 
|  | // Turn decimal into hex, just for consistency | 
|  | // with enum-derived constants. Otherwise | 
|  | // in the cgo -godefs output half the constants | 
|  | // are in hex and half are in whatever the #define used. | 
|  | n.Const = fmt.Sprintf("%#x", i) | 
|  | } else if n.Define[0] == '\'' { | 
|  | if _, err := parser.ParseExpr(n.Define); err == nil { | 
|  | n.Kind = "iconst" | 
|  | n.Const = n.Define | 
|  | } | 
|  | } else if n.Define[0] == '"' { | 
|  | if _, err := parser.ParseExpr(n.Define); err == nil { | 
|  | n.Kind = "sconst" | 
|  | n.Const = n.Define | 
|  | } | 
|  | } | 
|  |  | 
|  | if n.IsConst() { | 
|  | continue | 
|  | } | 
|  | } | 
|  |  | 
|  | // If this is a struct, union, or enum type name, no need to guess the kind. | 
|  | if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") { | 
|  | n.Kind = "type" | 
|  | needType = append(needType, n) | 
|  | continue | 
|  | } | 
|  |  | 
|  | if goos == "darwin" && strings.HasSuffix(n.C, "Ref") { | 
|  | // For FooRef, find out if FooGetTypeID exists. | 
|  | s := n.C[:len(n.C)-3] + "GetTypeID" | 
|  | n := &Name{Go: s, C: s} | 
|  | names = append(names, n) | 
|  | optional[n] = true | 
|  | } | 
|  |  | 
|  | // Otherwise, we'll need to find out from gcc. | 
|  | names = append(names, n) | 
|  | } | 
|  |  | 
|  | // Bypass gcc if there's nothing left to find out. | 
|  | if len(names) == 0 { | 
|  | return needType | 
|  | } | 
|  |  | 
|  | // Coerce gcc into telling us whether each name is a type, a value, or undeclared. | 
|  | // For names, find out whether they are integer constants. | 
|  | // We used to look at specific warning or error messages here, but that tied the | 
|  | // behavior too closely to specific versions of the compilers. | 
|  | // Instead, arrange that we can infer what we need from only the presence or absence | 
|  | // of an error on a specific line. | 
|  | // | 
|  | // For each name, we generate these lines, where xxx is the index in toSniff plus one. | 
|  | // | 
|  | //	#line xxx "not-declared" | 
|  | //	void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__1; } | 
|  | //	#line xxx "not-type" | 
|  | //	void __cgo_f_xxx_2(void) { name *__cgo_undefined__2; } | 
|  | //	#line xxx "not-int-const" | 
|  | //	void __cgo_f_xxx_3(void) { enum { __cgo_undefined__3 = (name)*1 }; } | 
|  | //	#line xxx "not-num-const" | 
|  | //	void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); } | 
|  | //	#line xxx "not-str-lit" | 
|  | //	void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); } | 
|  | // | 
|  | // If we see an error at not-declared:xxx, the corresponding name is not declared. | 
|  | // If we see an error at not-type:xxx, the corresponding name is a type. | 
|  | // If we see an error at not-int-const:xxx, the corresponding name is not an integer constant. | 
|  | // If we see an error at not-num-const:xxx, the corresponding name is not a number constant. | 
|  | // If we see an error at not-str-lit:xxx, the corresponding name is not a string literal. | 
|  | // | 
|  | // The specific input forms are chosen so that they are valid C syntax regardless of | 
|  | // whether name denotes a type or an expression. | 
|  |  | 
|  | var b bytes.Buffer | 
|  | b.WriteString(builtinProlog) | 
|  | b.WriteString(f.Preamble) | 
|  |  | 
|  | for i, n := range names { | 
|  | fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+ | 
|  | "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__1; }\n"+ | 
|  | "#line %d \"not-type\"\n"+ | 
|  | "void __cgo_f_%d_2(void) { %s *__cgo_undefined__2; }\n"+ | 
|  | "#line %d \"not-int-const\"\n"+ | 
|  | "void __cgo_f_%d_3(void) { enum { __cgo_undefined__3 = (%s)*1 }; }\n"+ | 
|  | "#line %d \"not-num-const\"\n"+ | 
|  | "void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+ | 
|  | "#line %d \"not-str-lit\"\n"+ | 
|  | "void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n", | 
|  | i+1, i+1, n.C, | 
|  | i+1, i+1, n.C, | 
|  | i+1, i+1, n.C, | 
|  | i+1, i+1, n.C, | 
|  | i+1, i+1, n.C, | 
|  | ) | 
|  | } | 
|  | fmt.Fprintf(&b, "#line 1 \"completed\"\n"+ | 
|  | "int __cgo__1 = __cgo__2;\n") | 
|  |  | 
|  | stderr := p.gccErrors(b.Bytes()) | 
|  | if stderr == "" { | 
|  | fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) | 
|  | } | 
|  |  | 
|  | completed := false | 
|  | sniff := make([]int, len(names)) | 
|  | const ( | 
|  | notType = 1 << iota | 
|  | notIntConst | 
|  | notNumConst | 
|  | notStrLiteral | 
|  | notDeclared | 
|  | ) | 
|  | sawUnmatchedErrors := false | 
|  | for _, line := range strings.Split(stderr, "\n") { | 
|  | // Ignore warnings and random comments, with one | 
|  | // exception: newer GCC versions will sometimes emit | 
|  | // an error on a macro #define with a note referring | 
|  | // to where the expansion occurs. We care about where | 
|  | // the expansion occurs, so in that case treat the note | 
|  | // as an error. | 
|  | isError := strings.Contains(line, ": error:") | 
|  | isErrorNote := strings.Contains(line, ": note:") && sawUnmatchedErrors | 
|  | if !isError && !isErrorNote { | 
|  | continue | 
|  | } | 
|  |  | 
|  | c1 := strings.Index(line, ":") | 
|  | if c1 < 0 { | 
|  | continue | 
|  | } | 
|  | c2 := strings.Index(line[c1+1:], ":") | 
|  | if c2 < 0 { | 
|  | continue | 
|  | } | 
|  | c2 += c1 + 1 | 
|  |  | 
|  | filename := line[:c1] | 
|  | i, _ := strconv.Atoi(line[c1+1 : c2]) | 
|  | i-- | 
|  | if i < 0 || i >= len(names) { | 
|  | if isError { | 
|  | sawUnmatchedErrors = true | 
|  | } | 
|  | continue | 
|  | } | 
|  |  | 
|  | switch filename { | 
|  | case "completed": | 
|  | // Strictly speaking, there is no guarantee that seeing the error at completed:1 | 
|  | // (at the end of the file) means we've seen all the errors from earlier in the file, | 
|  | // but usually it does. Certainly if we don't see the completed:1 error, we did | 
|  | // not get all the errors we expected. | 
|  | completed = true | 
|  |  | 
|  | case "not-declared": | 
|  | sniff[i] |= notDeclared | 
|  | case "not-type": | 
|  | sniff[i] |= notType | 
|  | case "not-int-const": | 
|  | sniff[i] |= notIntConst | 
|  | case "not-num-const": | 
|  | sniff[i] |= notNumConst | 
|  | case "not-str-lit": | 
|  | sniff[i] |= notStrLiteral | 
|  | default: | 
|  | if isError { | 
|  | sawUnmatchedErrors = true | 
|  | } | 
|  | continue | 
|  | } | 
|  |  | 
|  | sawUnmatchedErrors = false | 
|  | } | 
|  |  | 
|  | if !completed { | 
|  | fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", p.gccBaseCmd()[0], b.Bytes(), stderr) | 
|  | } | 
|  |  | 
|  | for i, n := range names { | 
|  | switch sniff[i] { | 
|  | default: | 
|  | if sniff[i]¬Declared != 0 && optional[n] { | 
|  | // Ignore optional undeclared identifiers. | 
|  | // Don't report an error, and skip adding n to the needType array. | 
|  | continue | 
|  | } | 
|  | error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go)) | 
|  | case notStrLiteral | notType: | 
|  | n.Kind = "iconst" | 
|  | case notIntConst | notStrLiteral | notType: | 
|  | n.Kind = "fconst" | 
|  | case notIntConst | notNumConst | notType: | 
|  | n.Kind = "sconst" | 
|  | case notIntConst | notNumConst | notStrLiteral: | 
|  | n.Kind = "type" | 
|  | case notIntConst | notNumConst | notStrLiteral | notType: | 
|  | n.Kind = "not-type" | 
|  | } | 
|  | needType = append(needType, n) | 
|  | } | 
|  | if nerrors > 0 { | 
|  | // Check if compiling the preamble by itself causes any errors, | 
|  | // because the messages we've printed out so far aren't helpful | 
|  | // to users debugging preamble mistakes. See issue 8442. | 
|  | preambleErrors := p.gccErrors([]byte(f.Preamble)) | 
|  | if len(preambleErrors) > 0 { | 
|  | error_(token.NoPos, "\n%s errors for preamble:\n%s", p.gccBaseCmd()[0], preambleErrors) | 
|  | } | 
|  |  | 
|  | fatalf("unresolved names") | 
|  | } | 
|  |  | 
|  | return needType | 
|  | } | 
|  |  | 
|  | // loadDWARF parses the DWARF debug information generated | 
|  | // by gcc to learn the details of the constants, variables, and types | 
|  | // being referred to as C.xxx. | 
|  | func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) { | 
|  | // Extract the types from the DWARF section of an object | 
|  | // from a well-formed C program. Gcc only generates DWARF info | 
|  | // for symbols in the object file, so it is not enough to print the | 
|  | // preamble and hope the symbols we care about will be there. | 
|  | // Instead, emit | 
|  | //	__typeof__(names[i]) *__cgo__i; | 
|  | // for each entry in names and then dereference the type we | 
|  | // learn for __cgo__i. | 
|  | var b bytes.Buffer | 
|  | b.WriteString(builtinProlog) | 
|  | b.WriteString(f.Preamble) | 
|  | b.WriteString("#line 1 \"cgo-dwarf-inference\"\n") | 
|  | for i, n := range names { | 
|  | fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i) | 
|  | if n.Kind == "iconst" { | 
|  | fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C) | 
|  | } | 
|  | } | 
|  |  | 
|  | // We create a data block initialized with the values, | 
|  | // so we can read them out of the object file. | 
|  | fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n") | 
|  | for _, n := range names { | 
|  | if n.Kind == "iconst" { | 
|  | fmt.Fprintf(&b, "\t%s,\n", n.C) | 
|  | } else { | 
|  | fmt.Fprintf(&b, "\t0,\n") | 
|  | } | 
|  | } | 
|  | // for the last entry, we cannot use 0, otherwise | 
|  | // in case all __cgodebug_data is zero initialized, | 
|  | // LLVM-based gcc will place the it in the __DATA.__common | 
|  | // zero-filled section (our debug/macho doesn't support | 
|  | // this) | 
|  | fmt.Fprintf(&b, "\t1\n") | 
|  | fmt.Fprintf(&b, "};\n") | 
|  |  | 
|  | // do the same work for floats. | 
|  | fmt.Fprintf(&b, "double __cgodebug_floats[] = {\n") | 
|  | for _, n := range names { | 
|  | if n.Kind == "fconst" { | 
|  | fmt.Fprintf(&b, "\t%s,\n", n.C) | 
|  | } else { | 
|  | fmt.Fprintf(&b, "\t0,\n") | 
|  | } | 
|  | } | 
|  | fmt.Fprintf(&b, "\t1\n") | 
|  | fmt.Fprintf(&b, "};\n") | 
|  |  | 
|  | // do the same work for strings. | 
|  | for i, n := range names { | 
|  | if n.Kind == "sconst" { | 
|  | fmt.Fprintf(&b, "const char __cgodebug_str__%d[] = %s;\n", i, n.C) | 
|  | fmt.Fprintf(&b, "const unsigned long long __cgodebug_strlen__%d = sizeof(%s)-1;\n", i, n.C) | 
|  | } | 
|  | } | 
|  |  | 
|  | d, ints, floats, strs := p.gccDebug(b.Bytes(), len(names)) | 
|  |  | 
|  | // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i. | 
|  | types := make([]dwarf.Type, len(names)) | 
|  | r := d.Reader() | 
|  | for { | 
|  | e, err := r.Next() | 
|  | if err != nil { | 
|  | fatalf("reading DWARF entry: %s", err) | 
|  | } | 
|  | if e == nil { | 
|  | break | 
|  | } | 
|  | switch e.Tag { | 
|  | case dwarf.TagVariable: | 
|  | name, _ := e.Val(dwarf.AttrName).(string) | 
|  | typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset) | 
|  | if name == "" || typOff == 0 { | 
|  | if e.Val(dwarf.AttrSpecification) != nil { | 
|  | // Since we are reading all the DWARF, | 
|  | // assume we will see the variable elsewhere. | 
|  | break | 
|  | } | 
|  | fatalf("malformed DWARF TagVariable entry") | 
|  | } | 
|  | if !strings.HasPrefix(name, "__cgo__") { | 
|  | break | 
|  | } | 
|  | typ, err := d.Type(typOff) | 
|  | if err != nil { | 
|  | fatalf("loading DWARF type: %s", err) | 
|  | } | 
|  | t, ok := typ.(*dwarf.PtrType) | 
|  | if !ok || t == nil { | 
|  | fatalf("internal error: %s has non-pointer type", name) | 
|  | } | 
|  | i, err := strconv.Atoi(name[7:]) | 
|  | if err != nil { | 
|  | fatalf("malformed __cgo__ name: %s", name) | 
|  | } | 
|  | types[i] = t.Type | 
|  | p.recordTypedefs(t.Type, f.NamePos[names[i]]) | 
|  | } | 
|  | if e.Tag != dwarf.TagCompileUnit { | 
|  | r.SkipChildren() | 
|  | } | 
|  | } | 
|  |  | 
|  | // Record types and typedef information. | 
|  | for i, n := range names { | 
|  | if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" { | 
|  | conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true | 
|  | } | 
|  | } | 
|  | for i, n := range names { | 
|  | if types[i] == nil { | 
|  | continue | 
|  | } | 
|  | pos := f.NamePos[n] | 
|  | f, fok := types[i].(*dwarf.FuncType) | 
|  | if n.Kind != "type" && fok { | 
|  | n.Kind = "func" | 
|  | n.FuncType = conv.FuncType(f, pos) | 
|  | } else { | 
|  | n.Type = conv.Type(types[i], pos) | 
|  | switch n.Kind { | 
|  | case "iconst": | 
|  | if i < len(ints) { | 
|  | if _, ok := types[i].(*dwarf.UintType); ok { | 
|  | n.Const = fmt.Sprintf("%#x", uint64(ints[i])) | 
|  | } else { | 
|  | n.Const = fmt.Sprintf("%#x", ints[i]) | 
|  | } | 
|  | } | 
|  | case "fconst": | 
|  | if i >= len(floats) { | 
|  | break | 
|  | } | 
|  | switch base(types[i]).(type) { | 
|  | case *dwarf.IntType, *dwarf.UintType: | 
|  | // This has an integer type so it's | 
|  | // not really a floating point | 
|  | // constant. This can happen when the | 
|  | // C compiler complains about using | 
|  | // the value as an integer constant, | 
|  | // but not as a general constant. | 
|  | // Treat this as a variable of the | 
|  | // appropriate type, not a constant, | 
|  | // to get C-style type handling, | 
|  | // avoiding the problem that C permits | 
|  | // uint64(-1) but Go does not. | 
|  | // See issue 26066. | 
|  | n.Kind = "var" | 
|  | default: | 
|  | n.Const = fmt.Sprintf("%f", floats[i]) | 
|  | } | 
|  | case "sconst": | 
|  | if i < len(strs) { | 
|  | n.Const = fmt.Sprintf("%q", strs[i]) | 
|  | } | 
|  | } | 
|  | } | 
|  | conv.FinishType(pos) | 
|  | } | 
|  | } | 
|  |  | 
|  | // recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children. | 
|  | func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) { | 
|  | p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{}) | 
|  | } | 
|  |  | 
|  | func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) { | 
|  | if dtype == nil { | 
|  | return | 
|  | } | 
|  | if visited[dtype] { | 
|  | return | 
|  | } | 
|  | visited[dtype] = true | 
|  | switch dt := dtype.(type) { | 
|  | case *dwarf.TypedefType: | 
|  | if strings.HasPrefix(dt.Name, "__builtin") { | 
|  | // Don't look inside builtin types. There be dragons. | 
|  | return | 
|  | } | 
|  | if !p.typedefs[dt.Name] { | 
|  | p.typedefs[dt.Name] = true | 
|  | p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos}) | 
|  | p.recordTypedefs1(dt.Type, pos, visited) | 
|  | } | 
|  | case *dwarf.PtrType: | 
|  | p.recordTypedefs1(dt.Type, pos, visited) | 
|  | case *dwarf.ArrayType: | 
|  | p.recordTypedefs1(dt.Type, pos, visited) | 
|  | case *dwarf.QualType: | 
|  | p.recordTypedefs1(dt.Type, pos, visited) | 
|  | case *dwarf.FuncType: | 
|  | p.recordTypedefs1(dt.ReturnType, pos, visited) | 
|  | for _, a := range dt.ParamType { | 
|  | p.recordTypedefs1(a, pos, visited) | 
|  | } | 
|  | case *dwarf.StructType: | 
|  | for _, f := range dt.Field { | 
|  | p.recordTypedefs1(f.Type, pos, visited) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // prepareNames finalizes the Kind field of not-type names and sets | 
|  | // the mangled name of all names. | 
|  | func (p *Package) prepareNames(f *File) { | 
|  | for _, n := range f.Name { | 
|  | if n.Kind == "not-type" { | 
|  | if n.Define == "" { | 
|  | n.Kind = "var" | 
|  | } else { | 
|  | n.Kind = "macro" | 
|  | n.FuncType = &FuncType{ | 
|  | Result: n.Type, | 
|  | Go: &ast.FuncType{ | 
|  | Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}}, | 
|  | }, | 
|  | } | 
|  | } | 
|  | } | 
|  | p.mangleName(n) | 
|  | } | 
|  | } | 
|  |  | 
|  | // mangleName does name mangling to translate names | 
|  | // from the original Go source files to the names | 
|  | // used in the final Go files generated by cgo. | 
|  | func (p *Package) mangleName(n *Name) { | 
|  | // When using gccgo variables have to be | 
|  | // exported so that they become global symbols | 
|  | // that the C code can refer to. | 
|  | prefix := "_C" | 
|  | if *gccgo && n.IsVar() { | 
|  | prefix = "C" | 
|  | } | 
|  | n.Mangle = prefix + n.Kind + "_" + n.Go | 
|  | } | 
|  |  | 
|  | func (f *File) isMangledName(s string) bool { | 
|  | prefix := "_C" | 
|  | if strings.HasPrefix(s, prefix) { | 
|  | t := s[len(prefix):] | 
|  | for _, k := range nameKinds { | 
|  | if strings.HasPrefix(t, k+"_") { | 
|  | return true | 
|  | } | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // rewriteCalls rewrites all calls that pass pointers to check that | 
|  | // they follow the rules for passing pointers between Go and C. | 
|  | // This reports whether the package needs to import unsafe as _cgo_unsafe. | 
|  | func (p *Package) rewriteCalls(f *File) bool { | 
|  | needsUnsafe := false | 
|  | // Walk backward so that in C.f1(C.f2()) we rewrite C.f2 first. | 
|  | for _, call := range f.Calls { | 
|  | if call.Done { | 
|  | continue | 
|  | } | 
|  | start := f.offset(call.Call.Pos()) | 
|  | end := f.offset(call.Call.End()) | 
|  | str, nu := p.rewriteCall(f, call) | 
|  | if str != "" { | 
|  | f.Edit.Replace(start, end, str) | 
|  | if nu { | 
|  | needsUnsafe = true | 
|  | } | 
|  | } | 
|  | } | 
|  | return needsUnsafe | 
|  | } | 
|  |  | 
|  | // rewriteCall rewrites one call to add pointer checks. | 
|  | // If any pointer checks are required, we rewrite the call into a | 
|  | // function literal that calls _cgoCheckPointer for each pointer | 
|  | // argument and then calls the original function. | 
|  | // This returns the rewritten call and whether the package needs to | 
|  | // import unsafe as _cgo_unsafe. | 
|  | // If it returns the empty string, the call did not need to be rewritten. | 
|  | func (p *Package) rewriteCall(f *File, call *Call) (string, bool) { | 
|  | // This is a call to C.xxx; set goname to "xxx". | 
|  | // It may have already been mangled by rewriteName. | 
|  | var goname string | 
|  | switch fun := call.Call.Fun.(type) { | 
|  | case *ast.SelectorExpr: | 
|  | goname = fun.Sel.Name | 
|  | case *ast.Ident: | 
|  | goname = strings.TrimPrefix(fun.Name, "_C2func_") | 
|  | goname = strings.TrimPrefix(goname, "_Cfunc_") | 
|  | } | 
|  | if goname == "" || goname == "malloc" { | 
|  | return "", false | 
|  | } | 
|  | name := f.Name[goname] | 
|  | if name == nil || name.Kind != "func" { | 
|  | // Probably a type conversion. | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | params := name.FuncType.Params | 
|  | args := call.Call.Args | 
|  |  | 
|  | // Avoid a crash if the number of arguments doesn't match | 
|  | // the number of parameters. | 
|  | // This will be caught when the generated file is compiled. | 
|  | if len(args) != len(params) { | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | any := false | 
|  | for i, param := range params { | 
|  | if p.needsPointerCheck(f, param.Go, args[i]) { | 
|  | any = true | 
|  | break | 
|  | } | 
|  | } | 
|  | if !any { | 
|  | return "", false | 
|  | } | 
|  |  | 
|  | // We need to rewrite this call. | 
|  | // | 
|  | // Rewrite C.f(p) to | 
|  | //    func() { | 
|  | //            _cgo0 := p | 
|  | //            _cgoCheckPointer(_cgo0, nil) | 
|  | //            C.f(_cgo0) | 
|  | //    }() | 
|  | // Using a function literal like this lets us evaluate the | 
|  | // function arguments only once while doing pointer checks. | 
|  | // This is particularly useful when passing additional arguments | 
|  | // to _cgoCheckPointer, as done in checkIndex and checkAddr. | 
|  | // | 
|  | // When the function argument is a conversion to unsafe.Pointer, | 
|  | // we unwrap the conversion before checking the pointer, | 
|  | // and then wrap again when calling C.f. This lets us check | 
|  | // the real type of the pointer in some cases. See issue #25941. | 
|  | // | 
|  | // When the call to C.f is deferred, we use an additional function | 
|  | // literal to evaluate the arguments at the right time. | 
|  | //    defer func() func() { | 
|  | //            _cgo0 := p | 
|  | //            return func() { | 
|  | //                    _cgoCheckPointer(_cgo0, nil) | 
|  | //                    C.f(_cgo0) | 
|  | //            } | 
|  | //    }()() | 
|  | // This works because the defer statement evaluates the first | 
|  | // function literal in order to get the function to call. | 
|  |  | 
|  | var sb bytes.Buffer | 
|  | sb.WriteString("func() ") | 
|  | if call.Deferred { | 
|  | sb.WriteString("func() ") | 
|  | } | 
|  |  | 
|  | needsUnsafe := false | 
|  | result := false | 
|  | twoResults := false | 
|  | if !call.Deferred { | 
|  | // Check whether this call expects two results. | 
|  | for _, ref := range f.Ref { | 
|  | if ref.Expr != &call.Call.Fun { | 
|  | continue | 
|  | } | 
|  | if ref.Context == ctxCall2 { | 
|  | sb.WriteString("(") | 
|  | result = true | 
|  | twoResults = true | 
|  | } | 
|  | break | 
|  | } | 
|  |  | 
|  | // Add the result type, if any. | 
|  | if name.FuncType.Result != nil { | 
|  | rtype := p.rewriteUnsafe(name.FuncType.Result.Go) | 
|  | if rtype != name.FuncType.Result.Go { | 
|  | needsUnsafe = true | 
|  | } | 
|  | sb.WriteString(gofmtLine(rtype)) | 
|  | result = true | 
|  | } | 
|  |  | 
|  | // Add the second result type, if any. | 
|  | if twoResults { | 
|  | if name.FuncType.Result == nil { | 
|  | // An explicit void result looks odd but it | 
|  | // seems to be how cgo has worked historically. | 
|  | sb.WriteString("_Ctype_void") | 
|  | } | 
|  | sb.WriteString(", error)") | 
|  | } | 
|  | } | 
|  |  | 
|  | sb.WriteString("{ ") | 
|  |  | 
|  | // Define _cgoN for each argument value. | 
|  | // Write _cgoCheckPointer calls to sbCheck. | 
|  | var sbCheck bytes.Buffer | 
|  | for i, param := range params { | 
|  | origArg := args[i] | 
|  | arg, nu := p.mangle(f, &args[i]) | 
|  | if nu { | 
|  | needsUnsafe = true | 
|  | } | 
|  |  | 
|  | // Use "var x T = ..." syntax to explicitly convert untyped | 
|  | // constants to the parameter type, to avoid a type mismatch. | 
|  | ptype := p.rewriteUnsafe(param.Go) | 
|  |  | 
|  | if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer { | 
|  | if ptype != param.Go { | 
|  | needsUnsafe = true | 
|  | } | 
|  | fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i, | 
|  | gofmtLine(ptype), gofmtPos(arg, origArg.Pos())) | 
|  | continue | 
|  | } | 
|  |  | 
|  | // Check for &a[i]. | 
|  | if p.checkIndex(&sb, &sbCheck, arg, i) { | 
|  | continue | 
|  | } | 
|  |  | 
|  | // Check for &x. | 
|  | if p.checkAddr(&sb, &sbCheck, arg, i) { | 
|  | continue | 
|  | } | 
|  |  | 
|  | fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos())) | 
|  | fmt.Fprintf(&sbCheck, "_cgoCheckPointer(_cgo%d, nil); ", i) | 
|  | } | 
|  |  | 
|  | if call.Deferred { | 
|  | sb.WriteString("return func() { ") | 
|  | } | 
|  |  | 
|  | // Write out the calls to _cgoCheckPointer. | 
|  | sb.WriteString(sbCheck.String()) | 
|  |  | 
|  | if result { | 
|  | sb.WriteString("return ") | 
|  | } | 
|  |  | 
|  | m, nu := p.mangle(f, &call.Call.Fun) | 
|  | if nu { | 
|  | needsUnsafe = true | 
|  | } | 
|  | sb.WriteString(gofmtLine(m)) | 
|  |  | 
|  | sb.WriteString("(") | 
|  | for i := range params { | 
|  | if i > 0 { | 
|  | sb.WriteString(", ") | 
|  | } | 
|  | fmt.Fprintf(&sb, "_cgo%d", i) | 
|  | } | 
|  | sb.WriteString("); ") | 
|  | if call.Deferred { | 
|  | sb.WriteString("}") | 
|  | } | 
|  | sb.WriteString("}") | 
|  | if call.Deferred { | 
|  | sb.WriteString("()") | 
|  | } | 
|  | sb.WriteString("()") | 
|  |  | 
|  | return sb.String(), needsUnsafe | 
|  | } | 
|  |  | 
|  | // needsPointerCheck reports whether the type t needs a pointer check. | 
|  | // This is true if t is a pointer and if the value to which it points | 
|  | // might contain a pointer. | 
|  | func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool { | 
|  | // An untyped nil does not need a pointer check, and when | 
|  | // _cgoCheckPointer returns the untyped nil the type assertion we | 
|  | // are going to insert will fail.  Easier to just skip nil arguments. | 
|  | // TODO: Note that this fails if nil is shadowed. | 
|  | if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" { | 
|  | return false | 
|  | } | 
|  |  | 
|  | return p.hasPointer(f, t, true) | 
|  | } | 
|  |  | 
|  | // hasPointer is used by needsPointerCheck. If top is true it returns | 
|  | // whether t is or contains a pointer that might point to a pointer. | 
|  | // If top is false it reports whether t is or contains a pointer. | 
|  | // f may be nil. | 
|  | func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool { | 
|  | switch t := t.(type) { | 
|  | case *ast.ArrayType: | 
|  | if t.Len == nil { | 
|  | if !top { | 
|  | return true | 
|  | } | 
|  | return p.hasPointer(f, t.Elt, false) | 
|  | } | 
|  | return p.hasPointer(f, t.Elt, top) | 
|  | case *ast.StructType: | 
|  | for _, field := range t.Fields.List { | 
|  | if p.hasPointer(f, field.Type, top) { | 
|  | return true | 
|  | } | 
|  | } | 
|  | return false | 
|  | case *ast.StarExpr: // Pointer type. | 
|  | if !top { | 
|  | return true | 
|  | } | 
|  | // Check whether this is a pointer to a C union (or class) | 
|  | // type that contains a pointer. | 
|  | if unionWithPointer[t.X] { | 
|  | return true | 
|  | } | 
|  | return p.hasPointer(f, t.X, false) | 
|  | case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType: | 
|  | return true | 
|  | case *ast.Ident: | 
|  | // TODO: Handle types defined within function. | 
|  | for _, d := range p.Decl { | 
|  | gd, ok := d.(*ast.GenDecl) | 
|  | if !ok || gd.Tok != token.TYPE { | 
|  | continue | 
|  | } | 
|  | for _, spec := range gd.Specs { | 
|  | ts, ok := spec.(*ast.TypeSpec) | 
|  | if !ok { | 
|  | continue | 
|  | } | 
|  | if ts.Name.Name == t.Name { | 
|  | return p.hasPointer(f, ts.Type, top) | 
|  | } | 
|  | } | 
|  | } | 
|  | if def := typedef[t.Name]; def != nil { | 
|  | return p.hasPointer(f, def.Go, top) | 
|  | } | 
|  | if t.Name == "string" { | 
|  | return !top | 
|  | } | 
|  | if t.Name == "error" { | 
|  | return true | 
|  | } | 
|  | if goTypes[t.Name] != nil { | 
|  | return false | 
|  | } | 
|  | // We can't figure out the type. Conservative | 
|  | // approach is to assume it has a pointer. | 
|  | return true | 
|  | case *ast.SelectorExpr: | 
|  | if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" { | 
|  | // Type defined in a different package. | 
|  | // Conservative approach is to assume it has a | 
|  | // pointer. | 
|  | return true | 
|  | } | 
|  | if f == nil { | 
|  | // Conservative approach: assume pointer. | 
|  | return true | 
|  | } | 
|  | name := f.Name[t.Sel.Name] | 
|  | if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil { | 
|  | return p.hasPointer(f, name.Type.Go, top) | 
|  | } | 
|  | // We can't figure out the type. Conservative | 
|  | // approach is to assume it has a pointer. | 
|  | return true | 
|  | default: | 
|  | error_(t.Pos(), "could not understand type %s", gofmt(t)) | 
|  | return true | 
|  | } | 
|  | } | 
|  |  | 
|  | // mangle replaces references to C names in arg with the mangled names, | 
|  | // rewriting calls when it finds them. | 
|  | // It removes the corresponding references in f.Ref and f.Calls, so that we | 
|  | // don't try to do the replacement again in rewriteRef or rewriteCall. | 
|  | func (p *Package) mangle(f *File, arg *ast.Expr) (ast.Expr, bool) { | 
|  | needsUnsafe := false | 
|  | f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) { | 
|  | px, ok := arg.(*ast.Expr) | 
|  | if !ok { | 
|  | return | 
|  | } | 
|  | sel, ok := (*px).(*ast.SelectorExpr) | 
|  | if ok { | 
|  | if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" { | 
|  | return | 
|  | } | 
|  |  | 
|  | for _, r := range f.Ref { | 
|  | if r.Expr == px { | 
|  | *px = p.rewriteName(f, r) | 
|  | r.Done = true | 
|  | break | 
|  | } | 
|  | } | 
|  |  | 
|  | return | 
|  | } | 
|  |  | 
|  | call, ok := (*px).(*ast.CallExpr) | 
|  | if !ok { | 
|  | return | 
|  | } | 
|  |  | 
|  | for _, c := range f.Calls { | 
|  | if !c.Done && c.Call.Lparen == call.Lparen { | 
|  | cstr, nu := p.rewriteCall(f, c) | 
|  | if cstr != "" { | 
|  | // Smuggle the rewritten call through an ident. | 
|  | *px = ast.NewIdent(cstr) | 
|  | if nu { | 
|  | needsUnsafe = true | 
|  | } | 
|  | c.Done = true | 
|  | } | 
|  | } | 
|  | } | 
|  | }) | 
|  | return *arg, needsUnsafe | 
|  | } | 
|  |  | 
|  | // checkIndex checks whether arg has the form &a[i], possibly inside | 
|  | // type conversions. If so, then in the general case it writes | 
|  | //    _cgoIndexNN := a | 
|  | //    _cgoNN := &cgoIndexNN[i] // with type conversions, if any | 
|  | // to sb, and writes | 
|  | //    _cgoCheckPointer(_cgoNN, _cgoIndexNN) | 
|  | // to sbCheck, and returns true. If a is a simple variable or field reference, | 
|  | // it writes | 
|  | //    _cgoIndexNN := &a | 
|  | // and dereferences the uses of _cgoIndexNN. Taking the address avoids | 
|  | // making a copy of an array. | 
|  | // | 
|  | // This tells _cgoCheckPointer to check the complete contents of the | 
|  | // slice or array being indexed, but no other part of the memory allocation. | 
|  | func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool { | 
|  | // Strip type conversions. | 
|  | x := arg | 
|  | for { | 
|  | c, ok := x.(*ast.CallExpr) | 
|  | if !ok || len(c.Args) != 1 || !p.isType(c.Fun) { | 
|  | break | 
|  | } | 
|  | x = c.Args[0] | 
|  | } | 
|  | u, ok := x.(*ast.UnaryExpr) | 
|  | if !ok || u.Op != token.AND { | 
|  | return false | 
|  | } | 
|  | index, ok := u.X.(*ast.IndexExpr) | 
|  | if !ok { | 
|  | return false | 
|  | } | 
|  |  | 
|  | addr := "" | 
|  | deref := "" | 
|  | if p.isVariable(index.X) { | 
|  | addr = "&" | 
|  | deref = "*" | 
|  | } | 
|  |  | 
|  | fmt.Fprintf(sb, "_cgoIndex%d := %s%s; ", i, addr, gofmtPos(index.X, index.X.Pos())) | 
|  | origX := index.X | 
|  | index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i)) | 
|  | if deref == "*" { | 
|  | index.X = &ast.StarExpr{X: index.X} | 
|  | } | 
|  | fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos())) | 
|  | index.X = origX | 
|  |  | 
|  | fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, %s_cgoIndex%d); ", i, deref, i) | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | // checkAddr checks whether arg has the form &x, possibly inside type | 
|  | // conversions. If so, it writes | 
|  | //    _cgoBaseNN := &x | 
|  | //    _cgoNN := _cgoBaseNN // with type conversions, if any | 
|  | // to sb, and writes | 
|  | //    _cgoCheckPointer(_cgoBaseNN, true) | 
|  | // to sbCheck, and returns true. This tells _cgoCheckPointer to check | 
|  | // just the contents of the pointer being passed, not any other part | 
|  | // of the memory allocation. This is run after checkIndex, which looks | 
|  | // for the special case of &a[i], which requires different checks. | 
|  | func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool { | 
|  | // Strip type conversions. | 
|  | px := &arg | 
|  | for { | 
|  | c, ok := (*px).(*ast.CallExpr) | 
|  | if !ok || len(c.Args) != 1 || !p.isType(c.Fun) { | 
|  | break | 
|  | } | 
|  | px = &c.Args[0] | 
|  | } | 
|  | if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND { | 
|  | return false | 
|  | } | 
|  |  | 
|  | fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos())) | 
|  |  | 
|  | origX := *px | 
|  | *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i)) | 
|  | fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos())) | 
|  | *px = origX | 
|  |  | 
|  | // Use "0 == 0" to do the right thing in the unlikely event | 
|  | // that "true" is shadowed. | 
|  | fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i) | 
|  |  | 
|  | return true | 
|  | } | 
|  |  | 
|  | // isType reports whether the expression is definitely a type. | 
|  | // This is conservative--it returns false for an unknown identifier. | 
|  | func (p *Package) isType(t ast.Expr) bool { | 
|  | switch t := t.(type) { | 
|  | case *ast.SelectorExpr: | 
|  | id, ok := t.X.(*ast.Ident) | 
|  | if !ok { | 
|  | return false | 
|  | } | 
|  | if id.Name == "unsafe" && t.Sel.Name == "Pointer" { | 
|  | return true | 
|  | } | 
|  | if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil { | 
|  | return true | 
|  | } | 
|  | return false | 
|  | case *ast.Ident: | 
|  | // TODO: This ignores shadowing. | 
|  | switch t.Name { | 
|  | case "unsafe.Pointer", "bool", "byte", | 
|  | "complex64", "complex128", | 
|  | "error", | 
|  | "float32", "float64", | 
|  | "int", "int8", "int16", "int32", "int64", | 
|  | "rune", "string", | 
|  | "uint", "uint8", "uint16", "uint32", "uint64", "uintptr": | 
|  |  | 
|  | return true | 
|  | } | 
|  | if strings.HasPrefix(t.Name, "_Ctype_") { | 
|  | return true | 
|  | } | 
|  | case *ast.ParenExpr: | 
|  | return p.isType(t.X) | 
|  | case *ast.StarExpr: | 
|  | return p.isType(t.X) | 
|  | case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType, | 
|  | *ast.MapType, *ast.ChanType: | 
|  |  | 
|  | return true | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // isVariable reports whether x is a variable, possibly with field references. | 
|  | func (p *Package) isVariable(x ast.Expr) bool { | 
|  | switch x := x.(type) { | 
|  | case *ast.Ident: | 
|  | return true | 
|  | case *ast.SelectorExpr: | 
|  | return p.isVariable(x.X) | 
|  | case *ast.IndexExpr: | 
|  | return true | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // rewriteUnsafe returns a version of t with references to unsafe.Pointer | 
|  | // rewritten to use _cgo_unsafe.Pointer instead. | 
|  | func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr { | 
|  | switch t := t.(type) { | 
|  | case *ast.Ident: | 
|  | // We don't see a SelectorExpr for unsafe.Pointer; | 
|  | // this is created by code in this file. | 
|  | if t.Name == "unsafe.Pointer" { | 
|  | return ast.NewIdent("_cgo_unsafe.Pointer") | 
|  | } | 
|  | case *ast.ArrayType: | 
|  | t1 := p.rewriteUnsafe(t.Elt) | 
|  | if t1 != t.Elt { | 
|  | r := *t | 
|  | r.Elt = t1 | 
|  | return &r | 
|  | } | 
|  | case *ast.StructType: | 
|  | changed := false | 
|  | fields := *t.Fields | 
|  | fields.List = nil | 
|  | for _, f := range t.Fields.List { | 
|  | ft := p.rewriteUnsafe(f.Type) | 
|  | if ft == f.Type { | 
|  | fields.List = append(fields.List, f) | 
|  | } else { | 
|  | fn := *f | 
|  | fn.Type = ft | 
|  | fields.List = append(fields.List, &fn) | 
|  | changed = true | 
|  | } | 
|  | } | 
|  | if changed { | 
|  | r := *t | 
|  | r.Fields = &fields | 
|  | return &r | 
|  | } | 
|  | case *ast.StarExpr: // Pointer type. | 
|  | x1 := p.rewriteUnsafe(t.X) | 
|  | if x1 != t.X { | 
|  | r := *t | 
|  | r.X = x1 | 
|  | return &r | 
|  | } | 
|  | } | 
|  | return t | 
|  | } | 
|  |  | 
|  | // rewriteRef rewrites all the C.xxx references in f.AST to refer to the | 
|  | // Go equivalents, now that we have figured out the meaning of all | 
|  | // the xxx. In *godefs mode, rewriteRef replaces the names | 
|  | // with full definitions instead of mangled names. | 
|  | func (p *Package) rewriteRef(f *File) { | 
|  | // Keep a list of all the functions, to remove the ones | 
|  | // only used as expressions and avoid generating bridge | 
|  | // code for them. | 
|  | functions := make(map[string]bool) | 
|  |  | 
|  | for _, n := range f.Name { | 
|  | if n.Kind == "func" { | 
|  | functions[n.Go] = false | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now that we have all the name types filled in, | 
|  | // scan through the Refs to identify the ones that | 
|  | // are trying to do a ,err call. Also check that | 
|  | // functions are only used in calls. | 
|  | for _, r := range f.Ref { | 
|  | if r.Name.IsConst() && r.Name.Const == "" { | 
|  | error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go)) | 
|  | } | 
|  |  | 
|  | if r.Name.Kind == "func" { | 
|  | switch r.Context { | 
|  | case ctxCall, ctxCall2: | 
|  | functions[r.Name.Go] = true | 
|  | } | 
|  | } | 
|  |  | 
|  | expr := p.rewriteName(f, r) | 
|  |  | 
|  | if *godefs { | 
|  | // Substitute definition for mangled type name. | 
|  | if id, ok := expr.(*ast.Ident); ok { | 
|  | if t := typedef[id.Name]; t != nil { | 
|  | expr = t.Go | 
|  | } | 
|  | if id.Name == r.Name.Mangle && r.Name.Const != "" { | 
|  | expr = ast.NewIdent(r.Name.Const) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Copy position information from old expr into new expr, | 
|  | // in case expression being replaced is first on line. | 
|  | // See golang.org/issue/6563. | 
|  | pos := (*r.Expr).Pos() | 
|  | if x, ok := expr.(*ast.Ident); ok { | 
|  | expr = &ast.Ident{NamePos: pos, Name: x.Name} | 
|  | } | 
|  |  | 
|  | // Change AST, because some later processing depends on it, | 
|  | // and also because -godefs mode still prints the AST. | 
|  | old := *r.Expr | 
|  | *r.Expr = expr | 
|  |  | 
|  | // Record source-level edit for cgo output. | 
|  | if !r.Done { | 
|  | // Prepend a space in case the earlier code ends | 
|  | // with '/', which would give us a "//" comment. | 
|  | repl := " " + gofmtPos(expr, old.Pos()) | 
|  | end := fset.Position(old.End()) | 
|  | // Subtract 1 from the column if we are going to | 
|  | // append a close parenthesis. That will set the | 
|  | // correct column for the following characters. | 
|  | sub := 0 | 
|  | if r.Name.Kind != "type" { | 
|  | sub = 1 | 
|  | } | 
|  | if end.Column > sub { | 
|  | repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub) | 
|  | } | 
|  | if r.Name.Kind != "type" { | 
|  | repl = "(" + repl + ")" | 
|  | } | 
|  | f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Remove functions only used as expressions, so their respective | 
|  | // bridge functions are not generated. | 
|  | for name, used := range functions { | 
|  | if !used { | 
|  | delete(f.Name, name) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // rewriteName returns the expression used to rewrite a reference. | 
|  | func (p *Package) rewriteName(f *File, r *Ref) ast.Expr { | 
|  | var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default | 
|  | switch r.Context { | 
|  | case ctxCall, ctxCall2: | 
|  | if r.Name.Kind != "func" { | 
|  | if r.Name.Kind == "type" { | 
|  | r.Context = ctxType | 
|  | if r.Name.Type == nil { | 
|  | error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) | 
|  | break | 
|  | } | 
|  | expr = r.Name.Type.Go | 
|  | break | 
|  | } | 
|  | error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go)) | 
|  | break | 
|  | } | 
|  | if r.Context == ctxCall2 { | 
|  | if r.Name.Go == "_CMalloc" { | 
|  | error_(r.Pos(), "no two-result form for C.malloc") | 
|  | break | 
|  | } | 
|  | // Invent new Name for the two-result function. | 
|  | n := f.Name["2"+r.Name.Go] | 
|  | if n == nil { | 
|  | n = new(Name) | 
|  | *n = *r.Name | 
|  | n.AddError = true | 
|  | n.Mangle = "_C2func_" + n.Go | 
|  | f.Name["2"+r.Name.Go] = n | 
|  | } | 
|  | expr = ast.NewIdent(n.Mangle) | 
|  | r.Name = n | 
|  | break | 
|  | } | 
|  | case ctxExpr: | 
|  | switch r.Name.Kind { | 
|  | case "func": | 
|  | if builtinDefs[r.Name.C] != "" { | 
|  | error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C)) | 
|  | } | 
|  |  | 
|  | // Function is being used in an expression, to e.g. pass around a C function pointer. | 
|  | // Create a new Name for this Ref which causes the variable to be declared in Go land. | 
|  | fpName := "fp_" + r.Name.Go | 
|  | name := f.Name[fpName] | 
|  | if name == nil { | 
|  | name = &Name{ | 
|  | Go:   fpName, | 
|  | C:    r.Name.C, | 
|  | Kind: "fpvar", | 
|  | Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")}, | 
|  | } | 
|  | p.mangleName(name) | 
|  | f.Name[fpName] = name | 
|  | } | 
|  | r.Name = name | 
|  | // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr | 
|  | // function is defined in out.go and simply returns its argument. See | 
|  | // issue 7757. | 
|  | expr = &ast.CallExpr{ | 
|  | Fun:  &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"}, | 
|  | Args: []ast.Expr{ast.NewIdent(name.Mangle)}, | 
|  | } | 
|  | case "type": | 
|  | // Okay - might be new(T) | 
|  | if r.Name.Type == nil { | 
|  | error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) | 
|  | break | 
|  | } | 
|  | expr = r.Name.Type.Go | 
|  | case "var": | 
|  | expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} | 
|  | case "macro": | 
|  | expr = &ast.CallExpr{Fun: expr} | 
|  | } | 
|  | case ctxSelector: | 
|  | if r.Name.Kind == "var" { | 
|  | expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} | 
|  | } else { | 
|  | error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go)) | 
|  | } | 
|  | case ctxType: | 
|  | if r.Name.Kind != "type" { | 
|  | error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go)) | 
|  | } else if r.Name.Type == nil { | 
|  | // Use of C.enum_x, C.struct_x or C.union_x without C definition. | 
|  | // GCC won't raise an error when using pointers to such unknown types. | 
|  | error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) | 
|  | } else { | 
|  | expr = r.Name.Type.Go | 
|  | } | 
|  | default: | 
|  | if r.Name.Kind == "func" { | 
|  | error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go)) | 
|  | } | 
|  | } | 
|  | return expr | 
|  | } | 
|  |  | 
|  | // gofmtPos returns the gofmt-formatted string for an AST node, | 
|  | // with a comment setting the position before the node. | 
|  | func gofmtPos(n ast.Expr, pos token.Pos) string { | 
|  | s := gofmtLine(n) | 
|  | p := fset.Position(pos) | 
|  | if p.Column == 0 { | 
|  | return s | 
|  | } | 
|  | return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s) | 
|  | } | 
|  |  | 
|  | // gccBaseCmd returns the start of the compiler command line. | 
|  | // It uses $CC if set, or else $GCC, or else the compiler recorded | 
|  | // during the initial build as defaultCC. | 
|  | // defaultCC is defined in zdefaultcc.go, written by cmd/dist. | 
|  | func (p *Package) gccBaseCmd() []string { | 
|  | // Use $CC if set, since that's what the build uses. | 
|  | if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 { | 
|  | return ret | 
|  | } | 
|  | // Try $GCC if set, since that's what we used to use. | 
|  | if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { | 
|  | return ret | 
|  | } | 
|  | return strings.Fields(defaultCC(goos, goarch)) | 
|  | } | 
|  |  | 
|  | // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". | 
|  | func (p *Package) gccMachine() []string { | 
|  | switch goarch { | 
|  | case "amd64": | 
|  | return []string{"-m64"} | 
|  | case "386": | 
|  | return []string{"-m32"} | 
|  | case "arm": | 
|  | return []string{"-marm"} // not thumb | 
|  | case "s390": | 
|  | return []string{"-m31"} | 
|  | case "s390x": | 
|  | return []string{"-m64"} | 
|  | case "mips64", "mips64le": | 
|  | return []string{"-mabi=64"} | 
|  | case "mips", "mipsle": | 
|  | return []string{"-mabi=32"} | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func gccTmp() string { | 
|  | return *objDir + "_cgo_.o" | 
|  | } | 
|  |  | 
|  | // gccCmd returns the gcc command line to use for compiling | 
|  | // the input. | 
|  | func (p *Package) gccCmd() []string { | 
|  | c := append(p.gccBaseCmd(), | 
|  | "-w",          // no warnings | 
|  | "-Wno-error",  // warnings are not errors | 
|  | "-o"+gccTmp(), // write object to tmp | 
|  | "-gdwarf-2",   // generate DWARF v2 debugging symbols | 
|  | "-c",          // do not link | 
|  | "-xc",         // input language is C | 
|  | ) | 
|  | if p.GccIsClang { | 
|  | c = append(c, | 
|  | "-ferror-limit=0", | 
|  | // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) | 
|  | // doesn't have -Wno-unneeded-internal-declaration, so we need yet another | 
|  | // flag to disable the warning. Yes, really good diagnostics, clang. | 
|  | "-Wno-unknown-warning-option", | 
|  | "-Wno-unneeded-internal-declaration", | 
|  | "-Wno-unused-function", | 
|  | "-Qunused-arguments", | 
|  | // Clang embeds prototypes for some builtin functions, | 
|  | // like malloc and calloc, but all size_t parameters are | 
|  | // incorrectly typed unsigned long. We work around that | 
|  | // by disabling the builtin functions (this is safe as | 
|  | // it won't affect the actual compilation of the C code). | 
|  | // See: https://golang.org/issue/6506. | 
|  | "-fno-builtin", | 
|  | ) | 
|  | } | 
|  |  | 
|  | c = append(c, p.GccOptions...) | 
|  | c = append(c, p.gccMachine()...) | 
|  | if goos == "aix" { | 
|  | c = append(c, "-maix64") | 
|  | c = append(c, "-mcmodel=large") | 
|  | } | 
|  | c = append(c, "-") //read input from standard input | 
|  | return c | 
|  | } | 
|  |  | 
|  | // gccDebug runs gcc -gdwarf-2 over the C program stdin and | 
|  | // returns the corresponding DWARF data and, if present, debug data block. | 
|  | func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) { | 
|  | runGcc(stdin, p.gccCmd()) | 
|  |  | 
|  | isDebugInts := func(s string) bool { | 
|  | // Some systems use leading _ to denote non-assembly symbols. | 
|  | return s == "__cgodebug_ints" || s == "___cgodebug_ints" | 
|  | } | 
|  | isDebugFloats := func(s string) bool { | 
|  | // Some systems use leading _ to denote non-assembly symbols. | 
|  | return s == "__cgodebug_floats" || s == "___cgodebug_floats" | 
|  | } | 
|  | indexOfDebugStr := func(s string) int { | 
|  | // Some systems use leading _ to denote non-assembly symbols. | 
|  | if strings.HasPrefix(s, "___") { | 
|  | s = s[1:] | 
|  | } | 
|  | if strings.HasPrefix(s, "__cgodebug_str__") { | 
|  | if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil { | 
|  | return n | 
|  | } | 
|  | } | 
|  | return -1 | 
|  | } | 
|  | indexOfDebugStrlen := func(s string) int { | 
|  | // Some systems use leading _ to denote non-assembly symbols. | 
|  | if strings.HasPrefix(s, "___") { | 
|  | s = s[1:] | 
|  | } | 
|  | if strings.HasPrefix(s, "__cgodebug_strlen__") { | 
|  | if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil { | 
|  | return n | 
|  | } | 
|  | } | 
|  | return -1 | 
|  | } | 
|  |  | 
|  | strs = make([]string, nnames) | 
|  |  | 
|  | strdata := make(map[int]string, nnames) | 
|  | strlens := make(map[int]int, nnames) | 
|  |  | 
|  | buildStrings := func() { | 
|  | for n, strlen := range strlens { | 
|  | data := strdata[n] | 
|  | if len(data) <= strlen { | 
|  | fatalf("invalid string literal") | 
|  | } | 
|  | strs[n] = data[:strlen] | 
|  | } | 
|  | } | 
|  |  | 
|  | if f, err := macho.Open(gccTmp()); err == nil { | 
|  | defer f.Close() | 
|  | d, err := f.DWARF() | 
|  | if err != nil { | 
|  | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | 
|  | } | 
|  | bo := f.ByteOrder | 
|  | if f.Symtab != nil { | 
|  | for i := range f.Symtab.Syms { | 
|  | s := &f.Symtab.Syms[i] | 
|  | switch { | 
|  | case isDebugInts(s.Name): | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | ints = make([]int64, len(data)/8) | 
|  | for i := range ints { | 
|  | ints[i] = int64(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | case isDebugFloats(s.Name): | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | floats = make([]float64, len(data)/8) | 
|  | for i := range floats { | 
|  | floats[i] = math.Float64frombits(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | default: | 
|  | if n := indexOfDebugStr(s.Name); n != -1 { | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | strdata[n] = string(data) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | if n := indexOfDebugStrlen(s.Name); n != -1 { | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | strlen := bo.Uint64(data[:8]) | 
|  | if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt? | 
|  | fatalf("string literal too big") | 
|  | } | 
|  | strlens[n] = int(strlen) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | buildStrings() | 
|  | } | 
|  | return d, ints, floats, strs | 
|  | } | 
|  |  | 
|  | if f, err := elf.Open(gccTmp()); err == nil { | 
|  | defer f.Close() | 
|  | d, err := f.DWARF() | 
|  | if err != nil { | 
|  | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | 
|  | } | 
|  | bo := f.ByteOrder | 
|  | symtab, err := f.Symbols() | 
|  | if err == nil { | 
|  | for i := range symtab { | 
|  | s := &symtab[i] | 
|  | switch { | 
|  | case isDebugInts(s.Name): | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Section); 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | ints = make([]int64, len(data)/8) | 
|  | for i := range ints { | 
|  | ints[i] = int64(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | case isDebugFloats(s.Name): | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Section); 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | floats = make([]float64, len(data)/8) | 
|  | for i := range floats { | 
|  | floats[i] = math.Float64frombits(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | default: | 
|  | if n := indexOfDebugStr(s.Name); n != -1 { | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Section); 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | strdata[n] = string(data) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | if n := indexOfDebugStrlen(s.Name); n != -1 { | 
|  | // Found it. Now find data section. | 
|  | if i := int(s.Section); 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value-sect.Addr:] | 
|  | strlen := bo.Uint64(data[:8]) | 
|  | if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt? | 
|  | fatalf("string literal too big") | 
|  | } | 
|  | strlens[n] = int(strlen) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | buildStrings() | 
|  | } | 
|  | return d, ints, floats, strs | 
|  | } | 
|  |  | 
|  | if f, err := pe.Open(gccTmp()); err == nil { | 
|  | defer f.Close() | 
|  | d, err := f.DWARF() | 
|  | if err != nil { | 
|  | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | 
|  | } | 
|  | bo := binary.LittleEndian | 
|  | for _, s := range f.Symbols { | 
|  | switch { | 
|  | case isDebugInts(s.Name): | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | ints = make([]int64, len(data)/8) | 
|  | for i := range ints { | 
|  | ints[i] = int64(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | case isDebugFloats(s.Name): | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | floats = make([]float64, len(data)/8) | 
|  | for i := range floats { | 
|  | floats[i] = math.Float64frombits(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | default: | 
|  | if n := indexOfDebugStr(s.Name); n != -1 { | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | strdata[n] = string(data) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | if n := indexOfDebugStrlen(s.Name); n != -1 { | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | strlen := bo.Uint64(data[:8]) | 
|  | if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt? | 
|  | fatalf("string literal too big") | 
|  | } | 
|  | strlens[n] = int(strlen) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | buildStrings() | 
|  |  | 
|  | return d, ints, floats, strs | 
|  | } | 
|  |  | 
|  | if f, err := xcoff.Open(gccTmp()); err == nil { | 
|  | defer f.Close() | 
|  | d, err := f.DWARF() | 
|  | if err != nil { | 
|  | fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) | 
|  | } | 
|  | bo := binary.BigEndian | 
|  | for _, s := range f.Symbols { | 
|  | switch { | 
|  | case isDebugInts(s.Name): | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | ints = make([]int64, len(data)/8) | 
|  | for i := range ints { | 
|  | ints[i] = int64(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | case isDebugFloats(s.Name): | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | floats = make([]float64, len(data)/8) | 
|  | for i := range floats { | 
|  | floats[i] = math.Float64frombits(bo.Uint64(data[i*8:])) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | default: | 
|  | if n := indexOfDebugStr(s.Name); n != -1 { | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | strdata[n] = string(data) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | if n := indexOfDebugStrlen(s.Name); n != -1 { | 
|  | if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { | 
|  | sect := f.Sections[i] | 
|  | if s.Value < sect.Size { | 
|  | if sdat, err := sect.Data(); err == nil { | 
|  | data := sdat[s.Value:] | 
|  | strlen := bo.Uint64(data[:8]) | 
|  | if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt? | 
|  | fatalf("string literal too big") | 
|  | } | 
|  | strlens[n] = int(strlen) | 
|  | } | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | buildStrings() | 
|  | return d, ints, floats, strs | 
|  | } | 
|  | fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp()) | 
|  | panic("not reached") | 
|  | } | 
|  |  | 
|  | // gccDefines runs gcc -E -dM -xc - over the C program stdin | 
|  | // and returns the corresponding standard output, which is the | 
|  | // #defines that gcc encountered while processing the input | 
|  | // and its included files. | 
|  | func (p *Package) gccDefines(stdin []byte) string { | 
|  | base := append(p.gccBaseCmd(), "-E", "-dM", "-xc") | 
|  | base = append(base, p.gccMachine()...) | 
|  | stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) | 
|  | return stdout | 
|  | } | 
|  |  | 
|  | // gccErrors runs gcc over the C program stdin and returns | 
|  | // the errors that gcc prints. That is, this function expects | 
|  | // gcc to fail. | 
|  | func (p *Package) gccErrors(stdin []byte) string { | 
|  | // TODO(rsc): require failure | 
|  | args := p.gccCmd() | 
|  |  | 
|  | // Optimization options can confuse the error messages; remove them. | 
|  | nargs := make([]string, 0, len(args)) | 
|  | for _, arg := range args { | 
|  | if !strings.HasPrefix(arg, "-O") { | 
|  | nargs = append(nargs, arg) | 
|  | } | 
|  | } | 
|  |  | 
|  | // Force -O0 optimization but keep the trailing "-" at the end. | 
|  | nargs = append(nargs, "-O0") | 
|  | nl := len(nargs) | 
|  | nargs[nl-2], nargs[nl-1] = nargs[nl-1], nargs[nl-2] | 
|  |  | 
|  | if *debugGcc { | 
|  | fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " ")) | 
|  | os.Stderr.Write(stdin) | 
|  | fmt.Fprint(os.Stderr, "EOF\n") | 
|  | } | 
|  | stdout, stderr, _ := run(stdin, nargs) | 
|  | if *debugGcc { | 
|  | os.Stderr.Write(stdout) | 
|  | os.Stderr.Write(stderr) | 
|  | } | 
|  | return string(stderr) | 
|  | } | 
|  |  | 
|  | // runGcc runs the gcc command line args with stdin on standard input. | 
|  | // If the command exits with a non-zero exit status, runGcc prints | 
|  | // details about what was run and exits. | 
|  | // Otherwise runGcc returns the data written to standard output and standard error. | 
|  | // Note that for some of the uses we expect useful data back | 
|  | // on standard error, but for those uses gcc must still exit 0. | 
|  | func runGcc(stdin []byte, args []string) (string, string) { | 
|  | if *debugGcc { | 
|  | fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) | 
|  | os.Stderr.Write(stdin) | 
|  | fmt.Fprint(os.Stderr, "EOF\n") | 
|  | } | 
|  | stdout, stderr, ok := run(stdin, args) | 
|  | if *debugGcc { | 
|  | os.Stderr.Write(stdout) | 
|  | os.Stderr.Write(stderr) | 
|  | } | 
|  | if !ok { | 
|  | os.Stderr.Write(stderr) | 
|  | os.Exit(2) | 
|  | } | 
|  | return string(stdout), string(stderr) | 
|  | } | 
|  |  | 
|  | // A typeConv is a translator from dwarf types to Go types | 
|  | // with equivalent memory layout. | 
|  | type typeConv struct { | 
|  | // Cache of already-translated or in-progress types. | 
|  | m map[string]*Type | 
|  |  | 
|  | // Map from types to incomplete pointers to those types. | 
|  | ptrs map[string][]*Type | 
|  | // Keys of ptrs in insertion order (deterministic worklist) | 
|  | // ptrKeys contains exactly the keys in ptrs. | 
|  | ptrKeys []dwarf.Type | 
|  |  | 
|  | // Type names X for which there exists an XGetTypeID function with type func() CFTypeID. | 
|  | getTypeIDs map[string]bool | 
|  |  | 
|  | // Predeclared types. | 
|  | bool                                   ast.Expr | 
|  | byte                                   ast.Expr // denotes padding | 
|  | int8, int16, int32, int64              ast.Expr | 
|  | uint8, uint16, uint32, uint64, uintptr ast.Expr | 
|  | float32, float64                       ast.Expr | 
|  | complex64, complex128                  ast.Expr | 
|  | void                                   ast.Expr | 
|  | string                                 ast.Expr | 
|  | goVoid                                 ast.Expr // _Ctype_void, denotes C's void | 
|  | goVoidPtr                              ast.Expr // unsafe.Pointer or *byte | 
|  |  | 
|  | ptrSize int64 | 
|  | intSize int64 | 
|  | } | 
|  |  | 
|  | var tagGen int | 
|  | var typedef = make(map[string]*Type) | 
|  | var goIdent = make(map[string]*ast.Ident) | 
|  |  | 
|  | // unionWithPointer is true for a Go type that represents a C union (or class) | 
|  | // that may contain a pointer. This is used for cgo pointer checking. | 
|  | var unionWithPointer = make(map[ast.Expr]bool) | 
|  |  | 
|  | func (c *typeConv) Init(ptrSize, intSize int64) { | 
|  | c.ptrSize = ptrSize | 
|  | c.intSize = intSize | 
|  | c.m = make(map[string]*Type) | 
|  | c.ptrs = make(map[string][]*Type) | 
|  | c.getTypeIDs = make(map[string]bool) | 
|  | c.bool = c.Ident("bool") | 
|  | c.byte = c.Ident("byte") | 
|  | c.int8 = c.Ident("int8") | 
|  | c.int16 = c.Ident("int16") | 
|  | c.int32 = c.Ident("int32") | 
|  | c.int64 = c.Ident("int64") | 
|  | c.uint8 = c.Ident("uint8") | 
|  | c.uint16 = c.Ident("uint16") | 
|  | c.uint32 = c.Ident("uint32") | 
|  | c.uint64 = c.Ident("uint64") | 
|  | c.uintptr = c.Ident("uintptr") | 
|  | c.float32 = c.Ident("float32") | 
|  | c.float64 = c.Ident("float64") | 
|  | c.complex64 = c.Ident("complex64") | 
|  | c.complex128 = c.Ident("complex128") | 
|  | c.void = c.Ident("void") | 
|  | c.string = c.Ident("string") | 
|  | c.goVoid = c.Ident("_Ctype_void") | 
|  |  | 
|  | // Normally cgo translates void* to unsafe.Pointer, | 
|  | // but for historical reasons -godefs uses *byte instead. | 
|  | if *godefs { | 
|  | c.goVoidPtr = &ast.StarExpr{X: c.byte} | 
|  | } else { | 
|  | c.goVoidPtr = c.Ident("unsafe.Pointer") | 
|  | } | 
|  | } | 
|  |  | 
|  | // base strips away qualifiers and typedefs to get the underlying type | 
|  | func base(dt dwarf.Type) dwarf.Type { | 
|  | for { | 
|  | if d, ok := dt.(*dwarf.QualType); ok { | 
|  | dt = d.Type | 
|  | continue | 
|  | } | 
|  | if d, ok := dt.(*dwarf.TypedefType); ok { | 
|  | dt = d.Type | 
|  | continue | 
|  | } | 
|  | break | 
|  | } | 
|  | return dt | 
|  | } | 
|  |  | 
|  | // unqual strips away qualifiers from a DWARF type. | 
|  | // In general we don't care about top-level qualifiers. | 
|  | func unqual(dt dwarf.Type) dwarf.Type { | 
|  | for { | 
|  | if d, ok := dt.(*dwarf.QualType); ok { | 
|  | dt = d.Type | 
|  | } else { | 
|  | break | 
|  | } | 
|  | } | 
|  | return dt | 
|  | } | 
|  |  | 
|  | // Map from dwarf text names to aliases we use in package "C". | 
|  | var dwarfToName = map[string]string{ | 
|  | "long int":               "long", | 
|  | "long unsigned int":      "ulong", | 
|  | "unsigned int":           "uint", | 
|  | "short unsigned int":     "ushort", | 
|  | "unsigned short":         "ushort", // Used by Clang; issue 13129. | 
|  | "short int":              "short", | 
|  | "long long int":          "longlong", | 
|  | "long long unsigned int": "ulonglong", | 
|  | "signed char":            "schar", | 
|  | "unsigned char":          "uchar", | 
|  | } | 
|  |  | 
|  | const signedDelta = 64 | 
|  |  | 
|  | // String returns the current type representation. Format arguments | 
|  | // are assembled within this method so that any changes in mutable | 
|  | // values are taken into account. | 
|  | func (tr *TypeRepr) String() string { | 
|  | if len(tr.Repr) == 0 { | 
|  | return "" | 
|  | } | 
|  | if len(tr.FormatArgs) == 0 { | 
|  | return tr.Repr | 
|  | } | 
|  | return fmt.Sprintf(tr.Repr, tr.FormatArgs...) | 
|  | } | 
|  |  | 
|  | // Empty reports whether the result of String would be "". | 
|  | func (tr *TypeRepr) Empty() bool { | 
|  | return len(tr.Repr) == 0 | 
|  | } | 
|  |  | 
|  | // Set modifies the type representation. | 
|  | // If fargs are provided, repr is used as a format for fmt.Sprintf. | 
|  | // Otherwise, repr is used unprocessed as the type representation. | 
|  | func (tr *TypeRepr) Set(repr string, fargs ...interface{}) { | 
|  | tr.Repr = repr | 
|  | tr.FormatArgs = fargs | 
|  | } | 
|  |  | 
|  | // FinishType completes any outstanding type mapping work. | 
|  | // In particular, it resolves incomplete pointer types. | 
|  | func (c *typeConv) FinishType(pos token.Pos) { | 
|  | // Completing one pointer type might produce more to complete. | 
|  | // Keep looping until they're all done. | 
|  | for len(c.ptrKeys) > 0 { | 
|  | dtype := c.ptrKeys[0] | 
|  | dtypeKey := dtype.String() | 
|  | c.ptrKeys = c.ptrKeys[1:] | 
|  | ptrs := c.ptrs[dtypeKey] | 
|  | delete(c.ptrs, dtypeKey) | 
|  |  | 
|  | // Note Type might invalidate c.ptrs[dtypeKey]. | 
|  | t := c.Type(dtype, pos) | 
|  | for _, ptr := range ptrs { | 
|  | ptr.Go.(*ast.StarExpr).X = t.Go | 
|  | ptr.C.Set("%s*", t.C) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // Type returns a *Type with the same memory layout as | 
|  | // dtype when used as the type of a variable or a struct field. | 
|  | func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { | 
|  | return c.loadType(dtype, pos, "") | 
|  | } | 
|  |  | 
|  | // loadType recursively loads the requested dtype and its dependency graph. | 
|  | func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Type { | 
|  | // Always recompute bad pointer typedefs, as the set of such | 
|  | // typedefs changes as we see more types. | 
|  | checkCache := true | 
|  | if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) { | 
|  | checkCache = false | 
|  | } | 
|  |  | 
|  | // The cache key should be relative to its parent. | 
|  | // See issue https://golang.org/issue/31891 | 
|  | key := parent + " > " + dtype.String() | 
|  |  | 
|  | if checkCache { | 
|  | if t, ok := c.m[key]; ok { | 
|  | if t.Go == nil { | 
|  | fatalf("%s: type conversion loop at %s", lineno(pos), dtype) | 
|  | } | 
|  | return t | 
|  | } | 
|  | } | 
|  |  | 
|  | t := new(Type) | 
|  | t.Size = dtype.Size() // note: wrong for array of pointers, corrected below | 
|  | t.Align = -1 | 
|  | t.C = &TypeRepr{Repr: dtype.Common().Name} | 
|  | c.m[key] = t | 
|  |  | 
|  | switch dt := dtype.(type) { | 
|  | default: | 
|  | fatalf("%s: unexpected type: %s", lineno(pos), dtype) | 
|  |  | 
|  | case *dwarf.AddrType: | 
|  | if t.Size != c.ptrSize { | 
|  | fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype) | 
|  | } | 
|  | t.Go = c.uintptr | 
|  | t.Align = t.Size | 
|  |  | 
|  | case *dwarf.ArrayType: | 
|  | if dt.StrideBitSize > 0 { | 
|  | // Cannot represent bit-sized elements in Go. | 
|  | t.Go = c.Opaque(t.Size) | 
|  | break | 
|  | } | 
|  | count := dt.Count | 
|  | if count == -1 { | 
|  | // Indicates flexible array member, which Go doesn't support. | 
|  | // Translate to zero-length array instead. | 
|  | count = 0 | 
|  | } | 
|  | sub := c.Type(dt.Type, pos) | 
|  | t.Align = sub.Align | 
|  | t.Go = &ast.ArrayType{ | 
|  | Len: c.intExpr(count), | 
|  | Elt: sub.Go, | 
|  | } | 
|  | // Recalculate t.Size now that we know sub.Size. | 
|  | t.Size = count * sub.Size | 
|  | t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) | 
|  |  | 
|  | case *dwarf.BoolType: | 
|  | t.Go = c.bool | 
|  | t.Align = 1 | 
|  |  | 
|  | case *dwarf.CharType: | 
|  | if t.Size != 1 { | 
|  | fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype) | 
|  | } | 
|  | t.Go = c.int8 | 
|  | t.Align = 1 | 
|  |  | 
|  | case *dwarf.EnumType: | 
|  | if t.Align = t.Size; t.Align >= c.ptrSize { | 
|  | t.Align = c.ptrSize | 
|  | } | 
|  | t.C.Set("enum " + dt.EnumName) | 
|  | signed := 0 | 
|  | t.EnumValues = make(map[string]int64) | 
|  | for _, ev := range dt.Val { | 
|  | t.EnumValues[ev.Name] = ev.Val | 
|  | if ev.Val < 0 { | 
|  | signed = signedDelta | 
|  | } | 
|  | } | 
|  | switch t.Size + int64(signed) { | 
|  | default: | 
|  | fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype) | 
|  | case 1: | 
|  | t.Go = c.uint8 | 
|  | case 2: | 
|  | t.Go = c.uint16 | 
|  | case 4: | 
|  | t.Go = c.uint32 | 
|  | case 8: | 
|  | t.Go = c.uint64 | 
|  | case 1 + signedDelta: | 
|  | t.Go = c.int8 | 
|  | case 2 + signedDelta: | 
|  | t.Go = c.int16 | 
|  | case 4 + signedDelta: | 
|  | t.Go = c.int32 | 
|  | case 8 + signedDelta: | 
|  | t.Go = c.int64 | 
|  | } | 
|  |  | 
|  | case *dwarf.FloatType: | 
|  | switch t.Size { | 
|  | default: | 
|  | fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype) | 
|  | case 4: | 
|  | t.Go = c.float32 | 
|  | case 8: | 
|  | t.Go = c.float64 | 
|  | } | 
|  | if t.Align = t.Size; t.Align >= c.ptrSize { | 
|  | t.Align = c.ptrSize | 
|  | } | 
|  |  | 
|  | case *dwarf.ComplexType: | 
|  | switch t.Size { | 
|  | default: | 
|  | fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype) | 
|  | case 8: | 
|  | t.Go = c.complex64 | 
|  | case 16: | 
|  | t.Go = c.complex128 | 
|  | } | 
|  | if t.Align = t.Size / 2; t.Align >= c.ptrSize { | 
|  | t.Align = c.ptrSize | 
|  | } | 
|  |  | 
|  | case *dwarf.FuncType: | 
|  | // No attempt at translation: would enable calls | 
|  | // directly between worlds, but we need to moderate those. | 
|  | t.Go = c.uintptr | 
|  | t.Align = c.ptrSize | 
|  |  | 
|  | case *dwarf.IntType: | 
|  | if dt.BitSize > 0 { | 
|  | fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype) | 
|  | } | 
|  | switch t.Size { | 
|  | default: | 
|  | fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype) | 
|  | case 1: | 
|  | t.Go = c.int8 | 
|  | case 2: | 
|  | t.Go = c.int16 | 
|  | case 4: | 
|  | t.Go = c.int32 | 
|  | case 8: | 
|  | t.Go = c.int64 | 
|  | case 16: | 
|  | t.Go = &ast.ArrayType{ | 
|  | Len: c.intExpr(t.Size), | 
|  | Elt: c.uint8, | 
|  | } | 
|  | } | 
|  | if t.Align = t.Size; t.Align >= c.ptrSize { | 
|  | t.Align = c.ptrSize | 
|  | } | 
|  |  | 
|  | case *dwarf.PtrType: | 
|  | // Clang doesn't emit DW_AT_byte_size for pointer types. | 
|  | if t.Size != c.ptrSize && t.Size != -1 { | 
|  | fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype) | 
|  | } | 
|  | t.Size = c.ptrSize | 
|  | t.Align = c.ptrSize | 
|  |  | 
|  | if _, ok := base(dt.Type).(*dwarf.VoidType); ok { | 
|  | t.Go = c.goVoidPtr | 
|  | t.C.Set("void*") | 
|  | dq := dt.Type | 
|  | for { | 
|  | if d, ok := dq.(*dwarf.QualType); ok { | 
|  | t.C.Set(d.Qual + " " + t.C.String()) | 
|  | dq = d.Type | 
|  | } else { | 
|  | break | 
|  | } | 
|  | } | 
|  | break | 
|  | } | 
|  |  | 
|  | // Placeholder initialization; completed in FinishType. | 
|  | t.Go = &ast.StarExpr{} | 
|  | t.C.Set("<incomplete>*") | 
|  | key := dt.Type.String() | 
|  | if _, ok := c.ptrs[key]; !ok { | 
|  | c.ptrKeys = append(c.ptrKeys, dt.Type) | 
|  | } | 
|  | c.ptrs[key] = append(c.ptrs[key], t) | 
|  |  | 
|  | case *dwarf.QualType: | 
|  | t1 := c.Type(dt.Type, pos) | 
|  | t.Size = t1.Size | 
|  | t.Align = t1.Align | 
|  | t.Go = t1.Go | 
|  | if unionWithPointer[t1.Go] { | 
|  | unionWithPointer[t.Go] = true | 
|  | } | 
|  | t.EnumValues = nil | 
|  | t.Typedef = "" | 
|  | t.C.Set("%s "+dt.Qual, t1.C) | 
|  | return t | 
|  |  | 
|  | case *dwarf.StructType: | 
|  | // Convert to Go struct, being careful about alignment. | 
|  | // Have to give it a name to simulate C "struct foo" references. | 
|  | tag := dt.StructName | 
|  | if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible | 
|  | break | 
|  | } | 
|  | if tag == "" { | 
|  | tag = "__" + strconv.Itoa(tagGen) | 
|  | tagGen++ | 
|  | } else if t.C.Empty() { | 
|  | t.C.Set(dt.Kind + " " + tag) | 
|  | } | 
|  | name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) | 
|  | t.Go = name // publish before recursive calls | 
|  | goIdent[name.Name] = name | 
|  | if dt.ByteSize < 0 { | 
|  | // Size calculation in c.Struct/c.Opaque will die with size=-1 (unknown), | 
|  | // so execute the basic things that the struct case would do | 
|  | // other than try to determine a Go representation. | 
|  | tt := *t | 
|  | tt.C = &TypeRepr{"%s %s", []interface{}{dt.Kind, tag}} | 
|  | tt.Go = c.Ident("struct{}") | 
|  | typedef[name.Name] = &tt | 
|  | break | 
|  | } | 
|  | switch dt.Kind { | 
|  | case "class", "union": | 
|  | t.Go = c.Opaque(t.Size) | 
|  | if c.dwarfHasPointer(dt, pos) { | 
|  | unionWithPointer[t.Go] = true | 
|  | } | 
|  | if t.C.Empty() { | 
|  | t.C.Set("__typeof__(unsigned char[%d])", t.Size) | 
|  | } | 
|  | t.Align = 1 // TODO: should probably base this on field alignment. | 
|  | typedef[name.Name] = t | 
|  | case "struct": | 
|  | g, csyntax, align := c.Struct(dt, pos) | 
|  | if t.C.Empty() { | 
|  | t.C.Set(csyntax) | 
|  | } | 
|  | t.Align = align | 
|  | tt := *t | 
|  | if tag != "" { | 
|  | tt.C = &TypeRepr{"struct %s", []interface{}{tag}} | 
|  | } | 
|  | tt.Go = g | 
|  | typedef[name.Name] = &tt | 
|  | } | 
|  |  | 
|  | case *dwarf.TypedefType: | 
|  | // Record typedef for printing. | 
|  | if dt.Name == "_GoString_" { | 
|  | // Special C name for Go string type. | 
|  | // Knows string layout used by compilers: pointer plus length, | 
|  | // which rounds up to 2 pointers after alignment. | 
|  | t.Go = c.string | 
|  | t.Size = c.ptrSize * 2 | 
|  | t.Align = c.ptrSize | 
|  | break | 
|  | } | 
|  | if dt.Name == "_GoBytes_" { | 
|  | // Special C name for Go []byte type. | 
|  | // Knows slice layout used by compilers: pointer, length, cap. | 
|  | t.Go = c.Ident("[]byte") | 
|  | t.Size = c.ptrSize + 4 + 4 | 
|  | t.Align = c.ptrSize | 
|  | break | 
|  | } | 
|  | name := c.Ident("_Ctype_" + dt.Name) | 
|  | goIdent[name.Name] = name | 
|  | akey := "" | 
|  | if c.anonymousStructTypedef(dt) { | 
|  | // only load type recursively for typedefs of anonymous | 
|  | // structs, see issues 37479 and 37621. | 
|  | akey = key | 
|  | } | 
|  | sub := c.loadType(dt.Type, pos, akey) | 
|  | if c.badPointerTypedef(dt) { | 
|  | // Treat this typedef as a uintptr. | 
|  | s := *sub | 
|  | s.Go = c.uintptr | 
|  | s.BadPointer = true | 
|  | sub = &s | 
|  | // Make sure we update any previously computed type. | 
|  | if oldType := typedef[name.Name]; oldType != nil { | 
|  | oldType.Go = sub.Go | 
|  | oldType.BadPointer = true | 
|  | } | 
|  | } | 
|  | t.Go = name | 
|  | t.BadPointer = sub.BadPointer | 
|  | if unionWithPointer[sub.Go] { | 
|  | unionWithPointer[t.Go] = true | 
|  | } | 
|  | t.Size = sub.Size | 
|  | t.Align = sub.Align | 
|  | oldType := typedef[name.Name] | 
|  | if oldType == nil { | 
|  | tt := *t | 
|  | tt.Go = sub.Go | 
|  | tt.BadPointer = sub.BadPointer | 
|  | typedef[name.Name] = &tt | 
|  | } | 
|  |  | 
|  | // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo", | 
|  | // use that as the Go form for this typedef too, so that the typedef will be interchangeable | 
|  | // with the base type. | 
|  | // In -godefs mode, do this for all typedefs. | 
|  | if isStructUnionClass(sub.Go) || *godefs { | 
|  | t.Go = sub.Go | 
|  |  | 
|  | if isStructUnionClass(sub.Go) { | 
|  | // Use the typedef name for C code. | 
|  | typedef[sub.Go.(*ast.Ident).Name].C = t.C | 
|  | } | 
|  |  | 
|  | // If we've seen this typedef before, and it | 
|  | // was an anonymous struct/union/class before | 
|  | // too, use the old definition. | 
|  | // TODO: it would be safer to only do this if | 
|  | // we verify that the types are the same. | 
|  | if oldType != nil && isStructUnionClass(oldType.Go) { | 
|  | t.Go = oldType.Go | 
|  | } | 
|  | } | 
|  |  | 
|  | case *dwarf.UcharType: | 
|  | if t.Size != 1 { | 
|  | fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype) | 
|  | } | 
|  | t.Go = c.uint8 | 
|  | t.Align = 1 | 
|  |  | 
|  | case *dwarf.UintType: | 
|  | if dt.BitSize > 0 { | 
|  | fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype) | 
|  | } | 
|  | switch t.Size { | 
|  | default: | 
|  | fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype) | 
|  | case 1: | 
|  | t.Go = c.uint8 | 
|  | case 2: | 
|  | t.Go = c.uint16 | 
|  | case 4: | 
|  | t.Go = c.uint32 | 
|  | case 8: | 
|  | t.Go = c.uint64 | 
|  | case 16: | 
|  | t.Go = &ast.ArrayType{ | 
|  | Len: c.intExpr(t.Size), | 
|  | Elt: c.uint8, | 
|  | } | 
|  | } | 
|  | if t.Align = t.Size; t.Align >= c.ptrSize { | 
|  | t.Align = c.ptrSize | 
|  | } | 
|  |  | 
|  | case *dwarf.VoidType: | 
|  | t.Go = c.goVoid | 
|  | t.C.Set("void") | 
|  | t.Align = 1 | 
|  | } | 
|  |  | 
|  | switch dtype.(type) { | 
|  | case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: | 
|  | s := dtype.Common().Name | 
|  | if s != "" { | 
|  | if ss, ok := dwarfToName[s]; ok { | 
|  | s = ss | 
|  | } | 
|  | s = strings.Replace(s, " ", "", -1) | 
|  | name := c.Ident("_Ctype_" + s) | 
|  | tt := *t | 
|  | typedef[name.Name] = &tt | 
|  | if !*godefs { | 
|  | t.Go = name | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if t.Size < 0 { | 
|  | // Unsized types are [0]byte, unless they're typedefs of other types | 
|  | // or structs with tags. | 
|  | // if so, use the name we've already defined. | 
|  | t.Size = 0 | 
|  | switch dt := dtype.(type) { | 
|  | case *dwarf.TypedefType: | 
|  | // ok | 
|  | case *dwarf.StructType: | 
|  | if dt.StructName != "" { | 
|  | break | 
|  | } | 
|  | t.Go = c.Opaque(0) | 
|  | default: | 
|  | t.Go = c.Opaque(0) | 
|  | } | 
|  | if t.C.Empty() { | 
|  | t.C.Set("void") | 
|  | } | 
|  | } | 
|  |  | 
|  | if t.C.Empty() { | 
|  | fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype) | 
|  | } | 
|  |  | 
|  | return t | 
|  | } | 
|  |  | 
|  | // isStructUnionClass reports whether the type described by the Go syntax x | 
|  | // is a struct, union, or class with a tag. | 
|  | func isStructUnionClass(x ast.Expr) bool { | 
|  | id, ok := x.(*ast.Ident) | 
|  | if !ok { | 
|  | return false | 
|  | } | 
|  | name := id.Name | 
|  | return strings.HasPrefix(name, "_Ctype_struct_") || | 
|  | strings.HasPrefix(name, "_Ctype_union_") || | 
|  | strings.HasPrefix(name, "_Ctype_class_") | 
|  | } | 
|  |  | 
|  | // FuncArg returns a Go type with the same memory layout as | 
|  | // dtype when used as the type of a C function argument. | 
|  | func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { | 
|  | t := c.Type(unqual(dtype), pos) | 
|  | switch dt := dtype.(type) { | 
|  | case *dwarf.ArrayType: | 
|  | // Arrays are passed implicitly as pointers in C. | 
|  | // In Go, we must be explicit. | 
|  | tr := &TypeRepr{} | 
|  | tr.Set("%s*", t.C) | 
|  | return &Type{ | 
|  | Size:  c.ptrSize, | 
|  | Align: c.ptrSize, | 
|  | Go:    &ast.StarExpr{X: t.Go}, | 
|  | C:     tr, | 
|  | } | 
|  | case *dwarf.TypedefType: | 
|  | // C has much more relaxed rules than Go for | 
|  | // implicit type conversions. When the parameter | 
|  | // is type T defined as *X, simulate a little of the | 
|  | // laxness of C by making the argument *X instead of T. | 
|  | if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok { | 
|  | // Unless the typedef happens to point to void* since | 
|  | // Go has special rules around using unsafe.Pointer. | 
|  | if _, void := base(ptr.Type).(*dwarf.VoidType); void { | 
|  | break | 
|  | } | 
|  | // ...or the typedef is one in which we expect bad pointers. | 
|  | // It will be a uintptr instead of *X. | 
|  | if c.baseBadPointerTypedef(dt) { | 
|  | break | 
|  | } | 
|  |  | 
|  | t = c.Type(ptr, pos) | 
|  | if t == nil { | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // For a struct/union/class, remember the C spelling, | 
|  | // in case it has __attribute__((unavailable)). | 
|  | // See issue 2888. | 
|  | if isStructUnionClass(t.Go) { | 
|  | t.Typedef = dt.Name | 
|  | } | 
|  | } | 
|  | } | 
|  | return t | 
|  | } | 
|  |  | 
|  | // FuncType returns the Go type analogous to dtype. | 
|  | // There is no guarantee about matching memory layout. | 
|  | func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType { | 
|  | p := make([]*Type, len(dtype.ParamType)) | 
|  | gp := make([]*ast.Field, len(dtype.ParamType)) | 
|  | for i, f := range dtype.ParamType { | 
|  | // gcc's DWARF generator outputs a single DotDotDotType parameter for | 
|  | // function pointers that specify no parameters (e.g. void | 
|  | // (*__cgo_0)()).  Treat this special case as void. This case is | 
|  | // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not | 
|  | // legal). | 
|  | if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 { | 
|  | p, gp = nil, nil | 
|  | break | 
|  | } | 
|  | p[i] = c.FuncArg(f, pos) | 
|  | gp[i] = &ast.Field{Type: p[i].Go} | 
|  | } | 
|  | var r *Type | 
|  | var gr []*ast.Field | 
|  | if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok { | 
|  | gr = []*ast.Field{{Type: c.goVoid}} | 
|  | } else if dtype.ReturnType != nil { | 
|  | r = c.Type(unqual(dtype.ReturnType), pos) | 
|  | gr = []*ast.Field{{Type: r.Go}} | 
|  | } | 
|  | return &FuncType{ | 
|  | Params: p, | 
|  | Result: r, | 
|  | Go: &ast.FuncType{ | 
|  | Params:  &ast.FieldList{List: gp}, | 
|  | Results: &ast.FieldList{List: gr}, | 
|  | }, | 
|  | } | 
|  | } | 
|  |  | 
|  | // Identifier | 
|  | func (c *typeConv) Ident(s string) *ast.Ident { | 
|  | return ast.NewIdent(s) | 
|  | } | 
|  |  | 
|  | // Opaque type of n bytes. | 
|  | func (c *typeConv) Opaque(n int64) ast.Expr { | 
|  | return &ast.ArrayType{ | 
|  | Len: c.intExpr(n), | 
|  | Elt: c.byte, | 
|  | } | 
|  | } | 
|  |  | 
|  | // Expr for integer n. | 
|  | func (c *typeConv) intExpr(n int64) ast.Expr { | 
|  | return &ast.BasicLit{ | 
|  | Kind:  token.INT, | 
|  | Value: strconv.FormatInt(n, 10), | 
|  | } | 
|  | } | 
|  |  | 
|  | // Add padding of given size to fld. | 
|  | func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) { | 
|  | n := len(fld) | 
|  | fld = fld[0 : n+1] | 
|  | fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)} | 
|  | sizes = sizes[0 : n+1] | 
|  | sizes[n] = size | 
|  | return fld, sizes | 
|  | } | 
|  |  | 
|  | // Struct conversion: return Go and (gc) C syntax for type. | 
|  | func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { | 
|  | // Minimum alignment for a struct is 1 byte. | 
|  | align = 1 | 
|  |  | 
|  | var buf bytes.Buffer | 
|  | buf.WriteString("struct {") | 
|  | fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field | 
|  | sizes := make([]int64, 0, 2*len(dt.Field)+1) | 
|  | off := int64(0) | 
|  |  | 
|  | // Rename struct fields that happen to be named Go keywords into | 
|  | // _{keyword}.  Create a map from C ident -> Go ident. The Go ident will | 
|  | // be mangled. Any existing identifier that already has the same name on | 
|  | // the C-side will cause the Go-mangled version to be prefixed with _. | 
|  | // (e.g. in a struct with fields '_type' and 'type', the latter would be | 
|  | // rendered as '__type' in Go). | 
|  | ident := make(map[string]string) | 
|  | used := make(map[string]bool) | 
|  | for _, f := range dt.Field { | 
|  | ident[f.Name] = f.Name | 
|  | used[f.Name] = true | 
|  | } | 
|  |  | 
|  | if !*godefs { | 
|  | for cid, goid := range ident { | 
|  | if token.Lookup(goid).IsKeyword() { | 
|  | // Avoid keyword | 
|  | goid = "_" + goid | 
|  |  | 
|  | // Also avoid existing fields | 
|  | for _, exist := used[goid]; exist; _, exist = used[goid] { | 
|  | goid = "_" + goid | 
|  | } | 
|  |  | 
|  | used[goid] = true | 
|  | ident[cid] = goid | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | anon := 0 | 
|  | for _, f := range dt.Field { | 
|  | name := f.Name | 
|  | ft := f.Type | 
|  |  | 
|  | // In godefs mode, if this field is a C11 | 
|  | // anonymous union then treat the first field in the | 
|  | // union as the field in the struct. This handles | 
|  | // cases like the glibc <sys/resource.h> file; see | 
|  | // issue 6677. | 
|  | if *godefs { | 
|  | if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] { | 
|  | name = st.Field[0].Name | 
|  | ident[name] = name | 
|  | ft = st.Field[0].Type | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO: Handle fields that are anonymous structs by | 
|  | // promoting the fields of the inner struct. | 
|  |  | 
|  | t := c.Type(ft, pos) | 
|  | tgo := t.Go | 
|  | size := t.Size | 
|  | talign := t.Align | 
|  | if f.BitSize > 0 { | 
|  | switch f.BitSize { | 
|  | case 8, 16, 32, 64: | 
|  | default: | 
|  | continue | 
|  | } | 
|  | size = f.BitSize / 8 | 
|  | name := tgo.(*ast.Ident).String() | 
|  | if strings.HasPrefix(name, "int") { | 
|  | name = "int" | 
|  | } else { | 
|  | name = "uint" | 
|  | } | 
|  | tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize)) | 
|  | talign = size | 
|  | } | 
|  |  | 
|  | if talign > 0 && f.ByteOffset%talign != 0 { | 
|  | // Drop misaligned fields, the same way we drop integer bit fields. | 
|  | // The goal is to make available what can be made available. | 
|  | // Otherwise one bad and unneeded field in an otherwise okay struct | 
|  | // makes the whole program not compile. Much of the time these | 
|  | // structs are in system headers that cannot be corrected. | 
|  | continue | 
|  | } | 
|  |  | 
|  | // Round off up to talign, assumed to be a power of 2. | 
|  | off = (off + talign - 1) &^ (talign - 1) | 
|  |  | 
|  | if f.ByteOffset > off { | 
|  | fld, sizes = c.pad(fld, sizes, f.ByteOffset-off) | 
|  | off = f.ByteOffset | 
|  | } | 
|  | if f.ByteOffset < off { | 
|  | // Drop a packed field that we can't represent. | 
|  | continue | 
|  | } | 
|  |  | 
|  | n := len(fld) | 
|  | fld = fld[0 : n+1] | 
|  | if name == "" { | 
|  | name = fmt.Sprintf("anon%d", anon) | 
|  | anon++ | 
|  | ident[name] = name | 
|  | } | 
|  | fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo} | 
|  | sizes = sizes[0 : n+1] | 
|  | sizes[n] = size | 
|  | off += size | 
|  | buf.WriteString(t.C.String()) | 
|  | buf.WriteString(" ") | 
|  | buf.WriteString(name) | 
|  | buf.WriteString("; ") | 
|  | if talign > align { | 
|  | align = talign | 
|  | } | 
|  | } | 
|  | if off < dt.ByteSize { | 
|  | fld, sizes = c.pad(fld, sizes, dt.ByteSize-off) | 
|  | off = dt.ByteSize | 
|  | } | 
|  |  | 
|  | // If the last field in a non-zero-sized struct is zero-sized | 
|  | // the compiler is going to pad it by one (see issue 9401). | 
|  | // We can't permit that, because then the size of the Go | 
|  | // struct will not be the same as the size of the C struct. | 
|  | // Our only option in such a case is to remove the field, | 
|  | // which means that it cannot be referenced from Go. | 
|  | for off > 0 && sizes[len(sizes)-1] == 0 { | 
|  | n := len(sizes) | 
|  | fld = fld[0 : n-1] | 
|  | sizes = sizes[0 : n-1] | 
|  | } | 
|  |  | 
|  | if off != dt.ByteSize { | 
|  | fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize) | 
|  | } | 
|  | buf.WriteString("}") | 
|  | csyntax = buf.String() | 
|  |  | 
|  | if *godefs { | 
|  | godefsFields(fld) | 
|  | } | 
|  | expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} | 
|  | return | 
|  | } | 
|  |  | 
|  | // dwarfHasPointer reports whether the DWARF type dt contains a pointer. | 
|  | func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool { | 
|  | switch dt := dt.(type) { | 
|  | default: | 
|  | fatalf("%s: unexpected type: %s", lineno(pos), dt) | 
|  | return false | 
|  |  | 
|  | case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType, | 
|  | *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType, | 
|  | *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType: | 
|  |  | 
|  | return false | 
|  |  | 
|  | case *dwarf.ArrayType: | 
|  | return c.dwarfHasPointer(dt.Type, pos) | 
|  |  | 
|  | case *dwarf.PtrType: | 
|  | return true | 
|  |  | 
|  | case *dwarf.QualType: | 
|  | return c.dwarfHasPointer(dt.Type, pos) | 
|  |  | 
|  | case *dwarf.StructType: | 
|  | for _, f := range dt.Field { | 
|  | if c.dwarfHasPointer(f.Type, pos) { | 
|  | return true | 
|  | } | 
|  | } | 
|  | return false | 
|  |  | 
|  | case *dwarf.TypedefType: | 
|  | if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" { | 
|  | return true | 
|  | } | 
|  | return c.dwarfHasPointer(dt.Type, pos) | 
|  | } | 
|  | } | 
|  |  | 
|  | func upper(s string) string { | 
|  | if s == "" { | 
|  | return "" | 
|  | } | 
|  | r, size := utf8.DecodeRuneInString(s) | 
|  | if r == '_' { | 
|  | return "X" + s | 
|  | } | 
|  | return string(unicode.ToUpper(r)) + s[size:] | 
|  | } | 
|  |  | 
|  | // godefsFields rewrites field names for use in Go or C definitions. | 
|  | // It strips leading common prefixes (like tv_ in tv_sec, tv_usec) | 
|  | // converts names to upper case, and rewrites _ into Pad_godefs_n, | 
|  | // so that all fields are exported. | 
|  | func godefsFields(fld []*ast.Field) { | 
|  | prefix := fieldPrefix(fld) | 
|  | npad := 0 | 
|  | for _, f := range fld { | 
|  | for _, n := range f.Names { | 
|  | if n.Name != prefix { | 
|  | n.Name = strings.TrimPrefix(n.Name, prefix) | 
|  | } | 
|  | if n.Name == "_" { | 
|  | // Use exported name instead. | 
|  | n.Name = "Pad_cgo_" + strconv.Itoa(npad) | 
|  | npad++ | 
|  | } | 
|  | n.Name = upper(n.Name) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // fieldPrefix returns the prefix that should be removed from all the | 
|  | // field names when generating the C or Go code. For generated | 
|  | // C, we leave the names as is (tv_sec, tv_usec), since that's what | 
|  | // people are used to seeing in C.  For generated Go code, such as | 
|  | // package syscall's data structures, we drop a common prefix | 
|  | // (so sec, usec, which will get turned into Sec, Usec for exporting). | 
|  | func fieldPrefix(fld []*ast.Field) string { | 
|  | prefix := "" | 
|  | for _, f := range fld { | 
|  | for _, n := range f.Names { | 
|  | // Ignore field names that don't have the prefix we're | 
|  | // looking for. It is common in C headers to have fields | 
|  | // named, say, _pad in an otherwise prefixed header. | 
|  | // If the struct has 3 fields tv_sec, tv_usec, _pad1, then we | 
|  | // still want to remove the tv_ prefix. | 
|  | // The check for "orig_" here handles orig_eax in the | 
|  | // x86 ptrace register sets, which otherwise have all fields | 
|  | // with reg_ prefixes. | 
|  | if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") { | 
|  | continue | 
|  | } | 
|  | i := strings.Index(n.Name, "_") | 
|  | if i < 0 { | 
|  | continue | 
|  | } | 
|  | if prefix == "" { | 
|  | prefix = n.Name[:i+1] | 
|  | } else if prefix != n.Name[:i+1] { | 
|  | return "" | 
|  | } | 
|  | } | 
|  | } | 
|  | return prefix | 
|  | } | 
|  |  | 
|  | // anonymousStructTypedef reports whether dt is a C typedef for an anonymous | 
|  | // struct. | 
|  | func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool { | 
|  | st, ok := dt.Type.(*dwarf.StructType) | 
|  | return ok && st.StructName == "" | 
|  | } | 
|  |  | 
|  | // badPointerTypedef reports whether t is a C typedef that should not be considered a pointer in Go. | 
|  | // A typedef is bad if C code sometimes stores non-pointers in this type. | 
|  | // TODO: Currently our best solution is to find these manually and list them as | 
|  | // they come up. A better solution is desired. | 
|  | func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool { | 
|  | if c.badCFType(dt) { | 
|  | return true | 
|  | } | 
|  | if c.badJNI(dt) { | 
|  | return true | 
|  | } | 
|  | if c.badEGLDisplay(dt) { | 
|  | return true | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef | 
|  | // as badPointerTypedef reports. | 
|  | func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool { | 
|  | for { | 
|  | if t, ok := dt.Type.(*dwarf.TypedefType); ok { | 
|  | dt = t | 
|  | continue | 
|  | } | 
|  | break | 
|  | } | 
|  | return c.badPointerTypedef(dt) | 
|  | } | 
|  |  | 
|  | func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool { | 
|  | // The real bad types are CFNumberRef and CFDateRef. | 
|  | // Sometimes non-pointers are stored in these types. | 
|  | // CFTypeRef is a supertype of those, so it can have bad pointers in it as well. | 
|  | // We return true for the other *Ref types just so casting between them is easier. | 
|  | // We identify the correct set of types as those ending in Ref and for which | 
|  | // there exists a corresponding GetTypeID function. | 
|  | // See comment below for details about the bad pointers. | 
|  | if goos != "darwin" { | 
|  | return false | 
|  | } | 
|  | s := dt.Name | 
|  | if !strings.HasSuffix(s, "Ref") { | 
|  | return false | 
|  | } | 
|  | s = s[:len(s)-3] | 
|  | if s == "CFType" { | 
|  | return true | 
|  | } | 
|  | if c.getTypeIDs[s] { | 
|  | return true | 
|  | } | 
|  | if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] { | 
|  | // Mutable and immutable variants share a type ID. | 
|  | return true | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // Comment from Darwin's CFInternal.h | 
|  | /* | 
|  | // Tagged pointer support | 
|  | // Low-bit set means tagged object, next 3 bits (currently) | 
|  | // define the tagged object class, next 4 bits are for type | 
|  | // information for the specific tagged object class.  Thus, | 
|  | // the low byte is for type info, and the rest of a pointer | 
|  | // (32 or 64-bit) is for payload, whatever the tagged class. | 
|  | // | 
|  | // Note that the specific integers used to identify the | 
|  | // specific tagged classes can and will change from release | 
|  | // to release (that's why this stuff is in CF*Internal*.h), | 
|  | // as can the definition of type info vs payload above. | 
|  | // | 
|  | #if __LP64__ | 
|  | #define CF_IS_TAGGED_OBJ(PTR)	((uintptr_t)(PTR) & 0x1) | 
|  | #define CF_TAGGED_OBJ_TYPE(PTR)	((uintptr_t)(PTR) & 0xF) | 
|  | #else | 
|  | #define CF_IS_TAGGED_OBJ(PTR)	0 | 
|  | #define CF_TAGGED_OBJ_TYPE(PTR)	0 | 
|  | #endif | 
|  |  | 
|  | enum { | 
|  | kCFTaggedObjectID_Invalid = 0, | 
|  | kCFTaggedObjectID_Atom = (0 << 1) + 1, | 
|  | kCFTaggedObjectID_Undefined3 = (1 << 1) + 1, | 
|  | kCFTaggedObjectID_Undefined2 = (2 << 1) + 1, | 
|  | kCFTaggedObjectID_Integer = (3 << 1) + 1, | 
|  | kCFTaggedObjectID_DateTS = (4 << 1) + 1, | 
|  | kCFTaggedObjectID_ManagedObjectID = (5 << 1) + 1, // Core Data | 
|  | kCFTaggedObjectID_Date = (6 << 1) + 1, | 
|  | kCFTaggedObjectID_Undefined7 = (7 << 1) + 1, | 
|  | }; | 
|  | */ | 
|  |  | 
|  | func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool { | 
|  | // In Dalvik and ART, the jobject type in the JNI interface of the JVM has the | 
|  | // property that it is sometimes (always?) a small integer instead of a real pointer. | 
|  | // Note: although only the android JVMs are bad in this respect, we declare the JNI types | 
|  | // bad regardless of platform, so the same Go code compiles on both android and non-android. | 
|  | if parent, ok := jniTypes[dt.Name]; ok { | 
|  | // Try to make sure we're talking about a JNI type, not just some random user's | 
|  | // type that happens to use the same name. | 
|  | // C doesn't have the notion of a package, so it's hard to be certain. | 
|  |  | 
|  | // Walk up to jobject, checking each typedef on the way. | 
|  | w := dt | 
|  | for parent != "" { | 
|  | t, ok := w.Type.(*dwarf.TypedefType) | 
|  | if !ok || t.Name != parent { | 
|  | return false | 
|  | } | 
|  | w = t | 
|  | parent, ok = jniTypes[w.Name] | 
|  | if !ok { | 
|  | return false | 
|  | } | 
|  | } | 
|  |  | 
|  | // Check that the typedef is either: | 
|  | // 1: | 
|  | //     	struct _jobject; | 
|  | //     	typedef struct _jobject *jobject; | 
|  | // 2: (in NDK16 in C++) | 
|  | //     	class _jobject {}; | 
|  | //     	typedef _jobject* jobject; | 
|  | // 3: (in NDK16 in C) | 
|  | //     	typedef void* jobject; | 
|  | if ptr, ok := w.Type.(*dwarf.PtrType); ok { | 
|  | switch v := ptr.Type.(type) { | 
|  | case *dwarf.VoidType: | 
|  | return true | 
|  | case *dwarf.StructType: | 
|  | if v.StructName == "_jobject" && len(v.Field) == 0 { | 
|  | switch v.Kind { | 
|  | case "struct": | 
|  | if v.Incomplete { | 
|  | return true | 
|  | } | 
|  | case "class": | 
|  | if !v.Incomplete { | 
|  | return true | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool { | 
|  | if dt.Name != "EGLDisplay" { | 
|  | return false | 
|  | } | 
|  | // Check that the typedef is "typedef void *EGLDisplay". | 
|  | if ptr, ok := dt.Type.(*dwarf.PtrType); ok { | 
|  | if _, ok := ptr.Type.(*dwarf.VoidType); ok { | 
|  | return true | 
|  | } | 
|  | } | 
|  | return false | 
|  | } | 
|  |  | 
|  | // jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which | 
|  | // they are mapped. The base "jobject" maps to the empty string. | 
|  | var jniTypes = map[string]string{ | 
|  | "jobject":       "", | 
|  | "jclass":        "jobject", | 
|  | "jthrowable":    "jobject", | 
|  | "jstring":       "jobject", | 
|  | "jarray":        "jobject", | 
|  | "jbooleanArray": "jarray", | 
|  | "jbyteArray":    "jarray", | 
|  | "jcharArray":    "jarray", | 
|  | "jshortArray":   "jarray", | 
|  | "jintArray":     "jarray", | 
|  | "jlongArray":    "jarray", | 
|  | "jfloatArray":   "jarray", | 
|  | "jdoubleArray":  "jarray", | 
|  | "jobjectArray":  "jarray", | 
|  | "jweak":         "jobject", | 
|  | } |