aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google/pprof/internal/binutils
diff options
context:
space:
mode:
authorEmmanuel T Odeke <emmanuel@orijtech.com>2021-02-26 02:27:24 -0800
committerEmmanuel Odeke <emmanuel@orijtech.com>2021-03-15 19:02:39 +0000
commit2d4042d4ab3a2021819dce91eb228daf8fa5e557 (patch)
tree0a0b71f4bc2859a19320760f54be55f891b5e07a /src/cmd/vendor/github.com/google/pprof/internal/binutils
parenta8d9fb2fcd1fc11b41651e0ea608b3a3e90755b7 (diff)
downloadgo-2d4042d4ab3a2021819dce91eb228daf8fa5e557.tar.xz
all: update golang.org/x/* dependencies
Updates src/ and src/cmd/* dependencies, using go mod vendor as well as updatestd -branch=master -goroot=$GOROOT This change was ran in anticipation of bringing in x/net/http2 CL 237957. For #32112. For #36905. Change-Id: If8cefc348463b6d82d85020b57db411213720ef8 Reviewed-on: https://go-review.googlesource.com/c/go/+/296789 Trust: Emmanuel Odeke <emmanuel@orijtech.com> Trust: Dmitri Shuralyov <dmitshur@golang.org> Trust: Bryan C. Mills <bcmills@google.com> Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Alexander Rakoczy <alex@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/addr2liner.go24
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go36
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go58
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go65
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go3
5 files changed, 133 insertions, 53 deletions
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go
index c0661bf4aa..0c702398d3 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner.go
@@ -70,7 +70,11 @@ func (a *addr2LinerJob) write(s string) error {
}
func (a *addr2LinerJob) readLine() (string, error) {
- return a.out.ReadString('\n')
+ s, err := a.out.ReadString('\n')
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(s), nil
}
// close releases any resources used by the addr2liner object.
@@ -115,19 +119,11 @@ func newAddr2Liner(cmd, file string, base uint64) (*addr2Liner, error) {
return a, nil
}
-func (d *addr2Liner) readString() (string, error) {
- s, err := d.rw.readLine()
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(s), nil
-}
-
// readFrame parses the addr2line output for a single address. It
// returns a populated plugin.Frame and whether it has reached the end of the
// data.
func (d *addr2Liner) readFrame() (plugin.Frame, bool) {
- funcname, err := d.readString()
+ funcname, err := d.rw.readLine()
if err != nil {
return plugin.Frame{}, true
}
@@ -135,12 +131,12 @@ func (d *addr2Liner) readFrame() (plugin.Frame, bool) {
// If addr2line returns a hex address we can assume it is the
// sentinel. Read and ignore next two lines of output from
// addr2line
- d.readString()
- d.readString()
+ d.rw.readLine()
+ d.rw.readLine()
return plugin.Frame{}, true
}
- fileline, err := d.readString()
+ fileline, err := d.rw.readLine()
if err != nil {
return plugin.Frame{}, true
}
@@ -186,7 +182,7 @@ func (d *addr2Liner) rawAddrInfo(addr uint64) ([]plugin.Frame, error) {
return nil, err
}
- resp, err := d.readString()
+ resp, err := d.rw.readLine()
if err != nil {
return nil, err
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
index 68fa5593ad..24c48e649b 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_llvm.go
@@ -43,15 +43,21 @@ type llvmSymbolizerJob struct {
cmd *exec.Cmd
in io.WriteCloser
out *bufio.Reader
+ // llvm-symbolizer requires the symbol type, CODE or DATA, for symbolization.
+ symType string
}
func (a *llvmSymbolizerJob) write(s string) error {
- _, err := fmt.Fprint(a.in, s+"\n")
+ _, err := fmt.Fprintln(a.in, a.symType, s)
return err
}
func (a *llvmSymbolizerJob) readLine() (string, error) {
- return a.out.ReadString('\n')
+ s, err := a.out.ReadString('\n')
+ if err != nil {
+ return "", err
+ }
+ return strings.TrimSpace(s), nil
}
// close releases any resources used by the llvmSymbolizer object.
@@ -64,13 +70,17 @@ func (a *llvmSymbolizerJob) close() {
// information about the given executable file. If file is a shared
// library, base should be the address at which it was mapped in the
// program under consideration.
-func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) {
+func newLLVMSymbolizer(cmd, file string, base uint64, isData bool) (*llvmSymbolizer, error) {
if cmd == "" {
cmd = defaultLLVMSymbolizer
}
j := &llvmSymbolizerJob{
- cmd: exec.Command(cmd, "-inlining", "-demangle=false"),
+ cmd: exec.Command(cmd, "-inlining", "-demangle=false"),
+ symType: "CODE",
+ }
+ if isData {
+ j.symType = "DATA"
}
var err error
@@ -97,19 +107,11 @@ func newLLVMSymbolizer(cmd, file string, base uint64) (*llvmSymbolizer, error) {
return a, nil
}
-func (d *llvmSymbolizer) readString() (string, error) {
- s, err := d.rw.readLine()
- if err != nil {
- return "", err
- }
- return strings.TrimSpace(s), nil
-}
-
// readFrame parses the llvm-symbolizer output for a single address. It
// returns a populated plugin.Frame and whether it has reached the end of the
// data.
func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) {
- funcname, err := d.readString()
+ funcname, err := d.rw.readLine()
if err != nil {
return plugin.Frame{}, true
}
@@ -121,13 +123,17 @@ func (d *llvmSymbolizer) readFrame() (plugin.Frame, bool) {
funcname = ""
}
- fileline, err := d.readString()
+ fileline, err := d.rw.readLine()
if err != nil {
return plugin.Frame{Func: funcname}, true
}
linenumber := 0
- if fileline == "??:0" {
+ // The llvm-symbolizer outputs the <file_name>:<line_number>:<column_number>.
+ // When it cannot identify the source code location, it outputs "??:0:0".
+ // Older versions output just the filename and line number, so we check for
+ // both conditions here.
+ if fileline == "??:0" || fileline == "??:0:0" {
fileline = ""
} else {
switch split := strings.Split(fileline, ":"); len(split) {
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go
index 1987bd3dab..8e0ccc728d 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/addr2liner_nm.go
@@ -29,27 +29,42 @@ const (
defaultNM = "nm"
)
-// addr2LinerNM is a connection to an nm command for obtaining address
+// addr2LinerNM is a connection to an nm command for obtaining symbol
// information from a binary.
type addr2LinerNM struct {
- m []symbolInfo // Sorted list of addresses from binary.
+ m []symbolInfo // Sorted list of symbol addresses from binary.
}
type symbolInfo struct {
address uint64
+ size uint64
name string
+ symType string
}
-// newAddr2LinerNM starts the given nm command reporting information about the
-// given executable file. If file is a shared library, base should be
-// the address at which it was mapped in the program under
-// consideration.
+// isData returns if the symbol has a known data object symbol type.
+func (s *symbolInfo) isData() bool {
+ // The following symbol types are taken from https://linux.die.net/man/1/nm:
+ // Lowercase letter means local symbol, uppercase denotes a global symbol.
+ // - b or B: the symbol is in the uninitialized data section, e.g. .bss;
+ // - d or D: the symbol is in the initialized data section;
+ // - r or R: the symbol is in a read only data section;
+ // - v or V: the symbol is a weak object;
+ // - W: the symbol is a weak symbol that has not been specifically tagged as a
+ // weak object symbol. Experiments with some binaries, showed these to be
+ // mostly data objects.
+ return strings.ContainsAny(s.symType, "bBdDrRvVW")
+}
+
+// newAddr2LinerNM starts the given nm command reporting information about the
+// given executable file. If file is a shared library, base should be the
+// address at which it was mapped in the program under consideration.
func newAddr2LinerNM(cmd, file string, base uint64) (*addr2LinerNM, error) {
if cmd == "" {
cmd = defaultNM
}
var b bytes.Buffer
- c := exec.Command(cmd, "-n", file)
+ c := exec.Command(cmd, "--numeric-sort", "--print-size", "--format=posix", file)
c.Stdout = &b
if err := c.Run(); err != nil {
return nil, err
@@ -74,17 +89,23 @@ func parseAddr2LinerNM(base uint64, nm io.Reader) (*addr2LinerNM, error) {
return nil, err
}
line = strings.TrimSpace(line)
- fields := strings.SplitN(line, " ", 3)
- if len(fields) != 3 {
+ fields := strings.Split(line, " ")
+ if len(fields) != 4 {
+ continue
+ }
+ address, err := strconv.ParseUint(fields[2], 16, 64)
+ if err != nil {
continue
}
- address, err := strconv.ParseUint(fields[0], 16, 64)
+ size, err := strconv.ParseUint(fields[3], 16, 64)
if err != nil {
continue
}
a.m = append(a.m, symbolInfo{
address: address + base,
- name: fields[2],
+ size: size,
+ name: fields[0],
+ symType: fields[1],
})
}
@@ -94,7 +115,7 @@ func parseAddr2LinerNM(base uint64, nm io.Reader) (*addr2LinerNM, error) {
// addrInfo returns the stack frame information for a specific program
// address. It returns nil if the address could not be identified.
func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) {
- if len(a.m) == 0 || addr < a.m[0].address || addr > a.m[len(a.m)-1].address {
+ if len(a.m) == 0 || addr < a.m[0].address || addr >= (a.m[len(a.m)-1].address+a.m[len(a.m)-1].size) {
return nil, nil
}
@@ -113,12 +134,11 @@ func (a *addr2LinerNM) addrInfo(addr uint64) ([]plugin.Frame, error) {
}
}
- // Address is between a.m[low] and a.m[high].
- // Pick low, as it represents [low, high).
- f := []plugin.Frame{
- {
- Func: a.m[low].name,
- },
+ // Address is between a.m[low] and a.m[high]. Pick low, as it represents
+ // [low, high). For data symbols, we use a strict check that the address is in
+ // the [start, start + size) range of a.m[low].
+ if a.m[low].isData() && addr >= (a.m[low].address+a.m[low].size) {
+ return nil, nil
}
- return f, nil
+ return []plugin.Frame{{Func: a.m[low].name}}, nil
}
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 4b67cc4ab0..576a6ee66a 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,6 +18,7 @@ package binutils
import (
"debug/elf"
"debug/macho"
+ "debug/pe"
"encoding/binary"
"errors"
"fmt"
@@ -255,7 +256,7 @@ func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([]
if !b.objdumpFound {
return nil, errors.New("cannot disasm: no objdump tool available")
}
- args := []string{"--disassemble-all", "--demangle", "--no-show-raw-insn",
+ args := []string{"--disassemble", "--demangle", "--no-show-raw-insn",
"--line-numbers", fmt.Sprintf("--start-address=%#x", start),
fmt.Sprintf("--stop-address=%#x", end)}
@@ -337,6 +338,15 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi
return f, nil
}
+ peMagic := string(header[:2])
+ if peMagic == "MZ" {
+ f, err := b.openPE(name, start, limit, offset)
+ if err != nil {
+ return nil, fmt.Errorf("error reading PE file %s: %v", name, err)
+ }
+ return f, nil
+ }
+
return nil, fmt.Errorf("unrecognized binary format: %s", name)
}
@@ -440,7 +450,23 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi
}
}
- base, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), stextOffset, start, limit, offset)
+ var ph *elf.ProgHeader
+ // For user space executables, find the actual program segment that is
+ // associated with the given mapping. Skip this search if limit <= start.
+ // We cannot use just a check on the start address of the mapping to tell if
+ // it's a kernel / .ko module mapping, because with quipper address remapping
+ // enabled, the address would be in the lower half of the address space.
+ if stextOffset == nil && start < limit && limit < (uint64(1)<<63) {
+ ph, err = elfexec.FindProgHeaderForMapping(ef, offset, limit-start)
+ if err != nil {
+ return nil, fmt.Errorf("failed to find program header for file %q, mapping pgoff %x, memsz=%x: %v", name, offset, limit-start, err)
+ }
+ } else {
+ // For the kernel, find the program segment that includes the .text section.
+ ph = elfexec.FindTextProgHeader(ef)
+ }
+
+ base, err := elfexec.GetBase(&ef.FileHeader, ph, stextOffset, start, limit, offset)
if err != nil {
return nil, fmt.Errorf("could not identify base for %s: %v", name, err)
}
@@ -451,10 +477,38 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi
buildID = fmt.Sprintf("%x", id)
}
}
+ isData := ph != nil && ph.Flags&elf.PF_X == 0
+ if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
+ return &fileNM{file: file{b, name, base, buildID, isData}}, nil
+ }
+ return &fileAddr2Line{file: file{b, name, base, buildID, isData}}, nil
+}
+
+func (b *binrep) openPE(name string, start, limit, offset uint64) (plugin.ObjFile, error) {
+ pf, err := pe.Open(name)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing %s: %v", name, err)
+ }
+ defer pf.Close()
+
+ var imageBase uint64
+ switch h := pf.OptionalHeader.(type) {
+ case *pe.OptionalHeader32:
+ imageBase = uint64(h.ImageBase)
+ case *pe.OptionalHeader64:
+ imageBase = uint64(h.ImageBase)
+ default:
+ return nil, fmt.Errorf("unknown OptionalHeader %T", pf.OptionalHeader)
+ }
+
+ var base uint64
+ if start > 0 {
+ base = start - imageBase
+ }
if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) {
- return &fileNM{file: file{b, name, base, buildID}}, nil
+ return &fileNM{file: file{b: b, name: name, base: base}}, nil
}
- return &fileAddr2Line{file: file{b, name, base, buildID}}, nil
+ return &fileAddr2Line{file: file{b: b, name: name, base: base}}, nil
}
// file implements the binutils.ObjFile interface.
@@ -463,6 +517,7 @@ type file struct {
name string
base uint64
buildID string
+ isData bool
}
func (f *file) Name() string {
@@ -538,7 +593,7 @@ func (f *fileAddr2Line) SourceLine(addr uint64) ([]plugin.Frame, error) {
}
func (f *fileAddr2Line) init() {
- if llvmSymbolizer, err := newLLVMSymbolizer(f.b.llvmSymbolizer, f.name, f.base); err == nil {
+ if llvmSymbolizer, err := newLLVMSymbolizer(f.b.llvmSymbolizer, f.name, f.base, f.isData); err == nil {
f.llvmSymbolizer = llvmSymbolizer
return
}
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
index d0be614bdc..e64adf58cd 100644
--- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
+++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/disasm.go
@@ -19,6 +19,7 @@ import (
"io"
"regexp"
"strconv"
+ "strings"
"github.com/google/pprof/internal/plugin"
"github.com/ianlancetaylor/demangle"
@@ -121,6 +122,7 @@ func disassemble(asm []byte) ([]plugin.Inst, error) {
break
}
}
+ input = strings.TrimSpace(input)
if fields := objdumpAsmOutputRE.FindStringSubmatch(input); len(fields) == 3 {
if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil {
@@ -167,6 +169,7 @@ func nextSymbol(buf *bytes.Buffer) (uint64, string, error) {
return 0, "", err
}
}
+ line = strings.TrimSpace(line)
if fields := nmOutputRE.FindStringSubmatch(line); len(fields) == 4 {
if address, err := strconv.ParseUint(fields[1], 16, 64); err == nil {