diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index 10411e94f32..e4e56d8dd66 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" @@ -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 diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go index f9acf119f39..a33785b049e 100644 --- a/src/pkg/debug/dwarf/type.go +++ b/src/pkg/debug/dwarf/type.go @@ -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: diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go index 9ae8b413d91..220ab940834 100644 --- a/src/pkg/debug/elf/file.go +++ b/src/pkg/debug/elf/file.go @@ -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