diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-01-06 23:26:02 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-01-06 23:26:02 +0000 |
commit | 7d7d64c1ae3c0732b167d2050b101808f078d711 (patch) | |
tree | 40ecf33efd29feac369ae050140bc3fefed352e9 /libgo/go/cmd/cgo | |
parent | efcdb22fe3288fbfa4cd8ba9554b3a561c4d6e08 (diff) | |
download | gcc-7d7d64c1ae3c0732b167d2050b101808f078d711.zip gcc-7d7d64c1ae3c0732b167d2050b101808f078d711.tar.gz gcc-7d7d64c1ae3c0732b167d2050b101808f078d711.tar.bz2 |
libgo: Add sources for go, cgo, and gofmt commands.
The new commands are not yet built. That will be done
separately.
Also include a few changes to go/build to support them.
From-SVN: r219272
Diffstat (limited to 'libgo/go/cmd/cgo')
-rw-r--r-- | libgo/go/cmd/cgo/ast.go | 460 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/doc.go | 748 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/gcc.go | 1728 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/godefs.go | 294 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/main.go | 360 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/out.go | 1299 | ||||
-rw-r--r-- | libgo/go/cmd/cgo/util.go | 84 |
7 files changed, 4973 insertions, 0 deletions
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go new file mode 100644 index 0000000..7757efa --- /dev/null +++ b/libgo/go/cmd/cgo/ast.go @@ -0,0 +1,460 @@ +// 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. + +// Parse input AST and prepare Prog structure. + +package main + +import ( + "fmt" + "go/ast" + "go/parser" + "go/scanner" + "go/token" + "os" + "path/filepath" + "strings" +) + +func parse(name string, flags parser.Mode) *ast.File { + ast1, err := parser.ParseFile(fset, name, nil, flags) + if err != nil { + if list, ok := err.(scanner.ErrorList); ok { + // If err is a scanner.ErrorList, its String will print just + // the first error and then (+n more errors). + // Instead, turn it into a new Error that will return + // details for all the errors. + for _, e := range list { + fmt.Fprintln(os.Stderr, e) + } + os.Exit(2) + } + fatalf("parsing %s: %s", name, err) + } + return ast1 +} + +func sourceLine(n ast.Node) int { + return fset.Position(n.Pos()).Line +} + +// ReadGo populates f with information learned from reading the +// Go source file with the given file name. It gathers the C preamble +// attached to the import "C" comment, a list of references to C.xxx, +// a list of exported functions, and the actual AST, to be rewritten and +// printed. +func (f *File) ReadGo(name string) { + // Create absolute path for file, so that it will be used in error + // messages and recorded in debug line number information. + // This matches the rest of the toolchain. See golang.org/issue/5122. + if aname, err := filepath.Abs(name); err == nil { + name = aname + } + + // Two different parses: once with comments, once without. + // The printer is not good enough at printing comments in the + // right place when we start editing the AST behind its back, + // so we use ast1 to look for the doc comments on import "C" + // and on exported functions, and we use ast2 for translating + // and reprinting. + ast1 := parse(name, parser.ParseComments) + ast2 := parse(name, 0) + + f.Package = ast1.Name.Name + f.Name = make(map[string]*Name) + + // In ast1, find the import "C" line and get any extra C preamble. + sawC := false + for _, decl := range ast1.Decls { + d, ok := decl.(*ast.GenDecl) + if !ok { + continue + } + for _, spec := range d.Specs { + s, ok := spec.(*ast.ImportSpec) + if !ok || string(s.Path.Value) != `"C"` { + continue + } + sawC = true + if s.Name != nil { + error_(s.Path.Pos(), `cannot rename import "C"`) + } + cg := s.Doc + if cg == nil && len(d.Specs) == 1 { + cg = d.Doc + } + if cg != nil { + f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), name) + f.Preamble += commentText(cg) + "\n" + } + } + } + if !sawC { + error_(token.NoPos, `cannot find import "C"`) + } + + // In ast2, strip the import "C" line. + w := 0 + for _, decl := range ast2.Decls { + d, ok := decl.(*ast.GenDecl) + if !ok { + ast2.Decls[w] = decl + w++ + continue + } + ws := 0 + for _, spec := range d.Specs { + s, ok := spec.(*ast.ImportSpec) + if !ok || string(s.Path.Value) != `"C"` { + d.Specs[ws] = spec + ws++ + } + } + if ws == 0 { + continue + } + d.Specs = d.Specs[0:ws] + ast2.Decls[w] = d + w++ + } + ast2.Decls = ast2.Decls[0:w] + + // Accumulate pointers to uses of C.x. + if f.Ref == nil { + f.Ref = make([]*Ref, 0, 8) + } + f.walk(ast2, "prog", (*File).saveRef) + + // Accumulate exported functions. + // The comments are only on ast1 but we need to + // save the function bodies from ast2. + // The first walk fills in ExpFunc, and the + // second walk changes the entries to + // refer to ast2 instead. + f.walk(ast1, "prog", (*File).saveExport) + f.walk(ast2, "prog", (*File).saveExport2) + + f.Comments = ast1.Comments + f.AST = ast2 +} + +// Like ast.CommentGroup's Text method but preserves +// leading blank lines, so that line numbers line up. +func commentText(g *ast.CommentGroup) string { + if g == nil { + return "" + } + var pieces []string + for _, com := range g.List { + c := string(com.Text) + // Remove comment markers. + // The parser has given us exactly the comment text. + switch c[1] { + case '/': + //-style comment (no newline at the end) + c = c[2:] + "\n" + case '*': + /*-style comment */ + c = c[2 : len(c)-2] + } + pieces = append(pieces, c) + } + return strings.Join(pieces, "") +} + +// Save references to C.xxx for later processing. +func (f *File) saveRef(x interface{}, context string) { + n, ok := x.(*ast.Expr) + if !ok { + return + } + if sel, ok := (*n).(*ast.SelectorExpr); ok { + // For now, assume that the only instance of capital C is + // when used as the imported package identifier. + // The parser should take care of scoping in the future, + // so that we will be able to distinguish a "top-level C" + // from a local C. + if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" { + if context == "as2" { + context = "expr" + } + if context == "embed-type" { + error_(sel.Pos(), "cannot embed C type") + } + goname := sel.Sel.Name + if goname == "errno" { + error_(sel.Pos(), "cannot refer to errno directly; see documentation") + return + } + if goname == "_CMalloc" { + error_(sel.Pos(), "cannot refer to C._CMalloc; use C.malloc") + return + } + if goname == "malloc" { + goname = "_CMalloc" + } + name := f.Name[goname] + if name == nil { + name = &Name{ + Go: goname, + } + f.Name[goname] = name + } + f.Ref = append(f.Ref, &Ref{ + Name: name, + Expr: n, + Context: context, + }) + return + } + } +} + +// If a function should be exported add it to ExpFunc. +func (f *File) saveExport(x interface{}, context string) { + n, ok := x.(*ast.FuncDecl) + if !ok { + return + } + + if n.Doc == nil { + return + } + for _, c := range n.Doc.List { + if !strings.HasPrefix(string(c.Text), "//export ") { + continue + } + + name := strings.TrimSpace(string(c.Text[9:])) + if name == "" { + error_(c.Pos(), "export missing name") + } + + if name != n.Name.Name { + error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name) + } + + f.ExpFunc = append(f.ExpFunc, &ExpFunc{ + Func: n, + ExpName: name, + }) + break + } +} + +// Make f.ExpFunc[i] point at the Func from this AST instead of the other one. +func (f *File) saveExport2(x interface{}, context string) { + n, ok := x.(*ast.FuncDecl) + if !ok { + return + } + + for _, exp := range f.ExpFunc { + if exp.Func.Name.Name == n.Name.Name { + exp.Func = n + break + } + } +} + +// walk walks the AST x, calling visit(f, x, context) for each node. +func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) { + visit(f, x, context) + switch n := x.(type) { + case *ast.Expr: + f.walk(*n, context, visit) + + // everything else just recurs + default: + error_(token.NoPos, "unexpected type %T in walk", x, visit) + panic("unexpected type") + + case nil: + + // These are ordered and grouped to match ../../pkg/go/ast/ast.go + case *ast.Field: + if len(n.Names) == 0 && context == "field" { + f.walk(&n.Type, "embed-type", visit) + } else { + f.walk(&n.Type, "type", visit) + } + case *ast.FieldList: + for _, field := range n.List { + f.walk(field, context, visit) + } + case *ast.BadExpr: + case *ast.Ident: + case *ast.Ellipsis: + case *ast.BasicLit: + case *ast.FuncLit: + f.walk(n.Type, "type", visit) + f.walk(n.Body, "stmt", visit) + case *ast.CompositeLit: + f.walk(&n.Type, "type", visit) + f.walk(n.Elts, "expr", visit) + case *ast.ParenExpr: + f.walk(&n.X, context, visit) + case *ast.SelectorExpr: + f.walk(&n.X, "selector", visit) + case *ast.IndexExpr: + f.walk(&n.X, "expr", visit) + f.walk(&n.Index, "expr", visit) + case *ast.SliceExpr: + f.walk(&n.X, "expr", visit) + if n.Low != nil { + f.walk(&n.Low, "expr", visit) + } + if n.High != nil { + f.walk(&n.High, "expr", visit) + } + case *ast.TypeAssertExpr: + f.walk(&n.X, "expr", visit) + f.walk(&n.Type, "type", visit) + case *ast.CallExpr: + if context == "as2" { + f.walk(&n.Fun, "call2", visit) + } else { + f.walk(&n.Fun, "call", visit) + } + f.walk(n.Args, "expr", visit) + case *ast.StarExpr: + f.walk(&n.X, context, visit) + case *ast.UnaryExpr: + f.walk(&n.X, "expr", visit) + case *ast.BinaryExpr: + f.walk(&n.X, "expr", visit) + f.walk(&n.Y, "expr", visit) + case *ast.KeyValueExpr: + f.walk(&n.Key, "expr", visit) + f.walk(&n.Value, "expr", visit) + + case *ast.ArrayType: + f.walk(&n.Len, "expr", visit) + f.walk(&n.Elt, "type", visit) + case *ast.StructType: + f.walk(n.Fields, "field", visit) + case *ast.FuncType: + f.walk(n.Params, "param", visit) + if n.Results != nil { + f.walk(n.Results, "param", visit) + } + case *ast.InterfaceType: + f.walk(n.Methods, "field", visit) + case *ast.MapType: + f.walk(&n.Key, "type", visit) + f.walk(&n.Value, "type", visit) + case *ast.ChanType: + f.walk(&n.Value, "type", visit) + + case *ast.BadStmt: + case *ast.DeclStmt: + f.walk(n.Decl, "decl", visit) + case *ast.EmptyStmt: + case *ast.LabeledStmt: + f.walk(n.Stmt, "stmt", visit) + case *ast.ExprStmt: + f.walk(&n.X, "expr", visit) + case *ast.SendStmt: + f.walk(&n.Chan, "expr", visit) + f.walk(&n.Value, "expr", visit) + case *ast.IncDecStmt: + f.walk(&n.X, "expr", visit) + case *ast.AssignStmt: + f.walk(n.Lhs, "expr", visit) + if len(n.Lhs) == 2 && len(n.Rhs) == 1 { + f.walk(n.Rhs, "as2", visit) + } else { + f.walk(n.Rhs, "expr", visit) + } + case *ast.GoStmt: + f.walk(n.Call, "expr", visit) + case *ast.DeferStmt: + f.walk(n.Call, "expr", visit) + case *ast.ReturnStmt: + f.walk(n.Results, "expr", visit) + case *ast.BranchStmt: + case *ast.BlockStmt: + f.walk(n.List, context, visit) + case *ast.IfStmt: + f.walk(n.Init, "stmt", visit) + f.walk(&n.Cond, "expr", visit) + f.walk(n.Body, "stmt", visit) + f.walk(n.Else, "stmt", visit) + case *ast.CaseClause: + if context == "typeswitch" { + context = "type" + } else { + context = "expr" + } + f.walk(n.List, context, visit) + f.walk(n.Body, "stmt", visit) + case *ast.SwitchStmt: + f.walk(n.Init, "stmt", visit) + f.walk(&n.Tag, "expr", visit) + f.walk(n.Body, "switch", visit) + case *ast.TypeSwitchStmt: + f.walk(n.Init, "stmt", visit) + f.walk(n.Assign, "stmt", visit) + f.walk(n.Body, "typeswitch", visit) + case *ast.CommClause: + f.walk(n.Comm, "stmt", visit) + f.walk(n.Body, "stmt", visit) + case *ast.SelectStmt: + f.walk(n.Body, "stmt", visit) + case *ast.ForStmt: + f.walk(n.Init, "stmt", visit) + f.walk(&n.Cond, "expr", visit) + f.walk(n.Post, "stmt", visit) + f.walk(n.Body, "stmt", visit) + case *ast.RangeStmt: + f.walk(&n.Key, "expr", visit) + f.walk(&n.Value, "expr", visit) + f.walk(&n.X, "expr", visit) + f.walk(n.Body, "stmt", visit) + + case *ast.ImportSpec: + case *ast.ValueSpec: + f.walk(&n.Type, "type", visit) + f.walk(n.Values, "expr", visit) + case *ast.TypeSpec: + f.walk(&n.Type, "type", visit) + + case *ast.BadDecl: + case *ast.GenDecl: + f.walk(n.Specs, "spec", visit) + case *ast.FuncDecl: + if n.Recv != nil { + f.walk(n.Recv, "param", visit) + } + f.walk(n.Type, "type", visit) + if n.Body != nil { + f.walk(n.Body, "stmt", visit) + } + + case *ast.File: + f.walk(n.Decls, "decl", visit) + + case *ast.Package: + for _, file := range n.Files { + f.walk(file, "file", visit) + } + + case []ast.Decl: + for _, d := range n { + f.walk(d, context, visit) + } + case []ast.Expr: + for i := range n { + f.walk(&n[i], context, visit) + } + case []ast.Stmt: + for _, s := range n { + f.walk(s, context, visit) + } + case []ast.Spec: + for _, s := range n { + f.walk(s, context, visit) + } + } +} diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go new file mode 100644 index 0000000..69c7ce8 --- /dev/null +++ b/libgo/go/cmd/cgo/doc.go @@ -0,0 +1,748 @@ +// 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. + +/* + +Cgo enables the creation of Go packages that call C code. + +Using cgo with the go command + +To use cgo write normal Go code that imports a pseudo-package "C". +The Go code can then refer to types such as C.size_t, variables such +as C.stdout, or functions such as C.putchar. + +If the import of "C" is immediately preceded by a comment, that +comment, called the preamble, is used as a header when compiling +the C parts of the package. For example: + + // #include <stdio.h> + // #include <errno.h> + import "C" + +See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See +"C? Go? Cgo!" for an introduction to using cgo: +http://golang.org/doc/articles/c_go_cgo.html. + +CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo +directives within these comments to tweak the behavior of the C or C++ +compiler. Values defined in multiple directives are concatenated +together. The directive can include a list of build constraints limiting its +effect to systems satisfying one of the constraints +(see http://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax). +For example: + + // #cgo CFLAGS: -DPNG_DEBUG=1 + // #cgo amd64 386 CFLAGS: -DX86=1 + // #cgo LDFLAGS: -lpng + // #include <png.h> + import "C" + +Alternatively, CPPFLAGS and LDFLAGS may be obtained via the pkg-config +tool using a '#cgo pkg-config:' directive followed by the package names. +For example: + + // #cgo pkg-config: png cairo + // #include <png.h> + import "C" + +When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS and +CGO_LDFLAGS environment variables are added to the flags derived from +these directives. Package-specific flags should be set using the +directives, not the environment variables, so that builds work in +unmodified environments. + +All the cgo CPPFLAGS and CFLAGS directives in a package are concatenated and +used to compile C files in that package. All the CPPFLAGS and CXXFLAGS +directives in a package are concatenated and used to compile C++ files in that +package. All the LDFLAGS directives in any package in the program are +concatenated and used at link time. All the pkg-config directives are +concatenated and sent to pkg-config simultaneously to add to each appropriate +set of command-line flags. + +When the Go tool sees that one or more Go files use the special import +"C", it will look for other non-Go files in the directory and compile +them as part of the Go package. Any .c, .s, or .S files will be +compiled with the C compiler. Any .cc, .cpp, or .cxx files will be +compiled with the C++ compiler. Any .h, .hh, .hpp, or .hxx files will +not be compiled separately, but, if these header files are changed, +the C and C++ files will be recompiled. The default C and C++ +compilers may be changed by the CC and CXX environment variables, +respectively; those environment variables may include command line +options. + +To enable cgo during cross compiling builds, set the CGO_ENABLED +environment variable to 1 when building the Go tools with make.bash. +Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will +be used for compiling for the host. + +After the Go tools are built, when running the go command, CC_FOR_TARGET is +ignored. The value of CC_FOR_TARGET when running make.bash is the default +compiler. However, you can set the environment variable CC, not CC_FOR_TARGET, +to control the compiler when running the go tool. + +CXX_FOR_TARGET works in a similar way for C++ code. + +Go references to C + +Within the Go file, C's struct field names that are keywords in Go +can be accessed by prefixing them with an underscore: if x points at a C +struct with a field named "type", x._type accesses the field. +C struct fields that cannot be expressed in Go, such as bit fields +or misaligned data, are omitted in the Go struct, replaced by +appropriate padding to reach the next field or the end of the struct. + +The standard C numeric types are available under the names +C.char, C.schar (signed char), C.uchar (unsigned char), +C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int), +C.long, C.ulong (unsigned long), C.longlong (long long), +C.ulonglong (unsigned long long), C.float, C.double. +The C type void* is represented by Go's unsafe.Pointer. + +To access a struct, union, or enum type directly, prefix it with +struct_, union_, or enum_, as in C.struct_stat. + +As Go doesn't have support for C's union type in the general case, +C's union types are represented as a Go byte array with the same length. + +Go structs cannot embed fields with C types. + +Cgo translates C types into equivalent unexported Go types. +Because the translations are unexported, a Go package should not +expose C types in its exported API: a C type used in one Go package +is different from the same C type used in another. + +Any C function (even void functions) may be called in a multiple +assignment context to retrieve both the return value (if any) and the +C errno variable as an error (use _ to skip the result value if the +function returns void). For example: + + n, err := C.sqrt(-1) + _, err := C.voidFunc() + +Calling C function pointers is currently not supported, however you can +declare Go variables which hold C function pointers and pass them +back and forth between Go and C. C code may call function pointers +received from Go. For example: + + package main + + // typedef int (*intFunc) (); + // + // int + // bridge_int_func(intFunc f) + // { + // return f(); + // } + // + // int fortytwo() + // { + // return 42; + // } + import "C" + import "fmt" + + func main() { + f := C.intFunc(C.fortytwo) + fmt.Println(int(C.bridge_int_func(f))) + // Output: 42 + } + +In C, a function argument written as a fixed size array +actually requires a pointer to the first element of the array. +C compilers are aware of this calling convention and adjust +the call accordingly, but Go cannot. In Go, you must pass +the pointer to the first element explicitly: C.f(&x[0]). + +A few special functions convert between Go and C types +by making copies of the data. In pseudo-Go definitions: + + // Go string to C string + // The C string is allocated in the C heap using malloc. + // It is the caller's responsibility to arrange for it to be + // freed, such as by calling C.free (be sure to include stdlib.h + // if C.free is needed). + func C.CString(string) *C.char + + // C string to Go string + func C.GoString(*C.char) string + + // C string, length to Go string + func C.GoStringN(*C.char, C.int) string + + // C pointer, length to Go []byte + func C.GoBytes(unsafe.Pointer, C.int) []byte + +C references to Go + +Go functions can be exported for use by C code in the following way: + + //export MyFunction + func MyFunction(arg1, arg2 int, arg3 string) int64 {...} + + //export MyFunction2 + func MyFunction2(arg1, arg2 int, arg3 string) (int64, *C.char) {...} + +They will be available in the C code as: + + extern int64 MyFunction(int arg1, int arg2, GoString arg3); + extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3); + +found in the _cgo_export.h generated header, after any preambles +copied from the cgo input files. Functions with multiple +return values are mapped to functions returning a struct. +Not all Go types can be mapped to C types in a useful way. + +Using //export in a file places a restriction on the preamble: +since it is copied into two different C output files, it must not +contain any definitions, only declarations. Definitions must be +placed in preambles in other files, or in C source files. + +Using cgo directly + +Usage: + go tool cgo [cgo options] [-- compiler options] file.go + +Cgo transforms the input file.go into four output files: two Go source +files, a C file for 6c (or 8c or 5c), and a C file for gcc. + +The compiler options are passed through uninterpreted when +invoking the C compiler to compile the C parts of the package. + +The following options are available when running cgo directly: + + -dynimport file + Write list of symbols imported by file. Write to + -dynout argument or to standard output. Used by go + build when building a cgo package. + -dynout file + Write -dynimport output to file. + -dynlinker + Write dynamic linker as part of -dynimport output. + -godefs + Write out input file in Go syntax replacing C package + names with real values. Used to generate files in the + syscall package when bootstrapping a new target. + -cdefs + Like -godefs, but write file in C syntax. + Used to generate files in the runtime package when + bootstrapping a new target. + -objdir directory + Put all generated files in directory. + -gccgo + Generate output for the gccgo compiler rather than the + gc compiler. + -gccgoprefix prefix + The -fgo-prefix option to be used with gccgo. + -gccgopkgpath path + The -fgo-pkgpath option to be used with gccgo. + -import_runtime_cgo + If set (which it is by default) import runtime/cgo in + generated output. + -import_syscall + If set (which it is by default) import syscall in + generated output. + -debug-define + Debugging option. Print #defines. + -debug-gcc + Debugging option. Trace C compiler execution and output. +*/ +package main + +/* +Implementation details. + +Cgo provides a way for Go programs to call C code linked into the same +address space. This comment explains the operation of cgo. + +Cgo reads a set of Go source files and looks for statements saying +import "C". If the import has a doc comment, that comment is +taken as literal C code to be used as a preamble to any C code +generated by cgo. A typical preamble #includes necessary definitions: + + // #include <stdio.h> + import "C" + +For more details about the usage of cgo, see the documentation +comment at the top of this file. + +Understanding C + +Cgo scans the Go source files that import "C" for uses of that +package, such as C.puts. It collects all such identifiers. The next +step is to determine each kind of name. In C.xxx the xxx might refer +to a type, a function, a constant, or a global variable. Cgo must +decide which. + +The obvious thing for cgo to do is to process the preamble, expanding +#includes and processing the corresponding C code. That would require +a full C parser and type checker that was also aware of any extensions +known to the system compiler (for example, all the GNU C extensions) as +well as the system-specific header locations and system-specific +pre-#defined macros. This is certainly possible to do, but it is an +enormous amount of work. + +Cgo takes a different approach. It determines the meaning of C +identifiers not by parsing C code but by feeding carefully constructed +programs into the system C compiler and interpreting the generated +error messages, debug information, and object files. In practice, +parsing these is significantly less work and more robust than parsing +C source. + +Cgo first invokes gcc -E -dM on the preamble, in order to find out +about simple #defines for constants and the like. These are recorded +for later use. + +Next, cgo needs to identify the kinds for each identifier. For the +identifiers C.foo and C.bar, cgo generates this C program: + + <preamble> + #line 1 "not-declared" + void __cgo_f_xxx_1(void) { __typeof__(foo) *__cgo_undefined__; } + #line 1 "not-type" + void __cgo_f_xxx_2(void) { foo *__cgo_undefined__; } + #line 1 "not-const" + void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (foo)*1 }; } + #line 2 "not-declared" + void __cgo_f_xxx_1(void) { __typeof__(bar) *__cgo_undefined__; } + #line 2 "not-type" + void __cgo_f_xxx_2(void) { bar *__cgo_undefined__; } + #line 2 "not-const" + void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (bar)*1 }; } + +This program will not compile, but cgo can use the presence or absence +of an error message on a given line to deduce the information it +needs. The program is syntactically valid regardless of whether each +name is a type or an ordinary identifier, so there will be no syntax +errors that might stop parsing early. + +An error on not-declared:1 indicates that foo is undeclared. +An error on not-type:1 indicates that foo is not a type (if declared at all, it is an identifier). +An error on not-const:1 indicates that foo is not an integer constant. + +The line number specifies the name involved. In the example, 1 is foo and 2 is bar. + +Next, cgo must learn the details of each type, variable, function, or +constant. It can do this by reading object files. If cgo has decided +that t1 is a type, v2 and v3 are variables or functions, and c4, c5, +and c6 are constants, it generates: + + <preamble> + __typeof__(t1) *__cgo__1; + __typeof__(v2) *__cgo__2; + __typeof__(v3) *__cgo__3; + __typeof__(c4) *__cgo__4; + enum { __cgo_enum__4 = c4 }; + __typeof__(c5) *__cgo__5; + enum { __cgo_enum__5 = c5 }; + __typeof__(c6) *__cgo__6; + enum { __cgo_enum__6 = c6 }; + + long long __cgo_debug_data[] = { + 0, // t1 + 0, // v2 + 0, // v3 + c4, + c5, + c6, + 1 + }; + +and again invokes the system C compiler, to produce an object file +containing debug information. Cgo parses the DWARF debug information +for __cgo__N to learn the type of each identifier. (The types also +distinguish functions from global variables.) If using a standard gcc, +cgo can parse the DWARF debug information for the __cgo_enum__N to +learn the identifier's value. The LLVM-based gcc on OS X emits +incomplete DWARF information for enums; in that case cgo reads the +constant values from the __cgo_debug_data from the object file's data +segment. + +At this point cgo knows the meaning of each C.xxx well enough to start +the translation process. + +Translating Go + +[The rest of this comment refers to 6g and 6c, the Go and C compilers +that are part of the amd64 port of the gc Go toolchain. Everything here +applies to another architecture's compilers as well.] + +Given the input Go files x.go and y.go, cgo generates these source +files: + + x.cgo1.go # for 6g + y.cgo1.go # for 6g + _cgo_gotypes.go # for 6g + _cgo_defun.c # for 6c + x.cgo2.c # for gcc + y.cgo2.c # for gcc + _cgo_export.c # for gcc + _cgo_main.c # for gcc + +The file x.cgo1.go is a copy of x.go with the import "C" removed and +references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx. +The definitions of those identifiers, written as Go functions, types, +or variables, are provided in _cgo_gotypes.go. + +Here is a _cgo_gotypes.go containing definitions for C.flush (provided +in the preamble) and C.puts (from stdio): + + type _Ctype_char int8 + type _Ctype_int int32 + type _Ctype_void [0]byte + + func _Cfunc_CString(string) *_Ctype_char + func _Cfunc_flush() _Ctype_void + func _Cfunc_puts(*_Ctype_char) _Ctype_int + +For functions, cgo only writes an external declaration in the Go +output. The implementation is in a combination of C for 6c (meaning +any gc-toolchain compiler) and C for gcc. + +The 6c file contains the definitions of the functions. They all have +similar bodies that invoke runtime·cgocall to make a switch from the +Go runtime world to the system C (GCC-based) world. + +For example, here is the definition of _Cfunc_puts: + + void _cgo_be59f0f25121_Cfunc_puts(void*); + + void + ·_Cfunc_puts(struct{uint8 x[1];}p) + { + runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p); + } + +The hexadecimal number is a hash of cgo's input, chosen to be +deterministic yet unlikely to collide with other uses. The actual +function _cgo_be59f0f25121_Cfunc_puts is implemented in a C source +file compiled by gcc, the file x.cgo2.c: + + void + _cgo_be59f0f25121_Cfunc_puts(void *v) + { + struct { + char* p0; + int r; + char __pad12[4]; + } __attribute__((__packed__, __gcc_struct__)) *a = v; + a->r = puts((void*)a->p0); + } + +It extracts the arguments from the pointer to _Cfunc_puts's argument +frame, invokes the system C function (in this case, puts), stores the +result in the frame, and returns. + +Linking + +Once the _cgo_export.c and *.cgo2.c files have been compiled with gcc, +they need to be linked into the final binary, along with the libraries +they might depend on (in the case of puts, stdio). 6l has been +extended to understand basic ELF files, but it does not understand ELF +in the full complexity that modern C libraries embrace, so it cannot +in general generate direct references to the system libraries. + +Instead, the build process generates an object file using dynamic +linkage to the desired libraries. The main function is provided by +_cgo_main.c: + + int main() { return 0; } + void crosscall2(void(*fn)(void*, int), void *a, int c) { } + void _cgo_allocate(void *a, int c) { } + void _cgo_panic(void *a, int c) { } + +The extra functions here are stubs to satisfy the references in the C +code generated for gcc. The build process links this stub, along with +_cgo_export.c and *.cgo2.c, into a dynamic executable and then lets +cgo examine the executable. Cgo records the list of shared library +references and resolved names and writes them into a new file +_cgo_import.c, which looks like: + + #pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2" + #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6" + #pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6" + #pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6" + #pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6" + #pragma cgo_import_dynamic _ _ "libpthread.so.0" + #pragma cgo_import_dynamic _ _ "libc.so.6" + +In the end, the compiled Go package, which will eventually be +presented to 6l as part of a larger program, contains: + + _go_.6 # 6g-compiled object for _cgo_gotypes.go *.cgo1.go + _cgo_defun.6 # 6c-compiled object for _cgo_defun.c + _all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c + _cgo_import.6 # 6c-compiled object for _cgo_import.c + +The final program will be a dynamic executable, so that 6l can avoid +needing to process arbitrary .o files. It only needs to process the .o +files generated from C files that cgo writes, and those are much more +limited in the ELF or other features that they use. + +In essence, the _cgo_import.6 file includes the extra linking +directives that 6l is not sophisticated enough to derive from _all.o +on its own. Similarly, the _all.o uses dynamic references to real +system object code because 6l is not sophisticated enough to process +the real code. + +The main benefits of this system are that 6l remains relatively simple +(it does not need to implement a complete ELF and Mach-O linker) and +that gcc is not needed after the package is compiled. For example, +package net uses cgo for access to name resolution functions provided +by libc. Although gcc is needed to compile package net, gcc is not +needed to link programs that import package net. + +Runtime + +When using cgo, Go must not assume that it owns all details of the +process. In particular it needs to coordinate with C in the use of +threads and thread-local storage. The runtime package, in its own +(6c-compiled) C code, declares a few uninitialized (default bss) +variables: + + bool runtime·iscgo; + void (*libcgo_thread_start)(void*); + void (*initcgo)(G*); + +Any package using cgo imports "runtime/cgo", which provides +initializations for these variables. It sets iscgo to 1, initcgo to a +gcc-compiled function that can be called early during program startup, +and libcgo_thread_start to a gcc-compiled function that can be used to +create a new thread, in place of the runtime's usual direct system +calls. + +Internal and External Linking + +The text above describes "internal" linking, in which 6l parses and +links host object files (ELF, Mach-O, PE, and so on) into the final +executable itself. Keeping 6l simple means we cannot possibly +implement the full semantics of the host linker, so the kinds of +objects that can be linked directly into the binary is limited (other +code can only be used as a dynamic library). On the other hand, when +using internal linking, 6l can generate Go binaries by itself. + +In order to allow linking arbitrary object files without requiring +dynamic libraries, cgo will soon support an "external" linking mode +too. In external linking mode, 6l does not process any host object +files. Instead, it collects all the Go code and writes a single go.o +object file containing it. Then it invokes the host linker (usually +gcc) to combine the go.o object file and any supporting non-Go code +into a final executable. External linking avoids the dynamic library +requirement but introduces a requirement that the host linker be +present to create such a binary. + +Most builds both compile source code and invoke the linker to create a +binary. When cgo is involved, the compile step already requires gcc, so +it is not problematic for the link step to require gcc too. + +An important exception is builds using a pre-compiled copy of the +standard library. In particular, package net uses cgo on most systems, +and we want to preserve the ability to compile pure Go code that +imports net without requiring gcc to be present at link time. (In this +case, the dynamic library requirement is less significant, because the +only library involved is libc.so, which can usually be assumed +present.) + +This conflict between functionality and the gcc requirement means we +must support both internal and external linking, depending on the +circumstances: if net is the only cgo-using package, then internal +linking is probably fine, but if other packages are involved, so that there +are dependencies on libraries beyond libc, external linking is likely +to work better. The compilation of a package records the relevant +information to support both linking modes, leaving the decision +to be made when linking the final binary. + +Linking Directives + +In either linking mode, package-specific directives must be passed +through to 6l. These are communicated by writing #pragma directives +in a C source file compiled by 6c. The directives are copied into the .6 object file +and then processed by the linker. + +The directives are: + +#pragma cgo_import_dynamic <local> [<remote> ["<library>"]] + + In internal linking mode, allow an unresolved reference to + <local>, assuming it will be resolved by a dynamic library + symbol. The optional <remote> specifies the symbol's name and + possibly version in the dynamic library, and the optional "<library>" + names the specific library where the symbol should be found. + + In the <remote>, # or @ can be used to introduce a symbol version. + + Examples: + #pragma cgo_import_dynamic puts + #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 + #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6" + + A side effect of the cgo_import_dynamic directive with a + library is to make the final binary depend on that dynamic + library. To get the dependency without importing any specific + symbols, use _ for local and remote. + + Example: + #pragma cgo_import_dynamic _ _ "libc.so.6" + + For compatibility with current versions of SWIG, + #pragma dynimport is an alias for #pragma cgo_import_dynamic. + +#pragma cgo_dynamic_linker "<path>" + + In internal linking mode, use "<path>" as the dynamic linker + in the final binary. This directive is only needed from one + package when constructing a binary; by convention it is + supplied by runtime/cgo. + + Example: + #pragma cgo_dynamic_linker "/lib/ld-linux.so.2" + +#pragma cgo_export_dynamic <local> <remote> + + In internal linking mode, put the Go symbol + named <local> into the program's exported symbol table as + <remote>, so that C code can refer to it by that name. This + mechanism makes it possible for C code to call back into Go or + to share Go's data. + + For compatibility with current versions of SWIG, + #pragma dynexport is an alias for #pragma cgo_export_dynamic. + +#pragma cgo_import_static <local> + + In external linking mode, allow unresolved references to + <local> in the go.o object file prepared for the host linker, + under the assumption that <local> will be supplied by the + other object files that will be linked with go.o. + + Example: + #pragma cgo_import_static puts_wrapper + +#pragma cgo_export_static <local> <remote> + + In external linking mode, put the Go symbol + named <local> into the program's exported symbol table as + <remote>, so that C code can refer to it by that name. This + mechanism makes it possible for C code to call back into Go or + to share Go's data. + +#pragma cgo_ldflag "<arg>" + + In external linking mode, invoke the host linker (usually gcc) + with "<arg>" as a command-line argument following the .o files. + Note that the arguments are for "gcc", not "ld". + + Example: + #pragma cgo_ldflag "-lpthread" + #pragma cgo_ldflag "-L/usr/local/sqlite3/lib" + +A package compiled with cgo will include directives for both +internal and external linking; the linker will select the appropriate +subset for the chosen linking mode. + +Example + +As a simple example, consider a package that uses cgo to call C.sin. +The following code will be generated by cgo: + + // compiled by 6g + + type _Ctype_double float64 + func _Cfunc_sin(_Ctype_double) _Ctype_double + + // compiled by 6c + + #pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6" + + #pragma cgo_import_static _cgo_gcc_Cfunc_sin + #pragma cgo_ldflag "-lm" + + void _cgo_gcc_Cfunc_sin(void*); + + void + ·_Cfunc_sin(struct{uint8 x[16];}p) + { + runtime·cgocall(_cgo_gcc_Cfunc_sin, &p); + } + + // compiled by gcc, into foo.cgo2.o + + void + _cgo_gcc_Cfunc_sin(void *v) + { + struct { + double p0; + double r; + } __attribute__((__packed__)) *a = v; + a->r = sin(a->p0); + } + +What happens at link time depends on whether the final binary is linked +using the internal or external mode. If other packages are compiled in +"external only" mode, then the final link will be an external one. +Otherwise the link will be an internal one. + +The directives in the 6c-compiled file are used according to the kind +of final link used. + +In internal mode, 6l itself processes all the host object files, in +particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and +cgo_dynamic_linker directives to learn that the otherwise undefined +reference to sin in foo.cgo2.o should be rewritten to refer to the +symbol sin with version GLIBC_2.2.5 from the dynamic library +"libm.so.6", and the binary should request "/lib/ld-linux.so.2" as its +runtime dynamic linker. + +In external mode, 6l does not process any host object files, in +particular foo.cgo2.o. It links together the 6g- and 6c-generated +object files, along with any other Go code, into a go.o file. While +doing that, 6l will discover that there is no definition for +_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This +is okay, because 6l also processes the cgo_import_static directive and +knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host +object file, so 6l does not treat the missing symbol as an error when +creating go.o. Indeed, the definition for _cgo_gcc_Cfunc_sin will be +provided to the host linker by foo2.cgo.o, which in turn will need the +symbol 'sin'. 6l also processes the cgo_ldflag directives, so that it +knows that the eventual host link command must include the -lm +argument, so that the host linker will be able to find 'sin' in the +math library. + +6l Command Line Interface + +The go command and any other Go-aware build systems invoke 6l +to link a collection of packages into a single binary. By default, 6l will +present the same interface it does today: + + 6l main.a + +produces a file named 6.out, even if 6l does so by invoking the host +linker in external linking mode. + +By default, 6l will decide the linking mode as follows: if the only +packages using cgo are those on a whitelist of standard library +packages (net, os/user, runtime/cgo), 6l will use internal linking +mode. Otherwise, there are non-standard cgo packages involved, and 6l +will use external linking mode. The first rule means that a build of +the godoc binary, which uses net but no other cgo, can run without +needing gcc available. The second rule means that a build of a +cgo-wrapped library like sqlite3 can generate a standalone executable +instead of needing to refer to a dynamic library. The specific choice +can be overridden using a command line flag: 6l -linkmode=internal or +6l -linkmode=external. + +In an external link, 6l will create a temporary directory, write any +host object files found in package archives to that directory (renamed +to avoid conflicts), write the go.o file to that directory, and invoke +the host linker. The default value for the host linker is $CC, split +into fields, or else "gcc". The specific host linker command line can +be overridden using command line flags: 6l -extld=clang +-extldflags='-ggdb -O3'. If any package in a build includes a .cc or +other file compiled by the C++ compiler, the go tool will use the +-extld option to set the host linker to the C++ compiler. + +These defaults mean that Go-aware build systems can ignore the linking +changes and keep running plain '6l' and get reasonable results, but +they can also control the linking details if desired. + +*/ diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go new file mode 100644 index 0000000..f55cfba --- /dev/null +++ b/libgo/go/cmd/cgo/gcc.go @@ -0,0 +1,1728 @@ +// 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" + "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. + p.GccOptions = append(p.GccOptions, args...) + } +} + +// 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 +} + +var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`) + +func safeName(s string) bool { + if s == "" { + return false + } + for i := 0; i < len(s); i++ { + if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { + return false + } + } + return true +} + +// 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) + } + p.loadDefines(f) + needType := p.guessKinds(f) + if len(needType) > 0 { + p.loadDWARF(f, needType) + } + 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(f.Preamble) + b.WriteString(builtinProlog) + 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 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 + for _, n := range f.Name { + // If we've already found this name as a #define + // and we can translate it as a constant value, do so. + if n.Define != "" { + isConst := false + if _, err := strconv.Atoi(n.Define); err == nil { + isConst = true + } else if n.Define[0] == '"' || n.Define[0] == '\'' { + if _, err := parser.ParseExpr(n.Define); err == nil { + isConst = true + } + } + if isConst { + n.Kind = "const" + // 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. + i, err := strconv.ParseInt(n.Define, 0, 64) + if err == nil { + n.Const = fmt.Sprintf("%#x", i) + } else { + n.Const = n.Define + } + continue + } + + if isName(n.Define) { + n.C = n.Define + } + } + + needType = append(needType, n) + + // 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" + continue + } + + // 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__; } + // #line xxx "not-type" + // void __cgo_f_xxx_2(void) { name *__cgo_undefined__; } + // #line xxx "not-const" + // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; } + // + // 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-const:xxx, the corresponding name is not an integer constant. + // If we see no errors, we assume the name is an expression but not a constant + // (so a variable or a function). + // + // 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(f.Preamble) + b.WriteString(builtinProlog) + + for i, n := range names { + fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+ + "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+ + "#line %d \"not-type\"\n"+ + "void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+ + "#line %d \"not-const\"\n"+ + "void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n", + 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 + notConst + ) + for _, line := range strings.Split(stderr, "\n") { + if !strings.Contains(line, ": error:") { + // we only care about errors. + // we tried to turn off warnings on the command line, but one never knows. + 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) { + 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": + error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:])) + case "not-type": + sniff[i] |= notType + case "not-const": + sniff[i] |= notConst + } + } + + if !completed { + fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) + } + + for i, n := range names { + switch sniff[i] { + case 0: + error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go)) + case notType: + n.Kind = "const" + case notConst: + n.Kind = "type" + case notConst | notType: + n.Kind = "not-type" + } + } + if nerrors > 0 { + fatalf("unresolved names") + } + + needType = append(needType, 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, 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(f.Preamble) + b.WriteString(builtinProlog) + for i, n := range names { + fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i) + if n.Kind == "const" { + fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C) + } + } + + // Apple's LLVM-based gcc does not include the enumeration + // names and values in its DWARF debug output. In case we're + // using such a gcc, create a data block initialized with the values. + // We can read them out of the object file. + fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n") + for _, n := range names { + if n.Kind == "const" { + fmt.Fprintf(&b, "\t%s,\n", n.C) + } else { + fmt.Fprintf(&b, "\t0,\n") + } + } + // for the last entry, we can not 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") + + d, bo, debugData := p.gccDebug(b.Bytes()) + enumVal := make([]int64, len(debugData)/8) + for i := range enumVal { + enumVal[i] = int64(bo.Uint64(debugData[i*8:])) + } + + // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i. + types := make([]dwarf.Type, len(names)) + enums := make([]dwarf.Offset, len(names)) + nameToIndex := make(map[*Name]int) + for i, n := range names { + nameToIndex[n] = i + } + nameToRef := make(map[*Name]*Ref) + for _, ref := range f.Ref { + nameToRef[ref.Name] = ref + } + 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.TagEnumerationType: + offset := e.Offset + for { + e, err := r.Next() + if err != nil { + fatalf("reading DWARF entry: %s", err) + } + if e.Tag == 0 { + break + } + if e.Tag == dwarf.TagEnumerator { + entryName := e.Val(dwarf.AttrName).(string) + if strings.HasPrefix(entryName, "__cgo_enum__") { + n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):]) + if 0 <= n && n < len(names) { + enums[n] = offset + } + } + } + } + case dwarf.TagVariable: + name, _ := e.Val(dwarf.AttrName).(string) + typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset) + if name == "" || typOff == 0 { + 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) + } + if enums[i] != 0 { + t, err := d.Type(enums[i]) + if err != nil { + fatalf("loading DWARF type: %s", err) + } + types[i] = t + } else { + types[i] = t.Type + } + } + if e.Tag != dwarf.TagCompileUnit { + r.SkipChildren() + } + } + + // Record types and typedef information. + var conv typeConv + conv.Init(p.PtrSize, p.IntSize) + for i, n := range names { + if types[i] == nil { + continue + } + pos := token.NoPos + if ref, ok := nameToRef[n]; ok { + pos = ref.Pos() + } + 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) + if enums[i] != 0 && n.Type.EnumValues != nil { + k := fmt.Sprintf("__cgo_enum__%d", i) + n.Kind = "const" + n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k]) + // Remove injected enum to ensure the value will deep-compare + // equally in future loads of the same constant. + delete(n.Type.EnumValues, k) + } + // Prefer debug data over DWARF debug output, if we have it. + if n.Kind == "const" && i < len(enumVal) { + n.Const = fmt.Sprintf("%#x", enumVal[i]) + } + } + conv.FinishType(pos) + } +} + +// 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 +} + +// 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 or *cdefs 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) + + // Assign mangled names. + for _, n := range f.Name { + if n.Kind == "not-type" { + n.Kind = "var" + } + if n.Mangle == "" { + p.mangleName(n) + } + 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.Kind == "const" && r.Name.Const == "" { + error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go)) + } + var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default + switch r.Context { + case "call", "call2": + if r.Name.Kind != "func" { + if r.Name.Kind == "type" { + r.Context = "type" + expr = r.Name.Type.Go + break + } + error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go)) + break + } + functions[r.Name.Go] = true + if r.Context == "call2" { + 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 "expr": + if r.Name.Kind == "func" { + // 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 + expr = ast.NewIdent(name.Mangle) + } else if r.Name.Kind == "type" { + // Okay - might be new(T) + expr = r.Name.Type.Go + } else if r.Name.Kind == "var" { + expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} + } + + case "type": + 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)) + } + } + if *godefs || *cdefs { + // 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() + switch x := expr.(type) { + case *ast.Ident: + expr = &ast.Ident{NamePos: pos, Name: x.Name} + } + + *r.Expr = expr + } + + // 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) + } + } +} + +// 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) +} + +// 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 + } + 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 strings.Contains(c[0], "clang") { + 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: http://golang.org/issue/6506. + "-fno-builtin", + ) + } + + c = append(c, p.GccOptions...) + c = append(c, p.gccMachine()...) + 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) (*dwarf.Data, binary.ByteOrder, []byte) { + runGcc(stdin, p.gccCmd()) + + isDebugData := func(s string) bool { + // Some systems use leading _ to denote non-assembly symbols. + return s == "__cgodebug_data" || s == "___cgodebug_data" + } + + 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) + } + var data []byte + if f.Symtab != nil { + for i := range f.Symtab.Syms { + s := &f.Symtab.Syms[i] + if isDebugData(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:] + } + } + } + } + } + } + return d, f.ByteOrder, data + } + + 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) + } + var data []byte + symtab, err := f.Symbols() + if err == nil { + for i := range symtab { + s := &symtab[i] + if isDebugData(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:] + } + } + } + } + } + } + return d, f.ByteOrder, data + } + + 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) + } + var data []byte + for _, s := range f.Symbols { + if isDebugData(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:] + } + } + } + } + } + return d, binary.LittleEndian, data + } + + fatalf("cannot parse gcc output %s as ELF, Mach-O, PE 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() + + if *debugGcc { + fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) + os.Stderr.Write(stdin) + fmt.Fprint(os.Stderr, "EOF\n") + } + stdout, stderr, _ := run(stdin, args) + 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[dwarf.Type]*Type + typedef map[string]ast.Expr + + // Map from types to incomplete pointers to those types. + ptrs map[dwarf.Type][]*Type + + // Fields to be processed by godefsField after completing pointers. + todoFlds [][]*ast.Field + + // 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 + unsafePointer ast.Expr + string ast.Expr + goVoid ast.Expr // _Ctype_void, denotes C's void + + ptrSize int64 + intSize int64 +} + +var tagGen int +var typedef = make(map[string]*Type) +var goIdent = make(map[string]*ast.Ident) + +func (c *typeConv) Init(ptrSize, intSize int64) { + c.ptrSize = ptrSize + c.intSize = intSize + c.m = make(map[dwarf.Type]*Type) + c.ptrs = make(map[dwarf.Type][]*Type) + 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.unsafePointer = c.Ident("unsafe.Pointer") + c.void = c.Ident("void") + c.string = c.Ident("string") + c.goVoid = c.Ident("_Ctype_void") +} + +// 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 +} + +// 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", + "short int": "short", + "long long int": "longlong", + "long long unsigned int": "ulonglong", + "signed char": "schar", + "float complex": "complexfloat", + "double complex": "complexdouble", +} + +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 returns true if 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 and also runs +// godefsFields on any new struct 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.ptrs) > 0 { + for dtype := range c.ptrs { + // Note Type might invalidate c.ptrs[dtype]. + t := c.Type(dtype, pos) + for _, ptr := range c.ptrs[dtype] { + ptr.Go.(*ast.StarExpr).X = t.Go + ptr.C.Set("%s*", t.C) + } + delete(c.ptrs, dtype) + } + } + + // Now that pointer types are completed, we can invoke godefsFields + // to rewrite struct definitions. + for _, fld := range c.todoFlds { + godefsFields(fld) + } + c.todoFlds = nil +} + +// 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 { + if t, ok := c.m[dtype]; ok { + if t.Go == nil { + fatalf("%s: type conversion loop at %s", lineno(pos), dtype) + } + return t + } + + // clang won't generate DW_AT_byte_size for pointer types, + // so we have to fix it here. + if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 { + dt.ByteSize = c.ptrSize + } + + 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[dtype] = 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 + } + sub := c.Type(dt.Type, pos) + t.Align = sub.Align + t.Go = &ast.ArrayType{ + Len: c.intExpr(dt.Count), + Elt: sub.Go, + } + 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; 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 + } + if t.Align = t.Size; t.Align >= c.ptrSize { + t.Align = c.ptrSize + } + + case *dwarf.PtrType: + t.Align = c.ptrSize + + // Translate void* as unsafe.Pointer + if _, ok := base(dt.Type).(*dwarf.VoidType); ok { + t.Go = c.unsafePointer + t.C.Set("void*") + break + } + + // Placeholder initialization; completed in FinishType. + t.Go = &ast.StarExpr{} + t.C.Set("<incomplete>*") + c.ptrs[dt.Type] = append(c.ptrs[dt.Type], t) + + case *dwarf.QualType: + // Ignore qualifier. + t = c.Type(dt.Type, pos) + c.m[dtype] = t + 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 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 + sub := c.Type(dt.Type, pos) + t.Go = name + t.Size = sub.Size + t.Align = sub.Align + oldType := typedef[name.Name] + if oldType == nil { + tt := *t + tt.Go = sub.Go + 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 and -cdefs mode, do this for all typedefs. + if isStructUnionClass(sub.Go) || *godefs || *cdefs { + 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 + } + 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.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: + s := dtype.Common().Name + if s != "" { + if ss, ok := dwarfToName[s]; ok { + s = ss + } + s = strings.Join(strings.Split(s, " "), "") // strip spaces + name := c.Ident("_Ctype_" + s) + tt := *t + typedef[name.Name] = &tt + if !*godefs && !*cdefs { + t.Go = name + } + } + } + + if t.Size <= 0 { + // Clang does not record the size of a pointer in its DWARF entry, + // so if dtype is an array, the call to dtype.Size at the top of the function + // computed the size as the array length * 0 = 0. + // The type switch called Type (this function) recursively on the pointer + // entry, and the code near the top of the function updated the size to + // be correct, so calling dtype.Size again will produce the correct value. + t.Size = dtype.Size() + 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") + } + return t + } + } + + 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(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 + } + + t = c.Type(ptr, pos) + if t == nil { + return nil + } + + // Remember the C spelling, in case the struct + // has __attribute__((unavailable)) on it. See issue 2888. + 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 := dtype.ReturnType.(*dwarf.VoidType); ok { + gr = []*ast.Field{{Type: c.goVoid}} + } else if dtype.ReturnType != nil { + r = c.Type(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, size int64) []*ast.Field { + n := len(fld) + fld = fld[0 : n+1] + fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)} + return fld +} + +// Struct conversion: return Go and (6g) C syntax for type. +func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { + var buf bytes.Buffer + buf.WriteString("struct {") + fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field + 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 && !*cdefs { + 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 { + if f.ByteOffset > off { + fld = c.pad(fld, f.ByteOffset-off) + off = f.ByteOffset + } + t := c.Type(f.Type, pos) + tgo := t.Go + size := t.Size + talign := t.Align + if f.BitSize > 0 { + if f.BitSize%8 != 0 { + 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 + } + n := len(fld) + fld = fld[0 : n+1] + name := f.Name + 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} + off += size + buf.WriteString(t.C.String()) + buf.WriteString(" ") + buf.WriteString(name) + buf.WriteString("; ") + if talign > align { + align = talign + } + } + if off < dt.ByteSize { + fld = c.pad(fld, dt.ByteSize-off) + off = dt.ByteSize + } + 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 || *cdefs { + c.todoFlds = append(c.todoFlds, fld) + } + expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} + return +} + +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++ + } + if !*cdefs { + n.Name = upper(n.Name) + } + } + p := &f.Type + t := *p + if star, ok := t.(*ast.StarExpr); ok { + star = &ast.StarExpr{X: star.X} + *p = star + p = &star.X + t = *p + } + if id, ok := t.(*ast.Ident); ok { + if id.Name == "unsafe.Pointer" { + *p = ast.NewIdent("*byte") + } + } + } +} + +// 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 { + if *cdefs { + return "" + } + 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 +} diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go new file mode 100644 index 0000000..ce5ac27 --- /dev/null +++ b/libgo/go/cmd/cgo/godefs.go @@ -0,0 +1,294 @@ +// Copyright 2011 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. + +package main + +import ( + "bytes" + "fmt" + "go/ast" + "go/printer" + "go/token" + "os" + "strings" +) + +// godefs returns the output for -godefs mode. +func (p *Package) godefs(f *File, srcfile string) string { + var buf bytes.Buffer + + fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n") + fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " ")) + fmt.Fprintf(&buf, "\n") + + override := make(map[string]string) + + // Allow source file to specify override mappings. + // For example, the socket data structures refer + // to in_addr and in_addr6 structs but we want to be + // able to treat them as byte arrays, so the godefs + // inputs in package syscall say + // + // // +godefs map struct_in_addr [4]byte + // // +godefs map struct_in_addr6 [16]byte + // + for _, g := range f.Comments { + for _, c := range g.List { + i := strings.Index(c.Text, "+godefs map") + if i < 0 { + continue + } + s := strings.TrimSpace(c.Text[i+len("+godefs map"):]) + i = strings.Index(s, " ") + if i < 0 { + fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text) + continue + } + override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:]) + } + } + for _, n := range f.Name { + if s := override[n.Go]; s != "" { + override[n.Mangle] = s + } + } + + // Otherwise, if the source file says type T C.whatever, + // use "T" as the mangling of C.whatever, + // except in the definition (handled at end of function). + refName := make(map[*ast.Expr]*Name) + for _, r := range f.Ref { + refName[r.Expr] = r.Name + } + for _, d := range f.AST.Decls { + d, ok := d.(*ast.GenDecl) + if !ok || d.Tok != token.TYPE { + continue + } + for _, s := range d.Specs { + s := s.(*ast.TypeSpec) + n := refName[&s.Type] + if n != nil && n.Mangle != "" { + override[n.Mangle] = s.Name.Name + } + } + } + + // Extend overrides using typedefs: + // If we know that C.xxx should format as T + // and xxx is a typedef for yyy, make C.yyy format as T. + for typ, def := range typedef { + if new := override[typ]; new != "" { + if id, ok := def.Go.(*ast.Ident); ok { + override[id.Name] = new + } + } + } + + // Apply overrides. + for old, new := range override { + if id := goIdent[old]; id != nil { + id.Name = new + } + } + + // Any names still using the _C syntax are not going to compile, + // although in general we don't know whether they all made it + // into the file, so we can't warn here. + // + // The most common case is union types, which begin with + // _Ctype_union and for which typedef[name] is a Go byte + // array of the appropriate size (such as [4]byte). + // Substitute those union types with byte arrays. + for name, id := range goIdent { + if id.Name == name && strings.Contains(name, "_Ctype_union") { + if def := typedef[name]; def != nil { + id.Name = gofmt(def) + } + } + } + + conf.Fprint(&buf, fset, f.AST) + + return buf.String() +} + +// cdefs returns the output for -cdefs mode. +// The easiest way to do this is to translate the godefs Go to C. +func (p *Package) cdefs(f *File, srcfile string) string { + godefsOutput := p.godefs(f, srcfile) + + lines := strings.Split(godefsOutput, "\n") + lines[0] = "// Created by cgo -cdefs - DO NOT EDIT" + + for i, line := range lines { + lines[i] = strings.TrimSpace(line) + } + + var out bytes.Buffer + printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) } + + didTypedef := false + for i := 0; i < len(lines); i++ { + line := lines[i] + + // Delete + // package x + if strings.HasPrefix(line, "package ") { + continue + } + + // Convert + // const ( + // A = 1 + // B = 2 + // ) + // + // to + // + // enum { + // A = 1, + // B = 2, + // }; + if line == "const (" { + printf("enum {\n") + for i++; i < len(lines) && lines[i] != ")"; i++ { + line = lines[i] + if line != "" { + printf("\t%s,", line) + } + printf("\n") + } + printf("};\n") + continue + } + + // Convert + // const A = 1 + // to + // enum { A = 1 }; + if strings.HasPrefix(line, "const ") { + printf("enum { %s };\n", line[len("const "):]) + continue + } + + // On first type definition, typedef all the structs + // in case there are dependencies between them. + if !didTypedef && strings.HasPrefix(line, "type ") { + didTypedef = true + for _, line := range lines { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") { + s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {") + printf("typedef struct %s %s;\n", s, s) + } + } + printf("\n") + printf("#pragma pack on\n") + printf("\n") + } + + // Convert + // type T struct { + // X int64 + // Y *int32 + // Z [4]byte + // } + // + // to + // + // struct T { + // int64 X; + // int32 *Y; + // byte Z[4]; + // } + if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") { + if len(lines) > i+1 && lines[i+1] == "}" { + // do not output empty struct + i++ + continue + } + s := line[len("type ") : len(line)-len(" struct {")] + printf("struct %s {\n", s) + for i++; i < len(lines) && lines[i] != "}"; i++ { + line := lines[i] + if line != "" { + f := strings.Fields(line) + if len(f) != 2 { + fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line) + nerrors++ + continue + } + printf("\t%s;", cdecl(f[0], f[1])) + } + printf("\n") + } + printf("};\n") + continue + } + + // Convert + // type T int + // to + // typedef int T; + if strings.HasPrefix(line, "type ") { + f := strings.Fields(line[len("type "):]) + if len(f) != 2 { + fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line) + nerrors++ + continue + } + printf("typedef\t%s;\n", cdecl(f[0], f[1])) + continue + } + + printf("%s\n", line) + } + + if didTypedef { + printf("\n") + printf("#pragma pack off\n") + } + + return out.String() +} + +// cdecl returns the C declaration for the given Go name and type. +// It only handles the specific cases necessary for converting godefs output. +func cdecl(name, typ string) string { + // X *[0]byte -> X *void + if strings.HasPrefix(typ, "*[0]") { + typ = "*void" + } + // X [4]byte -> X[4] byte + for strings.HasPrefix(typ, "[") { + i := strings.Index(typ, "]") + 1 + name = name + typ[:i] + typ = typ[i:] + } + // X *byte -> *X byte + for strings.HasPrefix(typ, "*") { + name = "*" + name + typ = typ[1:] + } + // X T -> T X + // Handle the special case: 'unsafe.Pointer' is 'void *' + if typ == "unsafe.Pointer" { + typ = "void" + name = "*" + name + } + return typ + "\t" + name +} + +var gofmtBuf bytes.Buffer + +// gofmt returns the gofmt-formatted string for an AST node. +func gofmt(n interface{}) string { + gofmtBuf.Reset() + err := printer.Fprint(&gofmtBuf, fset, n) + if err != nil { + return "<" + err.Error() + ">" + } + return gofmtBuf.String() +} diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go new file mode 100644 index 0000000..ea4b9c2 --- /dev/null +++ b/libgo/go/cmd/cgo/main.go @@ -0,0 +1,360 @@ +// 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. + +// Cgo; see gmp.go for an overview. + +// TODO(rsc): +// Emit correct line number annotations. +// Make 6g understand the annotations. + +package main + +import ( + "crypto/md5" + "flag" + "fmt" + "go/ast" + "go/printer" + "go/token" + "io" + "os" + "path/filepath" + "reflect" + "runtime" + "sort" + "strings" +) + +// A Package collects information about the package we're going to write. +type Package struct { + PackageName string // name of package + PackagePath string + PtrSize int64 + IntSize int64 + GccOptions []string + CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS) + Written map[string]bool + Name map[string]*Name // accumulated Name from Files + ExpFunc []*ExpFunc // accumulated ExpFunc from Files + Decl []ast.Decl + GoFiles []string // list of Go files + GccFiles []string // list of gcc output files + Preamble string // collected preamble for _cgo_export.h +} + +// A File collects information about a single Go input file. +type File struct { + AST *ast.File // parsed AST + Comments []*ast.CommentGroup // comments from file + Package string // Package name + Preamble string // C preamble (doc comment on import "C") + Ref []*Ref // all references to C.xxx in AST + ExpFunc []*ExpFunc // exported functions for this file + Name map[string]*Name // map from Go name to Name +} + +func nameKeys(m map[string]*Name) []string { + var ks []string + for k := range m { + ks = append(ks, k) + } + sort.Strings(ks) + return ks +} + +// A Ref refers to an expression of the form C.xxx in the AST. +type Ref struct { + Name *Name + Expr *ast.Expr + Context string // "type", "expr", "call", or "call2" +} + +func (r *Ref) Pos() token.Pos { + return (*r.Expr).Pos() +} + +// A Name collects information about C.xxx. +type Name struct { + Go string // name used in Go referring to package C + Mangle string // name used in generated Go + C string // name used in C + Define string // #define expansion + Kind string // "const", "type", "var", "fpvar", "func", "not-type" + Type *Type // the type of xxx + FuncType *FuncType + AddError bool + Const string // constant definition +} + +// IsVar returns true if Kind is either "var" or "fpvar" +func (n *Name) IsVar() bool { + return n.Kind == "var" || n.Kind == "fpvar" +} + +// A ExpFunc is an exported function, callable from C. +// Such functions are identified in the Go input file +// by doc comments containing the line //export ExpName +type ExpFunc struct { + Func *ast.FuncDecl + ExpName string // name to use from C +} + +// A TypeRepr contains the string representation of a type. +type TypeRepr struct { + Repr string + FormatArgs []interface{} +} + +// A Type collects information about a type in both the C and Go worlds. +type Type struct { + Size int64 + Align int64 + C *TypeRepr + Go ast.Expr + EnumValues map[string]int64 + Typedef string +} + +// A FuncType collects information about a function type in both the C and Go worlds. +type FuncType struct { + Params []*Type + Result *Type + Go *ast.FuncType +} + +func usage() { + fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n") + flag.PrintDefaults() + os.Exit(2) +} + +var ptrSizeMap = map[string]int64{ + "386": 4, + "amd64": 8, + "arm": 4, + "ppc64": 8, + "ppc64le": 8, + "s390x": 8, +} + +var intSizeMap = map[string]int64{ + "386": 4, + "amd64": 8, + "arm": 4, + "ppc64": 8, + "ppc64le": 8, + "s390x": 8, +} + +var cPrefix string + +var fset = token.NewFileSet() + +var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file") +var dynout = flag.String("dynout", "", "write -dynobj output to this file") +var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode") + +// These flags are for bootstrapping a new Go implementation, +// to generate Go and C headers that match the data layout and +// constant values used in the host's C libraries and system calls. +var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output") +var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output") +var objDir = flag.String("objdir", "", "object directory") + +var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo") +var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo") +var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo") +var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code") +var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code") +var goarch, goos string + +func main() { + flag.Usage = usage + flag.Parse() + + if *dynobj != "" { + // cgo -dynimport is essentially a separate helper command + // built into the cgo binary. It scans a gcc-produced executable + // and dumps information about the imported symbols and the + // imported libraries. The 'go build' rules for cgo prepare an + // appropriate executable and then use its import information + // instead of needing to make the linkers duplicate all the + // specialized knowledge gcc has about where to look for imported + // symbols and which ones to use. + dynimport(*dynobj) + return + } + + if *godefs && *cdefs { + fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n") + os.Exit(2) + } + + if *godefs || *cdefs { + // Generating definitions pulled from header files, + // to be checked into Go repositories. + // Line numbers are just noise. + conf.Mode &^= printer.SourcePos + } + + args := flag.Args() + if len(args) < 1 { + usage() + } + + // Find first arg that looks like a go file and assume everything before + // that are options to pass to gcc. + var i int + for i = len(args); i > 0; i-- { + if !strings.HasSuffix(args[i-1], ".go") { + break + } + } + if i == len(args) { + usage() + } + + goFiles := args[i:] + + p := newPackage(args[:i]) + + // Record CGO_LDFLAGS from the environment for external linking. + if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" { + args, err := splitQuoted(ldflags) + if err != nil { + fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err) + } + p.addToFlag("LDFLAGS", args) + } + + // Need a unique prefix for the global C symbols that + // we use to coordinate between gcc and ourselves. + // We already put _cgo_ at the beginning, so the main + // concern is other cgo wrappers for the same functions. + // Use the beginning of the md5 of the input to disambiguate. + h := md5.New() + for _, input := range goFiles { + f, err := os.Open(input) + if err != nil { + fatalf("%s", err) + } + io.Copy(h, f) + f.Close() + } + cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6]) + + fs := make([]*File, len(goFiles)) + for i, input := range goFiles { + f := new(File) + f.ReadGo(input) + f.DiscardCgoDirectives() + fs[i] = f + } + + if *objDir == "" { + // make sure that _obj directory exists, so that we can write + // all the output files there. + os.Mkdir("_obj", 0777) + *objDir = "_obj" + } + *objDir += string(filepath.Separator) + + for i, input := range goFiles { + f := fs[i] + p.Translate(f) + for _, cref := range f.Ref { + switch cref.Context { + case "call", "call2": + if cref.Name.Kind != "type" { + break + } + *cref.Expr = cref.Name.Type.Go + } + } + if nerrors > 0 { + os.Exit(2) + } + pkg := f.Package + if dir := os.Getenv("CGOPKGPATH"); dir != "" { + pkg = filepath.Join(dir, pkg) + } + p.PackagePath = pkg + p.Record(f) + if *godefs { + os.Stdout.WriteString(p.godefs(f, input)) + } else if *cdefs { + os.Stdout.WriteString(p.cdefs(f, input)) + } else { + p.writeOutput(f, input) + } + } + + if !*godefs && !*cdefs { + p.writeDefs() + } + if nerrors > 0 { + os.Exit(2) + } +} + +// newPackage returns a new Package that will invoke +// gcc with the additional arguments specified in args. +func newPackage(args []string) *Package { + goarch = runtime.GOARCH + if s := os.Getenv("GOARCH"); s != "" { + goarch = s + } + goos = runtime.GOOS + if s := os.Getenv("GOOS"); s != "" { + goos = s + } + ptrSize := ptrSizeMap[goarch] + if ptrSize == 0 { + fatalf("unknown ptrSize for $GOARCH %q", goarch) + } + intSize := intSizeMap[goarch] + if intSize == 0 { + fatalf("unknown intSize for $GOARCH %q", goarch) + } + + // Reset locale variables so gcc emits English errors [sic]. + os.Setenv("LANG", "en_US.UTF-8") + os.Setenv("LC_ALL", "C") + + p := &Package{ + PtrSize: ptrSize, + IntSize: intSize, + CgoFlags: make(map[string][]string), + Written: make(map[string]bool), + } + p.addToFlag("CFLAGS", args) + return p +} + +// Record what needs to be recorded about f. +func (p *Package) Record(f *File) { + if p.PackageName == "" { + p.PackageName = f.Package + } else if p.PackageName != f.Package { + error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package) + } + + if p.Name == nil { + p.Name = f.Name + } else { + for k, v := range f.Name { + if p.Name[k] == nil { + p.Name[k] = v + } else if !reflect.DeepEqual(p.Name[k], v) { + error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k)) + } + } + } + + if f.ExpFunc != nil { + p.ExpFunc = append(p.ExpFunc, f.ExpFunc...) + p.Preamble += "\n" + f.Preamble + } + p.Decl = append(p.Decl, f.AST.Decls...) +} diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go new file mode 100644 index 0000000..76c7247 --- /dev/null +++ b/libgo/go/cmd/cgo/out.go @@ -0,0 +1,1299 @@ +// 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. + +package main + +import ( + "bytes" + "debug/elf" + "debug/macho" + "debug/pe" + "fmt" + "go/ast" + "go/printer" + "go/token" + "os" + "sort" + "strings" +) + +var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8} + +// writeDefs creates output files to be compiled by 6g, 6c, and gcc. +// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) +func (p *Package) writeDefs() { + fgo2 := creat(*objDir + "_cgo_gotypes.go") + fc := creat(*objDir + "_cgo_defun.c") + fm := creat(*objDir + "_cgo_main.c") + + var gccgoInit bytes.Buffer + + fflg := creat(*objDir + "_cgo_flags") + for k, v := range p.CgoFlags { + fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " ")) + if k == "LDFLAGS" && !*gccgo { + for _, arg := range v { + fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg) + } + } + } + fflg.Close() + + // Write C main file for using gcc to resolve imports. + fmt.Fprintf(fm, "int main() { return 0; }\n") + if *importRuntimeCgo { + fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") + } else { + // If we're not importing runtime/cgo, we *are* runtime/cgo, + // which provides crosscall2. We just need a prototype. + fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n") + } + fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n") + fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n") + + // Write second Go output: definitions of _C_xxx. + // In a separate file so that the import of "unsafe" does not + // pollute the original file. + fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n") + fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName) + fmt.Fprintf(fgo2, "import \"unsafe\"\n\n") + if *importSyscall { + fmt.Fprintf(fgo2, "import \"syscall\"\n\n") + } + if !*gccgo && *importRuntimeCgo { + fmt.Fprintf(fgo2, "import _ \"runtime/cgo\"\n\n") + } + fmt.Fprintf(fgo2, "type _ unsafe.Pointer\n\n") + if *importSyscall { + fmt.Fprintf(fgo2, "func _Cerrno(dst *error, x int32) { *dst = syscall.Errno(x) }\n") + } + + typedefNames := make([]string, 0, len(typedef)) + for name := range typedef { + typedefNames = append(typedefNames, name) + } + sort.Strings(typedefNames) + for _, name := range typedefNames { + def := typedef[name] + fmt.Fprintf(fgo2, "type %s ", name) + conf.Fprint(fgo2, fset, def.Go) + fmt.Fprintf(fgo2, "\n\n") + } + if *gccgo { + fmt.Fprintf(fgo2, "type _Ctype_void byte\n") + } else { + fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n") + } + + if *gccgo { + fmt.Fprintf(fc, p.cPrologGccgo()) + } else { + fmt.Fprintf(fc, cProlog) + } + + gccgoSymbolPrefix := p.gccgoSymbolPrefix() + + cVars := make(map[string]bool) + for _, key := range nameKeys(p.Name) { + n := p.Name[key] + if !n.IsVar() { + continue + } + + if !cVars[n.C] { + fmt.Fprintf(fm, "extern char %s[];\n", n.C) + fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) + + if !*gccgo { + fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C) + } + + fmt.Fprintf(fc, "extern byte *%s;\n", n.C) + + cVars[n.C] = true + } + var amp string + var node ast.Node + if n.Kind == "var" { + amp = "&" + node = &ast.StarExpr{X: n.Type.Go} + } else if n.Kind == "fpvar" { + node = n.Type.Go + if *gccgo { + amp = "&" + } + } else { + panic(fmt.Errorf("invalid var kind %q", n.Kind)) + } + if *gccgo { + fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) + fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C) + } else { + fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C) + } + fmt.Fprintf(fc, "\n") + + fmt.Fprintf(fgo2, "var %s ", n.Mangle) + conf.Fprint(fgo2, fset, node) + fmt.Fprintf(fgo2, "\n") + } + fmt.Fprintf(fc, "\n") + + for _, key := range nameKeys(p.Name) { + n := p.Name[key] + if n.Const != "" { + fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const) + } + } + fmt.Fprintf(fgo2, "\n") + + for _, key := range nameKeys(p.Name) { + n := p.Name[key] + if n.FuncType != nil { + p.writeDefsFunc(fc, fgo2, n) + } + } + + if *gccgo { + p.writeGccgoExports(fgo2, fc, fm) + } else { + p.writeExports(fgo2, fc, fm) + } + + init := gccgoInit.String() + if init != "" { + fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor));") + fmt.Fprintln(fc, "static void init(void) {") + fmt.Fprint(fc, init) + fmt.Fprintln(fc, "}") + } + + fgo2.Close() + fc.Close() +} + +func dynimport(obj string) { + stdout := os.Stdout + if *dynout != "" { + f, err := os.Create(*dynout) + if err != nil { + fatalf("%s", err) + } + stdout = f + } + + if f, err := elf.Open(obj); err == nil { + if *dynlinker { + // Emit the cgo_dynamic_linker line. + if sec := f.Section(".interp"); sec != nil { + if data, err := sec.Data(); err == nil && len(data) > 1 { + // skip trailing \0 in data + fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1])) + } + } + } + sym, err := f.ImportedSymbols() + if err != nil { + fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) + } + for _, s := range sym { + targ := s.Name + if s.Version != "" { + targ += "#" + s.Version + } + fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) + } + lib, err := f.ImportedLibraries() + if err != nil { + fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) + } + for _, l := range lib { + fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l) + } + return + } + + if f, err := macho.Open(obj); err == nil { + sym, err := f.ImportedSymbols() + if err != nil { + fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err) + } + for _, s := range sym { + if len(s) > 0 && s[0] == '_' { + s = s[1:] + } + fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "") + } + lib, err := f.ImportedLibraries() + if err != nil { + fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) + } + for _, l := range lib { + fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l) + } + return + } + + if f, err := pe.Open(obj); err == nil { + sym, err := f.ImportedSymbols() + if err != nil { + fatalf("cannot load imported symbols from PE file %s: %v", obj, err) + } + for _, s := range sym { + ss := strings.Split(s, ":") + name := strings.Split(ss[0], "@")[0] + fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) + } + return + } + + fatalf("cannot parse %s as ELF, Mach-O or PE", obj) +} + +// Construct a gcc struct matching the 6c argument frame. +// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes. +// These assumptions are checked by the gccProlog. +// Also assumes that 6c convention is to word-align the +// input and output parameters. +func (p *Package) structType(n *Name) (string, int64) { + var buf bytes.Buffer + fmt.Fprint(&buf, "struct {\n") + off := int64(0) + for i, t := range n.FuncType.Params { + if off%t.Align != 0 { + pad := t.Align - off%t.Align + fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) + off += pad + } + c := t.Typedef + if c == "" { + c = t.C.String() + } + fmt.Fprintf(&buf, "\t\t%s p%d;\n", c, i) + off += t.Size + } + if off%p.PtrSize != 0 { + pad := p.PtrSize - off%p.PtrSize + fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) + off += pad + } + if t := n.FuncType.Result; t != nil { + if off%t.Align != 0 { + pad := t.Align - off%t.Align + fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) + off += pad + } + qual := "" + if c := t.C.String(); c[len(c)-1] == '*' { + qual = "const " + } + fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C) + off += t.Size + } + if off%p.PtrSize != 0 { + pad := p.PtrSize - off%p.PtrSize + fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad) + off += pad + } + if n.AddError { + fmt.Fprint(&buf, "\t\tint e[2*sizeof(void *)/sizeof(int)]; /* error */\n") + off += 2 * p.PtrSize + } + if off == 0 { + fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct + } + fmt.Fprintf(&buf, "\t}") + return buf.String(), off +} + +func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { + name := n.Go + gtype := n.FuncType.Go + void := gtype.Results == nil || len(gtype.Results.List) == 0 + if n.AddError { + // Add "error" to return type list. + // Type list is known to be 0 or 1 element - it's a C function. + err := &ast.Field{Type: ast.NewIdent("error")} + l := gtype.Results.List + if len(l) == 0 { + l = []*ast.Field{err} + } else { + l = []*ast.Field{l[0], err} + } + t := new(ast.FuncType) + *t = *gtype + t.Results = &ast.FieldList{List: l} + gtype = t + } + + // Go func declaration. + d := &ast.FuncDecl{ + Name: ast.NewIdent(n.Mangle), + Type: gtype, + } + + // Builtins defined in the C prolog. + inProlog := name == "CString" || name == "GoString" || name == "GoStringN" || name == "GoBytes" || name == "_CMalloc" + + if *gccgo { + // Gccgo style hooks. + fmt.Fprint(fgo2, "\n") + cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle) + paramnames := []string(nil) + for i, param := range d.Type.Params.List { + paramName := fmt.Sprintf("p%d", i) + param.Names = []*ast.Ident{ast.NewIdent(paramName)} + paramnames = append(paramnames, paramName) + } + + conf.Fprint(fgo2, fset, d) + fmt.Fprint(fgo2, " {\n") + if !inProlog { + fmt.Fprint(fgo2, "\tdefer syscall.CgocallDone()\n") + fmt.Fprint(fgo2, "\tsyscall.Cgocall()\n") + } + if n.AddError { + fmt.Fprint(fgo2, "\tsyscall.SetErrno(0)\n") + } + fmt.Fprint(fgo2, "\t") + if !void { + fmt.Fprint(fgo2, "r := ") + } + fmt.Fprintf(fgo2, "%s(%s)\n", cname, strings.Join(paramnames, ", ")) + + if n.AddError { + fmt.Fprint(fgo2, "\te := syscall.GetErrno()\n") + fmt.Fprint(fgo2, "\tif e != 0 {\n") + fmt.Fprint(fgo2, "\t\treturn ") + if !void { + fmt.Fprint(fgo2, "r, ") + } + fmt.Fprint(fgo2, "e\n") + fmt.Fprint(fgo2, "\t}\n") + fmt.Fprint(fgo2, "\treturn ") + if !void { + fmt.Fprint(fgo2, "r, ") + } + fmt.Fprint(fgo2, "nil\n") + } else if !void { + fmt.Fprint(fgo2, "\treturn r\n") + } + + fmt.Fprint(fgo2, "}\n") + + // declare the C function. + fmt.Fprintf(fgo2, "//extern _cgo%s%s\n", cPrefix, n.Mangle) + d.Name = ast.NewIdent(cname) + if n.AddError { + l := d.Type.Results.List + d.Type.Results.List = l[:len(l)-1] + } + conf.Fprint(fgo2, fset, d) + fmt.Fprint(fgo2, "\n") + + return + } + conf.Fprint(fgo2, fset, d) + fmt.Fprint(fgo2, "\n") + + if inProlog { + return + } + + var argSize int64 + _, argSize = p.structType(n) + + // C wrapper calls into gcc, passing a pointer to the argument frame. + fmt.Fprintf(fc, "#pragma cgo_import_static _cgo%s%s\n", cPrefix, n.Mangle) + fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle) + fmt.Fprintf(fc, "\n") + fmt.Fprintf(fc, "void\n") + if argSize == 0 { + argSize++ + } + // TODO(rsc): The struct here should declare pointers only where + // there are pointers in the actual argument frame. + // This is a workaround for golang.org/issue/6397. + fmt.Fprintf(fc, "·%s(struct{", n.Mangle) + if n := argSize / p.PtrSize; n > 0 { + fmt.Fprintf(fc, "void *y[%d];", n) + } + if n := argSize % p.PtrSize; n > 0 { + fmt.Fprintf(fc, "uint8 x[%d];", n) + } + fmt.Fprintf(fc, "}p)\n") + fmt.Fprintf(fc, "{\n") + fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle) + if n.AddError { + // gcc leaves errno in first word of interface at end of p. + // check whether it is zero; if so, turn interface into nil. + // if not, turn interface into errno. + // Go init function initializes ·_Cerrno with an os.Errno + // for us to copy. + fmt.Fprintln(fc, ` { + int32 e; + void **v; + v = (void**)(&p+1) - 2; /* v = final two void* of p */ + e = *(int32*)v; + v[0] = (void*)0xdeadbeef; + v[1] = (void*)0xdeadbeef; + if(e == 0) { + /* nil interface */ + v[0] = 0; + v[1] = 0; + } else { + ·_Cerrno(v, e); /* fill in v as error for errno e */ + } + }`) + } + fmt.Fprintf(fc, "}\n") + fmt.Fprintf(fc, "\n") +} + +// writeOutput creates stubs for a specific source file to be compiled by 6g +// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) +func (p *Package) writeOutput(f *File, srcfile string) { + base := srcfile + if strings.HasSuffix(base, ".go") { + base = base[0 : len(base)-3] + } + base = strings.Map(slashToUnderscore, base) + fgo1 := creat(*objDir + base + ".cgo1.go") + fgcc := creat(*objDir + base + ".cgo2.c") + + p.GoFiles = append(p.GoFiles, base+".cgo1.go") + p.GccFiles = append(p.GccFiles, base+".cgo2.c") + + // Write Go output: Go input with rewrites of C.xxx to _C_xxx. + fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") + conf.Fprint(fgo1, fset, f.AST) + + // While we process the vars and funcs, also write 6c and gcc output. + // Gcc output starts with the preamble. + fmt.Fprintf(fgcc, "%s\n", f.Preamble) + fmt.Fprintf(fgcc, "%s\n", gccProlog) + + for _, key := range nameKeys(f.Name) { + n := f.Name[key] + if n.FuncType != nil { + p.writeOutputFunc(fgcc, n) + } + } + + fgo1.Close() + fgcc.Close() +} + +// fixGo converts the internal Name.Go field into the name we should show +// to users in error messages. There's only one for now: on input we rewrite +// C.malloc into C._CMalloc, so change it back here. +func fixGo(name string) string { + if name == "_CMalloc" { + return "malloc" + } + return name +} + +var isBuiltin = map[string]bool{ + "_Cfunc_CString": true, + "_Cfunc_GoString": true, + "_Cfunc_GoStringN": true, + "_Cfunc_GoBytes": true, + "_Cfunc__CMalloc": true, +} + +func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { + name := n.Mangle + if isBuiltin[name] || p.Written[name] { + // The builtins are already defined in the C prolog, and we don't + // want to duplicate function definitions we've already done. + return + } + p.Written[name] = true + + if *gccgo { + p.writeGccgoOutputFunc(fgcc, n) + return + } + + ctype, _ := p.structType(n) + + // Gcc wrapper unpacks the C argument struct + // and calls the actual C function. + fmt.Fprintf(fgcc, "void\n") + fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle) + fmt.Fprintf(fgcc, "{\n") + if n.AddError { + fmt.Fprintf(fgcc, "\terrno = 0;\n") + } + // We're trying to write a gcc struct that matches 6c/8c/5c's layout. + // Use packed attribute to force no padding in this struct in case + // gcc has different packing requirements. + fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) + fmt.Fprintf(fgcc, "\t") + if t := n.FuncType.Result; t != nil { + fmt.Fprintf(fgcc, "a->r = ") + if c := t.C.String(); c[len(c)-1] == '*' { + fmt.Fprint(fgcc, "(__typeof__(a->r)) ") + } + } + fmt.Fprintf(fgcc, "%s(", n.C) + for i, t := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + // We know the type params are correct, because + // the Go equivalents had good type params. + // However, our version of the type omits the magic + // words const and volatile, which can provoke + // C compiler warnings. Silence them by casting + // all pointers to void*. (Eventually that will produce + // other warnings.) + if c := t.C.String(); c[len(c)-1] == '*' { + fmt.Fprintf(fgcc, "(void*)") + } + fmt.Fprintf(fgcc, "a->p%d", i) + } + fmt.Fprintf(fgcc, ");\n") + if n.AddError { + fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n") + } + fmt.Fprintf(fgcc, "}\n") + fmt.Fprintf(fgcc, "\n") +} + +// Write out a wrapper for a function when using gccgo. This is a +// simple wrapper that just calls the real function. We only need a +// wrapper to support static functions in the prologue--without a +// wrapper, we can't refer to the function, since the reference is in +// a different file. +func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { + if t := n.FuncType.Result; t != nil { + fmt.Fprintf(fgcc, "%s\n", t.C.String()) + } else { + fmt.Fprintf(fgcc, "void\n") + } + fmt.Fprintf(fgcc, "_cgo%s%s(", cPrefix, n.Mangle) + for i, t := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + c := t.Typedef + if c == "" { + c = t.C.String() + } + fmt.Fprintf(fgcc, "%s p%d", c, i) + } + fmt.Fprintf(fgcc, ")\n") + fmt.Fprintf(fgcc, "{\n") + fmt.Fprintf(fgcc, "\t") + if t := n.FuncType.Result; t != nil { + fmt.Fprintf(fgcc, "return ") + // Cast to void* to avoid warnings due to omitted qualifiers. + if c := t.C.String(); c[len(c)-1] == '*' { + fmt.Fprintf(fgcc, "(void*)") + } + } + fmt.Fprintf(fgcc, "%s(", n.C) + for i, t := range n.FuncType.Params { + if i > 0 { + fmt.Fprintf(fgcc, ", ") + } + // Cast to void* to avoid warnings due to omitted qualifiers. + if c := t.C.String(); c[len(c)-1] == '*' { + fmt.Fprintf(fgcc, "(void*)") + } + fmt.Fprintf(fgcc, "p%d", i) + } + fmt.Fprintf(fgcc, ");\n") + fmt.Fprintf(fgcc, "}\n") + fmt.Fprintf(fgcc, "\n") +} + +// packedAttribute returns host compiler struct attribute that will be +// used to match 6c/8c/5c's struct layout. For example, on 386 Windows, +// gcc wants to 8-align int64s, but 8c does not. +// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, +// and http://golang.org/issue/5603. +func (p *Package) packedAttribute() string { + s := "__attribute__((__packed__" + if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { + s += ", __gcc_struct__" + } + return s + "))" +} + +// Write out the various stubs we need to support functions exported +// from Go so that they are callable from C. +func (p *Package) writeExports(fgo2, fc, fm *os.File) { + fgcc := creat(*objDir + "_cgo_export.c") + fgcch := creat(*objDir + "_cgo_export.h") + + fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcch, "%s\n", p.Preamble) + fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) + + fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") + + fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n") + + for _, exp := range p.ExpFunc { + fn := exp.Func + + // Construct a gcc struct matching the 6c argument and + // result frame. The gcc struct will be compiled with + // __attribute__((packed)) so all padding must be accounted + // for explicitly. + ctype := "struct {\n" + off := int64(0) + npad := 0 + if fn.Recv != nil { + t := p.cgoType(fn.Recv.List[0].Type) + ctype += fmt.Sprintf("\t\t%s recv;\n", t.C) + off += t.Size + } + fntype := fn.Type + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + t := p.cgoType(atype) + if off%t.Align != 0 { + pad := t.Align - off%t.Align + ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) + off += pad + npad++ + } + ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i) + off += t.Size + }) + if off%p.PtrSize != 0 { + pad := p.PtrSize - off%p.PtrSize + ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) + off += pad + npad++ + } + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + t := p.cgoType(atype) + if off%t.Align != 0 { + pad := t.Align - off%t.Align + ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) + off += pad + npad++ + } + ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i) + off += t.Size + }) + if off%p.PtrSize != 0 { + pad := p.PtrSize - off%p.PtrSize + ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad) + off += pad + npad++ + } + if ctype == "struct {\n" { + ctype += "\t\tchar unused;\n" // avoid empty struct + } + ctype += "\t}" + + // Get the return type of the wrapper function + // compiled by gcc. + gccResult := "" + if fntype.Results == nil || len(fntype.Results.List) == 0 { + gccResult = "void" + } else if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { + gccResult = p.cgoType(fntype.Results.List[0].Type).C.String() + } else { + fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName) + fmt.Fprintf(fgcch, "struct %s_return {\n", exp.ExpName) + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + fmt.Fprintf(fgcch, "\t%s r%d;\n", p.cgoType(atype).C, i) + }) + fmt.Fprintf(fgcch, "};\n") + gccResult = "struct " + exp.ExpName + "_return" + } + + // Build the wrapper function compiled by gcc. + s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName) + if fn.Recv != nil { + s += p.cgoType(fn.Recv.List[0].Type).C.String() + s += " recv" + } + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + if i > 0 || fn.Recv != nil { + s += ", " + } + s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i) + }) + s += ")" + fmt.Fprintf(fgcch, "\nextern %s;\n", s) + + fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName) + fmt.Fprintf(fgcc, "\n%s\n", s) + fmt.Fprintf(fgcc, "{\n") + fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute()) + if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { + fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) + } + if fn.Recv != nil { + fmt.Fprintf(fgcc, "\ta.recv = recv;\n") + } + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i) + }) + fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, %d);\n", cPrefix, exp.ExpName, off) + if gccResult != "void" { + if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 { + fmt.Fprintf(fgcc, "\treturn a.r0;\n") + } else { + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + fmt.Fprintf(fgcc, "\tr.r%d = a.r%d;\n", i, i) + }) + fmt.Fprintf(fgcc, "\treturn r;\n") + } + } + fmt.Fprintf(fgcc, "}\n") + + // Build the wrapper function compiled by 6c/8c + goname := exp.Func.Name.Name + if fn.Recv != nil { + goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname + } + fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname) + fmt.Fprintf(fc, "extern void ·%s();\n\n", goname) + fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) + fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g + fmt.Fprintf(fc, "void\n") + fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName) + fmt.Fprintf(fc, "{\n") + fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname) + fmt.Fprintf(fc, "}\n") + + fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) + + // Calling a function with a receiver from C requires + // a Go wrapper function. + if fn.Recv != nil { + fmt.Fprintf(fgo2, "func %s(recv ", goname) + conf.Fprint(fgo2, fset, fn.Recv.List[0].Type) + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + fmt.Fprintf(fgo2, ", p%d ", i) + conf.Fprint(fgo2, fset, atype) + }) + fmt.Fprintf(fgo2, ")") + if gccResult != "void" { + fmt.Fprint(fgo2, " (") + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + if i > 0 { + fmt.Fprint(fgo2, ", ") + } + conf.Fprint(fgo2, fset, atype) + }) + fmt.Fprint(fgo2, ")") + } + fmt.Fprint(fgo2, " {\n") + fmt.Fprint(fgo2, "\t") + if gccResult != "void" { + fmt.Fprint(fgo2, "return ") + } + fmt.Fprintf(fgo2, "recv.%s(", exp.Func.Name) + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + if i > 0 { + fmt.Fprint(fgo2, ", ") + } + fmt.Fprintf(fgo2, "p%d", i) + }) + fmt.Fprint(fgo2, ")\n") + fmt.Fprint(fgo2, "}\n") + } + } +} + +// Write out the C header allowing C code to call exported gccgo functions. +func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { + fgcc := creat(*objDir + "_cgo_export.c") + fgcch := creat(*objDir + "_cgo_export.h") + + gccgoSymbolPrefix := p.gccgoSymbolPrefix() + + fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcch, "%s\n", p.Preamble) + fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) + + fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") + fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") + + fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n") + + for _, exp := range p.ExpFunc { + fn := exp.Func + fntype := fn.Type + + cdeclBuf := new(bytes.Buffer) + resultCount := 0 + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { resultCount++ }) + switch resultCount { + case 0: + fmt.Fprintf(cdeclBuf, "void") + case 1: + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + t := p.cgoType(atype) + fmt.Fprintf(cdeclBuf, "%s", t.C) + }) + default: + // Declare a result struct. + fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName) + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + t := p.cgoType(atype) + fmt.Fprintf(fgcch, "\t%s r%d;\n", t.C, i) + }) + fmt.Fprintf(fgcch, "};\n") + fmt.Fprintf(cdeclBuf, "struct %s_result", exp.ExpName) + } + + cRet := cdeclBuf.String() + + cdeclBuf = new(bytes.Buffer) + fmt.Fprintf(cdeclBuf, "(") + if fn.Recv != nil { + fmt.Fprintf(cdeclBuf, "%s recv", p.cgoType(fn.Recv.List[0].Type).C.String()) + } + // Function parameters. + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + if i > 0 || fn.Recv != nil { + fmt.Fprintf(cdeclBuf, ", ") + } + t := p.cgoType(atype) + fmt.Fprintf(cdeclBuf, "%s p%d", t.C, i) + }) + fmt.Fprintf(cdeclBuf, ")") + cParams := cdeclBuf.String() + + // We need to use a name that will be exported by the + // Go code; otherwise gccgo will make it static and we + // will not be able to link against it from the C + // code. + goName := "Cgoexp_" + exp.ExpName + fmt.Fprintf(fgcch, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) + fmt.Fprint(fgcch, "\n") + + // Use a #define so that the C code that includes + // cgo_export.h will be able to refer to the Go + // function using the expected name. + fmt.Fprintf(fgcch, "#define %s %s\n", exp.ExpName, goName) + + // Use a #undef in _cgo_export.c so that we ignore the + // #define from cgo_export.h, since here we are + // defining the real function. + fmt.Fprintf(fgcc, "#undef %s\n", exp.ExpName) + + fmt.Fprint(fgcc, "\n") + fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) + fmt.Fprint(fgcc, "\t") + if resultCount > 0 { + fmt.Fprint(fgcc, "return ") + } + fmt.Fprintf(fgcc, "%s(", goName) + if fn.Recv != nil { + fmt.Fprint(fgcc, "recv") + } + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + if i > 0 || fn.Recv != nil { + fmt.Fprintf(fgcc, ", ") + } + fmt.Fprintf(fgcc, "p%d", i) + }) + fmt.Fprint(fgcc, ");\n") + fmt.Fprint(fgcc, "}\n") + + // Dummy declaration for _cgo_main.c + fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams) + + // For gccgo we use a wrapper function in Go, in order + // to call CgocallBack and CgocallBackDone. + + // This code uses printer.Fprint, not conf.Fprint, + // because we don't want //line comments in the middle + // of the function types. + fmt.Fprint(fgo2, "\n") + fmt.Fprintf(fgo2, "func %s(", goName) + if fn.Recv != nil { + fmt.Fprint(fgo2, "recv ") + printer.Fprint(fgo2, fset, fn.Recv.List[0].Type) + } + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + if i > 0 || fn.Recv != nil { + fmt.Fprintf(fgo2, ", ") + } + fmt.Fprintf(fgo2, "p%d ", i) + printer.Fprint(fgo2, fset, atype) + }) + fmt.Fprintf(fgo2, ")") + if resultCount > 0 { + fmt.Fprintf(fgo2, " (") + forFieldList(fntype.Results, + func(i int, atype ast.Expr) { + if i > 0 { + fmt.Fprint(fgo2, ", ") + } + printer.Fprint(fgo2, fset, atype) + }) + fmt.Fprint(fgo2, ")") + } + fmt.Fprint(fgo2, " {\n") + fmt.Fprint(fgo2, "\tsyscall.CgocallBack()\n") + fmt.Fprint(fgo2, "\tdefer syscall.CgocallBackDone()\n") + fmt.Fprint(fgo2, "\t") + if resultCount > 0 { + fmt.Fprint(fgo2, "return ") + } + if fn.Recv != nil { + fmt.Fprint(fgo2, "recv.") + } + fmt.Fprintf(fgo2, "%s(", exp.Func.Name) + forFieldList(fntype.Params, + func(i int, atype ast.Expr) { + if i > 0 { + fmt.Fprint(fgo2, ", ") + } + fmt.Fprintf(fgo2, "p%d", i) + }) + fmt.Fprint(fgo2, ")\n") + fmt.Fprint(fgo2, "}\n") + } +} + +// Return the package prefix when using gccgo. +func (p *Package) gccgoSymbolPrefix() string { + if !*gccgo { + return "" + } + + clean := func(r rune) rune { + switch { + case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', + '0' <= r && r <= '9': + return r + } + return '_' + } + + if *gccgopkgpath != "" { + return strings.Map(clean, *gccgopkgpath) + } + if *gccgoprefix == "" && p.PackageName == "main" { + return "main" + } + prefix := strings.Map(clean, *gccgoprefix) + if prefix == "" { + prefix = "go" + } + return prefix + "." + p.PackageName +} + +// Call a function for each entry in an ast.FieldList, passing the +// index into the list and the type. +func forFieldList(fl *ast.FieldList, fn func(int, ast.Expr)) { + if fl == nil { + return + } + i := 0 + for _, r := range fl.List { + if r.Names == nil { + fn(i, r.Type) + i++ + } else { + for _ = range r.Names { + fn(i, r.Type) + i++ + } + } + } +} + +func c(repr string, args ...interface{}) *TypeRepr { + return &TypeRepr{repr, args} +} + +// Map predeclared Go types to Type. +var goTypes = map[string]*Type{ + "bool": {Size: 1, Align: 1, C: c("GoUint8")}, + "byte": {Size: 1, Align: 1, C: c("GoUint8")}, + "int": {Size: 0, Align: 0, C: c("GoInt")}, + "uint": {Size: 0, Align: 0, C: c("GoUint")}, + "rune": {Size: 4, Align: 4, C: c("GoInt32")}, + "int8": {Size: 1, Align: 1, C: c("GoInt8")}, + "uint8": {Size: 1, Align: 1, C: c("GoUint8")}, + "int16": {Size: 2, Align: 2, C: c("GoInt16")}, + "uint16": {Size: 2, Align: 2, C: c("GoUint16")}, + "int32": {Size: 4, Align: 4, C: c("GoInt32")}, + "uint32": {Size: 4, Align: 4, C: c("GoUint32")}, + "int64": {Size: 8, Align: 8, C: c("GoInt64")}, + "uint64": {Size: 8, Align: 8, C: c("GoUint64")}, + "float32": {Size: 4, Align: 4, C: c("GoFloat32")}, + "float64": {Size: 8, Align: 8, C: c("GoFloat64")}, + "complex64": {Size: 8, Align: 8, C: c("GoComplex64")}, + "complex128": {Size: 16, Align: 16, C: c("GoComplex128")}, +} + +// Map an ast type to a Type. +func (p *Package) cgoType(e ast.Expr) *Type { + switch t := e.(type) { + case *ast.StarExpr: + x := p.cgoType(t.X) + return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("%s*", x.C)} + case *ast.ArrayType: + if t.Len == nil { + // Slice: pointer, len, cap. + return &Type{Size: p.PtrSize * 3, Align: p.PtrSize, C: c("GoSlice")} + } + case *ast.StructType: + // TODO + case *ast.FuncType: + return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} + case *ast.InterfaceType: + return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} + case *ast.MapType: + return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoMap")} + case *ast.ChanType: + return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")} + case *ast.Ident: + // Look up the type in the top level declarations. + // TODO: Handle types defined within a 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.cgoType(ts.Type) + } + } + } + if def := typedef[t.Name]; def != nil { + return def + } + if t.Name == "uintptr" { + return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoUintptr")} + } + if t.Name == "string" { + // The string data is 1 pointer + 1 (pointer-sized) int. + return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoString")} + } + if t.Name == "error" { + return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")} + } + if r, ok := goTypes[t.Name]; ok { + if r.Size == 0 { // int or uint + rr := new(Type) + *rr = *r + rr.Size = p.IntSize + rr.Align = p.IntSize + r = rr + } + if r.Align > p.PtrSize { + r.Align = p.PtrSize + } + return r + } + error_(e.Pos(), "unrecognized Go type %s", t.Name) + return &Type{Size: 4, Align: 4, C: c("int")} + case *ast.SelectorExpr: + id, ok := t.X.(*ast.Ident) + if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" { + return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*")} + } + } + error_(e.Pos(), "Go type not supported in export: %s", gofmt(e)) + return &Type{Size: 4, Align: 4, C: c("int")} +} + +const gccProlog = ` +// Usual nonsense: if x and y are not equal, the type will be invalid +// (have a negative array count) and an inscrutable error will come +// out of the compiler and hopefully mention "name". +#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1]; + +// Check at compile time that the sizes we use match our expectations. +#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n) + +__cgo_size_assert(char, 1) +__cgo_size_assert(short, 2) +__cgo_size_assert(int, 4) +typedef long long __cgo_long_long; +__cgo_size_assert(__cgo_long_long, 8) +__cgo_size_assert(float, 4) +__cgo_size_assert(double, 8) + +#include <errno.h> +#include <string.h> +` + +const builtinProlog = ` +#include <sys/types.h> /* for size_t below */ + +/* Define intgo when compiling with GCC. */ +#ifdef __PTRDIFF_TYPE__ +typedef __PTRDIFF_TYPE__ intgo; +#elif defined(_LP64) +typedef long long intgo; +#else +typedef int intgo; +#endif + +typedef struct { char *p; intgo n; } _GoString_; +typedef struct { char *p; intgo n; intgo c; } _GoBytes_; +_GoString_ GoString(char *p); +_GoString_ GoStringN(char *p, int l); +_GoBytes_ GoBytes(void *p, int n); +char *CString(_GoString_); +void *_CMalloc(size_t); +` + +const cProlog = ` +#include "runtime.h" +#include "cgocall.h" + +void ·_Cerrno(void*, int32); + +void +·_Cfunc_GoString(int8 *p, String s) +{ + s = runtime·gostring((byte*)p); + FLUSH(&s); +} + +void +·_Cfunc_GoStringN(int8 *p, int32 l, String s) +{ + s = runtime·gostringn((byte*)p, l); + FLUSH(&s); +} + +void +·_Cfunc_GoBytes(int8 *p, int32 l, Slice s) +{ + s = runtime·gobytes((byte*)p, l); + FLUSH(&s); +} + +void +·_Cfunc_CString(String s, int8 *p) +{ + p = runtime·cmalloc(s.len+1); + runtime·memmove((byte*)p, s.str, s.len); + p[s.len] = 0; + FLUSH(&p); +} + +void +·_Cfunc__CMalloc(uintptr n, int8 *p) +{ + p = runtime·cmalloc(n); + FLUSH(&p); +} +` + +func (p *Package) cPrologGccgo() string { + return strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1) +} + +const cPrologGccgo = ` +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +typedef unsigned char byte; +typedef intptr_t intgo; + +struct __go_string { + const unsigned char *__data; + intgo __length; +}; + +typedef struct __go_open_array { + void* __values; + intgo __count; + intgo __capacity; +} Slice; + +struct __go_string __go_byte_array_to_string(const void* p, intgo len); +struct __go_open_array __go_string_to_byte_array (struct __go_string str); + +const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) { + char *p = malloc(s.__length+1); + memmove(p, s.__data, s.__length); + p[s.__length] = 0; + return p; +} + +struct __go_string _cgoPREFIX_Cfunc_GoString(char *p) { + intgo len = (p != NULL) ? strlen(p) : 0; + return __go_byte_array_to_string(p, len); +} + +struct __go_string _cgoPREFIX_Cfunc_GoStringN(char *p, int32_t n) { + return __go_byte_array_to_string(p, n); +} + +Slice _cgoPREFIX_Cfunc_GoBytes(char *p, int32_t n) { + struct __go_string s = { (const unsigned char *)p, n }; + return __go_string_to_byte_array(s); +} + +extern void runtime_throw(const char *); +void *_cgoPREFIX_Cfunc__CMalloc(size_t n) { + void *p = malloc(n); + if(p == NULL && n == 0) + p = malloc(1); + if(p == NULL) + runtime_throw("runtime: C malloc failed"); + return p; +} +` + +func (p *Package) gccExportHeaderProlog() string { + return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1) +} + +const gccExportHeaderProlog = ` +typedef signed char GoInt8; +typedef unsigned char GoUint8; +typedef short GoInt16; +typedef unsigned short GoUint16; +typedef int GoInt32; +typedef unsigned int GoUint32; +typedef long long GoInt64; +typedef unsigned long long GoUint64; +typedef GoIntGOINTBITS GoInt; +typedef GoUintGOINTBITS GoUint; +typedef __SIZE_TYPE__ GoUintptr; +typedef float GoFloat32; +typedef double GoFloat64; +typedef __complex float GoComplex64; +typedef __complex double GoComplex128; + +typedef struct { char *p; GoInt n; } GoString; +typedef void *GoMap; +typedef void *GoChan; +typedef struct { void *t; void *v; } GoInterface; +typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; +` diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go new file mode 100644 index 0000000..4e7800d --- /dev/null +++ b/libgo/go/cmd/cgo/util.go @@ -0,0 +1,84 @@ +// 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. + +package main + +import ( + "bytes" + "fmt" + "go/token" + "os" + "os/exec" +) + +// run runs the command argv, feeding in stdin on standard input. +// It returns the output to standard output and standard error. +// ok indicates whether the command exited successfully. +func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) { + p := exec.Command(argv[0], argv[1:]...) + p.Stdin = bytes.NewReader(stdin) + var bout, berr bytes.Buffer + p.Stdout = &bout + p.Stderr = &berr + err := p.Run() + if _, ok := err.(*exec.ExitError); err != nil && !ok { + fatalf("%s", err) + } + ok = p.ProcessState.Success() + stdout, stderr = bout.Bytes(), berr.Bytes() + return +} + +func lineno(pos token.Pos) string { + return fset.Position(pos).String() +} + +// Die with an error message. +func fatalf(msg string, args ...interface{}) { + // If we've already printed other errors, they might have + // caused the fatal condition. Assume they're enough. + if nerrors == 0 { + fmt.Fprintf(os.Stderr, msg+"\n", args...) + } + os.Exit(2) +} + +var nerrors int + +func error_(pos token.Pos, msg string, args ...interface{}) { + nerrors++ + if pos.IsValid() { + fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String()) + } + fmt.Fprintf(os.Stderr, msg, args...) + fmt.Fprintf(os.Stderr, "\n") +} + +// isName returns true if s is a valid C identifier +func isName(s string) bool { + for i, v := range s { + if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') { + return false + } + if i == 0 && '0' <= v && v <= '9' { + return false + } + } + return s != "" +} + +func creat(name string) *os.File { + f, err := os.Create(name) + if err != nil { + fatalf("%s", err) + } + return f +} + +func slashToUnderscore(c rune) rune { + if c == '/' || c == '\\' || c == ':' { + c = '_' + } + return c +} |