summaryrefslogtreecommitdiff
path: root/src/cmd/cgo
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-06-28 15:28:34 +0200
committerOndřej Surý <ondrej@sury.org>2011-06-28 15:28:34 +0200
commit8d00b02d82d86abe51773dc2c1751843bb538ae5 (patch)
tree6656d166a046fc751548e88f071fedbeb9355443 /src/cmd/cgo
parentc29cace1e8f3260389ea78fa4ef86d80cd5e5275 (diff)
downloadgolang-8d00b02d82d86abe51773dc2c1751843bb538ae5.tar.gz
Imported Upstream version 2011.06.23upstream-weekly/2011.06.23
Diffstat (limited to 'src/cmd/cgo')
-rw-r--r--src/cmd/cgo/gcc.go95
-rw-r--r--src/cmd/cgo/main.go3
-rw-r--r--src/cmd/cgo/out.go17
-rw-r--r--src/cmd/cgo/util.go2
4 files changed, 88 insertions, 29 deletions
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 10411e94f..6b930f151 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -13,6 +13,7 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
+ "encoding/binary"
"flag"
"fmt"
"go/ast"
@@ -229,9 +230,9 @@ func splitQuoted(s string) (r []string, err os.Error) {
args = append(args, string(arg[:i]))
}
if quote != 0 {
- err = os.ErrorString("unclosed quote")
+ err = os.NewError("unclosed quote")
} else if escaped {
- err = os.ErrorString("unfinished escaping")
+ err = os.NewError("unfinished escaping")
}
return args, err
}
@@ -477,7 +478,27 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
}
}
- d := p.gccDebug(b.Bytes())
+
+ // Apple's LLVM-based gcc does not include the enumeration
+ // names and values in its DWARF debug output. In case we're
+ // using such a gcc, create a data block initialized with the values.
+ // We can read them out of the object file.
+ fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n")
+ for _, n := range names {
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "\t%s,\n", n.C)
+ } else {
+ fmt.Fprintf(&b, "\t0,\n")
+ }
+ }
+ fmt.Fprintf(&b, "\t0\n")
+ fmt.Fprintf(&b, "};\n")
+
+ d, bo, debugData := p.gccDebug(b.Bytes())
+ enumVal := make([]int64, len(debugData)/8)
+ for i := range enumVal {
+ enumVal[i] = int64(bo.Uint64(debugData[i*8:]))
+ }
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
@@ -569,9 +590,12 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
// Remove injected enum to ensure the value will deep-compare
// equally in future loads of the same constant.
n.Type.EnumValues[k] = 0, false
+ } else if n.Kind == "const" && i < len(enumVal) {
+ n.Const = strconv.Itoa64(enumVal[i])
}
}
}
+
}
// rewriteRef rewrites all the C.xxx references in f.AST to refer to the
@@ -593,6 +617,9 @@ func (p *Package) rewriteRef(f *File) {
// are trying to do a ,err call. Also check that
// functions are only used in calls.
for _, r := range f.Ref {
+ if r.Name.Kind == "const" && r.Name.Const == "" {
+ error(r.Pos(), "unable to find value of constant C.%s", r.Name.Go)
+ }
var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
switch r.Context {
case "call", "call2":
@@ -670,7 +697,7 @@ func (p *Package) gccMachine() []string {
return nil
}
-const gccTmp = "_obj/_cgo_.o"
+var gccTmp = objDir + "_cgo_.o"
// gccCmd returns the gcc command line to use for compiling
// the input.
@@ -692,29 +719,57 @@ func (p *Package) gccCmd() []string {
}
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
-// returns the corresponding DWARF data and any messages
-// printed to standard error.
-func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
+// returns the corresponding DWARF data and, if present, debug data block.
+func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) {
runGcc(stdin, p.gccCmd())
- // Try to parse f as ELF and Mach-O and hope one works.
- var f interface {
- DWARF() (*dwarf.Data, os.Error)
- }
- var err os.Error
- if f, err = elf.Open(gccTmp); err != nil {
- if f, err = macho.Open(gccTmp); err != nil {
- if f, err = pe.Open(gccTmp); err != nil {
- fatalf("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp)
+ if f, err := macho.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ var data []byte
+ if f.Symtab != nil {
+ for i := range f.Symtab.Syms {
+ s := &f.Symtab.Syms[i]
+ // Mach-O still uses a leading _ to denote non-assembly symbols.
+ if s.Name == "_"+"__cgodebug_data" {
+ // Found it. Now find data section.
+ if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data = sdat[s.Value-sect.Addr:]
+ }
+ }
+ }
+ }
}
}
+ return d, f.ByteOrder, data
}
- d, err := f.DWARF()
- if err != nil {
- fatalf("cannot load DWARF debug information from %s: %s", gccTmp, err)
+ // Can skip debug data block in ELF and PE for now.
+ // The DWARF information is complete.
+
+ if f, err := elf.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ return d, f.ByteOrder, nil
}
- return d
+
+ if f, err := pe.Open(gccTmp); err == nil {
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp, err)
+ }
+ return d, binary.LittleEndian, nil
+ }
+
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp)
+ panic("not reached")
}
// gccDefines runs gcc -E -dM -xc - over the C program stdin
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 84aeccc21..be9c2bc4f 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -18,6 +18,7 @@ import (
"go/token"
"io"
"os"
+ "path/filepath"
"reflect"
"strings"
)
@@ -228,7 +229,7 @@ func main() {
}
pkg := f.Package
if dir := os.Getenv("CGOPKGPATH"); dir != "" {
- pkg = dir + "/" + pkg
+ pkg = filepath.Join(dir, pkg)
}
p.PackagePath = pkg
p.writeOutput(f, input)
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index dbc7bcf69..7eecb3437 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -14,17 +14,20 @@ import (
"go/printer"
"go/token"
"os"
+ "path/filepath"
"strings"
)
+var objDir = "_obj" + string(filepath.Separator)
+
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeDefs() {
- fgo2 := creat("_obj/_cgo_gotypes.go")
- fc := creat("_obj/_cgo_defun.c")
- fm := creat("_obj/_cgo_main.c")
+ fgo2 := creat(objDir + "_cgo_gotypes.go")
+ fc := creat(objDir + "_cgo_defun.c")
+ fm := creat(objDir + "_cgo_main.c")
- fflg := creat("_obj/_cgo_flags")
+ fflg := creat(objDir + "_cgo_flags")
for k, v := range p.CgoFlags {
fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, v)
}
@@ -285,8 +288,8 @@ func (p *Package) writeOutput(f *File, srcfile string) {
base = base[0 : len(base)-3]
}
base = strings.Map(slashToUnderscore, base)
- fgo1 := creat("_obj/" + base + ".cgo1.go")
- fgcc := creat("_obj/" + base + ".cgo2.c")
+ 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")
@@ -361,7 +364,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// Write out the various stubs we need to support functions exported
// from Go so that they are callable from C.
func (p *Package) writeExports(fgo2, fc, fm *os.File) {
- fgcc := creat("_obj/_cgo_export.c")
+ fgcc := creat(objDir + "_cgo_export.c")
fgcch := creat("_cgo_export.h")
fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 1ca24103e..e79b0e1bf 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -103,7 +103,7 @@ func creat(name string) *os.File {
}
func slashToUnderscore(c int) int {
- if c == '/' {
+ if c == '/' || c == '\\' || c == ':' {
c = '_'
}
return c