aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google/pprof/internal/binutils
diff options
context:
space:
mode:
authorHana (Hyang-Ah) Kim <hyangah@gmail.com>2018-11-06 17:48:08 -0500
committerHyang-Ah Hana Kim <hyangah@gmail.com>2018-11-07 12:27:21 +0000
commitc0a40e4fe5d4649672d0d430ca26551841fc4852 (patch)
tree4ccd82b68f0795d68bc43caff3cba7c9fabdb4d8 /src/cmd/vendor/github.com/google/pprof/internal/binutils
parent1100df58238a1b1c55af148a880b48caf4be6504 (diff)
downloadgo-c0a40e4fe5d4649672d0d430ca26551841fc4852.tar.xz
cmd/vendor: update github.com/google/pprof
Sync @ fde099a (Oct 26, 2018) Also update misc/nacl/testzip.proto to include new testdata. Change-Id: If41590be9f395a591056e89a417b589c4ba71b1a Reviewed-on: https://go-review.googlesource.com/c/147979 Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/cmd/vendor/github.com/google/pprof/internal/binutils')
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go109
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go29
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_elf1
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_macho1
4 files changed, 125 insertions, 15 deletions
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
index 12b6a5c4b2..309561112c 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go
@@ -18,11 +18,14 @@ package binutils
import (
"debug/elf"
"debug/macho"
+ "encoding/binary"
"fmt"
+ "io"
"os"
"os/exec"
"path/filepath"
"regexp"
+ "runtime"
"strings"
"sync"
@@ -173,12 +176,8 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi
b := bu.get()
// 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.
+ // This uses magic numbers, mainly to provide better error messages but
+ // it should also help speed.
if _, err := os.Stat(name); err != nil {
// For testing, do not require file name to exist.
@@ -188,21 +187,54 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi
return nil, err
}
- if f, err := b.openELF(name, start, limit, offset); err == nil {
+ // Read the first 4 bytes of the file.
+
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, fmt.Errorf("error opening %s: %v", name, err)
+ }
+ defer f.Close()
+
+ var header [4]byte
+ if _, err = io.ReadFull(f, header[:]); err != nil {
+ return nil, fmt.Errorf("error reading magic number from %s: %v", name, err)
+ }
+
+ elfMagic := string(header[:])
+
+ // Match against supported file types.
+ if elfMagic == elf.ELFMAG {
+ f, err := b.openELF(name, start, limit, offset)
+ if err != nil {
+ return nil, fmt.Errorf("error reading ELF file %s: %v", name, err)
+ }
return f, nil
}
- if f, err := b.openMachO(name, start, limit, offset); err == nil {
+
+ // Mach-O magic numbers can be big or little endian.
+ machoMagicLittle := binary.LittleEndian.Uint32(header[:])
+ machoMagicBig := binary.BigEndian.Uint32(header[:])
+
+ if machoMagicLittle == macho.Magic32 || machoMagicLittle == macho.Magic64 ||
+ machoMagicBig == macho.Magic32 || machoMagicBig == macho.Magic64 {
+ f, err := b.openMachO(name, start, limit, offset)
+ if err != nil {
+ return nil, fmt.Errorf("error reading Mach-O file %s: %v", name, err)
+ }
+ return f, nil
+ }
+ if machoMagicLittle == macho.MagicFat || machoMagicBig == macho.MagicFat {
+ f, err := b.openFatMachO(name, start, limit, offset)
+ if err != nil {
+ return nil, fmt.Errorf("error reading fat Mach-O file %s: %v", name, err)
+ }
return f, nil
}
- return nil, fmt.Errorf("unrecognized binary: %s", name)
+
+ return nil, fmt.Errorf("unrecognized binary format: %s", name)
}
-func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
- of, err := macho.Open(name)
- if err != nil {
- return nil, fmt.Errorf("error parsing %s: %v", name, err)
- }
- defer of.Close()
+func (b *binrep) openMachOCommon(name string, of *macho.File, start, limit, offset uint64) (plugin.ObjFile, error) {
// Subtract the load address of the __TEXT section. Usually 0 for shared
// libraries or 0x100000000 for executables. You can check this value by
@@ -225,6 +257,53 @@ func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.Obj
return &fileAddr2Line{file: file{b: b, name: name, base: base}}, nil
}
+func (b *binrep) openFatMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
+ of, err := macho.OpenFat(name)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing %s: %v", name, err)
+ }
+ defer of.Close()
+
+ if len(of.Arches) == 0 {
+ return nil, fmt.Errorf("empty fat Mach-O file: %s", name)
+ }
+
+ var arch macho.Cpu
+ // Use the host architecture.
+ // TODO: This is not ideal because the host architecture may not be the one
+ // that was profiled. E.g. an amd64 host can profile a 386 program.
+ switch runtime.GOARCH {
+ case "386":
+ arch = macho.Cpu386
+ case "amd64", "amd64p32":
+ arch = macho.CpuAmd64
+ case "arm", "armbe", "arm64", "arm64be":
+ arch = macho.CpuArm
+ case "ppc":
+ arch = macho.CpuPpc
+ case "ppc64", "ppc64le":
+ arch = macho.CpuPpc64
+ default:
+ return nil, fmt.Errorf("unsupported host architecture for %s: %s", name, runtime.GOARCH)
+ }
+ for i := range of.Arches {
+ if of.Arches[i].Cpu == arch {
+ return b.openMachOCommon(name, of.Arches[i].File, start, limit, offset)
+ }
+ }
+ return nil, fmt.Errorf("architecture not found in %s: %s", name, runtime.GOARCH)
+}
+
+func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
+ of, err := macho.Open(name)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing %s: %v", name, err)
+ }
+ defer of.Close()
+
+ return b.openMachOCommon(name, of, start, limit, offset)
+}
+
func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
ef, err := elf.Open(name)
if err != nil {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go
index d844ed7e4e..17d4225a87 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils_test.go
@@ -22,6 +22,7 @@ import (
"reflect"
"regexp"
"runtime"
+ "strings"
"testing"
"github.com/google/pprof/internal/plugin"
@@ -361,3 +362,31 @@ func TestLLVMSymbolizer(t *testing.T) {
}
}
}
+
+func TestOpenMalformedELF(t *testing.T) {
+ // Test that opening a malformed ELF file will report an error containing
+ // the word "ELF".
+ bu := &Binutils{}
+ _, err := bu.Open(filepath.Join("testdata", "malformed_elf"), 0, 0, 0)
+ if err == nil {
+ t.Fatalf("Open: unexpected success")
+ }
+
+ if !strings.Contains(err.Error(), "ELF") {
+ t.Errorf("Open: got %v, want error containing 'ELF'", err)
+ }
+}
+
+func TestOpenMalformedMachO(t *testing.T) {
+ // Test that opening a malformed Mach-O file will report an error containing
+ // the word "Mach-O".
+ bu := &Binutils{}
+ _, err := bu.Open(filepath.Join("testdata", "malformed_macho"), 0, 0, 0)
+ if err == nil {
+ t.Fatalf("Open: unexpected success")
+ }
+
+ if !strings.Contains(err.Error(), "Mach-O") {
+ t.Errorf("Open: got %v, want error containing 'Mach-O'", err)
+ }
+}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_elf b/src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_elf
new file mode 100644
index 0000000000..f0b503b0b6
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_elf
@@ -0,0 +1 @@
+ELFÿÿÿÿÿÿÿÿ \ No newline at end of file
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_macho b/src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_macho
new file mode 100644
index 0000000000..b01ddf69a9
--- /dev/null
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/testdata/malformed_macho
@@ -0,0 +1 @@
+Ïúíþÿÿÿÿÿÿÿÿ \ No newline at end of file