diff options
| author | Hana (Hyang-Ah) Kim <hyangah@gmail.com> | 2018-11-06 17:48:08 -0500 |
|---|---|---|
| committer | Hyang-Ah Hana Kim <hyangah@gmail.com> | 2018-11-07 12:27:21 +0000 |
| commit | c0a40e4fe5d4649672d0d430ca26551841fc4852 (patch) | |
| tree | 4ccd82b68f0795d68bc43caff3cba7c9fabdb4d8 /src/cmd/vendor/github.com/google/pprof/internal/binutils | |
| parent | 1100df58238a1b1c55af148a880b48caf4be6504 (diff) | |
| download | go-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')
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 |
