diff options
| author | Emmanuel T Odeke <emmanuel@orijtech.com> | 2021-02-26 02:27:24 -0800 |
|---|---|---|
| committer | Emmanuel Odeke <emmanuel@orijtech.com> | 2021-03-15 19:02:39 +0000 |
| commit | 2d4042d4ab3a2021819dce91eb228daf8fa5e557 (patch) | |
| tree | 0a0b71f4bc2859a19320760f54be55f891b5e07a /src/cmd/vendor/github.com/google/pprof/internal/binutils | |
| parent | a8d9fb2fcd1fc11b41651e0ea608b3a3e90755b7 (diff) | |
| download | go-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')
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 { |
