Example #1
0
//============================================================================
//		main : Entry point.
//----------------------------------------------------------------------------
func main() {

	var dwarfData *dwarf.Data
	var theFile *macho.File
	var theErr os.Error
	var relativeAddress uint64
	var runtimeAddress uint64
	var loadAddress uint64
	var segmentAddress uint64
	var pathMacho string
	var pathDsym string

	// Parse our arguments
	flag.Uint64Var(&runtimeAddress, "raddr", 0, "")
	flag.Uint64Var(&loadAddress, "laddr", 0, "")
	flag.StringVar(&pathMacho, "macho", "", "")
	flag.StringVar(&pathDsym, "dsym", "", "")
	flag.Parse()

	if runtimeAddress == 0 || loadAddress == 0 || pathMacho == "" || pathDsym == "" {
		printHelp()
	}

	// Find the text segment address
	theFile, theErr = macho.Open(pathMacho)
	if theErr != nil {
		fatalError("Can't open Mach-O file: " + theErr.String())
	}

	segmentAddress = theFile.Segment("__TEXT").Addr

	theFile.Close()

	// Calculate the target address
	relativeAddress = runtimeAddress - loadAddress
	gTargetAddress = segmentAddress + relativeAddress

	// Find the target
	theFile, theErr = macho.Open(pathDsym)
	if theErr != nil {
		fatalError("Can't open .dsym file: " + theErr.String())
	}

	dwarfData, theErr = theFile.DWARF()
	if theErr != nil {
		fatalError("Can't find DWARF info: " + theErr.String())
	}

	processChildren(dwarfData.Reader(), 0, false)

	theFile.Close()
}
Example #2
0
File: main.go Project: ebfe/gover
func openBinary(name string) (Binary, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	magic := make([]byte, 4)
	if _, err := f.ReadAt(magic[:], 0); err != nil {
		return nil, err
	}

	if bytes.HasPrefix(magic, []byte{0x7f, 'E', 'L', 'F'}) {
		e, err := elf.NewFile(f)
		if err != nil {
			return nil, err
		}
		return &elfBinary{File: e}, nil
	} else if bytes.HasPrefix(magic, []byte{'M', 'Z'}) {
		p, err := pe.Open(name)
		if err != nil {
			return nil, err
		}
		return &peBinary{File: p}, nil
	} else if bytes.HasPrefix(magic, []byte{0xcf, 0xfa, 0xed, 0xfe}) {
		m, err := macho.Open(name)
		if err != nil {
			return nil, err
		}
		return &machoBinary{File: m}, nil
	}
	return nil, fmt.Errorf("unsupported binary format")
}
Example #3
0
func TestMachO(filename, expectedArch, expectedOs string, isVerbose bool) error {
	file, err := macho.Open(filename)
	if err != nil {

		log.Printf("File '%s' is not a Mach-O file: %v\n", filename, err)
		return err
	}
	defer file.Close()
	if isVerbose {
		log.Printf("File '%s' is a Mach-O file (arch: %s)\n", filename, file.FileHeader.Cpu.String())
	}
	if expectedArch == platforms.X86 {
		if file.FileHeader.Cpu != macho.Cpu386 {
			return errors.New("Not a 386 executable")
		}

	}
	if expectedArch == platforms.AMD64 {
		if file.FileHeader.Cpu != macho.CpuAmd64 {
			return errors.New("Not an AMD64 executable")
		}

	}
	return nil
}
Example #4
0
func getDwarf(execname string) *dwarf.Data {
	e, err := elf.Open(execname)
	if err == nil {
		defer e.Close()
		d, err := e.DWARF()
		if err == nil {
			return d
		}
	}
	m, err := macho.Open(execname)
	if err == nil {
		defer m.Close()
		d, err := m.DWARF()
		if err == nil {
			return d
		}
	}
	p, err := pe.Open(execname)
	if err == nil {
		defer p.Close()
		d, err := p.DWARF()
		if err == nil {
			return d
		}
	}
	log.Fatal("can't get dwarf info from executable", err)
	return nil
}
Example #5
0
func IsMACHO(fPath string) error {
	if _, err := macho.Open(fPath); err != nil {
		return err
	}

	return nil
}
Example #6
0
// darwinRelink makes paths of linked libraries relative to executable.
//
//   /usr/local/Cellar/qt5/5.3.0/lib/QtWidgets.framework/Versions/5/QtWidgets
//   /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets
//   ->
//   @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets
func darwinRelink(qlib, name string, strict bool) (err error) {
	file, err := macho.Open(name)
	if err != nil {
		return
	}
	defer file.Close()
	libs, err := file.ImportedLibraries()
	if err != nil {
		return
	}
	var qlib2 string
	// detect alternative qlib (homebrew symlinks Qt to /usr/local/opt)
	for _, lib := range libs {
		idx := strings.Index(lib, "QtCore")
		if idx > 0 {
			qlib2 = lib[:idx-1] // drop sep
			break
		}
	}
	replacer := strings.NewReplacer(qlib, relinkBase, qlib2, relinkBase)
	if len(qlib2) < 1 && strict {
		return fmt.Errorf("darwin relink: corrupt binary: %s", name)
	} else if !strict {
		replacer = strings.NewReplacer(qlib, relinkBase)
	}
	// replace qlib/qlib2 to relinkBase
	for _, lib := range libs {
		rlib := replacer.Replace(lib)
		cmd := exec.Command("install_name_tool", "-change", lib, rlib, name)
		if err = cmd.Run(); err != nil {
			return fmt.Errorf("darwin relink: %v", err)
		}
	}
	return
}
Example #7
0
func main() {
	file, err := macho.Open("bash.macho")
	if err != nil {
		log.Fatalf("failed opening file: %s", err)
	}
	defer file.Close()
	printFileInformation(file)
}
Example #8
0
File: out.go Project: jnwhiteh/go
func dynimport(obj string) {
	if f, err := elf.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
		}
		for _, s := range sym {
			targ := s.Name
			if s.Version != "" {
				targ += "@" + s.Version
			}
			fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
		}
		for _, l := range lib {
			fmt.Printf("#pragma dynimport _ _ %q\n", l)
		}
		return
	}

	if f, err := macho.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
		}
		for _, s := range sym {
			if len(s) > 0 && s[0] == '_' {
				s = s[1:]
			}
			fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "")
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
		}
		for _, l := range lib {
			fmt.Printf("#pragma dynimport _ _ %q\n", l)
		}
		return
	}

	if f, err := pe.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
		}
		for _, s := range sym {
			ss := strings.Split(s, ":", -1)
			fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
		}
		return
	}

	fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
}
Example #9
0
func MACHOAnal(input string, symbolsDump bool) ([][]int, error) {
	// An array of arrays for storing the section offsets
	var sectionData [][]int

	fmt.Printf("[+] Analyzing binary: %s\n", input)

	// Check for executable type
	machoFmt, err := macho.Open(input)
	if err != nil {
		return sectionData, err
	}
	defer machoFmt.Close()

	sections := machoFmt.Sections
	sectionCount := len(sections)

	fmt.Printf("[+] Number of sections: %d\n", sectionCount)

	for k := range sections {
		sec := sections[k]
		secName := sec.Name
		secSize := sec.Size
		secOffset := sec.Offset + 1
		secEnd := int(secOffset) + int(secSize) - 1

		fmt.Printf("\t Name: %s\n", secName)
		fmt.Printf("\t Size: %d\n", secSize)
		fmt.Printf("\t Offset: %d\n", secOffset)
		fmt.Printf("\t Section end: %d\n", secEnd)
		fmt.Println("")

		sectionData = append(sectionData, []int{int(secOffset), int(secEnd)})
	}

	symbols, err := machoFmt.ImportedSymbols()
	if err != nil {
		return sectionData, err
	}

	numberOfSymbols := len(symbols)

	fmt.Printf("[+] Found %d symbols\n", numberOfSymbols)
	if numberOfSymbols > 0 && symbolsDump {
		for k := range symbols {
			symName := symbols[k]

			fmt.Printf("\t Name: %s\n", symName)
		}
		fmt.Println("")
	}

	return sectionData, nil
}
Example #10
0
func machoData(t *testing.T, name string) *Data {
	f, err := macho.Open(name)
	if err != nil {
		t.Fatal(err)
	}

	d, err := f.DWARF()
	if err != nil {
		t.Fatal(err)
	}
	return d
}
Example #11
0
func (b *Binutils) openMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
	of, err := macho.Open(name)
	if err != nil {
		return nil, fmt.Errorf("Parsing %s: %v", name, err)
	}
	defer of.Close()

	if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
		return &fileNM{file: file{b: b, name: name}}, nil
	}
	return &fileAddr2Line{file: file{b: b, name: name}}, nil
}
Example #12
0
File: gcc.go Project: WXB506/golang
// 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) (*dwarf.Data, binary.ByteOrder, []byte) {
	runGcc(stdin, p.gccCmd())

	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
	}

	// 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
	}

	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")
}
Example #13
0
func newmacho(path string) (tabler, error) {
	f, err := macho.Open(path)
	if err != nil {
		return nil, err
	}
	tbl := machotbl{f, nil}
	switch tbl.Cpu {
	case macho.Cpu386:
		tbl.typ = PlatformDarwin386
	case macho.CpuAmd64:
		tbl.typ = PlatformDarwinAMD64
	}
	return tbl, nil
}
Example #14
0
// Open an input file.
func open(name string) (*file, error) {
	efile, err := Open(name)
	var mfile *macho.File
	if err != nil {
		var merr error
		mfile, merr = macho.Open(name)
		if merr != nil {
			return nil, err
		}
	}

	r := &file{elf: efile, macho: mfile}

	if efile != nil {
		r.dwarf, err = efile.DWARF()
	} else {
		r.dwarf, err = mfile.DWARF()
	}
	if err != nil {
		return nil, err
	}

	var syms []sym
	if efile != nil {
		esyms, err := efile.Symbols()
		if err != nil {
			return nil, err
		}
		syms = make([]sym, 0, len(esyms))
		for _, s := range esyms {
			if ST_TYPE(s.Info) == STT_FUNC {
				syms = append(syms, sym{s.Name, uintptr(s.Value)})
			}
		}
	} else {
		syms = make([]sym, 0, len(mfile.Symtab.Syms))
		for _, s := range mfile.Symtab.Syms {
			syms = append(syms, sym{s.Name, uintptr(s.Value)})
		}
	}

	r.symsByName = make([]sym, len(syms))
	copy(r.symsByName, syms)
	sort.Sort(symsByName(r.symsByName))

	r.symsByAddr = syms
	sort.Sort(symsByAddr(r.symsByAddr))

	return r, nil
}
Example #15
0
func (dbp *Process) findExecutable(path string) (*macho.File, error) {
	if path == "" {
		path = C.GoString(C.find_executable(C.int(dbp.Pid)))
	}
	exe, err := macho.Open(path)
	if err != nil {
		return nil, err
	}
	data, err := exe.DWARF()
	if err != nil {
		return nil, err
	}
	dbp.dwarf = data
	return exe, nil
}
Example #16
0
func Open(name string) (binaryx.File, error) {
	elfBinary, err := elf.Open(name)
	if err == nil {
		return newFile(&elfx.File{elfBinary})
	}
	machoBinary, err := macho.Open(name)
	if err == nil {
		return newFile(&machox.File{machoBinary})
	}
	peBinary, err := pe.Open(name)
	if err == nil {
		return newFile(&pex.File{peBinary})
	}
	return nil, err
}
Example #17
0
func MACHOAnal(input string) ([]SectionData, []string, []string, error) {
	// An array of arrays for storing the section offsets
	var sectionData []SectionData

	// Check for executable type
	machoFmt, err := macho.Open(input)
	if err != nil {
		return sectionData, []string{}, []string{}, NotValidMACHOFileError
	}
	defer machoFmt.Close()

	// Extract sections
	sections := machoFmt.Sections
	for k := range sections {
		sec := sections[k]
		secName := sec.Name
		secSize := sec.Size
		secOffset := sec.Offset + 1
		secEnd := int(secOffset) + int(secSize) - 1

		sd := SectionData{
			Name:   secName,
			Size:   int(secSize),
			Offset: int(secOffset),
			End:    int(secEnd),
		}

		sectionData = append(sectionData, sd)
	}

	// Get imported symbols
	symbolsArr, err := machoFmt.ImportedSymbols()
	if err != nil {
		return sectionData, []string{}, []string{}, err
	}

	// Get imported libraries
	libraries, err := machoFmt.ImportedLibraries()
	if err != nil {
		return sectionData, []string{}, []string{}, err
	}

	return sectionData, libraries, symbolsArr, nil
}
Example #18
0
// 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 *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) {
	machine := "-m32"
	if p.PtrSize == 8 {
		machine = "-m64"
	}

	tmp := "_cgo_.o"
	base := []string{
		"gcc",
		machine,
		"-Wall",                             // many warnings
		"-Werror",                           // warnings are errors
		"-o" + tmp,                          // write object to tmp
		"-gdwarf-2",                         // generate DWARF v2 debugging symbols
		"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
		"-c",  // do not link
		"-xc", // input language is C
		"-",   // read input from standard input
	}
	_, stderr, ok := run(stdin, concat(base, p.GccOptions))
	if !ok {
		return nil, string(stderr)
	}

	// 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(tmp); err != nil {
		if f, err = macho.Open(tmp); err != nil {
			fatal("cannot parse gcc output %s as ELF or Mach-O object", tmp)
		}
	}

	d, err := f.DWARF()
	if err != nil {
		fatal("cannot load DWARF debug information from %s: %s", tmp, err)
	}
	return d, ""
}
Example #19
0
// 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 {
	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)
			}
		}
	}

	d, err := f.DWARF()
	if err != nil {
		fatalf("cannot load DWARF debug information from %s: %s", gccTmp, err)
	}
	return d
}
Example #20
0
// Check that aranges are valid even when lldb isn't installed.
func TestDwarfAranges(t *testing.T) {
	testenv.MustHaveGoBuild(t)
	dir, err := ioutil.TempDir("", "go-build")
	if err != nil {
		t.Fatalf("failed to create temp directory: %v", err)
	}
	defer os.RemoveAll(dir)

	src := filepath.Join(dir, "main.go")
	err = ioutil.WriteFile(src, []byte(lldbHelloSource), 0644)
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}

	cmd := exec.Command("go", "build", "-o", "a.exe")
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("building source %v\n%s", err, out)
	}

	filename := filepath.Join(dir, "a.exe")
	if f, err := elf.Open(filename); err == nil {
		sect := f.Section(".debug_aranges")
		if sect == nil {
			t.Fatal("Missing aranges section")
		}
		verifyAranges(t, f.ByteOrder, sect.Open())
	} else if f, err := macho.Open(filename); err == nil {
		sect := f.Section("__debug_aranges")
		if sect == nil {
			t.Fatal("Missing aranges section")
		}
		verifyAranges(t, f.ByteOrder, sect.Open())
	} else {
		t.Skip("Not an elf or macho binary.")
	}
}
Example #21
0
File: main.go Project: BenLubar/bit
func pclnMacho() (textStart uint64, symtab, pclntab []byte, err error) {
	f, err := macho.Open(*flagCompiler)
	if err != nil {
		return
	}
	defer f.Close()

	if sect := f.Section("__text"); sect != nil {
		textStart = sect.Addr
	}
	if sect := f.Section("__gosymtab"); sect != nil {
		if symtab, err = sect.Data(); err != nil {
			return
		}
	}
	if sect := f.Section("__gopclntab"); sect != nil {
		if pclntab, err = sect.Data(); err != nil {
			return
		}
	}

	return
}
Example #22
0
func macho_symsizes(path string) map[string]float64 {
	m := make(map[string]float64)
	f, err := macho.Open(path)
	if err != nil {
		panic(err.Error())
	}
	syms := make([]macho.Symbol, len(f.Symtab.Syms))
	copy(syms, f.Symtab.Syms)
	sort.Sort(bySectionThenOffset(syms))
	for i, sym := range syms {
		if sym.Sect == 0 {
			continue
		}
		var nextOffset uint64
		if i == len(syms)-1 || syms[i+1].Sect != sym.Sect {
			nextOffset = f.Sections[sym.Sect-1].Size
		} else {
			nextOffset = syms[i+1].Value
		}
		m[sym.Name] = float64(nextOffset - sym.Value)
	}
	return m
}
Example #23
0
File: out.go Project: Harvey-OS/go
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, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
		}
		for _, s := range sym {
			targ := s.Name
			if s.Version != "" {
				targ += "#" + s.Version
			}
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
		}
		for _, l := range lib {
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
		}
		return
	}

	if f, err := macho.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
		}
		for _, s := range sym {
			if len(s) > 0 && s[0] == '_' {
				s = s[1:]
			}
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
		}
		lib, err := f.ImportedLibraries()
		if err != nil {
			fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
		}
		for _, l := range lib {
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
		}
		return
	}

	if f, err := pe.Open(obj); err == nil {
		sym, err := f.ImportedSymbols()
		if err != nil {
			fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
		}
		for _, s := range sym {
			ss := strings.Split(s, ":")
			name := strings.Split(ss[0], "@")[0]
			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
		}
		return
	}

	fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
}
Example #24
0
// 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) (*dwarf.Data, binary.ByteOrder, []byte) {
	runGcc(stdin, p.gccCmd())

	isDebugData := func(s string) bool {
		// Some systems use leading _ to denote non-assembly symbols.
		return s == "__cgodebug_data" || s == "___cgodebug_data"
	}

	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)
		}
		var data []byte
		if f.Symtab != nil {
			for i := range f.Symtab.Syms {
				s := &f.Symtab.Syms[i]
				if isDebugData(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:]
							}
						}
					}
				}
			}
		}
		return d, f.ByteOrder, data
	}

	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)
		}
		var data []byte
		symtab, err := f.Symbols()
		if err == nil {
			for i := range symtab {
				s := &symtab[i]
				if isDebugData(s.Name) {
					// Found it.  Now find data section.
					if i := int(s.Section); 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
	}

	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)
		}
		var data []byte
		for _, s := range f.Symbols {
			if isDebugData(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:]
						}
					}
				}
			}
		}
		return d, binary.LittleEndian, data
	}

	fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
	panic("not reached")
}