diff options
| author | Ondřej Surý <ondrej@sury.org> | 2011-06-28 15:28:34 +0200 |
|---|---|---|
| committer | Ondřej Surý <ondrej@sury.org> | 2011-06-28 15:28:34 +0200 |
| commit | 8d00b02d82d86abe51773dc2c1751843bb538ae5 (patch) | |
| tree | 6656d166a046fc751548e88f071fedbeb9355443 /src/cmd/cgo | |
| parent | c29cace1e8f3260389ea78fa4ef86d80cd5e5275 (diff) | |
| download | golang-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.go | 95 | ||||
| -rw-r--r-- | src/cmd/cgo/main.go | 3 | ||||
| -rw-r--r-- | src/cmd/cgo/out.go | 17 | ||||
| -rw-r--r-- | src/cmd/cgo/util.go | 2 |
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 |
