]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.r58] cgo: handle new Apple LLVM-based gcc from Xcode 4.2 release.r58.1
authorRuss Cox <rsc@golang.org>
Tue, 12 Jul 2011 14:19:11 +0000 (10:19 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 12 Jul 2011 14:19:11 +0000 (10:19 -0400)
««« CL 4607045 / 142f0bc0d6e7
cgo: handle new Apple LLVM-based gcc from Xcode 4.2

That gcc does not include enumerator names and values
in its DWARF debug output.  Create a data block from which
we can read the values instead.

Fixes #1881.

R=iant
CC=golang-dev
https://golang.org/cl/4607045
»»»

R=adg
CC=golang-dev
https://golang.org/cl/4708042

src/cmd/cgo/gcc.go
src/pkg/debug/dwarf/type.go
src/pkg/debug/elf/file.go

index 10411e94f3224adf7ca14fd02525d7bcaa236c9e..e4e56d8dd6614d06f91b010c64569510bd072a5d 100644 (file)
@@ -13,6 +13,7 @@ import (
        "debug/elf"
        "debug/macho"
        "debug/pe"
+       "encoding/binary"
        "flag"
        "fmt"
        "go/ast"
@@ -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":
@@ -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
index f9acf119f396b66ad9cf6f86972dbdb7cf6a82eb..a33785b049e5743a1540ecfc5643abd098dc3b35 100644 (file)
@@ -352,8 +352,8 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
                        }
                }
                if ndim == 0 {
-                       err = DecodeError{"info", e.Offset, "missing dimension for array"}
-                       goto Error
+                       // LLVM generates this for x[].
+                       t.Count = -1
                }
 
        case TagBaseType:
index 9ae8b413d91f61f223032ebae39d474fb86956f3..220ab940834e6387a106e43ce6f5371909f6e8fd 100644 (file)
@@ -546,6 +546,12 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
        return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
 }
 
+// Symbols returns the symbol table for f.
+func (f *File) Symbols() ([]Symbol, os.Error) {
+       sym, _, err := f.getSymbols(SHT_SYMTAB)
+       return sym, err
+}
+
 type ImportedSymbol struct {
        Name    string
        Version string