示例#1
0
文件: binutils.go 项目: google/pprof
func (b *Binutils) openELF(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
	ef, err := elf.Open(name)
	if err != nil {
		return nil, fmt.Errorf("Parsing %s: %v", name, err)
	}
	defer ef.Close()

	var stextOffset *uint64
	var pageAligned = func(addr uint64) bool { return addr%4096 == 0 }
	if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) {
		// Reading all Symbols is expensive, and we only rarely need it so
		// we don't want to do it every time. But if _stext happens to be
		// page-aligned but isn't the same as Vaddr, we would symbolize
		// wrong. So if the name the addresses aren't page aligned, or if
		// the name is "vmlinux" we read _stext. We can be wrong if: (1)
		// someone passes a kernel path that doesn't contain "vmlinux" AND
		// (2) _stext is page-aligned AND (3) _stext is not at Vaddr
		symbols, err := ef.Symbols()
		if err != nil {
			return nil, err
		}
		for _, s := range symbols {
			if s.Name == "_stext" {
				// The kernel may use _stext as the mapping start address.
				stextOffset = &s.Value
				break
			}
		}
	}

	base, err := elfexec.GetBase(&ef.FileHeader, nil, stextOffset, start, limit, offset)
	if err != nil {
		return nil, fmt.Errorf("Could not identify base for %s: %v", name, err)
	}

	buildID := ""
	if f, err := os.Open(name); err == nil {
		if id, err := elfexec.GetBuildID(f); err == nil {
			buildID = fmt.Sprintf("%x", id)
		}
	}
	if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
		return &fileNM{file: file{b, name, base, buildID}}, nil
	}
	return &fileAddr2Line{file: file{b, name, base, buildID}}, nil
}
示例#2
0
// Open satisfies the plugin.ObjTool interface.
func (b *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
	if b.addr2line == "" {
		// Update the command invocations if not initialized.
		b.SetTools("")
	}

	// Make sure file is a supported executable.
	// The pprof driver uses Open to sniff the difference
	// between an executable and a profile.
	// For now, only ELF is supported.
	// Could read the first few bytes of the file and
	// use a table of prefixes if we need to support other
	// systems at some point.

	f, err := os.Open(name)
	if err != nil {
		// For testing, do not require file name to exist.
		if strings.Contains(b.addr2line, "testdata/") {
			return &fileAddr2Line{file: file{b: b, name: name}}, nil
		}

		return nil, err
	}
	defer f.Close()

	ef, err := elf.NewFile(f)
	if err != nil {
		return nil, fmt.Errorf("Parsing %s: %v", name, err)
	}

	var stextOffset *uint64
	var pageAligned = func(addr uint64) bool { return addr%4096 == 0 }
	if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) {
		// Reading all Symbols is expensive, and we only rarely need it so
		// we don't want to do it every time.  But if _stext happens to be
		// page-aligned but isn't the same as Vaddr, we would symbolize
		// wrong.  So if the name the addresses aren't page aligned, or if
		// the name is "vmlinux" we read _stext.  We can be wrong if: (1)
		// someone passes a kernel path that doesn't contain "vmlinux" AND
		// (2) _stext is page-aligned AND (3) _stext is not at Vaddr
		symbols, err := ef.Symbols()
		if err != nil {
			return nil, err
		}
		for _, s := range symbols {
			if s.Name == "_stext" {
				// The kernel may use _stext as the mapping start address.
				stextOffset = &s.Value
				break
			}
		}
	}

	base, err := elfexec.GetBase(&ef.FileHeader, nil, stextOffset, start, limit, offset)
	if err != nil {
		return nil, fmt.Errorf("Could not identify base for %s: %v", name, err)
	}

	// Find build ID, while we have the file open.
	buildID := ""
	if id, err := elfexec.GetBuildID(f); err == nil {
		buildID = fmt.Sprintf("%x", id)
	}
	if b.fast {
		return &fileNM{file: file{b, name, base, buildID}}, nil
	}
	return &fileAddr2Line{file: file{b, name, base, buildID}}, nil
}