summaryrefslogtreecommitdiffstats
path: root/src/cmd/cgo
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/cmd/cgo
parentInitial commit. (diff)
downloadgolang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.tar.xz
golang-1.20-43a123c1ae6613b3efeed291fa552ecd909d3acf.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/cmd/cgo/ast.go549
-rw-r--r--src/cmd/cgo/ast_go1.go25
-rw-r--r--src/cmd/cgo/ast_go118.go32
-rw-r--r--src/cmd/cgo/doc.go1043
-rw-r--r--src/cmd/cgo/gcc.go3421
-rw-r--r--src/cmd/cgo/godefs.go170
-rw-r--r--src/cmd/cgo/main.go501
-rw-r--r--src/cmd/cgo/out.go1988
-rw-r--r--src/cmd/cgo/util.go114
9 files changed, 7843 insertions, 0 deletions
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
new file mode 100644
index 0000000..ba3c7da
--- /dev/null
+++ b/src/cmd/cgo/ast.go
@@ -0,0 +1,549 @@
+// 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"
+ "strings"
+)
+
+func parse(name string, src []byte, flags parser.Mode) *ast.File {
+ ast1, err := parser.ParseFile(fset, name, src, 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
+}
+
+// ParseGo populates f with information learned from the Go source code
+// which was read from the named file. 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) ParseGo(abspath string, src []byte) {
+ // 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.
+ // In cgo mode, we ignore ast2 and just apply edits directly
+ // the text behind ast1. In godefs mode we modify and print ast2.
+ ast1 := parse(abspath, src, parser.SkipObjectResolution|parser.ParseComments)
+ ast2 := parse(abspath, src, parser.SkipObjectResolution)
+
+ f.Package = ast1.Name.Name
+ f.Name = make(map[string]*Name)
+ f.NamePos = make(map[*Name]token.Pos)
+
+ // 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 || 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 {
+ if strings.ContainsAny(abspath, "\r\n") {
+ // This should have been checked when the file path was first resolved,
+ // but we double check here just to be sure.
+ fatalf("internal error: ParseGo: abspath contains unexpected newline character: %q", abspath)
+ }
+ f.Preamble += fmt.Sprintf("#line %d %q\n", sourceLine(cg), abspath)
+ f.Preamble += commentText(cg) + "\n"
+ f.Preamble += "#line 1 \"cgo-generated-wrapper\"\n"
+ }
+ }
+ }
+ if !sawC {
+ error_(ast1.Package, `cannot find import "C"`)
+ }
+
+ // In ast2, strip the import "C" line.
+ if *godefs {
+ 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 || 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]
+ } else {
+ for _, decl := range ast2.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ continue
+ }
+ for _, spec := range d.Specs {
+ if s, ok := spec.(*ast.ImportSpec); ok && s.Path.Value == `"C"` {
+ // Replace "C" with _ "unsafe", to keep program valid.
+ // (Deleting import statement or clause is not safe if it is followed
+ // in the source by an explicit semicolon.)
+ f.Edit.Replace(f.offset(s.Path.Pos()), f.offset(s.Path.End()), `_ "unsafe"`)
+ }
+ }
+ }
+ }
+
+ // Accumulate pointers to uses of C.x.
+ if f.Ref == nil {
+ f.Ref = make([]*Ref, 0, 8)
+ }
+ f.walk(ast2, ctxProg, (*File).validateIdents)
+ f.walk(ast2, ctxProg, (*File).saveExprs)
+
+ // 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, ctxProg, (*File).saveExport)
+ f.walk(ast2, ctxProg, (*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 {
+ var pieces []string
+ for _, com := range g.List {
+ c := 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, "")
+}
+
+func (f *File) validateIdents(x interface{}, context astContext) {
+ if x, ok := x.(*ast.Ident); ok {
+ if f.isMangledName(x.Name) {
+ error_(x.Pos(), "identifier %q may conflict with identifiers generated by cgo", x.Name)
+ }
+ }
+}
+
+// Save various references we are going to need later.
+func (f *File) saveExprs(x interface{}, context astContext) {
+ switch x := x.(type) {
+ case *ast.Expr:
+ switch (*x).(type) {
+ case *ast.SelectorExpr:
+ f.saveRef(x, context)
+ }
+ case *ast.CallExpr:
+ f.saveCall(x, context)
+ }
+}
+
+// Save references to C.xxx for later processing.
+func (f *File) saveRef(n *ast.Expr, context astContext) {
+ sel := (*n).(*ast.SelectorExpr)
+ // 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" {
+ return
+ }
+ if context == ctxAssign2 {
+ context = ctxExpr
+ }
+ if context == ctxEmbedType {
+ 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.NamePos[name] = sel.Pos()
+ }
+ f.Ref = append(f.Ref, &Ref{
+ Name: name,
+ Expr: n,
+ Context: context,
+ })
+}
+
+// Save calls to C.xxx for later processing.
+func (f *File) saveCall(call *ast.CallExpr, context astContext) {
+ sel, ok := call.Fun.(*ast.SelectorExpr)
+ if !ok {
+ return
+ }
+ if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
+ return
+ }
+ c := &Call{Call: call, Deferred: context == ctxDefer}
+ f.Calls = append(f.Calls, c)
+}
+
+// If a function should be exported add it to ExpFunc.
+func (f *File) saveExport(x interface{}, context astContext) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ if n.Doc == nil {
+ return
+ }
+ for _, c := range n.Doc.List {
+ if !strings.HasPrefix(c.Text, "//export ") {
+ continue
+ }
+
+ name := strings.TrimSpace(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)
+ }
+
+ doc := ""
+ for _, c1 := range n.Doc.List {
+ if c1 != c {
+ doc += c1.Text + "\n"
+ }
+ }
+
+ f.ExpFunc = append(f.ExpFunc, &ExpFunc{
+ Func: n,
+ ExpName: name,
+ Doc: doc,
+ })
+ break
+ }
+}
+
+// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
+func (f *File) saveExport2(x interface{}, context astContext) {
+ 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
+ }
+ }
+}
+
+type astContext int
+
+const (
+ ctxProg astContext = iota
+ ctxEmbedType
+ ctxType
+ ctxStmt
+ ctxExpr
+ ctxField
+ ctxParam
+ ctxAssign2 // assignment of a single expression to two variables
+ ctxSwitch
+ ctxTypeSwitch
+ ctxFile
+ ctxDecl
+ ctxSpec
+ ctxDefer
+ ctxCall // any function call other than ctxCall2
+ ctxCall2 // function call whose result is assigned to two variables
+ ctxSelector
+)
+
+// walk walks the AST x, calling visit(f, x, context) for each node.
+func (f *File) walk(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
+ visit(f, x, context)
+ switch n := x.(type) {
+ case *ast.Expr:
+ f.walk(*n, context, visit)
+
+ // everything else just recurs
+ default:
+ f.walkUnexpected(x, context, visit)
+
+ case nil:
+
+ // These are ordered and grouped to match ../../go/ast/ast.go
+ case *ast.Field:
+ if len(n.Names) == 0 && context == ctxField {
+ f.walk(&n.Type, ctxEmbedType, visit)
+ } else {
+ f.walk(&n.Type, ctxType, visit)
+ }
+ case *ast.FieldList:
+ for _, field := range n.List {
+ f.walk(field, context, visit)
+ }
+ case *ast.BadExpr:
+ case *ast.Ident:
+ case *ast.Ellipsis:
+ f.walk(&n.Elt, ctxType, visit)
+ case *ast.BasicLit:
+ case *ast.FuncLit:
+ f.walk(n.Type, ctxType, visit)
+ f.walk(n.Body, ctxStmt, visit)
+ case *ast.CompositeLit:
+ f.walk(&n.Type, ctxType, visit)
+ f.walk(n.Elts, ctxExpr, visit)
+ case *ast.ParenExpr:
+ f.walk(&n.X, context, visit)
+ case *ast.SelectorExpr:
+ f.walk(&n.X, ctxSelector, visit)
+ case *ast.IndexExpr:
+ f.walk(&n.X, ctxExpr, visit)
+ f.walk(&n.Index, ctxExpr, visit)
+ case *ast.SliceExpr:
+ f.walk(&n.X, ctxExpr, visit)
+ if n.Low != nil {
+ f.walk(&n.Low, ctxExpr, visit)
+ }
+ if n.High != nil {
+ f.walk(&n.High, ctxExpr, visit)
+ }
+ if n.Max != nil {
+ f.walk(&n.Max, ctxExpr, visit)
+ }
+ case *ast.TypeAssertExpr:
+ f.walk(&n.X, ctxExpr, visit)
+ f.walk(&n.Type, ctxType, visit)
+ case *ast.CallExpr:
+ if context == ctxAssign2 {
+ f.walk(&n.Fun, ctxCall2, visit)
+ } else {
+ f.walk(&n.Fun, ctxCall, visit)
+ }
+ f.walk(n.Args, ctxExpr, visit)
+ case *ast.StarExpr:
+ f.walk(&n.X, context, visit)
+ case *ast.UnaryExpr:
+ f.walk(&n.X, ctxExpr, visit)
+ case *ast.BinaryExpr:
+ f.walk(&n.X, ctxExpr, visit)
+ f.walk(&n.Y, ctxExpr, visit)
+ case *ast.KeyValueExpr:
+ f.walk(&n.Key, ctxExpr, visit)
+ f.walk(&n.Value, ctxExpr, visit)
+
+ case *ast.ArrayType:
+ f.walk(&n.Len, ctxExpr, visit)
+ f.walk(&n.Elt, ctxType, visit)
+ case *ast.StructType:
+ f.walk(n.Fields, ctxField, visit)
+ case *ast.FuncType:
+ if tparams := funcTypeTypeParams(n); tparams != nil {
+ f.walk(tparams, ctxParam, visit)
+ }
+ f.walk(n.Params, ctxParam, visit)
+ if n.Results != nil {
+ f.walk(n.Results, ctxParam, visit)
+ }
+ case *ast.InterfaceType:
+ f.walk(n.Methods, ctxField, visit)
+ case *ast.MapType:
+ f.walk(&n.Key, ctxType, visit)
+ f.walk(&n.Value, ctxType, visit)
+ case *ast.ChanType:
+ f.walk(&n.Value, ctxType, visit)
+
+ case *ast.BadStmt:
+ case *ast.DeclStmt:
+ f.walk(n.Decl, ctxDecl, visit)
+ case *ast.EmptyStmt:
+ case *ast.LabeledStmt:
+ f.walk(n.Stmt, ctxStmt, visit)
+ case *ast.ExprStmt:
+ f.walk(&n.X, ctxExpr, visit)
+ case *ast.SendStmt:
+ f.walk(&n.Chan, ctxExpr, visit)
+ f.walk(&n.Value, ctxExpr, visit)
+ case *ast.IncDecStmt:
+ f.walk(&n.X, ctxExpr, visit)
+ case *ast.AssignStmt:
+ f.walk(n.Lhs, ctxExpr, visit)
+ if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
+ f.walk(n.Rhs, ctxAssign2, visit)
+ } else {
+ f.walk(n.Rhs, ctxExpr, visit)
+ }
+ case *ast.GoStmt:
+ f.walk(n.Call, ctxExpr, visit)
+ case *ast.DeferStmt:
+ f.walk(n.Call, ctxDefer, visit)
+ case *ast.ReturnStmt:
+ f.walk(n.Results, ctxExpr, visit)
+ case *ast.BranchStmt:
+ case *ast.BlockStmt:
+ f.walk(n.List, context, visit)
+ case *ast.IfStmt:
+ f.walk(n.Init, ctxStmt, visit)
+ f.walk(&n.Cond, ctxExpr, visit)
+ f.walk(n.Body, ctxStmt, visit)
+ f.walk(n.Else, ctxStmt, visit)
+ case *ast.CaseClause:
+ if context == ctxTypeSwitch {
+ context = ctxType
+ } else {
+ context = ctxExpr
+ }
+ f.walk(n.List, context, visit)
+ f.walk(n.Body, ctxStmt, visit)
+ case *ast.SwitchStmt:
+ f.walk(n.Init, ctxStmt, visit)
+ f.walk(&n.Tag, ctxExpr, visit)
+ f.walk(n.Body, ctxSwitch, visit)
+ case *ast.TypeSwitchStmt:
+ f.walk(n.Init, ctxStmt, visit)
+ f.walk(n.Assign, ctxStmt, visit)
+ f.walk(n.Body, ctxTypeSwitch, visit)
+ case *ast.CommClause:
+ f.walk(n.Comm, ctxStmt, visit)
+ f.walk(n.Body, ctxStmt, visit)
+ case *ast.SelectStmt:
+ f.walk(n.Body, ctxStmt, visit)
+ case *ast.ForStmt:
+ f.walk(n.Init, ctxStmt, visit)
+ f.walk(&n.Cond, ctxExpr, visit)
+ f.walk(n.Post, ctxStmt, visit)
+ f.walk(n.Body, ctxStmt, visit)
+ case *ast.RangeStmt:
+ f.walk(&n.Key, ctxExpr, visit)
+ f.walk(&n.Value, ctxExpr, visit)
+ f.walk(&n.X, ctxExpr, visit)
+ f.walk(n.Body, ctxStmt, visit)
+
+ case *ast.ImportSpec:
+ case *ast.ValueSpec:
+ f.walk(&n.Type, ctxType, visit)
+ if len(n.Names) == 2 && len(n.Values) == 1 {
+ f.walk(&n.Values[0], ctxAssign2, visit)
+ } else {
+ f.walk(n.Values, ctxExpr, visit)
+ }
+ case *ast.TypeSpec:
+ if tparams := typeSpecTypeParams(n); tparams != nil {
+ f.walk(tparams, ctxParam, visit)
+ }
+ f.walk(&n.Type, ctxType, visit)
+
+ case *ast.BadDecl:
+ case *ast.GenDecl:
+ f.walk(n.Specs, ctxSpec, visit)
+ case *ast.FuncDecl:
+ if n.Recv != nil {
+ f.walk(n.Recv, ctxParam, visit)
+ }
+ f.walk(n.Type, ctxType, visit)
+ if n.Body != nil {
+ f.walk(n.Body, ctxStmt, visit)
+ }
+
+ case *ast.File:
+ f.walk(n.Decls, ctxDecl, visit)
+
+ case *ast.Package:
+ for _, file := range n.Files {
+ f.walk(file, ctxFile, 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/src/cmd/cgo/ast_go1.go b/src/cmd/cgo/ast_go1.go
new file mode 100644
index 0000000..2f65f0f
--- /dev/null
+++ b/src/cmd/cgo/ast_go1.go
@@ -0,0 +1,25 @@
+// Copyright 2021 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.
+
+//go:build compiler_bootstrap
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
+ error_(token.NoPos, "unexpected type %T in walk", x)
+ panic("unexpected type")
+}
+
+func funcTypeTypeParams(n *ast.FuncType) *ast.FieldList {
+ return nil
+}
+
+func typeSpecTypeParams(n *ast.TypeSpec) *ast.FieldList {
+ return nil
+}
diff --git a/src/cmd/cgo/ast_go118.go b/src/cmd/cgo/ast_go118.go
new file mode 100644
index 0000000..ced3072
--- /dev/null
+++ b/src/cmd/cgo/ast_go118.go
@@ -0,0 +1,32 @@
+// Copyright 2021 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.
+
+//go:build !compiler_bootstrap
+
+package main
+
+import (
+ "go/ast"
+ "go/token"
+)
+
+func (f *File) walkUnexpected(x interface{}, context astContext, visit func(*File, interface{}, astContext)) {
+ switch n := x.(type) {
+ default:
+ error_(token.NoPos, "unexpected type %T in walk", x)
+ panic("unexpected type")
+
+ case *ast.IndexListExpr:
+ f.walk(&n.X, ctxExpr, visit)
+ f.walk(n.Indices, ctxExpr, visit)
+ }
+}
+
+func funcTypeTypeParams(n *ast.FuncType) *ast.FieldList {
+ return n.TypeParams
+}
+
+func typeSpecTypeParams(n *ast.TypeSpec) *ast.FieldList {
+ return n.TypeParams
+}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
new file mode 100644
index 0000000..70685c7
--- /dev/null
+++ b/src/cmd/cgo/doc.go
@@ -0,0 +1,1043 @@
+// 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"
+
+The preamble may contain any C code, including function and variable
+declarations and definitions. These may then be referred to from Go
+code as though they were defined in the package "C". All names
+declared in the preamble may be used, even if they start with a
+lower-case letter. Exception: static variables in the preamble may
+not be referenced from Go code; static functions are permitted.
+
+See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See
+"C? Go? Cgo!" for an introduction to using cgo:
+https://golang.org/doc/articles/c_go_cgo.html.
+
+CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS and LDFLAGS may be defined with pseudo
+#cgo directives within these comments to tweak the behavior of the C, C++
+or Fortran 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 https://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"
+
+The default pkg-config tool may be changed by setting the PKG_CONFIG environment variable.
+
+For security reasons, only a limited set of flags are allowed, notably -D, -U, -I, and -l.
+To allow additional flags, set CGO_CFLAGS_ALLOW to a regular expression
+matching the new flags. To disallow flags that would otherwise be allowed,
+set CGO_CFLAGS_DISALLOW to a regular expression matching arguments
+that must be disallowed. In both cases the regular expression must match
+a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
+not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
+the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
+
+Also for security reasons, only a limited set of characters are
+permitted, notably alphanumeric characters and a few symbols, such as
+'.', that will not be interpreted in unexpected ways. Attempts to use
+forbidden characters will get a "malformed #cgo argument" error.
+
+When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS 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. Flags obtained from environment variables
+are not subject to the security limitations described above.
+
+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 CPPFLAGS and FFLAGS directives in a package are concatenated
+and used to compile Fortran 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 cgo directives are parsed, any occurrence of the string ${SRCDIR}
+will be replaced by the absolute path to the directory containing the source
+file. This allows pre-compiled static libraries to be included in the package
+directory and linked properly.
+For example if package foo is in the directory /go/src/foo:
+
+ // #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo
+
+Will be expanded to:
+
+ // #cgo LDFLAGS: -L/go/src/foo/libs -lfoo
+
+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, .S or .sx files will be
+compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
+compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be
+compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
+not be compiled separately, but, if these header files are changed,
+the package (including its non-Go source files) will be recompiled.
+Note that changes to files in other directories do not cause the package
+to be recompiled, so all non-Go source code for the package should be
+stored in the package directory, not in subdirectories.
+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.
+
+The cgo tool will always invoke the C compiler with the source file's
+directory in the include path; i.e. -I${SRCDIR} is always implied. This
+means that if a header file foo/bar.h exists both in the source
+directory and also in the system include directory (or some other place
+specified by a -I flag), then "#include <foo/bar.h>" will always find the
+local version in preference to any other version.
+
+The cgo tool is enabled by default for native builds on systems where
+it is expected to work. It is disabled by default when cross-compiling
+as well as when the CC environment variable is unset and the default
+C compiler (typically gcc or clang) cannot be found on the system PATH.
+You can override the default by setting the CGO_ENABLED
+environment variable when running the go tool: set it to 1 to enable
+the use of cgo, and to 0 to disable it. The go tool will set the
+build constraint "cgo" if cgo is enabled. The special import "C"
+implies the "cgo" build constraint, as though the file also said
+"//go:build cgo". Therefore, if cgo is disabled, files that import
+"C" will not be built by the go tool. (For more about build constraints
+see https://golang.org/pkg/go/build/#hdr-Build_Constraints).
+
+When cross-compiling, you must specify a C cross-compiler for cgo to
+use. You can do this by setting the generic CC_FOR_TARGET or the
+more specific CC_FOR_${GOOS}_${GOARCH} (for example, CC_FOR_linux_arm)
+environment variable when building the toolchain using make.bash,
+or you can set the CC environment variable any time you run the go tool.
+
+The CXX_FOR_TARGET, CXX_FOR_${GOOS}_${GOARCH}, and CXX
+environment variables work 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,
+C.complexfloat (complex float), and C.complexdouble (complex double).
+The C type void* is represented by Go's unsafe.Pointer.
+The C types __int128_t and __uint128_t are represented by [16]byte.
+
+A few special C types which would normally be represented by a pointer
+type in Go are instead represented by a uintptr. See the Special
+cases section below.
+
+To access a struct, union, or enum type directly, prefix it with
+struct_, union_, or enum_, as in C.struct_stat.
+
+The size of any C type T is available as C.sizeof_T, as in
+C.sizeof_struct_stat.
+
+A C function may be declared in the Go file with a parameter type of
+the special name _GoString_. This function may be called with an
+ordinary Go string value. The string length, and a pointer to the
+string contents, may be accessed by calling the C functions
+
+ size_t _GoStringLen(_GoString_ s);
+ const char *_GoStringPtr(_GoString_ s);
+
+These functions are only available in the preamble, not in other C
+files. The C code must not modify the contents of the pointer returned
+by _GoStringPtr. Note that the string contents may not have a trailing
+NUL byte.
+
+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.
+
+Go code cannot refer to zero-sized fields that occur at the end of
+non-empty C structs. To get the address of such a field (which is the
+only operation you can do with a zero-sized field) you must take the
+address of the struct and add the size of the struct.
+
+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()
+ var n, err = C.sqrt(1)
+
+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(&C.x[0]).
+
+Calling variadic C functions is not supported. It is possible to
+circumvent this by using a C function wrapper. For example:
+
+ package main
+
+ // #include <stdio.h>
+ // #include <stdlib.h>
+ //
+ // static void myprint(char* s) {
+ // printf("%s\n", s);
+ // }
+ import "C"
+ import "unsafe"
+
+ func main() {
+ cs := C.CString("Hello from stdio")
+ C.myprint(cs)
+ C.free(unsafe.Pointer(cs))
+ }
+
+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
+
+ // Go []byte slice to C array
+ // The C array 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.CBytes([]byte) unsafe.Pointer
+
+ // C string to Go string
+ func C.GoString(*C.char) string
+
+ // C data with explicit length to Go string
+ func C.GoStringN(*C.char, C.int) string
+
+ // C data with explicit length to Go []byte
+ func C.GoBytes(unsafe.Pointer, C.int) []byte
+
+As a special case, C.malloc does not call the C library malloc directly
+but instead calls a Go helper function that wraps the C library malloc
+but guarantees never to return nil. If C's malloc indicates out of memory,
+the helper function crashes the program, like when Go itself runs out
+of memory. Because C.malloc cannot fail, it has no two-result form
+that returns errno.
+
+# 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 GoInt64 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.
+Go struct types are not supported; use a C struct type.
+Go array types are not supported; use a C pointer.
+
+Go functions that take arguments of type string may be called with the
+C type _GoString_, described above. The _GoString_ type will be
+automatically defined in the preamble. Note that there is no way for C
+code to create a value of this type; this is only useful for passing
+string values from Go to C and back to Go.
+
+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. If a file contains both
+definitions and declarations, then the two output files will produce
+duplicate symbols and the linker will fail. To avoid this, definitions
+must be placed in preambles in other files, or in C source files.
+
+# Passing pointers
+
+Go is a garbage collected language, and the garbage collector needs to
+know the location of every pointer to Go memory. Because of this,
+there are restrictions on passing pointers between Go and C.
+
+In this section the term Go pointer means a pointer to memory
+allocated by Go (such as by using the & operator or calling the
+predefined new function) and the term C pointer means a pointer to
+memory allocated by C (such as by a call to C.malloc). Whether a
+pointer is a Go pointer or a C pointer is a dynamic property
+determined by how the memory was allocated; it has nothing to do with
+the type of the pointer.
+
+Note that values of some Go types, other than the type's zero value,
+always include Go pointers. This is true of string, slice, interface,
+channel, map, and function types. A pointer type may hold a Go pointer
+or a C pointer. Array and struct types may or may not include Go
+pointers, depending on the element types. All the discussion below
+about Go pointers applies not just to pointer types, but also to other
+types that include Go pointers.
+
+Go code may pass a Go pointer to C provided the Go memory to which it
+points does not contain any Go pointers. The C code must preserve
+this property: it must not store any Go pointers in Go memory, even
+temporarily. When passing a pointer to a field in a struct, the Go
+memory in question is the memory occupied by the field, not the entire
+struct. When passing a pointer to an element in an array or slice,
+the Go memory in question is the entire array or the entire backing
+array of the slice.
+
+C code may not keep a copy of a Go pointer after the call returns.
+This includes the _GoString_ type, which, as noted above, includes a
+Go pointer; _GoString_ values may not be retained by C code.
+
+A Go function called by C code may not return a Go pointer (which
+implies that it may not return a string, slice, channel, and so
+forth). A Go function called by C code may take C pointers as
+arguments, and it may store non-pointer or C pointer data through
+those pointers, but it may not store a Go pointer in memory pointed to
+by a C pointer. A Go function called by C code may take a Go pointer
+as an argument, but it must preserve the property that the Go memory
+to which it points does not contain any Go pointers.
+
+Go code may not store a Go pointer in C memory. C code may store Go
+pointers in C memory, subject to the rule above: it must stop storing
+the Go pointer when the C function returns.
+
+These rules are checked dynamically at runtime. The checking is
+controlled by the cgocheck setting of the GODEBUG environment
+variable. The default setting is GODEBUG=cgocheck=1, which implements
+reasonably cheap dynamic checks. These checks may be disabled
+entirely using GODEBUG=cgocheck=0. Complete checking of pointer
+handling, at some cost in run time, is available via GODEBUG=cgocheck=2.
+
+It is possible to defeat this enforcement by using the unsafe package,
+and of course there is nothing stopping the C code from doing anything
+it likes. However, programs that break these rules are likely to fail
+in unexpected and unpredictable ways.
+
+The runtime/cgo.Handle type can be used to safely pass Go values
+between Go and C. See the runtime/cgo package documentation for details.
+
+Note: the current implementation has a bug. While Go code is permitted
+to write nil or a C pointer (but not a Go pointer) to C memory, the
+current implementation may sometimes cause a runtime error if the
+contents of the C memory appear to be a Go pointer. Therefore, avoid
+passing uninitialized C memory to Go code if the Go code is going to
+store pointer values in it. Zero out the memory in C before passing it
+to Go.
+
+# Special cases
+
+A few special C types which would normally be represented by a pointer
+type in Go are instead represented by a uintptr. Those include:
+
+1. The *Ref types on Darwin, rooted at CoreFoundation's CFTypeRef type.
+
+2. The object types from Java's JNI interface:
+
+ jobject
+ jclass
+ jthrowable
+ jstring
+ jarray
+ jbooleanArray
+ jbyteArray
+ jcharArray
+ jshortArray
+ jintArray
+ jlongArray
+ jfloatArray
+ jdoubleArray
+ jobjectArray
+ jweak
+
+3. The EGLDisplay and EGLConfig types from the EGL API.
+
+These types are uintptr on the Go side because they would otherwise
+confuse the Go garbage collector; they are sometimes not really
+pointers but data structures encoded in a pointer type. All operations
+on these types must happen in C. The proper constant to initialize an
+empty such reference is 0, not nil.
+
+These special cases were introduced in Go 1.10. For auto-updating code
+from Go 1.9 and earlier, use the cftype or jni rewrites in the Go fix tool:
+
+ go tool fix -r cftype <pkg>
+ go tool fix -r jni <pkg>
+
+It will replace nil with 0 in the appropriate places.
+
+The EGLDisplay case was introduced in Go 1.12. Use the egl rewrite
+to auto-update code from Go 1.11 and earlier:
+
+ go tool fix -r egl <pkg>
+
+The EGLConfig case was introduced in Go 1.15. Use the eglconf rewrite
+to auto-update code from Go 1.14 and earlier:
+
+ go tool fix -r eglconf <pkg>
+
+# Using cgo directly
+
+Usage:
+
+ go tool cgo [cgo options] [-- compiler options] gofiles...
+
+Cgo transforms the specified input Go source files into several output
+Go and C source files.
+
+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:
+
+ -V
+ Print cgo version and exit.
+ -debug-define
+ Debugging option. Print #defines.
+ -debug-gcc
+ Debugging option. Trace C compiler execution and output.
+ -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.
+ -dynlinker
+ Write dynamic linker as part of -dynimport output.
+ -dynout file
+ Write -dynimport output to file.
+ -dynpackage package
+ Set Go package for -dynimport output.
+ -exportheader file
+ If there are any exported functions, write the
+ generated export declarations to file.
+ C code can #include this to see the declarations.
+ -importpath string
+ The import path for the Go package. Optional; used for
+ nicer comments in the generated files.
+ -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.
+ -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.
+ -gccgo_define_cgoincomplete
+ Define cgo.Incomplete locally rather than importing it from
+ the "runtime/cgo" package. Used for old gccgo versions.
+ -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.
+ -objdir directory
+ Put all generated files in directory.
+ -srcdir directory
+*/
+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, cgo generates this C program:
+
+ <preamble>
+ #line 1 "not-declared"
+ void __cgo_f_1_1(void) { __typeof__(foo) *__cgo_undefined__1; }
+ #line 1 "not-type"
+ void __cgo_f_1_2(void) { foo *__cgo_undefined__2; }
+ #line 1 "not-int-const"
+ void __cgo_f_1_3(void) { enum { __cgo_undefined__3 = (foo)*1 }; }
+ #line 1 "not-num-const"
+ void __cgo_f_1_4(void) { static const double __cgo_undefined__4 = (foo); }
+ #line 1 "not-str-lit"
+ void __cgo_f_1_5(void) { static const char __cgo_undefined__5[] = (foo); }
+
+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-int-const:1 indicates that foo is not an integer constant.
+An error on not-num-const:1 indicates that foo is not a number constant.
+An error on not-str-lit:1 indicates that foo is not a string literal.
+An error on not-signed-int-const:1 indicates that foo is not a signed integer constant.
+
+The line number specifies the name involved. In the example, 1 is foo.
+
+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 i4, i5
+are integer constants, u6 is an unsigned integer constant, and f7 and f8
+are float constants, and s9 and s10 are string constants, it generates:
+
+ <preamble>
+ __typeof__(t1) *__cgo__1;
+ __typeof__(v2) *__cgo__2;
+ __typeof__(v3) *__cgo__3;
+ __typeof__(i4) *__cgo__4;
+ enum { __cgo_enum__4 = i4 };
+ __typeof__(i5) *__cgo__5;
+ enum { __cgo_enum__5 = i5 };
+ __typeof__(u6) *__cgo__6;
+ enum { __cgo_enum__6 = u6 };
+ __typeof__(f7) *__cgo__7;
+ __typeof__(f8) *__cgo__8;
+ __typeof__(s9) *__cgo__9;
+ __typeof__(s10) *__cgo__10;
+
+ long long __cgodebug_ints[] = {
+ 0, // t1
+ 0, // v2
+ 0, // v3
+ i4,
+ i5,
+ u6,
+ 0, // f7
+ 0, // f8
+ 0, // s9
+ 0, // s10
+ 1
+ };
+
+ double __cgodebug_floats[] = {
+ 0, // t1
+ 0, // v2
+ 0, // v3
+ 0, // i4
+ 0, // i5
+ 0, // u6
+ f7,
+ f8,
+ 0, // s9
+ 0, // s10
+ 1
+ };
+
+ const char __cgodebug_str__9[] = s9;
+ const unsigned long long __cgodebug_strlen__9 = sizeof(s9)-1;
+ const char __cgodebug_str__10[] = s10;
+ const unsigned long long __cgodebug_strlen__10 = sizeof(s10)-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.) Cgo reads the constant
+values from the __cgodebug_* 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
+
+Given the input Go files x.go and y.go, cgo generates these source
+files:
+
+ x.cgo1.go # for gc (cmd/compile)
+ y.cgo1.go # for gc
+ _cgo_gotypes.go # for gc
+ _cgo_import.go # for gc (if -dynout _cgo_import.go)
+ x.cgo2.c # for gcc
+ y.cgo2.c # for gcc
+ _cgo_defun.c # for gcc (if -gccgo)
+ _cgo_export.c # for gcc
+ _cgo_export.h # for gcc
+ _cgo_main.c # for gcc
+ _cgo_flags # for alternative build tools
+
+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 needed C types:
+
+ type _Ctype_char int8
+ type _Ctype_int int32
+ type _Ctype_void [0]byte
+
+The _cgo_gotypes.go file also 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:
+
+ //go:cgo_import_static _cgo_be59f0f25121_Cfunc_puts
+ //go:linkname __cgofn__cgo_be59f0f25121_Cfunc_puts _cgo_be59f0f25121_Cfunc_puts
+ var __cgofn__cgo_be59f0f25121_Cfunc_puts byte
+ var _cgo_be59f0f25121_Cfunc_puts = unsafe.Pointer(&__cgofn__cgo_be59f0f25121_Cfunc_puts)
+
+ func _Cfunc_puts(p0 *_Ctype_char) (r1 _Ctype_int) {
+ _cgo_runtime_cgocall(_cgo_be59f0f25121_Cfunc_puts, uintptr(unsafe.Pointer(&p0)))
+ return
+ }
+
+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). cmd/link 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*), void *a, int c, uintptr_t ctxt) { }
+ uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
+ void _cgo_release_context(uintptr_t ctxt) { }
+ char* _cgo_topofstack(void) { return (char*)0; }
+ void _cgo_allocate(void *a, int c) { }
+ void _cgo_panic(void *a, int c) { }
+ void _cgo_reginit(void) { }
+
+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.go, which looks like:
+
+ //go:cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
+ //go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
+ //go:cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
+ //go:cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
+ //go:cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
+ //go:cgo_import_dynamic _ _ "libpthread.so.0"
+ //go:cgo_import_dynamic _ _ "libc.so.6"
+
+In the end, the compiled Go package, which will eventually be
+presented to cmd/link as part of a larger program, contains:
+
+ _go_.o # gc-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
+ _all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c
+
+If there is an error generating the _cgo_import.go file, then, instead
+of adding _cgo_import.go to the package, the go tool adds an empty
+file named dynimportfail. The _cgo_import.go file is only needed when
+using internal linking mode, which is not the default when linking
+programs that use cgo (as described below). If the linker sees a file
+named dynimportfail it reports an error if it has been told to use
+internal linking mode. This approach is taken because generating
+_cgo_import.go requires doing a full C link of the package, which can
+fail for reasons that are irrelevant when using external linking mode.
+
+The final program will be a dynamic executable, so that cmd/link 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.o file includes the extra linking
+directives that cmd/link 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 cmd/link is not sophisticated enough to process
+the real code.
+
+The main benefits of this system are that cmd/link 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 declares a few
+variables:
+
+ var (
+ iscgo bool
+ _cgo_init unsafe.Pointer
+ _cgo_thread_start unsafe.Pointer
+ )
+
+Any package using cgo imports "runtime/cgo", which provides
+initializations for these variables. It sets iscgo to true, _cgo_init
+to a gcc-compiled function that can be called early during program
+startup, and _cgo_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 cmd/link parses and
+links host object files (ELF, Mach-O, PE, and so on) into the final
+executable itself. Keeping cmd/link 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, cmd/link can generate Go binaries by itself.
+
+In order to allow linking arbitrary object files without requiring
+dynamic libraries, cgo supports an "external" linking mode too. In
+external linking mode, cmd/link 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 cmd/link. These are communicated by writing //go: directives in a
+Go source file compiled by gc. The directives are copied into the .o
+object file and then processed by the linker.
+
+The directives are:
+
+//go: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.
+
+ On AIX, the library pattern is slightly different. It must be
+ "lib.a/obj.o" with obj.o the member of this library exporting
+ this symbol.
+
+ In the <remote>, # or @ can be used to introduce a symbol version.
+
+ Examples:
+ //go:cgo_import_dynamic puts
+ //go:cgo_import_dynamic puts puts#GLIBC_2.2.5
+ //go: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:
+ //go:cgo_import_dynamic _ _ "libc.so.6"
+
+ For compatibility with current versions of SWIG,
+ #pragma dynimport is an alias for //go:cgo_import_dynamic.
+
+//go: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:
+ //go:cgo_dynamic_linker "/lib/ld-linux.so.2"
+
+//go: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 //go:cgo_export_dynamic.
+
+//go: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:
+ //go:cgo_import_static puts_wrapper
+
+//go: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.
+
+//go: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:
+ //go:cgo_ldflag "-lpthread"
+ //go: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 gc
+
+ //go:cgo_ldflag "-lm"
+
+ type _Ctype_double float64
+
+ //go:cgo_import_static _cgo_gcc_Cfunc_sin
+ //go:linkname __cgo_gcc_Cfunc_sin _cgo_gcc_Cfunc_sin
+ var __cgo_gcc_Cfunc_sin byte
+ var _cgo_gcc_Cfunc_sin = unsafe.Pointer(&__cgo_gcc_Cfunc_sin)
+
+ func _Cfunc_sin(p0 _Ctype_double) (r1 _Ctype_double) {
+ _cgo_runtime_cgocall(_cgo_gcc_Cfunc_sin, uintptr(unsafe.Pointer(&p0)))
+ return
+ }
+
+ // 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 linking directives are used according to the kind of final link
+used.
+
+In internal mode, cmd/link 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, cmd/link does not process any host object files, in
+particular foo.cgo2.o. It links together the gc-generated object
+files, along with any other Go code, into a go.o file. While doing
+that, cmd/link will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the gc-compiled source file. This
+is okay, because cmd/link 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 cmd/link 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'. cmd/link 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.
+
+cmd/link Command Line Interface
+
+The go command and any other Go-aware build systems invoke cmd/link
+to link a collection of packages into a single binary. By default, cmd/link will
+present the same interface it does today:
+
+ cmd/link main.a
+
+produces a file named a.out, even if cmd/link does so by invoking the host
+linker in external linking mode.
+
+By default, cmd/link will decide the linking mode as follows: if the only
+packages using cgo are those on a list of known standard library
+packages (net, os/user, runtime/cgo), cmd/link will use internal linking
+mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
+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: cmd/link -linkmode=internal or
+cmd/link -linkmode=external.
+
+In an external link, cmd/link 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: cmd/link -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 'cmd/link' and get reasonable results, but
+they can also control the linking details if desired.
+
+*/
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
new file mode 100644
index 0000000..5df4a8c
--- /dev/null
+++ b/src/cmd/cgo/gcc.go
@@ -0,0 +1,3421 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Annotate Ref in Prog with C types by parsing gcc debug output.
+// Conversion of debug output to Go types.
+
+package main
+
+import (
+ "bytes"
+ "debug/dwarf"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "encoding/binary"
+ "errors"
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "internal/xcoff"
+ "math"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "cmd/internal/quoted"
+)
+
+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",
+}
+
+var incomplete = "_cgopackage.Incomplete"
+
+// cname returns the C name to use for C.s.
+// The expansions are listed in nameToC and also
+// struct_foo becomes "struct foo", and similarly for
+// union and enum.
+func cname(s string) string {
+ if t, ok := nameToC[s]; ok {
+ return t
+ }
+
+ if strings.HasPrefix(s, "struct_") {
+ return "struct " + s[len("struct_"):]
+ }
+ if strings.HasPrefix(s, "union_") {
+ return "union " + s[len("union_"):]
+ }
+ if strings.HasPrefix(s, "enum_") {
+ return "enum " + s[len("enum_"):]
+ }
+ if strings.HasPrefix(s, "sizeof_") {
+ return "sizeof(" + cname(s[len("sizeof_"):]) + ")"
+ }
+ return s
+}
+
+// DiscardCgoDirectives processes the import C preamble, and discards
+// all #cgo CFLAGS and LDFLAGS directives, so they don't make their
+// way into _cgo_export.h.
+func (f *File) DiscardCgoDirectives() {
+ linesIn := strings.Split(f.Preamble, "\n")
+ linesOut := make([]string, 0, len(linesIn))
+ for _, line := range linesIn {
+ l := strings.TrimSpace(line)
+ if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {
+ linesOut = append(linesOut, line)
+ } else {
+ linesOut = append(linesOut, "")
+ }
+ }
+ f.Preamble = strings.Join(linesOut, "\n")
+}
+
+// addToFlag appends args to flag. All flags are later written out onto the
+// _cgo_flags file for the build system to use.
+func (p *Package) addToFlag(flag string, args []string) {
+ p.CgoFlags[flag] = append(p.CgoFlags[flag], args...)
+ if flag == "CFLAGS" {
+ // We'll also need these when preprocessing for dwarf information.
+ // However, discard any -g options: we need to be able
+ // to parse the debug info, so stick to what we expect.
+ for _, arg := range args {
+ if !strings.HasPrefix(arg, "-g") {
+ p.GccOptions = append(p.GccOptions, arg)
+ }
+ }
+ }
+}
+
+// splitQuoted splits the string s around each instance of one or more consecutive
+// white space characters while taking into account quotes and escaping, and
+// returns an array of substrings of s or an empty list if s contains only white space.
+// Single quotes and double quotes are recognized to prevent splitting within the
+// quoted region, and are removed from the resulting substrings. If a quote in s
+// isn't closed err will be set and r will have the unclosed argument as the
+// last element. The backslash is used for escaping.
+//
+// For example, the following string:
+//
+// `a b:"c d" 'e''f' "g\""`
+//
+// Would be parsed as:
+//
+// []string{"a", "b:c d", "ef", `g"`}
+func splitQuoted(s string) (r []string, err error) {
+ var args []string
+ arg := make([]rune, len(s))
+ escaped := false
+ quoted := false
+ quote := '\x00'
+ i := 0
+ for _, r := range s {
+ switch {
+ case escaped:
+ escaped = false
+ case r == '\\':
+ escaped = true
+ continue
+ case quote != 0:
+ if r == quote {
+ quote = 0
+ continue
+ }
+ case r == '"' || r == '\'':
+ quoted = true
+ quote = r
+ continue
+ case unicode.IsSpace(r):
+ if quoted || i > 0 {
+ quoted = false
+ args = append(args, string(arg[:i]))
+ i = 0
+ }
+ continue
+ }
+ arg[i] = r
+ i++
+ }
+ if quoted || i > 0 {
+ args = append(args, string(arg[:i]))
+ }
+ if quote != 0 {
+ err = errors.New("unclosed quote")
+ } else if escaped {
+ err = errors.New("unfinished escaping")
+ }
+ return args, err
+}
+
+// Translate rewrites f.AST, the original Go input, to remove
+// references to the imported package C, replacing them with
+// references to the equivalent Go types, functions, and variables.
+func (p *Package) Translate(f *File) {
+ for _, cref := range f.Ref {
+ // Convert C.ulong to C.unsigned long, etc.
+ cref.Name.C = cname(cref.Name.Go)
+ }
+
+ var conv typeConv
+ conv.Init(p.PtrSize, p.IntSize)
+
+ p.loadDefines(f)
+ p.typedefs = map[string]bool{}
+ p.typedefList = nil
+ numTypedefs := -1
+ for len(p.typedefs) > numTypedefs {
+ numTypedefs = len(p.typedefs)
+ // Also ask about any typedefs we've seen so far.
+ for _, info := range p.typedefList {
+ if f.Name[info.typedef] != nil {
+ continue
+ }
+ n := &Name{
+ Go: info.typedef,
+ C: info.typedef,
+ }
+ f.Name[info.typedef] = n
+ f.NamePos[n] = info.pos
+ }
+ needType := p.guessKinds(f)
+ if len(needType) > 0 {
+ p.loadDWARF(f, &conv, needType)
+ }
+
+ // In godefs mode we're OK with the typedefs, which
+ // will presumably also be defined in the file, we
+ // don't want to resolve them to their base types.
+ if *godefs {
+ break
+ }
+ }
+ p.prepareNames(f)
+ if p.rewriteCalls(f) {
+ // Add `import _cgo_unsafe "unsafe"` after the package statement.
+ f.Edit.Insert(f.offset(f.AST.Name.End()), "; import _cgo_unsafe \"unsafe\"")
+ }
+ p.rewriteRef(f)
+}
+
+// loadDefines coerces gcc into spitting out the #defines in use
+// in the file f and saves relevant renamings in f.Name[name].Define.
+func (p *Package) loadDefines(f *File) {
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
+ stdout := p.gccDefines(b.Bytes())
+
+ for _, line := range strings.Split(stdout, "\n") {
+ if len(line) < 9 || line[0:7] != "#define" {
+ continue
+ }
+
+ line = strings.TrimSpace(line[8:])
+
+ var key, val string
+ spaceIndex := strings.Index(line, " ")
+ tabIndex := strings.Index(line, "\t")
+
+ if spaceIndex == -1 && tabIndex == -1 {
+ continue
+ } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) {
+ key = line[0:spaceIndex]
+ val = strings.TrimSpace(line[spaceIndex:])
+ } else {
+ key = line[0:tabIndex]
+ val = strings.TrimSpace(line[tabIndex:])
+ }
+
+ if key == "__clang__" {
+ p.GccIsClang = true
+ }
+
+ if n := f.Name[key]; n != nil {
+ if *debugDefine {
+ fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
+ }
+ n.Define = val
+ }
+ }
+}
+
+// guessKinds tricks gcc into revealing the kind of each
+// name xxx for the references C.xxx in the Go input.
+// The kind is either a constant, type, or variable.
+func (p *Package) guessKinds(f *File) []*Name {
+ // Determine kinds for names we already know about,
+ // like #defines or 'struct foo', before bothering with gcc.
+ var names, needType []*Name
+ optional := map[*Name]bool{}
+ for _, key := range nameKeys(f.Name) {
+ n := f.Name[key]
+ // If we've already found this name as a #define
+ // and we can translate it as a constant value, do so.
+ if n.Define != "" {
+ if i, err := strconv.ParseInt(n.Define, 0, 64); err == nil {
+ n.Kind = "iconst"
+ // Turn decimal into hex, just for consistency
+ // with enum-derived constants. Otherwise
+ // in the cgo -godefs output half the constants
+ // are in hex and half are in whatever the #define used.
+ n.Const = fmt.Sprintf("%#x", i)
+ } else if n.Define[0] == '\'' {
+ if _, err := parser.ParseExpr(n.Define); err == nil {
+ n.Kind = "iconst"
+ n.Const = n.Define
+ }
+ } else if n.Define[0] == '"' {
+ if _, err := parser.ParseExpr(n.Define); err == nil {
+ n.Kind = "sconst"
+ n.Const = n.Define
+ }
+ }
+
+ if n.IsConst() {
+ continue
+ }
+ }
+
+ // If this is a struct, union, or enum type name, no need to guess the kind.
+ if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
+ n.Kind = "type"
+ needType = append(needType, n)
+ continue
+ }
+
+ if (goos == "darwin" || goos == "ios") && strings.HasSuffix(n.C, "Ref") {
+ // For FooRef, find out if FooGetTypeID exists.
+ s := n.C[:len(n.C)-3] + "GetTypeID"
+ n := &Name{Go: s, C: s}
+ names = append(names, n)
+ optional[n] = true
+ }
+
+ // Otherwise, we'll need to find out from gcc.
+ names = append(names, n)
+ }
+
+ // Bypass gcc if there's nothing left to find out.
+ if len(names) == 0 {
+ return needType
+ }
+
+ // Coerce gcc into telling us whether each name is a type, a value, or undeclared.
+ // For names, find out whether they are integer constants.
+ // We used to look at specific warning or error messages here, but that tied the
+ // behavior too closely to specific versions of the compilers.
+ // Instead, arrange that we can infer what we need from only the presence or absence
+ // of an error on a specific line.
+ //
+ // For each name, we generate these lines, where xxx is the index in toSniff plus one.
+ //
+ // #line xxx "not-declared"
+ // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__1; }
+ // #line xxx "not-type"
+ // void __cgo_f_xxx_2(void) { name *__cgo_undefined__2; }
+ // #line xxx "not-int-const"
+ // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__3 = (name)*1 }; }
+ // #line xxx "not-num-const"
+ // void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); }
+ // #line xxx "not-str-lit"
+ // void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); }
+ //
+ // If we see an error at not-declared:xxx, the corresponding name is not declared.
+ // If we see an error at not-type:xxx, the corresponding name is not a type.
+ // If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
+ // If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
+ // If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
+ //
+ // The specific input forms are chosen so that they are valid C syntax regardless of
+ // whether name denotes a type or an expression.
+
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
+
+ for i, n := range names {
+ fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+
+ "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__1; }\n"+
+ "#line %d \"not-type\"\n"+
+ "void __cgo_f_%d_2(void) { %s *__cgo_undefined__2; }\n"+
+ "#line %d \"not-int-const\"\n"+
+ "void __cgo_f_%d_3(void) { enum { __cgo_undefined__3 = (%s)*1 }; }\n"+
+ "#line %d \"not-num-const\"\n"+
+ "void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+
+ "#line %d \"not-str-lit\"\n"+
+ "void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n",
+ i+1, i+1, n.C,
+ i+1, i+1, n.C,
+ i+1, i+1, n.C,
+ i+1, i+1, n.C,
+ i+1, i+1, n.C,
+ )
+ }
+ fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
+ "int __cgo__1 = __cgo__2;\n")
+
+ // We need to parse the output from this gcc command, so ensure that it
+ // doesn't have any ANSI escape sequences in it. (TERM=dumb is
+ // insufficient; if the user specifies CGO_CFLAGS=-fdiagnostics-color,
+ // GCC will ignore TERM, and GCC can also be configured at compile-time
+ // to ignore TERM.)
+ stderr := p.gccErrors(b.Bytes(), "-fdiagnostics-color=never")
+ if strings.Contains(stderr, "unrecognized command line option") {
+ // We're using an old version of GCC that doesn't understand
+ // -fdiagnostics-color. Those versions can't print color anyway,
+ // so just rerun without that option.
+ stderr = p.gccErrors(b.Bytes())
+ }
+ if stderr == "" {
+ fatalf("%s produced no output\non input:\n%s", gccBaseCmd[0], b.Bytes())
+ }
+
+ completed := false
+ sniff := make([]int, len(names))
+ const (
+ notType = 1 << iota
+ notIntConst
+ notNumConst
+ notStrLiteral
+ notDeclared
+ )
+ sawUnmatchedErrors := false
+ for _, line := range strings.Split(stderr, "\n") {
+ // Ignore warnings and random comments, with one
+ // exception: newer GCC versions will sometimes emit
+ // an error on a macro #define with a note referring
+ // to where the expansion occurs. We care about where
+ // the expansion occurs, so in that case treat the note
+ // as an error.
+ isError := strings.Contains(line, ": error:")
+ isErrorNote := strings.Contains(line, ": note:") && sawUnmatchedErrors
+ if !isError && !isErrorNote {
+ continue
+ }
+
+ c1 := strings.Index(line, ":")
+ if c1 < 0 {
+ continue
+ }
+ c2 := strings.Index(line[c1+1:], ":")
+ if c2 < 0 {
+ continue
+ }
+ c2 += c1 + 1
+
+ filename := line[:c1]
+ i, _ := strconv.Atoi(line[c1+1 : c2])
+ i--
+ if i < 0 || i >= len(names) {
+ if isError {
+ sawUnmatchedErrors = true
+ }
+ continue
+ }
+
+ switch filename {
+ case "completed":
+ // Strictly speaking, there is no guarantee that seeing the error at completed:1
+ // (at the end of the file) means we've seen all the errors from earlier in the file,
+ // but usually it does. Certainly if we don't see the completed:1 error, we did
+ // not get all the errors we expected.
+ completed = true
+
+ case "not-declared":
+ sniff[i] |= notDeclared
+ case "not-type":
+ sniff[i] |= notType
+ case "not-int-const":
+ sniff[i] |= notIntConst
+ case "not-num-const":
+ sniff[i] |= notNumConst
+ case "not-str-lit":
+ sniff[i] |= notStrLiteral
+ default:
+ if isError {
+ sawUnmatchedErrors = true
+ }
+ continue
+ }
+
+ sawUnmatchedErrors = false
+ }
+
+ if !completed {
+ fatalf("%s did not produce error at completed:1\non input:\n%s\nfull error output:\n%s", gccBaseCmd[0], b.Bytes(), stderr)
+ }
+
+ for i, n := range names {
+ switch sniff[i] {
+ default:
+ if sniff[i]&notDeclared != 0 && optional[n] {
+ // Ignore optional undeclared identifiers.
+ // Don't report an error, and skip adding n to the needType array.
+ continue
+ }
+ error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
+ case notStrLiteral | notType:
+ n.Kind = "iconst"
+ case notIntConst | notStrLiteral | notType:
+ n.Kind = "fconst"
+ case notIntConst | notNumConst | notType:
+ n.Kind = "sconst"
+ case notIntConst | notNumConst | notStrLiteral:
+ n.Kind = "type"
+ case notIntConst | notNumConst | notStrLiteral | notType:
+ n.Kind = "not-type"
+ }
+ needType = append(needType, n)
+ }
+ if nerrors > 0 {
+ // Check if compiling the preamble by itself causes any errors,
+ // because the messages we've printed out so far aren't helpful
+ // to users debugging preamble mistakes. See issue 8442.
+ preambleErrors := p.gccErrors([]byte(builtinProlog + f.Preamble))
+ if len(preambleErrors) > 0 {
+ error_(token.NoPos, "\n%s errors for preamble:\n%s", gccBaseCmd[0], preambleErrors)
+ }
+
+ fatalf("unresolved names")
+ }
+
+ return needType
+}
+
+// loadDWARF parses the DWARF debug information generated
+// by gcc to learn the details of the constants, variables, and types
+// being referred to as C.xxx.
+func (p *Package) loadDWARF(f *File, conv *typeConv, names []*Name) {
+ // Extract the types from the DWARF section of an object
+ // from a well-formed C program. Gcc only generates DWARF info
+ // for symbols in the object file, so it is not enough to print the
+ // preamble and hope the symbols we care about will be there.
+ // Instead, emit
+ // __typeof__(names[i]) *__cgo__i;
+ // for each entry in names and then dereference the type we
+ // learn for __cgo__i.
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
+ b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
+ for i, n := range names {
+ fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
+ if n.Kind == "iconst" {
+ fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
+ }
+ }
+
+ // We create a data block initialized with the values,
+ // so we can read them out of the object file.
+ fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
+ for _, n := range names {
+ if n.Kind == "iconst" {
+ fmt.Fprintf(&b, "\t%s,\n", n.C)
+ } else {
+ fmt.Fprintf(&b, "\t0,\n")
+ }
+ }
+ // for the last entry, we cannot use 0, otherwise
+ // in case all __cgodebug_data is zero initialized,
+ // LLVM-based gcc will place the it in the __DATA.__common
+ // zero-filled section (our debug/macho doesn't support
+ // this)
+ fmt.Fprintf(&b, "\t1\n")
+ fmt.Fprintf(&b, "};\n")
+
+ // do the same work for floats.
+ fmt.Fprintf(&b, "double __cgodebug_floats[] = {\n")
+ for _, n := range names {
+ if n.Kind == "fconst" {
+ fmt.Fprintf(&b, "\t%s,\n", n.C)
+ } else {
+ fmt.Fprintf(&b, "\t0,\n")
+ }
+ }
+ fmt.Fprintf(&b, "\t1\n")
+ fmt.Fprintf(&b, "};\n")
+
+ // do the same work for strings.
+ for i, n := range names {
+ if n.Kind == "sconst" {
+ fmt.Fprintf(&b, "const char __cgodebug_str__%d[] = %s;\n", i, n.C)
+ fmt.Fprintf(&b, "const unsigned long long __cgodebug_strlen__%d = sizeof(%s)-1;\n", i, n.C)
+ }
+ }
+
+ d, ints, floats, strs := p.gccDebug(b.Bytes(), len(names))
+
+ // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
+ types := make([]dwarf.Type, len(names))
+ r := d.Reader()
+ for {
+ e, err := r.Next()
+ if err != nil {
+ fatalf("reading DWARF entry: %s", err)
+ }
+ if e == nil {
+ break
+ }
+ switch e.Tag {
+ case dwarf.TagVariable:
+ name, _ := e.Val(dwarf.AttrName).(string)
+ // As of https://reviews.llvm.org/D123534, clang
+ // now emits DW_TAG_variable DIEs that have
+ // no name (so as to be able to describe the
+ // type and source locations of constant strings
+ // like the second arg in the call below:
+ //
+ // myfunction(42, "foo")
+ //
+ // If a var has no name we won't see attempts to
+ // refer to it via "C.<name>", so skip these vars
+ //
+ // See issue 53000 for more context.
+ if name == "" {
+ break
+ }
+ typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset)
+ if typOff == 0 {
+ if e.Val(dwarf.AttrSpecification) != nil {
+ // Since we are reading all the DWARF,
+ // assume we will see the variable elsewhere.
+ break
+ }
+ fatalf("malformed DWARF TagVariable entry")
+ }
+ if !strings.HasPrefix(name, "__cgo__") {
+ break
+ }
+ typ, err := d.Type(typOff)
+ if err != nil {
+ fatalf("loading DWARF type: %s", err)
+ }
+ t, ok := typ.(*dwarf.PtrType)
+ if !ok || t == nil {
+ fatalf("internal error: %s has non-pointer type", name)
+ }
+ i, err := strconv.Atoi(name[7:])
+ if err != nil {
+ fatalf("malformed __cgo__ name: %s", name)
+ }
+ types[i] = t.Type
+ p.recordTypedefs(t.Type, f.NamePos[names[i]])
+ }
+ if e.Tag != dwarf.TagCompileUnit {
+ r.SkipChildren()
+ }
+ }
+
+ // Record types and typedef information.
+ for i, n := range names {
+ if strings.HasSuffix(n.Go, "GetTypeID") && types[i].String() == "func() CFTypeID" {
+ conv.getTypeIDs[n.Go[:len(n.Go)-9]] = true
+ }
+ }
+ for i, n := range names {
+ if types[i] == nil {
+ continue
+ }
+ pos := f.NamePos[n]
+ f, fok := types[i].(*dwarf.FuncType)
+ if n.Kind != "type" && fok {
+ n.Kind = "func"
+ n.FuncType = conv.FuncType(f, pos)
+ } else {
+ n.Type = conv.Type(types[i], pos)
+ switch n.Kind {
+ case "iconst":
+ if i < len(ints) {
+ if _, ok := types[i].(*dwarf.UintType); ok {
+ n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
+ } else {
+ n.Const = fmt.Sprintf("%#x", ints[i])
+ }
+ }
+ case "fconst":
+ if i >= len(floats) {
+ break
+ }
+ switch base(types[i]).(type) {
+ case *dwarf.IntType, *dwarf.UintType:
+ // This has an integer type so it's
+ // not really a floating point
+ // constant. This can happen when the
+ // C compiler complains about using
+ // the value as an integer constant,
+ // but not as a general constant.
+ // Treat this as a variable of the
+ // appropriate type, not a constant,
+ // to get C-style type handling,
+ // avoiding the problem that C permits
+ // uint64(-1) but Go does not.
+ // See issue 26066.
+ n.Kind = "var"
+ default:
+ n.Const = fmt.Sprintf("%f", floats[i])
+ }
+ case "sconst":
+ if i < len(strs) {
+ n.Const = fmt.Sprintf("%q", strs[i])
+ }
+ }
+ }
+ conv.FinishType(pos)
+ }
+}
+
+// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
+func (p *Package) recordTypedefs(dtype dwarf.Type, pos token.Pos) {
+ p.recordTypedefs1(dtype, pos, map[dwarf.Type]bool{})
+}
+
+func (p *Package) recordTypedefs1(dtype dwarf.Type, pos token.Pos, visited map[dwarf.Type]bool) {
+ if dtype == nil {
+ return
+ }
+ if visited[dtype] {
+ return
+ }
+ visited[dtype] = true
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ if strings.HasPrefix(dt.Name, "__builtin") {
+ // Don't look inside builtin types. There be dragons.
+ return
+ }
+ if !p.typedefs[dt.Name] {
+ p.typedefs[dt.Name] = true
+ p.typedefList = append(p.typedefList, typedefInfo{dt.Name, pos})
+ p.recordTypedefs1(dt.Type, pos, visited)
+ }
+ case *dwarf.PtrType:
+ p.recordTypedefs1(dt.Type, pos, visited)
+ case *dwarf.ArrayType:
+ p.recordTypedefs1(dt.Type, pos, visited)
+ case *dwarf.QualType:
+ p.recordTypedefs1(dt.Type, pos, visited)
+ case *dwarf.FuncType:
+ p.recordTypedefs1(dt.ReturnType, pos, visited)
+ for _, a := range dt.ParamType {
+ p.recordTypedefs1(a, pos, visited)
+ }
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ p.recordTypedefs1(f.Type, pos, visited)
+ }
+ }
+}
+
+// prepareNames finalizes the Kind field of not-type names and sets
+// the mangled name of all names.
+func (p *Package) prepareNames(f *File) {
+ for _, n := range f.Name {
+ if n.Kind == "not-type" {
+ if n.Define == "" {
+ n.Kind = "var"
+ } else {
+ n.Kind = "macro"
+ n.FuncType = &FuncType{
+ Result: n.Type,
+ Go: &ast.FuncType{
+ Results: &ast.FieldList{List: []*ast.Field{{Type: n.Type.Go}}},
+ },
+ }
+ }
+ }
+ p.mangleName(n)
+ if n.Kind == "type" && typedef[n.Mangle] == nil {
+ typedef[n.Mangle] = n.Type
+ }
+ }
+}
+
+// mangleName does name mangling to translate names
+// from the original Go source files to the names
+// used in the final Go files generated by cgo.
+func (p *Package) mangleName(n *Name) {
+ // When using gccgo variables have to be
+ // exported so that they become global symbols
+ // that the C code can refer to.
+ prefix := "_C"
+ if *gccgo && n.IsVar() {
+ prefix = "C"
+ }
+ n.Mangle = prefix + n.Kind + "_" + n.Go
+}
+
+func (f *File) isMangledName(s string) bool {
+ prefix := "_C"
+ if strings.HasPrefix(s, prefix) {
+ t := s[len(prefix):]
+ for _, k := range nameKinds {
+ if strings.HasPrefix(t, k+"_") {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// rewriteCalls rewrites all calls that pass pointers to check that
+// they follow the rules for passing pointers between Go and C.
+// This reports whether the package needs to import unsafe as _cgo_unsafe.
+func (p *Package) rewriteCalls(f *File) bool {
+ needsUnsafe := false
+ // Walk backward so that in C.f1(C.f2()) we rewrite C.f2 first.
+ for _, call := range f.Calls {
+ if call.Done {
+ continue
+ }
+ start := f.offset(call.Call.Pos())
+ end := f.offset(call.Call.End())
+ str, nu := p.rewriteCall(f, call)
+ if str != "" {
+ f.Edit.Replace(start, end, str)
+ if nu {
+ needsUnsafe = true
+ }
+ }
+ }
+ return needsUnsafe
+}
+
+// rewriteCall rewrites one call to add pointer checks.
+// If any pointer checks are required, we rewrite the call into a
+// function literal that calls _cgoCheckPointer for each pointer
+// argument and then calls the original function.
+// This returns the rewritten call and whether the package needs to
+// import unsafe as _cgo_unsafe.
+// If it returns the empty string, the call did not need to be rewritten.
+func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
+ // This is a call to C.xxx; set goname to "xxx".
+ // It may have already been mangled by rewriteName.
+ var goname string
+ switch fun := call.Call.Fun.(type) {
+ case *ast.SelectorExpr:
+ goname = fun.Sel.Name
+ case *ast.Ident:
+ goname = strings.TrimPrefix(fun.Name, "_C2func_")
+ goname = strings.TrimPrefix(goname, "_Cfunc_")
+ }
+ if goname == "" || goname == "malloc" {
+ return "", false
+ }
+ name := f.Name[goname]
+ if name == nil || name.Kind != "func" {
+ // Probably a type conversion.
+ return "", false
+ }
+
+ params := name.FuncType.Params
+ args := call.Call.Args
+ end := call.Call.End()
+
+ // Avoid a crash if the number of arguments doesn't match
+ // the number of parameters.
+ // This will be caught when the generated file is compiled.
+ if len(args) != len(params) {
+ return "", false
+ }
+
+ any := false
+ for i, param := range params {
+ if p.needsPointerCheck(f, param.Go, args[i]) {
+ any = true
+ break
+ }
+ }
+ if !any {
+ return "", false
+ }
+
+ // We need to rewrite this call.
+ //
+ // Rewrite C.f(p) to
+ // func() {
+ // _cgo0 := p
+ // _cgoCheckPointer(_cgo0, nil)
+ // C.f(_cgo0)
+ // }()
+ // Using a function literal like this lets us evaluate the
+ // function arguments only once while doing pointer checks.
+ // This is particularly useful when passing additional arguments
+ // to _cgoCheckPointer, as done in checkIndex and checkAddr.
+ //
+ // When the function argument is a conversion to unsafe.Pointer,
+ // we unwrap the conversion before checking the pointer,
+ // and then wrap again when calling C.f. This lets us check
+ // the real type of the pointer in some cases. See issue #25941.
+ //
+ // When the call to C.f is deferred, we use an additional function
+ // literal to evaluate the arguments at the right time.
+ // defer func() func() {
+ // _cgo0 := p
+ // return func() {
+ // _cgoCheckPointer(_cgo0, nil)
+ // C.f(_cgo0)
+ // }
+ // }()()
+ // This works because the defer statement evaluates the first
+ // function literal in order to get the function to call.
+
+ var sb bytes.Buffer
+ sb.WriteString("func() ")
+ if call.Deferred {
+ sb.WriteString("func() ")
+ }
+
+ needsUnsafe := false
+ result := false
+ twoResults := false
+ if !call.Deferred {
+ // Check whether this call expects two results.
+ for _, ref := range f.Ref {
+ if ref.Expr != &call.Call.Fun {
+ continue
+ }
+ if ref.Context == ctxCall2 {
+ sb.WriteString("(")
+ result = true
+ twoResults = true
+ }
+ break
+ }
+
+ // Add the result type, if any.
+ if name.FuncType.Result != nil {
+ rtype := p.rewriteUnsafe(name.FuncType.Result.Go)
+ if rtype != name.FuncType.Result.Go {
+ needsUnsafe = true
+ }
+ sb.WriteString(gofmtLine(rtype))
+ result = true
+ }
+
+ // Add the second result type, if any.
+ if twoResults {
+ if name.FuncType.Result == nil {
+ // An explicit void result looks odd but it
+ // seems to be how cgo has worked historically.
+ sb.WriteString("_Ctype_void")
+ }
+ sb.WriteString(", error)")
+ }
+ }
+
+ sb.WriteString("{ ")
+
+ // Define _cgoN for each argument value.
+ // Write _cgoCheckPointer calls to sbCheck.
+ var sbCheck bytes.Buffer
+ for i, param := range params {
+ origArg := args[i]
+ arg, nu := p.mangle(f, &args[i], true)
+ if nu {
+ needsUnsafe = true
+ }
+
+ // Use "var x T = ..." syntax to explicitly convert untyped
+ // constants to the parameter type, to avoid a type mismatch.
+ ptype := p.rewriteUnsafe(param.Go)
+
+ if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer {
+ if ptype != param.Go {
+ needsUnsafe = true
+ }
+ fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
+ gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
+ continue
+ }
+
+ // Check for &a[i].
+ if p.checkIndex(&sb, &sbCheck, arg, i) {
+ continue
+ }
+
+ // Check for &x.
+ if p.checkAddr(&sb, &sbCheck, arg, i) {
+ continue
+ }
+
+ fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
+ fmt.Fprintf(&sbCheck, "_cgoCheckPointer(_cgo%d, nil); ", i)
+ }
+
+ if call.Deferred {
+ sb.WriteString("return func() { ")
+ }
+
+ // Write out the calls to _cgoCheckPointer.
+ sb.WriteString(sbCheck.String())
+
+ if result {
+ sb.WriteString("return ")
+ }
+
+ m, nu := p.mangle(f, &call.Call.Fun, false)
+ if nu {
+ needsUnsafe = true
+ }
+ sb.WriteString(gofmtPos(m, end))
+
+ sb.WriteString("(")
+ for i := range params {
+ if i > 0 {
+ sb.WriteString(", ")
+ }
+ fmt.Fprintf(&sb, "_cgo%d", i)
+ }
+ sb.WriteString("); ")
+ if call.Deferred {
+ sb.WriteString("}")
+ }
+ sb.WriteString("}")
+ if call.Deferred {
+ sb.WriteString("()")
+ }
+ sb.WriteString("()")
+
+ return sb.String(), needsUnsafe
+}
+
+// needsPointerCheck reports whether the type t needs a pointer check.
+// This is true if t is a pointer and if the value to which it points
+// might contain a pointer.
+func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
+ // An untyped nil does not need a pointer check, and when
+ // _cgoCheckPointer returns the untyped nil the type assertion we
+ // are going to insert will fail. Easier to just skip nil arguments.
+ // TODO: Note that this fails if nil is shadowed.
+ if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
+ return false
+ }
+
+ return p.hasPointer(f, t, true)
+}
+
+// hasPointer is used by needsPointerCheck. If top is true it returns
+// whether t is or contains a pointer that might point to a pointer.
+// If top is false it reports whether t is or contains a pointer.
+// f may be nil.
+func (p *Package) hasPointer(f *File, t ast.Expr, top bool) bool {
+ switch t := t.(type) {
+ case *ast.ArrayType:
+ if t.Len == nil {
+ if !top {
+ return true
+ }
+ return p.hasPointer(f, t.Elt, false)
+ }
+ return p.hasPointer(f, t.Elt, top)
+ case *ast.StructType:
+ for _, field := range t.Fields.List {
+ if p.hasPointer(f, field.Type, top) {
+ return true
+ }
+ }
+ return false
+ case *ast.StarExpr: // Pointer type.
+ if !top {
+ return true
+ }
+ // Check whether this is a pointer to a C union (or class)
+ // type that contains a pointer.
+ if unionWithPointer[t.X] {
+ return true
+ }
+ return p.hasPointer(f, t.X, false)
+ case *ast.FuncType, *ast.InterfaceType, *ast.MapType, *ast.ChanType:
+ return true
+ case *ast.Ident:
+ // TODO: Handle types defined within function.
+ for _, d := range p.Decl {
+ gd, ok := d.(*ast.GenDecl)
+ if !ok || gd.Tok != token.TYPE {
+ continue
+ }
+ for _, spec := range gd.Specs {
+ ts, ok := spec.(*ast.TypeSpec)
+ if !ok {
+ continue
+ }
+ if ts.Name.Name == t.Name {
+ return p.hasPointer(f, ts.Type, top)
+ }
+ }
+ }
+ if def := typedef[t.Name]; def != nil {
+ return p.hasPointer(f, def.Go, top)
+ }
+ if t.Name == "string" {
+ return !top
+ }
+ if t.Name == "error" {
+ return true
+ }
+ if goTypes[t.Name] != nil {
+ return false
+ }
+ // We can't figure out the type. Conservative
+ // approach is to assume it has a pointer.
+ return true
+ case *ast.SelectorExpr:
+ if l, ok := t.X.(*ast.Ident); !ok || l.Name != "C" {
+ // Type defined in a different package.
+ // Conservative approach is to assume it has a
+ // pointer.
+ return true
+ }
+ if f == nil {
+ // Conservative approach: assume pointer.
+ return true
+ }
+ name := f.Name[t.Sel.Name]
+ if name != nil && name.Kind == "type" && name.Type != nil && name.Type.Go != nil {
+ return p.hasPointer(f, name.Type.Go, top)
+ }
+ // We can't figure out the type. Conservative
+ // approach is to assume it has a pointer.
+ return true
+ default:
+ error_(t.Pos(), "could not understand type %s", gofmt(t))
+ return true
+ }
+}
+
+// mangle replaces references to C names in arg with the mangled names,
+// rewriting calls when it finds them.
+// It removes the corresponding references in f.Ref and f.Calls, so that we
+// don't try to do the replacement again in rewriteRef or rewriteCall.
+// If addPosition is true, add position info to the idents of C names in arg.
+func (p *Package) mangle(f *File, arg *ast.Expr, addPosition bool) (ast.Expr, bool) {
+ needsUnsafe := false
+ f.walk(arg, ctxExpr, func(f *File, arg interface{}, context astContext) {
+ px, ok := arg.(*ast.Expr)
+ if !ok {
+ return
+ }
+ sel, ok := (*px).(*ast.SelectorExpr)
+ if ok {
+ if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
+ return
+ }
+
+ for _, r := range f.Ref {
+ if r.Expr == px {
+ *px = p.rewriteName(f, r, addPosition)
+ r.Done = true
+ break
+ }
+ }
+
+ return
+ }
+
+ call, ok := (*px).(*ast.CallExpr)
+ if !ok {
+ return
+ }
+
+ for _, c := range f.Calls {
+ if !c.Done && c.Call.Lparen == call.Lparen {
+ cstr, nu := p.rewriteCall(f, c)
+ if cstr != "" {
+ // Smuggle the rewritten call through an ident.
+ *px = ast.NewIdent(cstr)
+ if nu {
+ needsUnsafe = true
+ }
+ c.Done = true
+ }
+ }
+ }
+ })
+ return *arg, needsUnsafe
+}
+
+// checkIndex checks whether arg has the form &a[i], possibly inside
+// type conversions. If so, then in the general case it writes
+//
+// _cgoIndexNN := a
+// _cgoNN := &cgoIndexNN[i] // with type conversions, if any
+//
+// to sb, and writes
+//
+// _cgoCheckPointer(_cgoNN, _cgoIndexNN)
+//
+// to sbCheck, and returns true. If a is a simple variable or field reference,
+// it writes
+//
+// _cgoIndexNN := &a
+//
+// and dereferences the uses of _cgoIndexNN. Taking the address avoids
+// making a copy of an array.
+//
+// This tells _cgoCheckPointer to check the complete contents of the
+// slice or array being indexed, but no other part of the memory allocation.
+func (p *Package) checkIndex(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
+ // Strip type conversions.
+ x := arg
+ for {
+ c, ok := x.(*ast.CallExpr)
+ if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
+ break
+ }
+ x = c.Args[0]
+ }
+ u, ok := x.(*ast.UnaryExpr)
+ if !ok || u.Op != token.AND {
+ return false
+ }
+ index, ok := u.X.(*ast.IndexExpr)
+ if !ok {
+ return false
+ }
+
+ addr := ""
+ deref := ""
+ if p.isVariable(index.X) {
+ addr = "&"
+ deref = "*"
+ }
+
+ fmt.Fprintf(sb, "_cgoIndex%d := %s%s; ", i, addr, gofmtPos(index.X, index.X.Pos()))
+ origX := index.X
+ index.X = ast.NewIdent(fmt.Sprintf("_cgoIndex%d", i))
+ if deref == "*" {
+ index.X = &ast.StarExpr{X: index.X}
+ }
+ fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
+ index.X = origX
+
+ fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgo%d, %s_cgoIndex%d); ", i, deref, i)
+
+ return true
+}
+
+// checkAddr checks whether arg has the form &x, possibly inside type
+// conversions. If so, it writes
+//
+// _cgoBaseNN := &x
+// _cgoNN := _cgoBaseNN // with type conversions, if any
+//
+// to sb, and writes
+//
+// _cgoCheckPointer(_cgoBaseNN, true)
+//
+// to sbCheck, and returns true. This tells _cgoCheckPointer to check
+// just the contents of the pointer being passed, not any other part
+// of the memory allocation. This is run after checkIndex, which looks
+// for the special case of &a[i], which requires different checks.
+func (p *Package) checkAddr(sb, sbCheck *bytes.Buffer, arg ast.Expr, i int) bool {
+ // Strip type conversions.
+ px := &arg
+ for {
+ c, ok := (*px).(*ast.CallExpr)
+ if !ok || len(c.Args) != 1 || !p.isType(c.Fun) {
+ break
+ }
+ px = &c.Args[0]
+ }
+ if u, ok := (*px).(*ast.UnaryExpr); !ok || u.Op != token.AND {
+ return false
+ }
+
+ fmt.Fprintf(sb, "_cgoBase%d := %s; ", i, gofmtPos(*px, (*px).Pos()))
+
+ origX := *px
+ *px = ast.NewIdent(fmt.Sprintf("_cgoBase%d", i))
+ fmt.Fprintf(sb, "_cgo%d := %s; ", i, gofmtPos(arg, arg.Pos()))
+ *px = origX
+
+ // Use "0 == 0" to do the right thing in the unlikely event
+ // that "true" is shadowed.
+ fmt.Fprintf(sbCheck, "_cgoCheckPointer(_cgoBase%d, 0 == 0); ", i)
+
+ return true
+}
+
+// isType reports whether the expression is definitely a type.
+// This is conservative--it returns false for an unknown identifier.
+func (p *Package) isType(t ast.Expr) bool {
+ switch t := t.(type) {
+ case *ast.SelectorExpr:
+ id, ok := t.X.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ if id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+ return true
+ }
+ if id.Name == "C" && typedef["_Ctype_"+t.Sel.Name] != nil {
+ return true
+ }
+ return false
+ case *ast.Ident:
+ // TODO: This ignores shadowing.
+ switch t.Name {
+ case "unsafe.Pointer", "bool", "byte",
+ "complex64", "complex128",
+ "error",
+ "float32", "float64",
+ "int", "int8", "int16", "int32", "int64",
+ "rune", "string",
+ "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
+
+ return true
+ }
+ if strings.HasPrefix(t.Name, "_Ctype_") {
+ return true
+ }
+ case *ast.ParenExpr:
+ return p.isType(t.X)
+ case *ast.StarExpr:
+ return p.isType(t.X)
+ case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,
+ *ast.MapType, *ast.ChanType:
+
+ return true
+ }
+ return false
+}
+
+// isVariable reports whether x is a variable, possibly with field references.
+func (p *Package) isVariable(x ast.Expr) bool {
+ switch x := x.(type) {
+ case *ast.Ident:
+ return true
+ case *ast.SelectorExpr:
+ return p.isVariable(x.X)
+ case *ast.IndexExpr:
+ return true
+ }
+ return false
+}
+
+// rewriteUnsafe returns a version of t with references to unsafe.Pointer
+// rewritten to use _cgo_unsafe.Pointer instead.
+func (p *Package) rewriteUnsafe(t ast.Expr) ast.Expr {
+ switch t := t.(type) {
+ case *ast.Ident:
+ // We don't see a SelectorExpr for unsafe.Pointer;
+ // this is created by code in this file.
+ if t.Name == "unsafe.Pointer" {
+ return ast.NewIdent("_cgo_unsafe.Pointer")
+ }
+ case *ast.ArrayType:
+ t1 := p.rewriteUnsafe(t.Elt)
+ if t1 != t.Elt {
+ r := *t
+ r.Elt = t1
+ return &r
+ }
+ case *ast.StructType:
+ changed := false
+ fields := *t.Fields
+ fields.List = nil
+ for _, f := range t.Fields.List {
+ ft := p.rewriteUnsafe(f.Type)
+ if ft == f.Type {
+ fields.List = append(fields.List, f)
+ } else {
+ fn := *f
+ fn.Type = ft
+ fields.List = append(fields.List, &fn)
+ changed = true
+ }
+ }
+ if changed {
+ r := *t
+ r.Fields = &fields
+ return &r
+ }
+ case *ast.StarExpr: // Pointer type.
+ x1 := p.rewriteUnsafe(t.X)
+ if x1 != t.X {
+ r := *t
+ r.X = x1
+ return &r
+ }
+ }
+ return t
+}
+
+// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
+// Go equivalents, now that we have figured out the meaning of all
+// the xxx. In *godefs mode, rewriteRef replaces the names
+// with full definitions instead of mangled names.
+func (p *Package) rewriteRef(f *File) {
+ // Keep a list of all the functions, to remove the ones
+ // only used as expressions and avoid generating bridge
+ // code for them.
+ functions := make(map[string]bool)
+
+ for _, n := range f.Name {
+ if n.Kind == "func" {
+ functions[n.Go] = false
+ }
+ }
+
+ // Now that we have all the name types filled in,
+ // scan through the Refs to identify the ones that
+ // are trying to do a ,err call. Also check that
+ // functions are only used in calls.
+ for _, r := range f.Ref {
+ if r.Name.IsConst() && r.Name.Const == "" {
+ error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go))
+ }
+
+ if r.Name.Kind == "func" {
+ switch r.Context {
+ case ctxCall, ctxCall2:
+ functions[r.Name.Go] = true
+ }
+ }
+
+ expr := p.rewriteName(f, r, false)
+
+ if *godefs {
+ // Substitute definition for mangled type name.
+ if r.Name.Type != nil && r.Name.Kind == "type" {
+ expr = r.Name.Type.Go
+ }
+ if id, ok := expr.(*ast.Ident); ok {
+ if t := typedef[id.Name]; t != nil {
+ expr = t.Go
+ }
+ if id.Name == r.Name.Mangle && r.Name.Const != "" {
+ expr = ast.NewIdent(r.Name.Const)
+ }
+ }
+ }
+
+ // Copy position information from old expr into new expr,
+ // in case expression being replaced is first on line.
+ // See golang.org/issue/6563.
+ pos := (*r.Expr).Pos()
+ if x, ok := expr.(*ast.Ident); ok {
+ expr = &ast.Ident{NamePos: pos, Name: x.Name}
+ }
+
+ // Change AST, because some later processing depends on it,
+ // and also because -godefs mode still prints the AST.
+ old := *r.Expr
+ *r.Expr = expr
+
+ // Record source-level edit for cgo output.
+ if !r.Done {
+ // Prepend a space in case the earlier code ends
+ // with '/', which would give us a "//" comment.
+ repl := " " + gofmtPos(expr, old.Pos())
+ end := fset.Position(old.End())
+ // Subtract 1 from the column if we are going to
+ // append a close parenthesis. That will set the
+ // correct column for the following characters.
+ sub := 0
+ if r.Name.Kind != "type" {
+ sub = 1
+ }
+ if end.Column > sub {
+ repl = fmt.Sprintf("%s /*line :%d:%d*/", repl, end.Line, end.Column-sub)
+ }
+ if r.Name.Kind != "type" {
+ repl = "(" + repl + ")"
+ }
+ f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), repl)
+ }
+ }
+
+ // Remove functions only used as expressions, so their respective
+ // bridge functions are not generated.
+ for name, used := range functions {
+ if !used {
+ delete(f.Name, name)
+ }
+ }
+}
+
+// rewriteName returns the expression used to rewrite a reference.
+// If addPosition is true, add position info in the ident name.
+func (p *Package) rewriteName(f *File, r *Ref, addPosition bool) ast.Expr {
+ getNewIdent := ast.NewIdent
+ if addPosition {
+ getNewIdent = func(newName string) *ast.Ident {
+ mangledIdent := ast.NewIdent(newName)
+ if len(newName) == len(r.Name.Go) {
+ return mangledIdent
+ }
+ p := fset.Position((*r.Expr).End())
+ if p.Column == 0 {
+ return mangledIdent
+ }
+ return ast.NewIdent(fmt.Sprintf("%s /*line :%d:%d*/", newName, p.Line, p.Column))
+ }
+ }
+ var expr ast.Expr = getNewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case ctxCall, ctxCall2:
+ if r.Name.Kind != "func" {
+ if r.Name.Kind == "type" {
+ r.Context = ctxType
+ if r.Name.Type == nil {
+ error_(r.Pos(), "invalid conversion to C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ }
+ break
+ }
+ error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go))
+ break
+ }
+ if r.Context == ctxCall2 {
+ if r.Name.Go == "_CMalloc" {
+ error_(r.Pos(), "no two-result form for C.malloc")
+ break
+ }
+ // Invent new Name for the two-result function.
+ n := f.Name["2"+r.Name.Go]
+ if n == nil {
+ n = new(Name)
+ *n = *r.Name
+ n.AddError = true
+ n.Mangle = "_C2func_" + n.Go
+ f.Name["2"+r.Name.Go] = n
+ }
+ expr = getNewIdent(n.Mangle)
+ r.Name = n
+ break
+ }
+ case ctxExpr:
+ switch r.Name.Kind {
+ case "func":
+ if builtinDefs[r.Name.C] != "" {
+ error_(r.Pos(), "use of builtin '%s' not in function call", fixGo(r.Name.C))
+ }
+
+ // Function is being used in an expression, to e.g. pass around a C function pointer.
+ // Create a new Name for this Ref which causes the variable to be declared in Go land.
+ fpName := "fp_" + r.Name.Go
+ name := f.Name[fpName]
+ if name == nil {
+ name = &Name{
+ Go: fpName,
+ C: r.Name.C,
+ Kind: "fpvar",
+ Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")},
+ }
+ p.mangleName(name)
+ f.Name[fpName] = name
+ }
+ r.Name = name
+ // Rewrite into call to _Cgo_ptr to prevent assignments. The _Cgo_ptr
+ // function is defined in out.go and simply returns its argument. See
+ // issue 7757.
+ expr = &ast.CallExpr{
+ Fun: &ast.Ident{NamePos: (*r.Expr).Pos(), Name: "_Cgo_ptr"},
+ Args: []ast.Expr{getNewIdent(name.Mangle)},
+ }
+ case "type":
+ // Okay - might be new(T), T(x), Generic[T], etc.
+ if r.Name.Type == nil {
+ error_(r.Pos(), "expression C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ }
+ case "var":
+ expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+ case "macro":
+ expr = &ast.CallExpr{Fun: expr}
+ }
+ case ctxSelector:
+ if r.Name.Kind == "var" {
+ expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+ } else {
+ error_(r.Pos(), "only C variables allowed in selector expression %s", fixGo(r.Name.Go))
+ }
+ case ctxType:
+ if r.Name.Kind != "type" {
+ error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
+ } else if r.Name.Type == nil {
+ // Use of C.enum_x, C.struct_x or C.union_x without C definition.
+ // GCC won't raise an error when using pointers to such unknown types.
+ error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C)
+ }
+ default:
+ if r.Name.Kind == "func" {
+ error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
+ }
+ }
+ return expr
+}
+
+// gofmtPos returns the gofmt-formatted string for an AST node,
+// with a comment setting the position before the node.
+func gofmtPos(n ast.Expr, pos token.Pos) string {
+ s := gofmtLine(n)
+ p := fset.Position(pos)
+ if p.Column == 0 {
+ return s
+ }
+ return fmt.Sprintf("/*line :%d:%d*/%s", p.Line, p.Column, s)
+}
+
+// checkGCCBaseCmd 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.
+//
+// The compiler command line is split into arguments on whitespace. Quotes
+// are understood, so arguments may contain whitespace.
+//
+// checkGCCBaseCmd confirms that the compiler exists in PATH, returning
+// an error if it does not.
+func checkGCCBaseCmd() ([]string, error) {
+ // Use $CC if set, since that's what the build uses.
+ value := os.Getenv("CC")
+ if value == "" {
+ // Try $GCC if set, since that's what we used to use.
+ value = os.Getenv("GCC")
+ }
+ if value == "" {
+ value = defaultCC(goos, goarch)
+ }
+ args, err := quoted.Split(value)
+ if err != nil {
+ return nil, err
+ }
+ if len(args) == 0 {
+ return nil, errors.New("CC not set and no default found")
+ }
+ if _, err := exec.LookPath(args[0]); err != nil {
+ return nil, fmt.Errorf("C compiler %q not found: %v", args[0], err)
+ }
+ return args[:len(args):len(args)], nil
+}
+
+// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm".
+func (p *Package) gccMachine() []string {
+ switch goarch {
+ case "amd64":
+ if goos == "darwin" {
+ return []string{"-arch", "x86_64", "-m64"}
+ }
+ return []string{"-m64"}
+ case "arm64":
+ if goos == "darwin" {
+ return []string{"-arch", "arm64"}
+ }
+ case "386":
+ return []string{"-m32"}
+ case "arm":
+ return []string{"-marm"} // not thumb
+ case "s390":
+ return []string{"-m31"}
+ case "s390x":
+ return []string{"-m64"}
+ case "mips64", "mips64le":
+ if gomips64 == "hardfloat" {
+ return []string{"-mabi=64", "-mhard-float"}
+ } else if gomips64 == "softfloat" {
+ return []string{"-mabi=64", "-msoft-float"}
+ }
+ case "mips", "mipsle":
+ if gomips == "hardfloat" {
+ return []string{"-mabi=32", "-mfp32", "-mhard-float", "-mno-odd-spreg"}
+ } else if gomips == "softfloat" {
+ return []string{"-mabi=32", "-msoft-float"}
+ }
+ case "loong64":
+ return []string{"-mabi=lp64d"}
+ }
+ 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(gccBaseCmd,
+ "-w", // no warnings
+ "-Wno-error", // warnings are not errors
+ "-o"+gccTmp(), // write object to tmp
+ "-gdwarf-2", // generate DWARF v2 debugging symbols
+ "-c", // do not link
+ "-xc", // input language is C
+ )
+ if p.GccIsClang {
+ c = append(c,
+ "-ferror-limit=0",
+ // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
+ // doesn't have -Wno-unneeded-internal-declaration, so we need yet another
+ // flag to disable the warning. Yes, really good diagnostics, clang.
+ "-Wno-unknown-warning-option",
+ "-Wno-unneeded-internal-declaration",
+ "-Wno-unused-function",
+ "-Qunused-arguments",
+ // Clang embeds prototypes for some builtin functions,
+ // like malloc and calloc, but all size_t parameters are
+ // incorrectly typed unsigned long. We work around that
+ // by disabling the builtin functions (this is safe as
+ // it won't affect the actual compilation of the C code).
+ // See: https://golang.org/issue/6506.
+ "-fno-builtin",
+ )
+ }
+
+ c = append(c, p.GccOptions...)
+ c = append(c, p.gccMachine()...)
+ if goos == "aix" {
+ c = append(c, "-maix64")
+ c = append(c, "-mcmodel=large")
+ }
+ // disable LTO so we get an object whose symbols we can read
+ c = append(c, "-fno-lto")
+ c = append(c, "-") //read input from standard input
+ return c
+}
+
+// gccDebug runs gcc -gdwarf-2 over the C program stdin and
+// returns the corresponding DWARF data and, if present, debug data block.
+func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int64, floats []float64, strs []string) {
+ runGcc(stdin, p.gccCmd())
+
+ isDebugInts := func(s string) bool {
+ // Some systems use leading _ to denote non-assembly symbols.
+ return s == "__cgodebug_ints" || s == "___cgodebug_ints"
+ }
+ isDebugFloats := func(s string) bool {
+ // Some systems use leading _ to denote non-assembly symbols.
+ return s == "__cgodebug_floats" || s == "___cgodebug_floats"
+ }
+ indexOfDebugStr := func(s string) int {
+ // Some systems use leading _ to denote non-assembly symbols.
+ if strings.HasPrefix(s, "___") {
+ s = s[1:]
+ }
+ if strings.HasPrefix(s, "__cgodebug_str__") {
+ if n, err := strconv.Atoi(s[len("__cgodebug_str__"):]); err == nil {
+ return n
+ }
+ }
+ return -1
+ }
+ indexOfDebugStrlen := func(s string) int {
+ // Some systems use leading _ to denote non-assembly symbols.
+ if strings.HasPrefix(s, "___") {
+ s = s[1:]
+ }
+ if strings.HasPrefix(s, "__cgodebug_strlen__") {
+ if n, err := strconv.Atoi(s[len("__cgodebug_strlen__"):]); err == nil {
+ return n
+ }
+ }
+ return -1
+ }
+
+ strs = make([]string, nnames)
+
+ strdata := make(map[int]string, nnames)
+ strlens := make(map[int]int, nnames)
+
+ buildStrings := func() {
+ for n, strlen := range strlens {
+ data := strdata[n]
+ if len(data) <= strlen {
+ fatalf("invalid string literal")
+ }
+ strs[n] = data[:strlen]
+ }
+ }
+
+ if f, err := macho.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ bo := f.ByteOrder
+ if f.Symtab != nil {
+ for i := range f.Symtab.Syms {
+ s := &f.Symtab.Syms[i]
+ switch {
+ case isDebugInts(s.Name):
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value-sect.Addr:]
+ ints = make([]int64, len(data)/8)
+ for i := range ints {
+ ints[i] = int64(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ case isDebugFloats(s.Name):
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value-sect.Addr:]
+ floats = make([]float64, len(data)/8)
+ for i := range floats {
+ floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ default:
+ if n := indexOfDebugStr(s.Name); n != -1 {
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value-sect.Addr:]
+ strdata[n] = string(data)
+ }
+ }
+ }
+ break
+ }
+ if n := indexOfDebugStrlen(s.Name); n != -1 {
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value-sect.Addr:]
+ strlen := bo.Uint64(data[:8])
+ if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+ fatalf("string literal too big")
+ }
+ strlens[n] = int(strlen)
+ }
+ }
+ }
+ break
+ }
+ }
+ }
+
+ buildStrings()
+ }
+ return d, ints, floats, strs
+ }
+
+ if f, err := elf.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ bo := f.ByteOrder
+ symtab, err := f.Symbols()
+ if err == nil {
+ // Check for use of -fsanitize=hwaddress (issue 53285).
+ removeTag := func(v uint64) uint64 { return v }
+ if goarch == "arm64" {
+ for i := range symtab {
+ if symtab[i].Name == "__hwasan_init" {
+ // -fsanitize=hwaddress on ARM
+ // uses the upper byte of a
+ // memory address as a hardware
+ // tag. Remove it so that
+ // we can find the associated
+ // data.
+ removeTag = func(v uint64) uint64 { return v &^ (0xff << (64 - 8)) }
+ break
+ }
+ }
+ }
+
+ for i := range symtab {
+ s := &symtab[i]
+ switch {
+ case isDebugInts(s.Name):
+ // Found it. Now find data section.
+ if i := int(s.Section); 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ val := removeTag(s.Value)
+ if sect.Addr <= val && val < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[val-sect.Addr:]
+ ints = make([]int64, len(data)/8)
+ for i := range ints {
+ ints[i] = int64(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ case isDebugFloats(s.Name):
+ // Found it. Now find data section.
+ if i := int(s.Section); 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ val := removeTag(s.Value)
+ if sect.Addr <= val && val < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[val-sect.Addr:]
+ floats = make([]float64, len(data)/8)
+ for i := range floats {
+ floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ default:
+ if n := indexOfDebugStr(s.Name); n != -1 {
+ // Found it. Now find data section.
+ if i := int(s.Section); 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ val := removeTag(s.Value)
+ if sect.Addr <= val && val < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[val-sect.Addr:]
+ strdata[n] = string(data)
+ }
+ }
+ }
+ break
+ }
+ if n := indexOfDebugStrlen(s.Name); n != -1 {
+ // Found it. Now find data section.
+ if i := int(s.Section); 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ val := removeTag(s.Value)
+ if sect.Addr <= val && val < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[val-sect.Addr:]
+ strlen := bo.Uint64(data[:8])
+ if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+ fatalf("string literal too big")
+ }
+ strlens[n] = int(strlen)
+ }
+ }
+ }
+ break
+ }
+ }
+ }
+
+ buildStrings()
+ }
+ return d, ints, floats, strs
+ }
+
+ if f, err := pe.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ bo := binary.LittleEndian
+ for _, s := range f.Symbols {
+ switch {
+ case isDebugInts(s.Name):
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ ints = make([]int64, len(data)/8)
+ for i := range ints {
+ ints[i] = int64(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ case isDebugFloats(s.Name):
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ floats = make([]float64, len(data)/8)
+ for i := range floats {
+ floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ default:
+ if n := indexOfDebugStr(s.Name); n != -1 {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ strdata[n] = string(data)
+ }
+ }
+ }
+ break
+ }
+ if n := indexOfDebugStrlen(s.Name); n != -1 {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ strlen := bo.Uint64(data[:8])
+ if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+ fatalf("string literal too big")
+ }
+ strlens[n] = int(strlen)
+ }
+ }
+ }
+ break
+ }
+ }
+ }
+
+ buildStrings()
+
+ return d, ints, floats, strs
+ }
+
+ if f, err := xcoff.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ bo := binary.BigEndian
+ for _, s := range f.Symbols {
+ switch {
+ case isDebugInts(s.Name):
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ ints = make([]int64, len(data)/8)
+ for i := range ints {
+ ints[i] = int64(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ case isDebugFloats(s.Name):
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ floats = make([]float64, len(data)/8)
+ for i := range floats {
+ floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ default:
+ if n := indexOfDebugStr(s.Name); n != -1 {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ strdata[n] = string(data)
+ }
+ }
+ }
+ break
+ }
+ if n := indexOfDebugStrlen(s.Name); n != -1 {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ strlen := bo.Uint64(data[:8])
+ if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+ fatalf("string literal too big")
+ }
+ strlens[n] = int(strlen)
+ }
+ }
+ }
+ break
+ }
+ }
+ }
+
+ buildStrings()
+ return d, ints, floats, strs
+ }
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
+ panic("not reached")
+}
+
+// gccDefines runs gcc -E -dM -xc - over the C program stdin
+// and returns the corresponding standard output, which is the
+// #defines that gcc encountered while processing the input
+// and its included files.
+func (p *Package) gccDefines(stdin []byte) string {
+ base := append(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, extraArgs ...string) string {
+ // TODO(rsc): require failure
+ args := p.gccCmd()
+
+ // Optimization options can confuse the error messages; remove them.
+ nargs := make([]string, 0, len(args)+len(extraArgs))
+ for _, arg := range args {
+ if !strings.HasPrefix(arg, "-O") {
+ nargs = append(nargs, arg)
+ }
+ }
+
+ // Force -O0 optimization and append extra arguments, but keep the
+ // trailing "-" at the end.
+ li := len(nargs) - 1
+ last := nargs[li]
+ nargs[li] = "-O0"
+ nargs = append(nargs, extraArgs...)
+ nargs = append(nargs, last)
+
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(nargs, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, _ := run(stdin, nargs)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
+ }
+ return string(stderr)
+}
+
+// runGcc runs the gcc command line args with stdin on standard input.
+// If the command exits with a non-zero exit status, runGcc prints
+// details about what was run and exits.
+// Otherwise runGcc returns the data written to standard output and standard error.
+// Note that for some of the uses we expect useful data back
+// on standard error, but for those uses gcc must still exit 0.
+func runGcc(stdin []byte, args []string) (string, string) {
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, ok := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
+ }
+ if !ok {
+ os.Stderr.Write(stderr)
+ os.Exit(2)
+ }
+ return string(stdout), string(stderr)
+}
+
+// A typeConv is a translator from dwarf types to Go types
+// with equivalent memory layout.
+type typeConv struct {
+ // Cache of already-translated or in-progress types.
+ m map[string]*Type
+
+ // Map from types to incomplete pointers to those types.
+ ptrs map[string][]*Type
+ // Keys of ptrs in insertion order (deterministic worklist)
+ // ptrKeys contains exactly the keys in ptrs.
+ ptrKeys []dwarf.Type
+
+ // Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
+ getTypeIDs map[string]bool
+
+ // incompleteStructs contains C structs that should be marked Incomplete.
+ incompleteStructs map[string]bool
+
+ // Predeclared types.
+ bool ast.Expr
+ byte ast.Expr // denotes padding
+ int8, int16, int32, int64 ast.Expr
+ uint8, uint16, uint32, uint64, uintptr ast.Expr
+ float32, float64 ast.Expr
+ complex64, complex128 ast.Expr
+ void ast.Expr
+ string ast.Expr
+ goVoid ast.Expr // _Ctype_void, denotes C's void
+ goVoidPtr ast.Expr // unsafe.Pointer or *byte
+
+ ptrSize int64
+ intSize int64
+}
+
+var tagGen int
+var typedef = make(map[string]*Type)
+var goIdent = make(map[string]*ast.Ident)
+
+// unionWithPointer is true for a Go type that represents a C union (or class)
+// that may contain a pointer. This is used for cgo pointer checking.
+var unionWithPointer = make(map[ast.Expr]bool)
+
+// anonymousStructTag provides a consistent tag for an anonymous struct.
+// The same dwarf.StructType pointer will always get the same tag.
+var anonymousStructTag = make(map[*dwarf.StructType]string)
+
+func (c *typeConv) Init(ptrSize, intSize int64) {
+ c.ptrSize = ptrSize
+ c.intSize = intSize
+ c.m = make(map[string]*Type)
+ c.ptrs = make(map[string][]*Type)
+ c.getTypeIDs = make(map[string]bool)
+ c.incompleteStructs = make(map[string]bool)
+ c.bool = c.Ident("bool")
+ c.byte = c.Ident("byte")
+ c.int8 = c.Ident("int8")
+ c.int16 = c.Ident("int16")
+ c.int32 = c.Ident("int32")
+ c.int64 = c.Ident("int64")
+ c.uint8 = c.Ident("uint8")
+ c.uint16 = c.Ident("uint16")
+ c.uint32 = c.Ident("uint32")
+ c.uint64 = c.Ident("uint64")
+ c.uintptr = c.Ident("uintptr")
+ c.float32 = c.Ident("float32")
+ c.float64 = c.Ident("float64")
+ c.complex64 = c.Ident("complex64")
+ c.complex128 = c.Ident("complex128")
+ c.void = c.Ident("void")
+ c.string = c.Ident("string")
+ c.goVoid = c.Ident("_Ctype_void")
+
+ // Normally cgo translates void* to unsafe.Pointer,
+ // but for historical reasons -godefs uses *byte instead.
+ if *godefs {
+ c.goVoidPtr = &ast.StarExpr{X: c.byte}
+ } else {
+ c.goVoidPtr = c.Ident("unsafe.Pointer")
+ }
+}
+
+// base strips away qualifiers and typedefs to get the underlying type.
+func base(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ continue
+ }
+ if d, ok := dt.(*dwarf.TypedefType); ok {
+ dt = d.Type
+ continue
+ }
+ break
+ }
+ return dt
+}
+
+// unqual strips away qualifiers from a DWARF type.
+// In general we don't care about top-level qualifiers.
+func unqual(dt dwarf.Type) dwarf.Type {
+ for {
+ if d, ok := dt.(*dwarf.QualType); ok {
+ dt = d.Type
+ } else {
+ break
+ }
+ }
+ return dt
+}
+
+// Map from dwarf text names to aliases we use in package "C".
+var dwarfToName = map[string]string{
+ "long int": "long",
+ "long unsigned int": "ulong",
+ "unsigned int": "uint",
+ "short unsigned int": "ushort",
+ "unsigned short": "ushort", // Used by Clang; issue 13129.
+ "short int": "short",
+ "long long int": "longlong",
+ "long long unsigned int": "ulonglong",
+ "signed char": "schar",
+ "unsigned char": "uchar",
+ "unsigned long": "ulong", // Used by Clang 14; issue 53013.
+ "unsigned long long": "ulonglong", // Used by Clang 14; issue 53013.
+}
+
+const signedDelta = 64
+
+// String returns the current type representation. Format arguments
+// are assembled within this method so that any changes in mutable
+// values are taken into account.
+func (tr *TypeRepr) String() string {
+ if len(tr.Repr) == 0 {
+ return ""
+ }
+ if len(tr.FormatArgs) == 0 {
+ return tr.Repr
+ }
+ return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
+}
+
+// Empty reports whether the result of String would be "".
+func (tr *TypeRepr) Empty() bool {
+ return len(tr.Repr) == 0
+}
+
+// Set modifies the type representation.
+// If fargs are provided, repr is used as a format for fmt.Sprintf.
+// Otherwise, repr is used unprocessed as the type representation.
+func (tr *TypeRepr) Set(repr string, fargs ...interface{}) {
+ tr.Repr = repr
+ tr.FormatArgs = fargs
+}
+
+// FinishType completes any outstanding type mapping work.
+// In particular, it resolves incomplete pointer types.
+func (c *typeConv) FinishType(pos token.Pos) {
+ // Completing one pointer type might produce more to complete.
+ // Keep looping until they're all done.
+ for len(c.ptrKeys) > 0 {
+ dtype := c.ptrKeys[0]
+ dtypeKey := dtype.String()
+ c.ptrKeys = c.ptrKeys[1:]
+ ptrs := c.ptrs[dtypeKey]
+ delete(c.ptrs, dtypeKey)
+
+ // Note Type might invalidate c.ptrs[dtypeKey].
+ t := c.Type(dtype, pos)
+ for _, ptr := range ptrs {
+ ptr.Go.(*ast.StarExpr).X = t.Go
+ ptr.C.Set("%s*", t.C)
+ }
+ }
+}
+
+// Type returns a *Type with the same memory layout as
+// dtype when used as the type of a variable or a struct field.
+func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
+ return c.loadType(dtype, pos, "")
+}
+
+// loadType recursively loads the requested dtype and its dependency graph.
+func (c *typeConv) loadType(dtype dwarf.Type, pos token.Pos, parent string) *Type {
+ // Always recompute bad pointer typedefs, as the set of such
+ // typedefs changes as we see more types.
+ checkCache := true
+ if dtt, ok := dtype.(*dwarf.TypedefType); ok && c.badPointerTypedef(dtt) {
+ checkCache = false
+ }
+
+ // The cache key should be relative to its parent.
+ // See issue https://golang.org/issue/31891
+ key := parent + " > " + dtype.String()
+
+ if checkCache {
+ if t, ok := c.m[key]; ok {
+ if t.Go == nil {
+ fatalf("%s: type conversion loop at %s", lineno(pos), dtype)
+ }
+ return t
+ }
+ }
+
+ t := new(Type)
+ t.Size = dtype.Size() // note: wrong for array of pointers, corrected below
+ t.Align = -1
+ t.C = &TypeRepr{Repr: dtype.Common().Name}
+ c.m[key] = t
+
+ switch dt := dtype.(type) {
+ default:
+ fatalf("%s: unexpected type: %s", lineno(pos), dtype)
+
+ case *dwarf.AddrType:
+ if t.Size != c.ptrSize {
+ fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Go = c.uintptr
+ t.Align = t.Size
+
+ case *dwarf.ArrayType:
+ if dt.StrideBitSize > 0 {
+ // Cannot represent bit-sized elements in Go.
+ t.Go = c.Opaque(t.Size)
+ break
+ }
+ count := dt.Count
+ if count == -1 {
+ // Indicates flexible array member, which Go doesn't support.
+ // Translate to zero-length array instead.
+ count = 0
+ }
+ sub := c.Type(dt.Type, pos)
+ t.Align = sub.Align
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(count),
+ Elt: sub.Go,
+ }
+ // Recalculate t.Size now that we know sub.Size.
+ t.Size = count * sub.Size
+ t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count)
+
+ case *dwarf.BoolType:
+ t.Go = c.bool
+ t.Align = 1
+
+ case *dwarf.CharType:
+ if t.Size != 1 {
+ fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Go = c.int8
+ t.Align = 1
+
+ case *dwarf.EnumType:
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+ t.C.Set("enum " + dt.EnumName)
+ signed := 0
+ t.EnumValues = make(map[string]int64)
+ for _, ev := range dt.Val {
+ t.EnumValues[ev.Name] = ev.Val
+ if ev.Val < 0 {
+ signed = signedDelta
+ }
+ }
+ switch t.Size + int64(signed) {
+ default:
+ fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype)
+ case 1:
+ t.Go = c.uint8
+ case 2:
+ t.Go = c.uint16
+ case 4:
+ t.Go = c.uint32
+ case 8:
+ t.Go = c.uint64
+ case 1 + signedDelta:
+ t.Go = c.int8
+ case 2 + signedDelta:
+ t.Go = c.int16
+ case 4 + signedDelta:
+ t.Go = c.int32
+ case 8 + signedDelta:
+ t.Go = c.int64
+ }
+
+ case *dwarf.FloatType:
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype)
+ case 4:
+ t.Go = c.float32
+ case 8:
+ t.Go = c.float64
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.ComplexType:
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype)
+ case 8:
+ t.Go = c.complex64
+ case 16:
+ t.Go = c.complex128
+ }
+ if t.Align = t.Size / 2; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.FuncType:
+ // No attempt at translation: would enable calls
+ // directly between worlds, but we need to moderate those.
+ t.Go = c.uintptr
+ t.Align = c.ptrSize
+
+ case *dwarf.IntType:
+ if dt.BitSize > 0 {
+ fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype)
+ }
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype)
+ case 1:
+ t.Go = c.int8
+ case 2:
+ t.Go = c.int16
+ case 4:
+ t.Go = c.int32
+ case 8:
+ t.Go = c.int64
+ case 16:
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(t.Size),
+ Elt: c.uint8,
+ }
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.PtrType:
+ // Clang doesn't emit DW_AT_byte_size for pointer types.
+ if t.Size != c.ptrSize && t.Size != -1 {
+ fatalf("%s: unexpected: %d-byte pointer type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Size = c.ptrSize
+ t.Align = c.ptrSize
+
+ if _, ok := base(dt.Type).(*dwarf.VoidType); ok {
+ t.Go = c.goVoidPtr
+ t.C.Set("void*")
+ dq := dt.Type
+ for {
+ if d, ok := dq.(*dwarf.QualType); ok {
+ t.C.Set(d.Qual + " " + t.C.String())
+ dq = d.Type
+ } else {
+ break
+ }
+ }
+ break
+ }
+
+ // Placeholder initialization; completed in FinishType.
+ t.Go = &ast.StarExpr{}
+ t.C.Set("<incomplete>*")
+ key := dt.Type.String()
+ if _, ok := c.ptrs[key]; !ok {
+ c.ptrKeys = append(c.ptrKeys, dt.Type)
+ }
+ c.ptrs[key] = append(c.ptrs[key], t)
+
+ case *dwarf.QualType:
+ t1 := c.Type(dt.Type, pos)
+ t.Size = t1.Size
+ t.Align = t1.Align
+ t.Go = t1.Go
+ if unionWithPointer[t1.Go] {
+ unionWithPointer[t.Go] = true
+ }
+ t.EnumValues = nil
+ t.Typedef = ""
+ t.C.Set("%s "+dt.Qual, t1.C)
+ return t
+
+ case *dwarf.StructType:
+ // Convert to Go struct, being careful about alignment.
+ // Have to give it a name to simulate C "struct foo" references.
+ tag := dt.StructName
+ if dt.ByteSize < 0 && tag == "" { // opaque unnamed struct - should not be possible
+ break
+ }
+ if tag == "" {
+ tag = anonymousStructTag[dt]
+ if tag == "" {
+ tag = "__" + strconv.Itoa(tagGen)
+ tagGen++
+ anonymousStructTag[dt] = tag
+ }
+ } 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 {
+ // Don't override old type
+ if _, ok := typedef[name.Name]; ok {
+ break
+ }
+
+ // 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}}
+ // We don't know what the representation of this struct is, so don't let
+ // anyone allocate one on the Go side. As a side effect of this annotation,
+ // pointers to this type will not be considered pointers in Go. They won't
+ // get writebarrier-ed or adjusted during a stack copy. This should handle
+ // all the cases badPointerTypedef used to handle, but hopefully will
+ // continue to work going forward without any more need for cgo changes.
+ tt.Go = c.Ident(incomplete)
+ typedef[name.Name] = &tt
+ break
+ }
+ switch dt.Kind {
+ case "class", "union":
+ t.Go = c.Opaque(t.Size)
+ if c.dwarfHasPointer(dt, pos) {
+ unionWithPointer[t.Go] = true
+ }
+ if t.C.Empty() {
+ t.C.Set("__typeof__(unsigned char[%d])", t.Size)
+ }
+ t.Align = 1 // TODO: should probably base this on field alignment.
+ typedef[name.Name] = t
+ case "struct":
+ g, csyntax, align := c.Struct(dt, pos)
+ if t.C.Empty() {
+ t.C.Set(csyntax)
+ }
+ t.Align = align
+ tt := *t
+ if tag != "" {
+ tt.C = &TypeRepr{"struct %s", []interface{}{tag}}
+ }
+ tt.Go = g
+ if c.incompleteStructs[tag] {
+ tt.Go = c.Ident(incomplete)
+ }
+ typedef[name.Name] = &tt
+ }
+
+ case *dwarf.TypedefType:
+ // Record typedef for printing.
+ if dt.Name == "_GoString_" {
+ // Special C name for Go string type.
+ // Knows string layout used by compilers: pointer plus length,
+ // which rounds up to 2 pointers after alignment.
+ t.Go = c.string
+ t.Size = c.ptrSize * 2
+ t.Align = c.ptrSize
+ break
+ }
+ if dt.Name == "_GoBytes_" {
+ // Special C name for Go []byte type.
+ // Knows slice layout used by compilers: pointer, length, cap.
+ t.Go = c.Ident("[]byte")
+ t.Size = c.ptrSize + 4 + 4
+ t.Align = c.ptrSize
+ break
+ }
+ name := c.Ident("_Ctype_" + dt.Name)
+ goIdent[name.Name] = name
+ akey := ""
+ if c.anonymousStructTypedef(dt) {
+ // only load type recursively for typedefs of anonymous
+ // structs, see issues 37479 and 37621.
+ akey = key
+ }
+ sub := c.loadType(dt.Type, pos, akey)
+ if c.badPointerTypedef(dt) {
+ // Treat this typedef as a uintptr.
+ s := *sub
+ s.Go = c.uintptr
+ s.BadPointer = true
+ sub = &s
+ // Make sure we update any previously computed type.
+ if oldType := typedef[name.Name]; oldType != nil {
+ oldType.Go = sub.Go
+ oldType.BadPointer = true
+ }
+ }
+ if c.badVoidPointerTypedef(dt) {
+ // Treat this typedef as a pointer to a _cgopackage.Incomplete.
+ s := *sub
+ s.Go = c.Ident("*" + incomplete)
+ sub = &s
+ // Make sure we update any previously computed type.
+ if oldType := typedef[name.Name]; oldType != nil {
+ oldType.Go = sub.Go
+ }
+ }
+ // Check for non-pointer "struct <tag>{...}; typedef struct <tag> *<name>"
+ // typedefs that should be marked Incomplete.
+ if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
+ if strct, ok := ptr.Type.(*dwarf.StructType); ok {
+ if c.badStructPointerTypedef(dt.Name, strct) {
+ c.incompleteStructs[strct.StructName] = true
+ // Make sure we update any previously computed type.
+ name := "_Ctype_struct_" + strct.StructName
+ if oldType := typedef[name]; oldType != nil {
+ oldType.Go = c.Ident(incomplete)
+ }
+ }
+ }
+ }
+ t.Go = name
+ t.BadPointer = sub.BadPointer
+ if unionWithPointer[sub.Go] {
+ unionWithPointer[t.Go] = true
+ }
+ t.Size = sub.Size
+ t.Align = sub.Align
+ oldType := typedef[name.Name]
+ if oldType == nil {
+ tt := *t
+ tt.Go = sub.Go
+ tt.BadPointer = sub.BadPointer
+ typedef[name.Name] = &tt
+ }
+
+ // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
+ // use that as the Go form for this typedef too, so that the typedef will be interchangeable
+ // with the base type.
+ // In -godefs mode, do this for all typedefs.
+ if isStructUnionClass(sub.Go) || *godefs {
+ t.Go = sub.Go
+
+ if isStructUnionClass(sub.Go) {
+ // Use the typedef name for C code.
+ typedef[sub.Go.(*ast.Ident).Name].C = t.C
+ }
+
+ // If we've seen this typedef before, and it
+ // was an anonymous struct/union/class before
+ // too, use the old definition.
+ // TODO: it would be safer to only do this if
+ // we verify that the types are the same.
+ if oldType != nil && isStructUnionClass(oldType.Go) {
+ t.Go = oldType.Go
+ }
+ }
+
+ case *dwarf.UcharType:
+ if t.Size != 1 {
+ fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype)
+ }
+ t.Go = c.uint8
+ t.Align = 1
+
+ case *dwarf.UintType:
+ if dt.BitSize > 0 {
+ fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype)
+ }
+ switch t.Size {
+ default:
+ fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype)
+ case 1:
+ t.Go = c.uint8
+ case 2:
+ t.Go = c.uint16
+ case 4:
+ t.Go = c.uint32
+ case 8:
+ t.Go = c.uint64
+ case 16:
+ t.Go = &ast.ArrayType{
+ Len: c.intExpr(t.Size),
+ Elt: c.uint8,
+ }
+ }
+ if t.Align = t.Size; t.Align >= c.ptrSize {
+ t.Align = c.ptrSize
+ }
+
+ case *dwarf.VoidType:
+ t.Go = c.goVoid
+ t.C.Set("void")
+ t.Align = 1
+ }
+
+ switch dtype.(type) {
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.ComplexType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
+ s := dtype.Common().Name
+ if s != "" {
+ if ss, ok := dwarfToName[s]; ok {
+ s = ss
+ }
+ s = strings.Replace(s, " ", "", -1)
+ name := c.Ident("_Ctype_" + s)
+ tt := *t
+ typedef[name.Name] = &tt
+ if !*godefs {
+ t.Go = name
+ }
+ }
+ }
+
+ if t.Size < 0 {
+ // Unsized types are [0]byte, unless they're typedefs of other types
+ // or structs with tags.
+ // if so, use the name we've already defined.
+ t.Size = 0
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ // ok
+ case *dwarf.StructType:
+ if dt.StructName != "" {
+ break
+ }
+ t.Go = c.Opaque(0)
+ default:
+ t.Go = c.Opaque(0)
+ }
+ if t.C.Empty() {
+ t.C.Set("void")
+ }
+ }
+
+ if t.C.Empty() {
+ fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype)
+ }
+
+ return t
+}
+
+// isStructUnionClass reports whether the type described by the Go syntax x
+// is a struct, union, or class with a tag.
+func isStructUnionClass(x ast.Expr) bool {
+ id, ok := x.(*ast.Ident)
+ if !ok {
+ return false
+ }
+ name := id.Name
+ return strings.HasPrefix(name, "_Ctype_struct_") ||
+ strings.HasPrefix(name, "_Ctype_union_") ||
+ strings.HasPrefix(name, "_Ctype_class_")
+}
+
+// FuncArg returns a Go type with the same memory layout as
+// dtype when used as the type of a C function argument.
+func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
+ t := c.Type(unqual(dtype), pos)
+ switch dt := dtype.(type) {
+ case *dwarf.ArrayType:
+ // Arrays are passed implicitly as pointers in C.
+ // In Go, we must be explicit.
+ tr := &TypeRepr{}
+ tr.Set("%s*", t.C)
+ return &Type{
+ Size: c.ptrSize,
+ Align: c.ptrSize,
+ Go: &ast.StarExpr{X: t.Go},
+ C: tr,
+ }
+ case *dwarf.TypedefType:
+ // C has much more relaxed rules than Go for
+ // implicit type conversions. When the parameter
+ // is type T defined as *X, simulate a little of the
+ // laxness of C by making the argument *X instead of T.
+ if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok {
+ // Unless the typedef happens to point to void* since
+ // Go has special rules around using unsafe.Pointer.
+ if _, void := base(ptr.Type).(*dwarf.VoidType); void {
+ break
+ }
+ // ...or the typedef is one in which we expect bad pointers.
+ // It will be a uintptr instead of *X.
+ if c.baseBadPointerTypedef(dt) {
+ break
+ }
+
+ t = c.Type(ptr, pos)
+ if t == nil {
+ return nil
+ }
+
+ // For a struct/union/class, remember the C spelling,
+ // in case it has __attribute__((unavailable)).
+ // See issue 2888.
+ if isStructUnionClass(t.Go) {
+ t.Typedef = dt.Name
+ }
+ }
+ }
+ return t
+}
+
+// FuncType returns the Go type analogous to dtype.
+// There is no guarantee about matching memory layout.
+func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType {
+ p := make([]*Type, len(dtype.ParamType))
+ gp := make([]*ast.Field, len(dtype.ParamType))
+ for i, f := range dtype.ParamType {
+ // gcc's DWARF generator outputs a single DotDotDotType parameter for
+ // function pointers that specify no parameters (e.g. void
+ // (*__cgo_0)()). Treat this special case as void. This case is
+ // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not
+ // legal).
+ if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 {
+ p, gp = nil, nil
+ break
+ }
+ p[i] = c.FuncArg(f, pos)
+ gp[i] = &ast.Field{Type: p[i].Go}
+ }
+ var r *Type
+ var gr []*ast.Field
+ if _, ok := base(dtype.ReturnType).(*dwarf.VoidType); ok {
+ gr = []*ast.Field{{Type: c.goVoid}}
+ } else if dtype.ReturnType != nil {
+ r = c.Type(unqual(dtype.ReturnType), pos)
+ gr = []*ast.Field{{Type: r.Go}}
+ }
+ return &FuncType{
+ Params: p,
+ Result: r,
+ Go: &ast.FuncType{
+ Params: &ast.FieldList{List: gp},
+ Results: &ast.FieldList{List: gr},
+ },
+ }
+}
+
+// Identifier
+func (c *typeConv) Ident(s string) *ast.Ident {
+ return ast.NewIdent(s)
+}
+
+// Opaque type of n bytes.
+func (c *typeConv) Opaque(n int64) ast.Expr {
+ return &ast.ArrayType{
+ Len: c.intExpr(n),
+ Elt: c.byte,
+ }
+}
+
+// Expr for integer n.
+func (c *typeConv) intExpr(n int64) ast.Expr {
+ return &ast.BasicLit{
+ Kind: token.INT,
+ Value: strconv.FormatInt(n, 10),
+ }
+}
+
+// Add padding of given size to fld.
+func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
+ n := len(fld)
+ fld = fld[0 : n+1]
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
+ sizes = sizes[0 : n+1]
+ sizes[n] = size
+ return fld, sizes
+}
+
+// Struct conversion: return Go and (gc) C syntax for type.
+func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
+ // Minimum alignment for a struct is 1 byte.
+ align = 1
+
+ var buf strings.Builder
+ buf.WriteString("struct {")
+ fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
+ sizes := make([]int64, 0, 2*len(dt.Field)+1)
+ off := int64(0)
+
+ // Rename struct fields that happen to be named Go keywords into
+ // _{keyword}. Create a map from C ident -> Go ident. The Go ident will
+ // be mangled. Any existing identifier that already has the same name on
+ // the C-side will cause the Go-mangled version to be prefixed with _.
+ // (e.g. in a struct with fields '_type' and 'type', the latter would be
+ // rendered as '__type' in Go).
+ ident := make(map[string]string)
+ used := make(map[string]bool)
+ for _, f := range dt.Field {
+ ident[f.Name] = f.Name
+ used[f.Name] = true
+ }
+
+ if !*godefs {
+ for cid, goid := range ident {
+ if token.Lookup(goid).IsKeyword() {
+ // Avoid keyword
+ goid = "_" + goid
+
+ // Also avoid existing fields
+ for _, exist := used[goid]; exist; _, exist = used[goid] {
+ goid = "_" + goid
+ }
+
+ used[goid] = true
+ ident[cid] = goid
+ }
+ }
+ }
+
+ anon := 0
+ for _, f := range dt.Field {
+ name := f.Name
+ ft := f.Type
+
+ // In godefs mode, if this field is a C11
+ // anonymous union then treat the first field in the
+ // union as the field in the struct. This handles
+ // cases like the glibc <sys/resource.h> file; see
+ // issue 6677.
+ if *godefs {
+ if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
+ name = st.Field[0].Name
+ ident[name] = name
+ ft = st.Field[0].Type
+ }
+ }
+
+ // TODO: Handle fields that are anonymous structs by
+ // promoting the fields of the inner struct.
+
+ t := c.Type(ft, pos)
+ tgo := t.Go
+ size := t.Size
+ talign := t.Align
+ if f.BitOffset > 0 || f.BitSize > 0 {
+ // The layout of bitfields is implementation defined,
+ // so we don't know how they correspond to Go fields
+ // even if they are aligned at byte boundaries.
+ continue
+ }
+
+ if talign > 0 && f.ByteOffset%talign != 0 {
+ // Drop misaligned fields, the same way we drop integer bit fields.
+ // The goal is to make available what can be made available.
+ // Otherwise one bad and unneeded field in an otherwise okay struct
+ // makes the whole program not compile. Much of the time these
+ // structs are in system headers that cannot be corrected.
+ continue
+ }
+
+ // Round off up to talign, assumed to be a power of 2.
+ off = (off + talign - 1) &^ (talign - 1)
+
+ if f.ByteOffset > off {
+ fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
+ off = f.ByteOffset
+ }
+ if f.ByteOffset < off {
+ // Drop a packed field that we can't represent.
+ continue
+ }
+
+ n := len(fld)
+ fld = fld[0 : n+1]
+ if name == "" {
+ name = fmt.Sprintf("anon%d", anon)
+ anon++
+ ident[name] = name
+ }
+ fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
+ sizes = sizes[0 : n+1]
+ sizes[n] = size
+ off += size
+ buf.WriteString(t.C.String())
+ buf.WriteString(" ")
+ buf.WriteString(name)
+ buf.WriteString("; ")
+ if talign > align {
+ align = talign
+ }
+ }
+ if off < dt.ByteSize {
+ fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
+ off = dt.ByteSize
+ }
+
+ // If the last field in a non-zero-sized struct is zero-sized
+ // the compiler is going to pad it by one (see issue 9401).
+ // We can't permit that, because then the size of the Go
+ // struct will not be the same as the size of the C struct.
+ // Our only option in such a case is to remove the field,
+ // which means that it cannot be referenced from Go.
+ for off > 0 && sizes[len(sizes)-1] == 0 {
+ n := len(sizes)
+ fld = fld[0 : n-1]
+ sizes = sizes[0 : n-1]
+ }
+
+ if off != dt.ByteSize {
+ fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
+ }
+ buf.WriteString("}")
+ csyntax = buf.String()
+
+ if *godefs {
+ godefsFields(fld)
+ }
+ expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
+ return
+}
+
+// dwarfHasPointer reports whether the DWARF type dt contains a pointer.
+func (c *typeConv) dwarfHasPointer(dt dwarf.Type, pos token.Pos) bool {
+ switch dt := dt.(type) {
+ default:
+ fatalf("%s: unexpected type: %s", lineno(pos), dt)
+ return false
+
+ case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType,
+ *dwarf.FloatType, *dwarf.ComplexType, *dwarf.FuncType,
+ *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType, *dwarf.VoidType:
+
+ return false
+
+ case *dwarf.ArrayType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.PtrType:
+ return true
+
+ case *dwarf.QualType:
+ return c.dwarfHasPointer(dt.Type, pos)
+
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ if c.dwarfHasPointer(f.Type, pos) {
+ return true
+ }
+ }
+ return false
+
+ case *dwarf.TypedefType:
+ if dt.Name == "_GoString_" || dt.Name == "_GoBytes_" {
+ return true
+ }
+ return c.dwarfHasPointer(dt.Type, pos)
+ }
+}
+
+func upper(s string) string {
+ if s == "" {
+ return ""
+ }
+ r, size := utf8.DecodeRuneInString(s)
+ if r == '_' {
+ return "X" + s
+ }
+ return string(unicode.ToUpper(r)) + s[size:]
+}
+
+// godefsFields rewrites field names for use in Go or C definitions.
+// It strips leading common prefixes (like tv_ in tv_sec, tv_usec)
+// converts names to upper case, and rewrites _ into Pad_godefs_n,
+// so that all fields are exported.
+func godefsFields(fld []*ast.Field) {
+ prefix := fieldPrefix(fld)
+
+ // Issue 48396: check for duplicate field names.
+ if prefix != "" {
+ names := make(map[string]bool)
+ fldLoop:
+ for _, f := range fld {
+ for _, n := range f.Names {
+ name := n.Name
+ if name == "_" {
+ continue
+ }
+ if name != prefix {
+ name = strings.TrimPrefix(n.Name, prefix)
+ }
+ name = upper(name)
+ if names[name] {
+ // Field name conflict: don't remove prefix.
+ prefix = ""
+ break fldLoop
+ }
+ names[name] = true
+ }
+ }
+ }
+
+ npad := 0
+ for _, f := range fld {
+ for _, n := range f.Names {
+ if n.Name != prefix {
+ n.Name = strings.TrimPrefix(n.Name, prefix)
+ }
+ if n.Name == "_" {
+ // Use exported name instead.
+ n.Name = "Pad_cgo_" + strconv.Itoa(npad)
+ npad++
+ }
+ n.Name = upper(n.Name)
+ }
+ }
+}
+
+// fieldPrefix returns the prefix that should be removed from all the
+// field names when generating the C or Go code. For generated
+// C, we leave the names as is (tv_sec, tv_usec), since that's what
+// people are used to seeing in C. For generated Go code, such as
+// package syscall's data structures, we drop a common prefix
+// (so sec, usec, which will get turned into Sec, Usec for exporting).
+func fieldPrefix(fld []*ast.Field) string {
+ prefix := ""
+ for _, f := range fld {
+ for _, n := range f.Names {
+ // Ignore field names that don't have the prefix we're
+ // looking for. It is common in C headers to have fields
+ // named, say, _pad in an otherwise prefixed header.
+ // If the struct has 3 fields tv_sec, tv_usec, _pad1, then we
+ // still want to remove the tv_ prefix.
+ // The check for "orig_" here handles orig_eax in the
+ // x86 ptrace register sets, which otherwise have all fields
+ // with reg_ prefixes.
+ if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") {
+ continue
+ }
+ i := strings.Index(n.Name, "_")
+ if i < 0 {
+ continue
+ }
+ if prefix == "" {
+ prefix = n.Name[:i+1]
+ } else if prefix != n.Name[:i+1] {
+ return ""
+ }
+ }
+ }
+ return prefix
+}
+
+// anonymousStructTypedef reports whether dt is a C typedef for an anonymous
+// struct.
+func (c *typeConv) anonymousStructTypedef(dt *dwarf.TypedefType) bool {
+ st, ok := dt.Type.(*dwarf.StructType)
+ return ok && st.StructName == ""
+}
+
+// badPointerTypedef reports whether dt is a C typedef that should not be
+// considered a pointer in Go. A typedef is bad if C code sometimes stores
+// non-pointers in this type.
+// TODO: Currently our best solution is to find these manually and list them as
+// they come up. A better solution is desired.
+// Note: DEPRECATED. There is now a better solution. Search for incomplete in this file.
+func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
+ if c.badCFType(dt) {
+ return true
+ }
+ if c.badJNI(dt) {
+ return true
+ }
+ if c.badEGLType(dt) {
+ return true
+ }
+ return false
+}
+
+// badVoidPointerTypedef is like badPointerTypeDef, but for "void *" typedefs that should be _cgopackage.Incomplete.
+func (c *typeConv) badVoidPointerTypedef(dt *dwarf.TypedefType) bool {
+ // Match the Windows HANDLE type (#42018).
+ if goos != "windows" || dt.Name != "HANDLE" {
+ return false
+ }
+ // Check that the typedef is "typedef void *<name>".
+ if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
+ if _, ok := ptr.Type.(*dwarf.VoidType); ok {
+ return true
+ }
+ }
+ return false
+}
+
+// badStructPointerTypedef is like badVoidPointerTypedefs but for structs.
+func (c *typeConv) badStructPointerTypedef(name string, dt *dwarf.StructType) bool {
+ // Windows handle types can all potentially contain non-pointers.
+ // badVoidPointerTypedef handles the "void *" HANDLE type, but other
+ // handles are defined as
+ //
+ // struct <name>__{int unused;}; typedef struct <name>__ *name;
+ //
+ // by the DECLARE_HANDLE macro in STRICT mode. The macro is declared in
+ // the Windows ntdef.h header,
+ //
+ // https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/ntdef.h#L779
+ if goos != "windows" {
+ return false
+ }
+ if len(dt.Field) != 1 {
+ return false
+ }
+ if dt.StructName != name+"__" {
+ return false
+ }
+ if f := dt.Field[0]; f.Name != "unused" || f.Type.Common().Name != "int" {
+ return false
+ }
+ return true
+}
+
+// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
+// as badPointerTypedef reports.
+func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
+ for {
+ if t, ok := dt.Type.(*dwarf.TypedefType); ok {
+ dt = t
+ continue
+ }
+ break
+ }
+ return c.badPointerTypedef(dt)
+}
+
+func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
+ // The real bad types are CFNumberRef and CFDateRef.
+ // Sometimes non-pointers are stored in these types.
+ // CFTypeRef is a supertype of those, so it can have bad pointers in it as well.
+ // We return true for the other *Ref types just so casting between them is easier.
+ // We identify the correct set of types as those ending in Ref and for which
+ // there exists a corresponding GetTypeID function.
+ // See comment below for details about the bad pointers.
+ if goos != "darwin" && goos != "ios" {
+ return false
+ }
+ s := dt.Name
+ if !strings.HasSuffix(s, "Ref") {
+ return false
+ }
+ s = s[:len(s)-3]
+ if s == "CFType" {
+ return true
+ }
+ if c.getTypeIDs[s] {
+ return true
+ }
+ if i := strings.Index(s, "Mutable"); i >= 0 && c.getTypeIDs[s[:i]+s[i+7:]] {
+ // Mutable and immutable variants share a type ID.
+ return true
+ }
+ return false
+}
+
+// Comment from Darwin's CFInternal.h
+/*
+// Tagged pointer support
+// Low-bit set means tagged object, next 3 bits (currently)
+// define the tagged object class, next 4 bits are for type
+// information for the specific tagged object class. Thus,
+// the low byte is for type info, and the rest of a pointer
+// (32 or 64-bit) is for payload, whatever the tagged class.
+//
+// Note that the specific integers used to identify the
+// specific tagged classes can and will change from release
+// to release (that's why this stuff is in CF*Internal*.h),
+// as can the definition of type info vs payload above.
+//
+#if __LP64__
+#define CF_IS_TAGGED_OBJ(PTR) ((uintptr_t)(PTR) & 0x1)
+#define CF_TAGGED_OBJ_TYPE(PTR) ((uintptr_t)(PTR) & 0xF)
+#else
+#define CF_IS_TAGGED_OBJ(PTR) 0
+#define CF_TAGGED_OBJ_TYPE(PTR) 0
+#endif
+
+enum {
+ kCFTaggedObjectID_Invalid = 0,
+ kCFTaggedObjectID_Atom = (0 << 1) + 1,
+ kCFTaggedObjectID_Undefined3 = (1 << 1) + 1,
+ kCFTaggedObjectID_Undefined2 = (2 << 1) + 1,
+ kCFTaggedObjectID_Integer = (3 << 1) + 1,
+ kCFTaggedObjectID_DateTS = (4 << 1) + 1,
+ kCFTaggedObjectID_ManagedObjectID = (5 << 1) + 1, // Core Data
+ kCFTaggedObjectID_Date = (6 << 1) + 1,
+ kCFTaggedObjectID_Undefined7 = (7 << 1) + 1,
+};
+*/
+
+func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
+ // In Dalvik and ART, the jobject type in the JNI interface of the JVM has the
+ // property that it is sometimes (always?) a small integer instead of a real pointer.
+ // Note: although only the android JVMs are bad in this respect, we declare the JNI types
+ // bad regardless of platform, so the same Go code compiles on both android and non-android.
+ if parent, ok := jniTypes[dt.Name]; ok {
+ // Try to make sure we're talking about a JNI type, not just some random user's
+ // type that happens to use the same name.
+ // C doesn't have the notion of a package, so it's hard to be certain.
+
+ // Walk up to jobject, checking each typedef on the way.
+ w := dt
+ for parent != "" {
+ t, ok := w.Type.(*dwarf.TypedefType)
+ if !ok || t.Name != parent {
+ return false
+ }
+ w = t
+ parent, ok = jniTypes[w.Name]
+ if !ok {
+ return false
+ }
+ }
+
+ // Check that the typedef is either:
+ // 1:
+ // struct _jobject;
+ // typedef struct _jobject *jobject;
+ // 2: (in NDK16 in C++)
+ // class _jobject {};
+ // typedef _jobject* jobject;
+ // 3: (in NDK16 in C)
+ // typedef void* jobject;
+ if ptr, ok := w.Type.(*dwarf.PtrType); ok {
+ switch v := ptr.Type.(type) {
+ case *dwarf.VoidType:
+ return true
+ case *dwarf.StructType:
+ if v.StructName == "_jobject" && len(v.Field) == 0 {
+ switch v.Kind {
+ case "struct":
+ if v.Incomplete {
+ return true
+ }
+ case "class":
+ if !v.Incomplete {
+ return true
+ }
+ }
+ }
+ }
+ }
+ }
+ return false
+}
+
+func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
+ if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
+ return false
+ }
+ // Check that the typedef is "typedef void *<name>".
+ if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
+ if _, ok := ptr.Type.(*dwarf.VoidType); ok {
+ return true
+ }
+ }
+ return false
+}
+
+// jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
+// they are mapped. The base "jobject" maps to the empty string.
+var jniTypes = map[string]string{
+ "jobject": "",
+ "jclass": "jobject",
+ "jthrowable": "jobject",
+ "jstring": "jobject",
+ "jarray": "jobject",
+ "jbooleanArray": "jarray",
+ "jbyteArray": "jarray",
+ "jcharArray": "jarray",
+ "jshortArray": "jarray",
+ "jintArray": "jarray",
+ "jlongArray": "jarray",
+ "jfloatArray": "jarray",
+ "jdoubleArray": "jarray",
+ "jobjectArray": "jarray",
+ "jweak": "jobject",
+}
diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go
new file mode 100644
index 0000000..f628670
--- /dev/null
+++ b/src/cmd/cgo/godefs.go
@@ -0,0 +1,170 @@
+// 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 (
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// godefs returns the output for -godefs mode.
+func (p *Package) godefs(f *File, args []string) string {
+ var buf strings.Builder
+
+ fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
+ fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(args[0]), strings.Join(args[1:], " "))
+ 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()
+}
+
+var gofmtBuf strings.Builder
+
+// 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()
+}
+
+// gofmtLineReplacer is used to put a gofmt-formatted string for an
+// AST expression onto a single line. The lexer normally inserts a
+// semicolon at each newline, so we can replace newline with semicolon.
+// However, we can't do that in cases where the lexer would not insert
+// a semicolon. We only have to worry about cases that can occur in an
+// expression passed through gofmt, which means composite literals and
+// (due to the printer possibly inserting newlines because of position
+// information) operators.
+var gofmtLineReplacer = strings.NewReplacer(
+ // Want to replace \n without ; after everything from
+ // https://golang.org/ref/spec#Operators_and_punctuation
+ // EXCEPT ++ -- ) ] }
+ "++\n", "++;",
+ "--\n", "--;",
+
+ "+\n", "+ ",
+ "-\n", "- ",
+ "*\n", "* ",
+ "/\n", "/ ",
+ "%\n", "% ",
+ "&\n", "& ",
+ "|\n", "| ",
+ "^\n", "^ ",
+ "<\n", "< ",
+ ">\n", "> ",
+ "=\n", "= ",
+ "!\n", "! ", // not possible in gofmt today
+ "(\n", "(",
+ "[\n", "[", // not possible in gofmt today
+ "{\n", "{",
+ ",\n", ",",
+ ".\n", ". ",
+ ":\n", ": ", // not possible in gofmt today
+
+ "\n", ";",
+)
+
+// gofmtLine returns the gofmt-formatted string for an AST node,
+// ensuring that it is on a single line.
+func gofmtLine(n interface{}) string {
+ return gofmtLineReplacer.Replace(gofmt(n))
+}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
new file mode 100644
index 0000000..78020ae
--- /dev/null
+++ b/src/cmd/cgo/main.go
@@ -0,0 +1,501 @@
+// 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 doc.go for an overview.
+
+// TODO(rsc):
+// Emit correct line number annotations.
+// Make gc understand the annotations.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "internal/buildcfg"
+ "io"
+ "os"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "sort"
+ "strings"
+
+ "cmd/internal/edit"
+ "cmd/internal/notsha256"
+ "cmd/internal/objabi"
+)
+
+// 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
+ GccIsClang bool
+ 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
+ typedefs map[string]bool // type names that appear in the types of the objects we're interested in
+ typedefList []typedefInfo
+}
+
+// A typedefInfo is an element on Package.typedefList: a typedef name
+// and the position where it was required.
+type typedefInfo struct {
+ typedef string
+ pos token.Pos
+}
+
+// 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
+ Calls []*Call // all calls to C.xxx in AST
+ ExpFunc []*ExpFunc // exported functions for this file
+ Name map[string]*Name // map from Go name to Name
+ NamePos map[*Name]token.Pos // map from Name to position of the first reference
+ Edit *edit.Buffer
+}
+
+func (f *File) offset(p token.Pos) int {
+ return fset.Position(p).Offset
+}
+
+func nameKeys(m map[string]*Name) []string {
+ var ks []string
+ for k := range m {
+ ks = append(ks, k)
+ }
+ sort.Strings(ks)
+ return ks
+}
+
+// A Call refers to a call of a C.xxx function in the AST.
+type Call struct {
+ Call *ast.CallExpr
+ Deferred bool
+ Done bool
+}
+
+// A Ref refers to an expression of the form C.xxx in the AST.
+type Ref struct {
+ Name *Name
+ Expr *ast.Expr
+ Context astContext
+ Done bool
+}
+
+func (r *Ref) Pos() token.Pos {
+ return (*r.Expr).Pos()
+}
+
+var nameKinds = []string{"iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"}
+
+// 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 // one of the nameKinds
+ Type *Type // the type of xxx
+ FuncType *FuncType
+ AddError bool
+ Const string // constant definition
+}
+
+// IsVar reports whether Kind is either "var" or "fpvar"
+func (n *Name) IsVar() bool {
+ return n.Kind == "var" || n.Kind == "fpvar"
+}
+
+// IsConst reports whether Kind is either "iconst", "fconst" or "sconst"
+func (n *Name) IsConst() bool {
+ return strings.HasSuffix(n.Kind, "const")
+}
+
+// An 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
+ Doc string
+}
+
+// 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
+ BadPointer bool // this pointer type should be represented as a uintptr (deprecated)
+}
+
+// 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,
+ "alpha": 8,
+ "amd64": 8,
+ "arm": 4,
+ "arm64": 8,
+ "loong64": 8,
+ "m68k": 4,
+ "mips": 4,
+ "mipsle": 4,
+ "mips64": 8,
+ "mips64le": 8,
+ "nios2": 4,
+ "ppc": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "riscv": 4,
+ "riscv64": 8,
+ "s390": 4,
+ "s390x": 8,
+ "sh": 4,
+ "shbe": 4,
+ "sparc": 4,
+ "sparc64": 8,
+}
+
+var intSizeMap = map[string]int64{
+ "386": 4,
+ "alpha": 8,
+ "amd64": 8,
+ "arm": 4,
+ "arm64": 8,
+ "loong64": 8,
+ "m68k": 4,
+ "mips": 4,
+ "mipsle": 4,
+ "mips64": 8,
+ "mips64le": 8,
+ "nios2": 4,
+ "ppc": 4,
+ "ppc64": 8,
+ "ppc64le": 8,
+ "riscv": 4,
+ "riscv64": 8,
+ "s390": 4,
+ "s390x": 8,
+ "sh": 4,
+ "shbe": 4,
+ "sparc": 4,
+ "sparc64": 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 -dynimport output to this file")
+var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimport output")
+var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
+
+// This flag is for bootstrapping a new Go implementation,
+// to generate Go types 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 srcDir = flag.String("srcdir", "", "source directory")
+var objDir = flag.String("objdir", "", "object directory")
+var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
+var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
+
+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 gccgoMangler func(string) string
+var gccgoDefineCgoIncomplete = flag.Bool("gccgo_define_cgoincomplete", false, "define cgo.Incomplete for older gccgo/GoLLVM")
+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 trimpath = flag.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
+
+var goarch, goos, gomips, gomips64 string
+var gccBaseCmd []string
+
+func main() {
+ objabi.AddVersionFlag() // -V
+ objabi.Flagparse(usage)
+
+ if *gccgoDefineCgoIncomplete {
+ if !*gccgo {
+ fmt.Fprintf(os.Stderr, "cgo: -gccgo_define_cgoincomplete without -gccgo\n")
+ os.Exit(2)
+ }
+ incomplete = "_cgopackage_Incomplete"
+ }
+
+ 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 {
+ // 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()
+ }
+
+ // Save original command line arguments for the godefs generated comment. Relative file
+ // paths in os.Args will be rewritten to absolute file paths in the loop below.
+ osArgs := make([]string, len(os.Args))
+ copy(osArgs, os.Args[:])
+ goFiles := args[i:]
+
+ for _, arg := range args[:i] {
+ if arg == "-fsanitize=thread" {
+ tsanProlog = yesTsanProlog
+ }
+ if arg == "-fsanitize=memory" {
+ msanProlog = yesMsanProlog
+ }
+ }
+
+ p := newPackage(args[:i])
+
+ // We need a C compiler to be available. Check this.
+ var err error
+ gccBaseCmd, err = checkGCCBaseCmd()
+ if err != nil {
+ fatalf("%v", err)
+ os.Exit(2)
+ }
+
+ // 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 notsha256 of the input to disambiguate.
+ h := notsha256.New()
+ io.WriteString(h, *importPath)
+ fs := make([]*File, len(goFiles))
+ for i, input := range goFiles {
+ if *srcDir != "" {
+ input = filepath.Join(*srcDir, input)
+ }
+
+ // 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(input); err == nil {
+ input = aname
+ }
+
+ b, err := os.ReadFile(input)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ if _, err = h.Write(b); err != nil {
+ fatalf("%s", err)
+ }
+
+ // Apply trimpath to the file path. The path won't be read from after this point.
+ input, _ = objabi.ApplyRewrites(input, *trimpath)
+ if strings.ContainsAny(input, "\r\n") {
+ // ParseGo, (*Package).writeOutput, and printer.Fprint in SourcePos mode
+ // all emit line directives, which don't permit newlines in the file path.
+ // Bail early if we see anything newline-like in the trimmed path.
+ fatalf("input path contains newline character: %q", input)
+ }
+ goFiles[i] = input
+
+ f := new(File)
+ f.Edit = edit.NewBuffer(b)
+ f.ParseGo(input, b)
+ f.DiscardCgoDirectives()
+ fs[i] = f
+ }
+
+ cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
+
+ 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 ctxCall, ctxCall2:
+ if cref.Name.Kind != "type" {
+ break
+ }
+ old := *cref.Expr
+ *cref.Expr = cref.Name.Type.Go
+ f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), gofmt(cref.Name.Type.Go))
+ }
+ }
+ if nerrors > 0 {
+ os.Exit(2)
+ }
+ p.PackagePath = f.Package
+ p.Record(f)
+ if *godefs {
+ os.Stdout.WriteString(p.godefs(f, osArgs))
+ } else {
+ p.writeOutput(f, input)
+ }
+ }
+
+ if !*godefs {
+ 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
+ }
+ buildcfg.Check()
+ gomips = buildcfg.GOMIPS
+ gomips64 = buildcfg.GOMIPS64
+ 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 p.incompleteTypedef(p.Name[k].Type) {
+ p.Name[k] = v
+ } else if p.incompleteTypedef(v.Type) {
+ // Nothing to do.
+ } else if _, ok := nameToC[k]; ok {
+ // Names we predefine may appear inconsistent
+ // if some files typedef them and some don't.
+ // Issue 26743.
+ } 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...)
+}
+
+// incompleteTypedef reports whether t appears to be an incomplete
+// typedef definition.
+func (p *Package) incompleteTypedef(t *Type) bool {
+ return t == nil || (t.Size == 0 && t.Align == -1)
+}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
new file mode 100644
index 0000000..b2933e2
--- /dev/null
+++ b/src/cmd/cgo/out.go
@@ -0,0 +1,1988 @@
+// 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"
+ "cmd/internal/pkgpath"
+ "debug/elf"
+ "debug/macho"
+ "debug/pe"
+ "fmt"
+ "go/ast"
+ "go/printer"
+ "go/token"
+ "internal/xcoff"
+ "io"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strings"
+ "unicode"
+)
+
+var (
+ conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+ noSourceConf = printer.Config{Tabwidth: 8}
+)
+
+// writeDefs creates output files to be compiled by gc and gcc.
+func (p *Package) writeDefs() {
+ var fgo2, fc io.Writer
+ f := creat(*objDir + "_cgo_gotypes.go")
+ defer f.Close()
+ fgo2 = f
+ if *gccgo {
+ f := creat(*objDir + "_cgo_defun.c")
+ defer f.Close()
+ fc = f
+ }
+ fm := creat(*objDir + "_cgo_main.c")
+
+ var gccgoInit strings.Builder
+
+ fflg := creat(*objDir + "_cgo_flags")
+ for k, v := range p.CgoFlags {
+ for _, arg := range v {
+ fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, arg)
+ }
+ if k == "LDFLAGS" && !*gccgo {
+ for _, arg := range v {
+ fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
+ }
+ }
+ }
+ fflg.Close()
+
+ // Write C main file for using gcc to resolve imports.
+ fmt.Fprintf(fm, "#include <stddef.h>\n") // For size_t below.
+ fmt.Fprintf(fm, "int main() { return 0; }\n")
+ if *importRuntimeCgo {
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*) __attribute__((unused)), void *a __attribute__((unused)), int c __attribute__((unused)), size_t ctxt __attribute__((unused))) { }\n")
+ fmt.Fprintf(fm, "size_t _cgo_wait_runtime_init_done(void) { return 0; }\n")
+ fmt.Fprintf(fm, "void _cgo_release_context(size_t ctxt __attribute__((unused))) { }\n")
+ fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
+ } else {
+ // If we're not importing runtime/cgo, we *are* runtime/cgo,
+ // which provides these functions. We just need a prototype.
+ fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, size_t ctxt);\n")
+ fmt.Fprintf(fm, "size_t _cgo_wait_runtime_init_done(void);\n")
+ fmt.Fprintf(fm, "void _cgo_release_context(size_t);\n")
+ }
+ fmt.Fprintf(fm, "void _cgo_allocate(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
+ fmt.Fprintf(fm, "void _cgo_panic(void *a __attribute__((unused)), int c __attribute__((unused))) { }\n")
+ fmt.Fprintf(fm, "void _cgo_reginit(void) { }\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, "// Code generated by cmd/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 *importRuntimeCgo {
+ if !*gccgoDefineCgoIncomplete {
+ fmt.Fprintf(fgo2, "import _cgopackage \"runtime/cgo\"\n\n")
+ fmt.Fprintf(fgo2, "type _ _cgopackage.Incomplete\n") // prevent import-not-used error
+ } else {
+ fmt.Fprintf(fgo2, "//go:notinheap\n")
+ fmt.Fprintf(fgo2, "type _cgopackage_Incomplete struct{ _ struct{ _ struct{} } }\n")
+ }
+ }
+ if *importSyscall {
+ fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
+ }
+ fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
+
+ if !*gccgo {
+ fmt.Fprintf(fgo2, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n")
+ fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n")
+ fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n")
+ fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n")
+ }
+
+ typedefNames := make([]string, 0, len(typedef))
+ for name := range typedef {
+ if name == "_Ctype_void" {
+ // We provide an appropriate declaration for
+ // _Ctype_void below (#39877).
+ continue
+ }
+ typedefNames = append(typedefNames, name)
+ }
+ sort.Strings(typedefNames)
+ for _, name := range typedefNames {
+ def := typedef[name]
+ fmt.Fprintf(fgo2, "type %s ", name)
+ // We don't have source info for these types, so write them out without source info.
+ // Otherwise types would look like:
+ //
+ // type _Ctype_struct_cb struct {
+ // //line :1
+ // on_test *[0]byte
+ // //line :1
+ // }
+ //
+ // Which is not useful. Moreover we never override source info,
+ // so subsequent source code uses the same source info.
+ // Moreover, empty file name makes compile emit no source debug info at all.
+ var buf bytes.Buffer
+ noSourceConf.Fprint(&buf, fset, def.Go)
+ if bytes.HasPrefix(buf.Bytes(), []byte("_Ctype_")) ||
+ strings.HasPrefix(name, "_Ctype_enum_") ||
+ strings.HasPrefix(name, "_Ctype_union_") {
+ // This typedef is of the form `typedef a b` and should be an alias.
+ fmt.Fprintf(fgo2, "= ")
+ }
+ fmt.Fprintf(fgo2, "%s", buf.Bytes())
+ 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.Fprint(fgo2, gccgoGoProlog)
+ fmt.Fprint(fc, p.cPrologGccgo())
+ } else {
+ fmt.Fprint(fgo2, goProlog)
+ }
+
+ if fc != nil {
+ fmt.Fprintf(fc, "#line 1 \"cgo-generated-wrappers\"\n")
+ }
+ if fm != nil {
+ fmt.Fprintf(fm, "#line 1 \"cgo-generated-wrappers\"\n")
+ }
+
+ 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] {
+ if *gccgo {
+ fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
+ } else {
+ // Force a reference to all symbols so that
+ // the external linker will add DT_NEEDED
+ // entries as needed on ELF systems.
+ // Treat function variables differently
+ // to avoid type conflict errors from LTO
+ // (Link Time Optimization).
+ if n.Kind == "fpvar" {
+ fmt.Fprintf(fm, "extern void %s();\n", n.C)
+ } else {
+ fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+ fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+ }
+ fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
+ fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
+ fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
+ }
+ cVars[n.C] = true
+ }
+
+ var node ast.Node
+ if n.Kind == "var" {
+ node = &ast.StarExpr{X: n.Type.Go}
+ } else if n.Kind == "fpvar" {
+ node = n.Type.Go
+ } else {
+ panic(fmt.Errorf("invalid var kind %q", n.Kind))
+ }
+ if *gccgo {
+ fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, gccgoToSymbol(n.Mangle))
+ fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
+ fmt.Fprintf(fc, "\n")
+ }
+
+ fmt.Fprintf(fgo2, "var %s ", n.Mangle)
+ conf.Fprint(fgo2, fset, node)
+ if !*gccgo {
+ fmt.Fprintf(fgo2, " = (")
+ conf.Fprint(fgo2, fset, node)
+ fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C)
+ }
+ fmt.Fprintf(fgo2, "\n")
+ }
+ if *gccgo {
+ fmt.Fprintf(fc, "\n")
+ }
+
+ for _, key := range nameKeys(p.Name) {
+ n := p.Name[key]
+ if n.Const != "" {
+ fmt.Fprintf(fgo2, "const %s = %s\n", n.Mangle, n.Const)
+ }
+ }
+ fmt.Fprintf(fgo2, "\n")
+
+ callsMalloc := false
+ for _, key := range nameKeys(p.Name) {
+ n := p.Name[key]
+ if n.FuncType != nil {
+ p.writeDefsFunc(fgo2, n, &callsMalloc)
+ }
+ }
+
+ fgcc := creat(*objDir + "_cgo_export.c")
+ fgcch := creat(*objDir + "_cgo_export.h")
+ if *gccgo {
+ p.writeGccgoExports(fgo2, fm, fgcc, fgcch)
+ } else {
+ p.writeExports(fgo2, fm, fgcc, fgcch)
+ }
+
+ if callsMalloc && !*gccgo {
+ fmt.Fprint(fgo2, strings.Replace(cMallocDefGo, "PREFIX", cPrefix, -1))
+ fmt.Fprint(fgcc, strings.Replace(strings.Replace(cMallocDefC, "PREFIX", cPrefix, -1), "PACKED", p.packedAttribute(), -1))
+ }
+
+ if err := fgcc.Close(); err != nil {
+ fatalf("%s", err)
+ }
+ if err := fgcch.Close(); err != nil {
+ fatalf("%s", err)
+ }
+
+ if *exportHeader != "" && len(p.ExpFunc) > 0 {
+ fexp := creat(*exportHeader)
+ fgcch, err := os.Open(*objDir + "_cgo_export.h")
+ if err != nil {
+ fatalf("%s", err)
+ }
+ defer fgcch.Close()
+ _, err = io.Copy(fexp, fgcch)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ if err = fexp.Close(); err != nil {
+ fatalf("%s", err)
+ }
+ }
+
+ init := gccgoInit.String()
+ if init != "" {
+ // The init function does nothing but simple
+ // assignments, so it won't use much stack space, so
+ // it's OK to not split the stack. Splitting the stack
+ // can run into a bug in clang (as of 2018-11-09):
+ // this is a leaf function, and when clang sees a leaf
+ // function it won't emit the split stack prologue for
+ // the function. However, if this function refers to a
+ // non-split-stack function, which will happen if the
+ // cgo code refers to a C function not compiled with
+ // -fsplit-stack, then the linker will think that it
+ // needs to adjust the split stack prologue, but there
+ // won't be one. Marking the function explicitly
+ // no_split_stack works around this problem by telling
+ // the linker that it's OK if there is no split stack
+ // prologue.
+ fmt.Fprintln(fc, "static void init(void) __attribute__ ((constructor, no_split_stack));")
+ fmt.Fprintln(fc, "static void init(void) {")
+ fmt.Fprint(fc, init)
+ fmt.Fprintln(fc, "}")
+ }
+}
+
+// elfImportedSymbols is like elf.File.ImportedSymbols, but it
+// includes weak symbols.
+//
+// A bug in some versions of LLD (at least LLD 8) cause it to emit
+// several pthreads symbols as weak, but we need to import those. See
+// issue #31912 or https://bugs.llvm.org/show_bug.cgi?id=42442.
+//
+// When doing external linking, we hand everything off to the external
+// linker, which will create its own dynamic symbol tables. For
+// internal linking, this may turn weak imports into strong imports,
+// which could cause dynamic linking to fail if a symbol really isn't
+// defined. However, the standard library depends on everything it
+// imports, and this is the primary use of dynamic symbol tables with
+// internal linking.
+func elfImportedSymbols(f *elf.File) []elf.ImportedSymbol {
+ syms, _ := f.DynamicSymbols()
+ var imports []elf.ImportedSymbol
+ for _, s := range syms {
+ if (elf.ST_BIND(s.Info) == elf.STB_GLOBAL || elf.ST_BIND(s.Info) == elf.STB_WEAK) && s.Section == elf.SHN_UNDEF {
+ imports = append(imports, elf.ImportedSymbol{
+ Name: s.Name,
+ Library: s.Library,
+ Version: s.Version,
+ })
+ }
+ }
+ return imports
+}
+
+func dynimport(obj string) {
+ stdout := os.Stdout
+ if *dynout != "" {
+ f, err := os.Create(*dynout)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ stdout = f
+ }
+
+ fmt.Fprintf(stdout, "package %s\n", *dynpackage)
+
+ 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, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
+ }
+ }
+ }
+ sym := elfImportedSymbols(f)
+ for _, s := range sym {
+ targ := s.Name
+ if s.Version != "" {
+ targ += "#" + s.Version
+ }
+ checkImportSymName(s.Name)
+ checkImportSymName(targ)
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
+ }
+ lib, _ := f.ImportedLibraries()
+ for _, l := range lib {
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
+ }
+ return
+ }
+
+ if f, err := macho.Open(obj); err == nil {
+ sym, _ := f.ImportedSymbols()
+ for _, s := range sym {
+ if len(s) > 0 && s[0] == '_' {
+ s = s[1:]
+ }
+ checkImportSymName(s)
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
+ }
+ lib, _ := f.ImportedLibraries()
+ for _, l := range lib {
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
+ }
+ return
+ }
+
+ if f, err := pe.Open(obj); err == nil {
+ sym, _ := f.ImportedSymbols()
+ for _, s := range sym {
+ ss := strings.Split(s, ":")
+ name := strings.Split(ss[0], "@")[0]
+ checkImportSymName(name)
+ checkImportSymName(ss[0])
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
+ }
+ return
+ }
+
+ if f, err := xcoff.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from XCOFF file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ if s.Name == "runtime_rt0_go" || s.Name == "_rt0_ppc64_aix_lib" {
+ // These symbols are imported by runtime/cgo but
+ // must not be added to _cgo_import.go as there are
+ // Go symbols.
+ continue
+ }
+ checkImportSymName(s.Name)
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
+ }
+ lib, err := f.ImportedLibraries()
+ if err != nil {
+ fatalf("cannot load imported libraries from XCOFF file %s: %v", obj, err)
+ }
+ for _, l := range lib {
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
+ }
+ return
+ }
+
+ fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
+}
+
+// checkImportSymName checks a symbol name we are going to emit as part
+// of a //go:cgo_import_dynamic pragma. These names come from object
+// files, so they may be corrupt. We are going to emit them unquoted,
+// so while they don't need to be valid symbol names (and in some cases,
+// involving symbol versions, they won't be) they must contain only
+// graphic characters and must not contain Go comments.
+func checkImportSymName(s string) {
+ for _, c := range s {
+ if !unicode.IsGraphic(c) || unicode.IsSpace(c) {
+ fatalf("dynamic symbol %q contains unsupported character", s)
+ }
+ }
+ if strings.Contains(s, "//") || strings.Contains(s, "/*") {
+ fatalf("dynamic symbol %q contains Go comment")
+ }
+}
+
+// Construct a gcc struct matching the gc 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 gc convention is to word-align the
+// input and output parameters.
+func (p *Package) structType(n *Name) (string, int64) {
+ var buf strings.Builder
+ 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
+ }
+ fmt.Fprintf(&buf, "\t\t%s r;\n", 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 off == 0 {
+ fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
+ }
+ fmt.Fprintf(&buf, "\t}")
+ return buf.String(), off
+}
+
+func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name, callsMalloc *bool) {
+ 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 := builtinDefs[name] != ""
+ cname := fmt.Sprintf("_cgo%s%s", cPrefix, n.Mangle)
+ paramnames := []string(nil)
+ if d.Type.Params != 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)
+ }
+ }
+
+ if *gccgo {
+ // Gccgo style hooks.
+ fmt.Fprint(fgo2, "\n")
+ 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 %s\n", cname)
+ 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
+ }
+
+ if inProlog {
+ fmt.Fprint(fgo2, builtinDefs[name])
+ if strings.Contains(builtinDefs[name], "_cgo_cmalloc") {
+ *callsMalloc = true
+ }
+ return
+ }
+
+ // Wrapper calls into gcc, passing a pointer to the argument frame.
+ fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname)
+ fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname)
+ fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname)
+ fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname)
+
+ nret := 0
+ if !void {
+ d.Type.Results.List[0].Names = []*ast.Ident{ast.NewIdent("r1")}
+ nret = 1
+ }
+ if n.AddError {
+ d.Type.Results.List[nret].Names = []*ast.Ident{ast.NewIdent("r2")}
+ }
+
+ fmt.Fprint(fgo2, "\n")
+ fmt.Fprint(fgo2, "//go:cgo_unsafe_args\n")
+ conf.Fprint(fgo2, fset, d)
+ fmt.Fprint(fgo2, " {\n")
+
+ // NOTE: Using uintptr to hide from escape analysis.
+ arg := "0"
+ if len(paramnames) > 0 {
+ arg = "uintptr(unsafe.Pointer(&p0))"
+ } else if !void {
+ arg = "uintptr(unsafe.Pointer(&r1))"
+ }
+
+ prefix := ""
+ if n.AddError {
+ prefix = "errno := "
+ }
+ fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg)
+ if n.AddError {
+ fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
+ }
+ fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
+ if d.Type.Params != nil {
+ for i := range d.Type.Params.List {
+ fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
+ }
+ }
+ fmt.Fprintf(fgo2, "\t}\n")
+ fmt.Fprintf(fgo2, "\treturn\n")
+ fmt.Fprintf(fgo2, "}\n")
+}
+
+// writeOutput creates stubs for a specific source file to be compiled by gc
+func (p *Package) writeOutput(f *File, srcfile string) {
+ base := srcfile
+ base = strings.TrimSuffix(base, ".go")
+ base = filepath.Base(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, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
+ if strings.ContainsAny(srcfile, "\r\n") {
+ // This should have been checked when the file path was first resolved,
+ // but we double check here just to be sure.
+ fatalf("internal error: writeOutput: srcfile contains unexpected newline character: %q", srcfile)
+ }
+ fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile)
+ fgo1.Write(f.Edit.Bytes())
+
+ // While we process the vars and funcs, also write gcc output.
+ // Gcc output starts with the preamble.
+ fmt.Fprintf(fgcc, "%s\n", builtinProlog)
+ fmt.Fprintf(fgcc, "%s\n", f.Preamble)
+ fmt.Fprintf(fgcc, "%s\n", gccProlog)
+ fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
+
+ 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_CBytes": 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, "CGO_NO_SANITIZE_THREAD\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "int\n")
+ } else {
+ 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, "\tint _cgo_errno;\n")
+ }
+ // We're trying to write a gcc struct that matches gc'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 *_cgo_a = v;\n", ctype, p.packedAttribute())
+ if n.FuncType.Result != nil {
+ // Save the stack top for use below.
+ fmt.Fprintf(fgcc, "\tchar *_cgo_stktop = _cgo_topofstack();\n")
+ }
+ tr := n.FuncType.Result
+ if tr != nil {
+ fmt.Fprintf(fgcc, "\t__typeof__(_cgo_a->r) _cgo_r;\n")
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\terrno = 0;\n")
+ }
+ fmt.Fprintf(fgcc, "\t")
+ if tr != nil {
+ fmt.Fprintf(fgcc, "_cgo_r = ")
+ if c := tr.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprint(fgcc, "(__typeof__(_cgo_a->r)) ")
+ }
+ }
+ if n.Kind == "macro" {
+ fmt.Fprintf(fgcc, "%s;\n", n.C)
+ } else {
+ fmt.Fprintf(fgcc, "%s(", n.C)
+ for i := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "_cgo_a->p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ }
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\t_cgo_errno = errno;\n")
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+ if n.FuncType.Result != nil {
+ // The cgo call may have caused a stack copy (via a callback).
+ // Adjust the return value pointer appropriately.
+ fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n")
+ // Save the return value.
+ fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n")
+ // The return value is on the Go stack. If we are using msan,
+ // and if the C value is partially or completely uninitialized,
+ // the assignment will mark the Go stack as uninitialized.
+ // The Go compiler does not update msan for changes to the
+ // stack. It is possible that the stack will remain
+ // uninitialized, and then later be used in a way that is
+ // visible to msan, possibly leading to a false positive.
+ // Mark the stack space as written, to avoid this problem.
+ // See issue 26209.
+ fmt.Fprintf(fgcc, "\t_cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));\n")
+ }
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\treturn _cgo_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) {
+ fmt.Fprintf(fgcc, "CGO_NO_SANITIZE_THREAD\n")
+ 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")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "\t%s _cgo_r;\n", t.C.String())
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ fmt.Fprintf(fgcc, "\t")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "_cgo_r = ")
+ // Cast to void* to avoid warnings due to omitted qualifiers.
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
+ }
+ if n.Kind == "macro" {
+ fmt.Fprintf(fgcc, "%s;\n", n.C)
+ } else {
+ fmt.Fprintf(fgcc, "%s(", n.C)
+ for i := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ }
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+ if t := n.FuncType.Result; t != nil {
+ fmt.Fprintf(fgcc, "\treturn ")
+ // Cast to void* to avoid warnings due to omitted qualifiers
+ // and explicit incompatible struct types.
+ if c := t.C.String(); c[len(c)-1] == '*' {
+ fmt.Fprintf(fgcc, "(void*)")
+ }
+ fmt.Fprintf(fgcc, "_cgo_r;\n")
+ }
+ fmt.Fprintf(fgcc, "}\n")
+ fmt.Fprintf(fgcc, "\n")
+}
+
+// packedAttribute returns host compiler struct attribute that will be
+// used to match gc's struct layout. For example, on 386 Windows,
+// gcc wants to 8-align int64s, but gc does not.
+// Use __gcc_struct__ to work around https://gcc.gnu.org/PR52991 on x86,
+// and https://golang.org/issue/5603.
+func (p *Package) packedAttribute() string {
+ s := "__attribute__((__packed__"
+ if !p.GccIsClang && (goarch == "amd64" || goarch == "386") {
+ s += ", __gcc_struct__"
+ }
+ return s + "))"
+}
+
+// exportParamName returns the value of param as it should be
+// displayed in a c header file. If param contains any non-ASCII
+// characters, this function will return the character p followed by
+// the value of position; otherwise, this function will return the
+// value of param.
+func exportParamName(param string, position int) string {
+ if param == "" {
+ return fmt.Sprintf("p%d", position)
+ }
+
+ pname := param
+
+ for i := 0; i < len(param); i++ {
+ if param[i] > unicode.MaxASCII {
+ pname = fmt.Sprintf("p%d", position)
+ break
+ }
+ }
+
+ return pname
+}
+
+// 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, fm, fgcc, fgcch io.Writer) {
+ p.writeExportHeader(fgcch)
+
+ fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
+ fmt.Fprintf(fgcc, "#include <stdlib.h>\n")
+ fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
+
+ // We use packed structs, but they are always aligned.
+ // The pragmas and address-of-packed-member are only recognized as
+ // warning groups in clang 4.0+, so ignore unknown pragmas first.
+ fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wunknown-pragmas\"\n")
+ fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
+ fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
+
+ fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, size_t);\n")
+ fmt.Fprintf(fgcc, "extern size_t _cgo_wait_runtime_init_done(void);\n")
+ fmt.Fprintf(fgcc, "extern void _cgo_release_context(size_t);\n\n")
+ fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
+ fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
+
+ for _, exp := range p.ExpFunc {
+ fn := exp.Func
+
+ // Construct a struct that will be used to communicate
+ // arguments from C to Go. The C and Go definitions
+ // just have to agree. The gcc struct will be compiled
+ // with __attribute__((packed)) so all padding must be
+ // accounted for explicitly.
+ ctype := "struct {\n"
+ gotype := new(bytes.Buffer)
+ fmt.Fprintf(gotype, "struct {\n")
+ off := int64(0)
+ npad := 0
+ argField := func(typ ast.Expr, namePat string, args ...interface{}) {
+ name := fmt.Sprintf(namePat, args...)
+ t := p.cgoType(typ)
+ 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 %s;\n", t.C, name)
+ fmt.Fprintf(gotype, "\t\t%s ", name)
+ noSourceConf.Fprint(gotype, fset, typ)
+ fmt.Fprintf(gotype, "\n")
+ off += t.Size
+ }
+ if fn.Recv != nil {
+ argField(fn.Recv.List[0].Type, "recv")
+ }
+ fntype := fn.Type
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ argField(atype, "p%d", i)
+ })
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ argField(atype, "r%d", i)
+ })
+ if ctype == "struct {\n" {
+ ctype += "\t\tchar unused;\n" // avoid empty struct
+ }
+ ctype += "\t}"
+ fmt.Fprintf(gotype, "\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, aname string, atype ast.Expr) {
+ fmt.Fprintf(fgcch, "\t%s r%d;", p.cgoType(atype).C, i)
+ if len(aname) > 0 {
+ fmt.Fprintf(fgcch, " /* %s */", aname)
+ }
+ fmt.Fprint(fgcch, "\n")
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ gccResult = "struct " + exp.ExpName + "_return"
+ }
+
+ // Build the wrapper function compiled by gcc.
+ gccExport := ""
+ if goos == "windows" {
+ gccExport = "__declspec(dllexport) "
+ }
+ s := fmt.Sprintf("%s%s %s(", gccExport, 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, aname string, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ s += ", "
+ }
+ s += fmt.Sprintf("%s %s", p.cgoType(atype).C, exportParamName(aname, i))
+ })
+ s += ")"
+
+ if len(exp.Doc) > 0 {
+ fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+ if !strings.HasSuffix(exp.Doc, "\n") {
+ fmt.Fprint(fgcch, "\n")
+ }
+ }
+ fmt.Fprintf(fgcch, "extern %s;\n", s)
+
+ fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
+ fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
+ fmt.Fprintf(fgcc, "\n%s\n", s)
+ fmt.Fprintf(fgcc, "{\n")
+ fmt.Fprintf(fgcc, "\tsize_t _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
+ // The results part of the argument structure must be
+ // initialized to 0 so the write barriers generated by
+ // the assignments to these fields in Go are safe.
+ //
+ // We use a local static variable to get the zeroed
+ // value of the argument type. This avoids including
+ // string.h for memset, and is also robust to C++
+ // types with constructors. Both GCC and LLVM optimize
+ // this into just zeroing _cgo_a.
+ fmt.Fprintf(fgcc, "\ttypedef %s %v _cgo_argtype;\n", ctype, p.packedAttribute())
+ fmt.Fprintf(fgcc, "\tstatic _cgo_argtype _cgo_zero;\n")
+ fmt.Fprintf(fgcc, "\t_cgo_argtype _cgo_a = _cgo_zero;\n")
+ 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, "\t_cgo_a.recv = recv;\n")
+ }
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ fmt.Fprintf(fgcc, "\t_cgo_a.p%d = %s;\n", i, exportParamName(aname, i))
+ })
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &_cgo_a, %d, _cgo_ctxt);\n", cPrefix, exp.ExpName, off)
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ fmt.Fprintf(fgcc, "\t_cgo_release_context(_cgo_ctxt);\n")
+ if gccResult != "void" {
+ if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
+ fmt.Fprintf(fgcc, "\treturn _cgo_a.r0;\n")
+ } else {
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ fmt.Fprintf(fgcc, "\tr.r%d = _cgo_a.r%d;\n", i, i)
+ })
+ fmt.Fprintf(fgcc, "\treturn r;\n")
+ }
+ }
+ fmt.Fprintf(fgcc, "}\n")
+
+ // In internal linking mode, the Go linker sees both
+ // the C wrapper written above and the Go wrapper it
+ // references. Hence, export the C wrapper (e.g., for
+ // if we're building a shared object). The Go linker
+ // will resolve the C wrapper's reference to the Go
+ // wrapper without a separate export.
+ fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
+ // cgo_export_static refers to a symbol by its linker
+ // name, so set the linker name of the Go wrapper.
+ fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
+ // In external linking mode, the Go linker sees the Go
+ // wrapper, but not the C wrapper. For this case,
+ // export the Go wrapper so the host linker can
+ // resolve the reference from the C wrapper to the Go
+ // wrapper.
+ fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
+
+ // Build the wrapper function compiled by cmd/compile.
+ // This unpacks the argument struct above and calls the Go function.
+ fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
+
+ fmt.Fprintf(fm, "void _cgoexp%s_%s(void* p){}\n", cPrefix, exp.ExpName)
+
+ fmt.Fprintf(fgo2, "\t")
+
+ if gccResult != "void" {
+ // Write results back to frame.
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprintf(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "a.r%d", i)
+ })
+ fmt.Fprintf(fgo2, " = ")
+ }
+ if fn.Recv != nil {
+ fmt.Fprintf(fgo2, "a.recv.")
+ }
+ fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "a.p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ if gccResult != "void" {
+ // Verify that any results don't contain any
+ // Go pointers.
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ if !p.hasPointer(nil, atype, false) {
+ return
+ }
+ fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i)
+ })
+ }
+ fmt.Fprint(fgo2, "}\n")
+ }
+
+ fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
+}
+
+// Write out the C header allowing C code to call exported gccgo functions.
+func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
+ gccgoSymbolPrefix := p.gccgoSymbolPrefix()
+
+ p.writeExportHeader(fgcch)
+
+ fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
+ fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+
+ fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
+ fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
+
+ for _, exp := range p.ExpFunc {
+ fn := exp.Func
+ fntype := fn.Type
+
+ cdeclBuf := new(strings.Builder)
+ resultCount := 0
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) { resultCount++ })
+ switch resultCount {
+ case 0:
+ fmt.Fprintf(cdeclBuf, "void")
+ case 1:
+ forFieldList(fntype.Results,
+ func(i int, aname string, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(cdeclBuf, "%s", t.C)
+ })
+ default:
+ // Declare a result struct.
+ 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, aname string, atype ast.Expr) {
+ t := p.cgoType(atype)
+ fmt.Fprintf(fgcch, "\t%s r%d;", t.C, i)
+ if len(aname) > 0 {
+ fmt.Fprintf(fgcch, " /* %s */", aname)
+ }
+ fmt.Fprint(fgcch, "\n")
+ })
+ fmt.Fprintf(fgcch, "};\n")
+ fmt.Fprintf(cdeclBuf, "struct %s_return", exp.ExpName)
+ }
+
+ cRet := cdeclBuf.String()
+
+ cdeclBuf = new(strings.Builder)
+ 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, aname string, 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()
+
+ if len(exp.Doc) > 0 {
+ fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+ }
+
+ fmt.Fprintf(fgcch, "extern %s %s%s;\n", cRet, exp.ExpName, cParams)
+
+ // 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(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, gccgoToSymbol(goName))
+ fmt.Fprint(fgcc, "\n")
+
+ fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
+ fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
+ if resultCount > 0 {
+ fmt.Fprintf(fgcc, "\t%s r;\n", cRet)
+ }
+ fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
+ fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_release();\n")
+ fmt.Fprint(fgcc, "\t")
+ if resultCount > 0 {
+ fmt.Fprint(fgcc, "r = ")
+ }
+ fmt.Fprintf(fgcc, "%s(", goName)
+ if fn.Recv != nil {
+ fmt.Fprint(fgcc, "recv")
+ }
+ forFieldList(fntype.Params,
+ func(i int, aname string, atype ast.Expr) {
+ if i > 0 || fn.Recv != nil {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "p%d", i)
+ })
+ fmt.Fprint(fgcc, ");\n")
+ fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
+ if resultCount > 0 {
+ fmt.Fprint(fgcc, "\treturn r;\n")
+ }
+ fmt.Fprint(fgcc, "}\n")
+
+ // Dummy declaration for _cgo_main.c
+ fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, gccgoToSymbol(goName))
+ fmt.Fprint(fm, "\n")
+
+ // 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, aname string, 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, aname string, 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, aname string, atype ast.Expr) {
+ if i > 0 {
+ fmt.Fprint(fgo2, ", ")
+ }
+ fmt.Fprintf(fgo2, "p%d", i)
+ })
+ fmt.Fprint(fgo2, ")\n")
+ fmt.Fprint(fgo2, "}\n")
+ }
+
+ fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
+}
+
+// writeExportHeader writes out the start of the _cgo_export.h file.
+func (p *Package) writeExportHeader(fgcch io.Writer) {
+ fmt.Fprintf(fgcch, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
+ pkg := *importPath
+ if pkg == "" {
+ pkg = p.PackagePath
+ }
+ fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
+ fmt.Fprintf(fgcch, "%s\n", builtinExportProlog)
+
+ // Remove absolute paths from #line comments in the preamble.
+ // They aren't useful for people using the header file,
+ // and they mean that the header files change based on the
+ // exact location of GOPATH.
+ re := regexp.MustCompile(`(?m)^(#line\s+\d+\s+")[^"]*[/\\]([^"]*")`)
+ preamble := re.ReplaceAllString(p.Preamble, "$1$2")
+
+ fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n")
+ fmt.Fprintf(fgcch, "%s\n", preamble)
+ fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments. */\n\n")
+
+ fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
+}
+
+// gccgoToSymbol converts a name to a mangled symbol for gccgo.
+func gccgoToSymbol(ppath string) string {
+ if gccgoMangler == nil {
+ var err error
+ cmd := os.Getenv("GCCGO")
+ if cmd == "" {
+ cmd, err = exec.LookPath("gccgo")
+ if err != nil {
+ fatalf("unable to locate gccgo: %v", err)
+ }
+ }
+ gccgoMangler, err = pkgpath.ToSymbolFunc(cmd, *objDir)
+ if err != nil {
+ fatalf("%v", err)
+ }
+ }
+ return gccgoMangler(ppath)
+}
+
+// Return the package prefix when using gccgo.
+func (p *Package) gccgoSymbolPrefix() string {
+ if !*gccgo {
+ return ""
+ }
+
+ if *gccgopkgpath != "" {
+ return gccgoToSymbol(*gccgopkgpath)
+ }
+ if *gccgoprefix == "" && p.PackageName == "main" {
+ return "main"
+ }
+ prefix := gccgoToSymbol(*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, the name if any, and the type.
+func forFieldList(fl *ast.FieldList, fn func(int, string, ast.Expr)) {
+ if fl == nil {
+ return
+ }
+ i := 0
+ for _, r := range fl.List {
+ if r.Names == nil {
+ fn(i, "", r.Type)
+ i++
+ } else {
+ for _, n := range r.Names {
+ fn(i, n.Name, 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: 4, C: c("GoComplex64")},
+ "complex128": {Size: 16, Align: 8, 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")}
+ }
+ // Non-slice array types are not supported.
+ case *ast.StructType:
+ // Not supported.
+ 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:
+ goTypesFixup := func(r *Type) *Type {
+ 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
+ }
+ // 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 {
+ if defgo, ok := def.Go.(*ast.Ident); ok {
+ switch defgo.Name {
+ case "complex64", "complex128":
+ // MSVC does not support the _Complex keyword
+ // nor the complex macro.
+ // Use GoComplex64 and GoComplex128 instead,
+ // which are typedef-ed to a compatible type.
+ // See go.dev/issues/36233.
+ return goTypesFixup(goTypes[defgo.Name])
+ }
+ }
+ 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 {
+ return goTypesFixup(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 = `
+#line 1 "cgo-gcc-prolog"
+/*
+ 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)*-2UL+1UL];
+
+/* Check at compile time that the sizes we use match our expectations. */
+#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), (size_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)
+
+extern char* _cgo_topofstack(void);
+
+/*
+ We use packed structs, but they are always aligned.
+ The pragmas and address-of-packed-member are only recognized as warning
+ groups in clang 4.0+, so ignore unknown pragmas first.
+*/
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#pragma GCC diagnostic ignored "-Wpragmas"
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+
+#include <errno.h>
+#include <string.h>
+`
+
+// Prologue defining TSAN functions in C.
+const noTsanProlog = `
+#define CGO_NO_SANITIZE_THREAD
+#define _cgo_tsan_acquire()
+#define _cgo_tsan_release()
+`
+
+// This must match the TSAN code in runtime/cgo/libcgo.h.
+// This is used when the code is built with the C/C++ Thread SANitizer,
+// which is not the same as the Go race detector.
+// __tsan_acquire tells TSAN that we are acquiring a lock on a variable,
+// in this case _cgo_sync. __tsan_release releases the lock.
+// (There is no actual lock, we are just telling TSAN that there is.)
+//
+// When we call from Go to C we call _cgo_tsan_acquire.
+// When the C function returns we call _cgo_tsan_release.
+// Similarly, when C calls back into Go we call _cgo_tsan_release
+// and then call _cgo_tsan_acquire when we return to C.
+// These calls tell TSAN that there is a serialization point at the C call.
+//
+// This is necessary because TSAN, which is a C/C++ tool, can not see
+// the synchronization in the Go code. Without these calls, when
+// multiple goroutines call into C code, TSAN does not understand
+// that the calls are properly synchronized on the Go side.
+//
+// To be clear, if the calls are not properly synchronized on the Go side,
+// we will be hiding races. But when using TSAN on mixed Go C/C++ code
+// it is more important to avoid false positives, which reduce confidence
+// in the tool, than to avoid false negatives.
+const yesTsanProlog = `
+#line 1 "cgo-tsan-prolog"
+#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
+
+long long _cgo_sync __attribute__ ((common));
+
+extern void __tsan_acquire(void*);
+extern void __tsan_release(void*);
+
+__attribute__ ((unused))
+static void _cgo_tsan_acquire() {
+ __tsan_acquire(&_cgo_sync);
+}
+
+__attribute__ ((unused))
+static void _cgo_tsan_release() {
+ __tsan_release(&_cgo_sync);
+}
+`
+
+// Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
+var tsanProlog = noTsanProlog
+
+// noMsanProlog is a prologue defining an MSAN function in C.
+// This is used when not compiling with -fsanitize=memory.
+const noMsanProlog = `
+#define _cgo_msan_write(addr, sz)
+`
+
+// yesMsanProlog is a prologue defining an MSAN function in C.
+// This is used when compiling with -fsanitize=memory.
+// See the comment above where _cgo_msan_write is called.
+const yesMsanProlog = `
+extern void __msan_unpoison(const volatile void *, size_t);
+
+#define _cgo_msan_write(addr, sz) __msan_unpoison((addr), (sz))
+`
+
+// msanProlog is set to yesMsanProlog if we see -fsanitize=memory in the flags
+// for the C compiler.
+var msanProlog = noMsanProlog
+
+const builtinProlog = `
+#line 1 "cgo-builtin-prolog"
+#include <stddef.h>
+
+/* Define intgo when compiling with GCC. */
+typedef ptrdiff_t intgo;
+
+#define GO_CGO_GOSTRING_TYPEDEF
+typedef struct { const 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 *CBytes(_GoBytes_);
+void *_CMalloc(size_t);
+
+__attribute__ ((unused))
+static size_t _GoStringLen(_GoString_ s) { return (size_t)s.n; }
+
+__attribute__ ((unused))
+static const char *_GoStringPtr(_GoString_ s) { return s.p; }
+`
+
+const goProlog = `
+//go:linkname _cgo_runtime_cgocall runtime.cgocall
+func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
+
+//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
+func _cgoCheckPointer(interface{}, interface{})
+
+//go:linkname _cgoCheckResult runtime.cgoCheckResult
+func _cgoCheckResult(interface{})
+`
+
+const gccgoGoProlog = `
+func _cgoCheckPointer(interface{}, interface{})
+
+func _cgoCheckResult(interface{})
+`
+
+const goStringDef = `
+//go:linkname _cgo_runtime_gostring runtime.gostring
+func _cgo_runtime_gostring(*_Ctype_char) string
+
+// GoString converts the C string p into a Go string.
+func _Cfunc_GoString(p *_Ctype_char) string {
+ return _cgo_runtime_gostring(p)
+}
+`
+
+const goStringNDef = `
+//go:linkname _cgo_runtime_gostringn runtime.gostringn
+func _cgo_runtime_gostringn(*_Ctype_char, int) string
+
+// GoStringN converts the C data p with explicit length l to a Go string.
+func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
+ return _cgo_runtime_gostringn(p, int(l))
+}
+`
+
+const goBytesDef = `
+//go:linkname _cgo_runtime_gobytes runtime.gobytes
+func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
+
+// GoBytes converts the C data p with explicit length l to a Go []byte.
+func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
+ return _cgo_runtime_gobytes(p, int(l))
+}
+`
+
+const cStringDef = `
+// CString converts the Go string s to a 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 _Cfunc_CString(s string) *_Ctype_char {
+ if len(s)+1 <= 0 {
+ panic("string too large")
+ }
+ p := _cgo_cmalloc(uint64(len(s)+1))
+ sliceHeader := struct {
+ p unsafe.Pointer
+ len int
+ cap int
+ }{p, len(s)+1, len(s)+1}
+ b := *(*[]byte)(unsafe.Pointer(&sliceHeader))
+ copy(b, s)
+ b[len(s)] = 0
+ return (*_Ctype_char)(p)
+}
+`
+
+const cBytesDef = `
+// CBytes converts the Go []byte slice b to a C array.
+//
+// The C array 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 _Cfunc_CBytes(b []byte) unsafe.Pointer {
+ p := _cgo_cmalloc(uint64(len(b)))
+ sliceHeader := struct {
+ p unsafe.Pointer
+ len int
+ cap int
+ }{p, len(b), len(b)}
+ s := *(*[]byte)(unsafe.Pointer(&sliceHeader))
+ copy(s, b)
+ return p
+}
+`
+
+const cMallocDef = `
+func _Cfunc__CMalloc(n _Ctype_size_t) unsafe.Pointer {
+ return _cgo_cmalloc(uint64(n))
+}
+`
+
+var builtinDefs = map[string]string{
+ "GoString": goStringDef,
+ "GoStringN": goStringNDef,
+ "GoBytes": goBytesDef,
+ "CString": cStringDef,
+ "CBytes": cBytesDef,
+ "_CMalloc": cMallocDef,
+}
+
+// Definitions for C.malloc in Go and in C. We define it ourselves
+// since we call it from functions we define, such as C.CString.
+// Also, we have historically ensured that C.malloc does not return
+// nil even for an allocation of 0.
+
+const cMallocDefGo = `
+//go:cgo_import_static _cgoPREFIX_Cfunc__Cmalloc
+//go:linkname __cgofn__cgoPREFIX_Cfunc__Cmalloc _cgoPREFIX_Cfunc__Cmalloc
+var __cgofn__cgoPREFIX_Cfunc__Cmalloc byte
+var _cgoPREFIX_Cfunc__Cmalloc = unsafe.Pointer(&__cgofn__cgoPREFIX_Cfunc__Cmalloc)
+
+//go:linkname runtime_throw runtime.throw
+func runtime_throw(string)
+
+//go:cgo_unsafe_args
+func _cgo_cmalloc(p0 uint64) (r1 unsafe.Pointer) {
+ _cgo_runtime_cgocall(_cgoPREFIX_Cfunc__Cmalloc, uintptr(unsafe.Pointer(&p0)))
+ if r1 == nil {
+ runtime_throw("runtime: C malloc failed")
+ }
+ return
+}
+`
+
+// cMallocDefC defines the C version of C.malloc for the gc compiler.
+// It is defined here because C.CString and friends need a definition.
+// We define it by hand, rather than simply inventing a reference to
+// C.malloc, because <stdlib.h> may not have been included.
+// This is approximately what writeOutputFunc would generate, but
+// skips the cgo_topofstack code (which is only needed if the C code
+// calls back into Go). This also avoids returning nil for an
+// allocation of 0 bytes.
+const cMallocDefC = `
+CGO_NO_SANITIZE_THREAD
+void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
+ struct {
+ unsigned long long p0;
+ void *r1;
+ } PACKED *a = v;
+ void *ret;
+ _cgo_tsan_acquire();
+ ret = malloc(a->p0);
+ if (ret == 0 && a->p0 == 0) {
+ ret = malloc(1);
+ }
+ a->r1 = ret;
+ _cgo_tsan_release();
+}
+`
+
+func (p *Package) cPrologGccgo() string {
+ r := strings.NewReplacer(
+ "PREFIX", cPrefix,
+ "GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(),
+ "_cgoCheckPointer", gccgoToSymbol("_cgoCheckPointer"),
+ "_cgoCheckResult", gccgoToSymbol("_cgoCheckResult"))
+ return r.Replace(cPrologGccgo)
+}
+
+const cPrologGccgo = `
+#line 1 "cgo-c-prolog-gccgo"
+#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);
+
+extern void runtime_throw(const char *);
+
+const char *_cgoPREFIX_Cfunc_CString(struct __go_string s) {
+ char *p = malloc(s.__length+1);
+ if(p == NULL)
+ runtime_throw("runtime: C malloc failed");
+ memmove(p, s.__data, s.__length);
+ p[s.__length] = 0;
+ return p;
+}
+
+void *_cgoPREFIX_Cfunc_CBytes(struct __go_open_array b) {
+ char *p = malloc(b.__count);
+ if(p == NULL)
+ runtime_throw("runtime: C malloc failed");
+ memmove(p, b.__values, b.__count);
+ 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);
+}
+
+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;
+}
+
+struct __go_type_descriptor;
+typedef struct __go_empty_interface {
+ const struct __go_type_descriptor *__type_descriptor;
+ void *__object;
+} Eface;
+
+extern void runtimeCgoCheckPointer(Eface, Eface)
+ __asm__("runtime.cgoCheckPointer")
+ __attribute__((weak));
+
+extern void localCgoCheckPointer(Eface, Eface)
+ __asm__("GCCGOSYMBOLPREF._cgoCheckPointer");
+
+void localCgoCheckPointer(Eface ptr, Eface arg) {
+ if(runtimeCgoCheckPointer) {
+ runtimeCgoCheckPointer(ptr, arg);
+ }
+}
+
+extern void runtimeCgoCheckResult(Eface)
+ __asm__("runtime.cgoCheckResult")
+ __attribute__((weak));
+
+extern void localCgoCheckResult(Eface)
+ __asm__("GCCGOSYMBOLPREF._cgoCheckResult");
+
+void localCgoCheckResult(Eface val) {
+ if(runtimeCgoCheckResult) {
+ runtimeCgoCheckResult(val);
+ }
+}
+`
+
+// builtinExportProlog is a shorter version of builtinProlog,
+// to be put into the _cgo_export.h file.
+// For historical reasons we can't use builtinProlog in _cgo_export.h,
+// because _cgo_export.h defines GoString as a struct while builtinProlog
+// defines it as a function. We don't change this to avoid unnecessarily
+// breaking existing code.
+// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
+// error if a Go file with a cgo comment #include's the export header
+// generated by a different package.
+const builtinExportProlog = `
+#line 1 "cgo-builtin-export-prolog"
+
+#include <stddef.h>
+
+#ifndef GO_CGO_EXPORT_PROLOGUE_H
+#define GO_CGO_EXPORT_PROLOGUE_H
+
+#ifndef GO_CGO_GOSTRING_TYPEDEF
+typedef struct { const char *p; ptrdiff_t n; } _GoString_;
+#endif
+
+#endif
+`
+
+func (p *Package) gccExportHeaderProlog() string {
+ return strings.Replace(gccExportHeaderProlog, "GOINTBITS", fmt.Sprint(8*p.IntSize), -1)
+}
+
+// gccExportHeaderProlog is written to the exported header, after the
+// import "C" comment preamble but before the generated declarations
+// of exported functions. This permits the generated declarations to
+// use the type names that appear in goTypes, above.
+//
+// The test of GO_CGO_GOSTRING_TYPEDEF avoids a duplicate definition
+// error if a Go file with a cgo comment #include's the export header
+// generated by a different package. Unfortunately GoString means two
+// different things: in this prolog it means a C name for the Go type,
+// while in the prolog written into the start of the C code generated
+// from a cgo-using Go file it means the C.GoString function. There is
+// no way to resolve this conflict, but it also doesn't make much
+// difference, as Go code never wants to refer to the latter meaning.
+const gccExportHeaderProlog = `
+/* Start of boilerplate cgo prologue. */
+#line 1 "cgo-gcc-export-header-prolog"
+
+#ifndef GO_CGO_PROLOGUE_H
+#define GO_CGO_PROLOGUE_H
+
+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_t GoUintptr;
+typedef float GoFloat32;
+typedef double GoFloat64;
+#ifdef _MSC_VER
+#include <complex.h>
+typedef _Fcomplex GoComplex64;
+typedef _Dcomplex GoComplex128;
+#else
+typedef float _Complex GoComplex64;
+typedef double _Complex GoComplex128;
+#endif
+
+/*
+ static assertion to make sure the file is being used on architecture
+ at least with matching size of GoInt.
+*/
+typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
+
+#ifndef GO_CGO_GOSTRING_TYPEDEF
+typedef _GoString_ GoString;
+#endif
+typedef void *GoMap;
+typedef void *GoChan;
+typedef struct { void *t; void *v; } GoInterface;
+typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
+
+#endif
+
+/* End of boilerplate cgo prologue. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+`
+
+// gccExportHeaderEpilog goes at the end of the generated header file.
+const gccExportHeaderEpilog = `
+#ifdef __cplusplus
+}
+#endif
+`
+
+// gccgoExportFileProlog is written to the _cgo_export.c file when
+// using gccgo.
+// We use weak declarations, and test the addresses, so that this code
+// works with older versions of gccgo.
+const gccgoExportFileProlog = `
+#line 1 "cgo-gccgo-export-file-prolog"
+extern _Bool runtime_iscgo __attribute__ ((weak));
+
+static void GoInit(void) __attribute__ ((constructor));
+static void GoInit(void) {
+ if(&runtime_iscgo)
+ runtime_iscgo = 1;
+}
+
+extern size_t _cgo_wait_runtime_init_done(void) __attribute__ ((weak));
+`
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
new file mode 100644
index 0000000..054cd6c
--- /dev/null
+++ b/src/cmd/cgo/util.go
@@ -0,0 +1,114 @@
+// 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) {
+ if i := find(argv, "-xc"); i >= 0 && argv[len(argv)-1] == "-" {
+ // Some compilers have trouble with standard input.
+ // Others have trouble with -xc.
+ // Avoid both problems by writing a file with a .c extension.
+ f, err := os.CreateTemp("", "cgo-gcc-input-")
+ if err != nil {
+ fatalf("%s", err)
+ }
+ name := f.Name()
+ f.Close()
+ if err := os.WriteFile(name+".c", stdin, 0666); err != nil {
+ os.Remove(name)
+ fatalf("%s", err)
+ }
+ defer os.Remove(name)
+ defer os.Remove(name + ".c")
+
+ // Build new argument list without -xc and trailing -.
+ new := append(argv[:i:i], argv[i+1:len(argv)-1]...)
+
+ // Since we are going to write the file to a temporary directory,
+ // we will need to add -I . explicitly to the command line:
+ // any #include "foo" before would have looked in the current
+ // directory as the directory "holding" standard input, but now
+ // the temporary directory holds the input.
+ // We've also run into compilers that reject "-I." but allow "-I", ".",
+ // so be sure to use two arguments.
+ // This matters mainly for people invoking cgo -godefs by hand.
+ new = append(new, "-I", ".")
+
+ // Finish argument list with path to C file.
+ new = append(new, name+".c")
+
+ argv = new
+ stdin = nil
+ }
+
+ p := exec.Command(argv[0], argv[1:]...)
+ p.Stdin = bytes.NewReader(stdin)
+ var bout, berr bytes.Buffer
+ p.Stdout = &bout
+ p.Stderr = &berr
+ // Disable escape codes in clang error messages.
+ p.Env = append(os.Environ(), "TERM=dumb")
+ err := p.Run()
+ if _, ok := err.(*exec.ExitError); err != nil && !ok {
+ fatalf("exec %s: %s", argv[0], err)
+ }
+ ok = p.ProcessState.Success()
+ stdout, stderr = bout.Bytes(), berr.Bytes()
+ return
+}
+
+func find(argv []string, target string) int {
+ for i, arg := range argv {
+ if arg == target {
+ return i
+ }
+ }
+ return -1
+}
+
+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, "cgo: "+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())
+ } else {
+ fmt.Fprintf(os.Stderr, "cgo: ")
+ }
+ fmt.Fprintf(os.Stderr, msg, args...)
+ fmt.Fprintf(os.Stderr, "\n")
+}
+
+func creat(name string) *os.File {
+ f, err := os.Create(name)
+ if err != nil {
+ fatalf("%s", err)
+ }
+ return f
+}