diff options
| author | Dmitri Shuralyov <dmitshur@golang.org> | 2021-09-08 10:51:06 -0400 |
|---|---|---|
| committer | Dmitri Shuralyov <dmitshur@golang.org> | 2021-09-08 15:36:36 +0000 |
| commit | 9581d891ab8c88bbf9e5b5142926fbca653551e6 (patch) | |
| tree | 3f563b03dc6bdf9f7c8c478f682995b236ae415f /src/cmd/vendor/github.com/google/pprof/internal/elfexec | |
| parent | 8214257347b16a03464ace16bbcf6346fc784a3e (diff) | |
| download | go-9581d891ab8c88bbf9e5b5142926fbca653551e6.tar.xz | |
cmd/pprof: update vendored github.com/google/pprof
Pull in the latest published version of github.com/google/pprof
that is available at this time in the Go 1.18 development cycle.
Done with:
go get -d github.com/google/pprof@latest
go mod tidy
go mod vendor
For #36905.
Change-Id: Ib25aa38365ec70a0bed2a8a6527e5823ab9f9ded
Reviewed-on: https://go-review.googlesource.com/c/go/+/348410
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/cmd/vendor/github.com/google/pprof/internal/elfexec')
| -rw-r--r-- | src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go | 96 |
1 files changed, 53 insertions, 43 deletions
diff --git a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go index 2638b2db2d..4f11645185 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go @@ -284,10 +284,16 @@ func FindTextProgHeader(f *elf.File) *elf.ProgHeader { return nil } -// ProgramHeadersForMapping returns the loadable program segment headers that -// are fully contained in the runtime mapping with file offset pgoff and memory -// size memsz, and if the binary includes any loadable segments. -func ProgramHeadersForMapping(f *elf.File, pgoff, memsz uint64) ([]*elf.ProgHeader, bool) { +// ProgramHeadersForMapping returns the program segment headers that overlap +// the runtime mapping with file offset mapOff and memory size mapSz. We skip +// over segments zero file size because their file offset values are unreliable. +// Even if overlapping, a segment is not selected if its aligned file offset is +// greater than the mapping file offset, or if the mapping includes the last +// page of the segment, but not the full segment and the mapping includes +// additional pages after the segment end. +// The function returns a slice of pointers to the headers in the input +// slice, which are valid only while phdrs is not modified or discarded. +func ProgramHeadersForMapping(phdrs []elf.ProgHeader, mapOff, mapSz uint64) []*elf.ProgHeader { const ( // pageSize defines the virtual memory page size used by the loader. This // value is dependent on the memory management unit of the CPU. The page @@ -298,57 +304,61 @@ func ProgramHeadersForMapping(f *elf.File, pgoff, memsz uint64) ([]*elf.ProgHead // specified in the ELF file header. pageSize = 4096 pageOffsetMask = pageSize - 1 - pageMask = ^uint64(pageOffsetMask) ) + mapLimit := mapOff + mapSz var headers []*elf.ProgHeader - hasLoadables := false - for _, p := range f.Progs { - // The segment must be fully included in the mapping. - if p.Type == elf.PT_LOAD && pgoff <= p.Off && p.Off+p.Memsz <= pgoff+memsz { - alignedOffset := uint64(0) + for i := range phdrs { + p := &phdrs[i] + // Skip over segments with zero file size. Their file offsets can have + // arbitrary values, see b/195427553. + if p.Filesz == 0 { + continue + } + segLimit := p.Off + p.Memsz + // The segment must overlap the mapping. + if p.Type == elf.PT_LOAD && mapOff < segLimit && p.Off < mapLimit { + // If the mapping offset is strictly less than the page aligned segment + // offset, then this mapping comes from a different segment, fixes + // b/179920361. + alignedSegOffset := uint64(0) if p.Off > (p.Vaddr & pageOffsetMask) { - alignedOffset = p.Off - (p.Vaddr & pageOffsetMask) + alignedSegOffset = p.Off - (p.Vaddr & pageOffsetMask) } - if alignedOffset <= pgoff { - headers = append(headers, &p.ProgHeader) + if mapOff < alignedSegOffset { + continue } + // If the mapping starts in the middle of the segment, it covers less than + // one page of the segment, and it extends at least one page past the + // segment, then this mapping comes from a different segment. + if mapOff > p.Off && (segLimit < mapOff+pageSize) && (mapLimit >= segLimit+pageSize) { + continue + } + headers = append(headers, p) } - if p.Type == elf.PT_LOAD { - hasLoadables = true - } - } - if len(headers) < 2 { - return headers, hasLoadables - } - - // If we have more than one matching segments, try a strict check on the - // segment memory size. We use a heuristic to compute the minimum mapping size - // required for a segment, assuming mappings are page aligned. - // The memory size based heuristic makes sense only if the mapping size is a - // multiple of page size. - if memsz%pageSize != 0 { - return headers, hasLoadables } + return headers +} - // Return all found headers if we cannot narrow the selection to a single - // program segment. +// HeaderForFileOffset attempts to identify a unique program header that +// includes the given file offset. It returns an error if it cannot identify a +// unique header. +func HeaderForFileOffset(headers []*elf.ProgHeader, fileOffset uint64) (*elf.ProgHeader, error) { var ph *elf.ProgHeader for _, h := range headers { - wantSize := (h.Vaddr+h.Memsz+pageSize-1)&pageMask - (h.Vaddr & pageMask) - if wantSize != memsz { - continue - } - if ph != nil { - // Found a second program header matching, so return all previously - // identified headers. - return headers, hasLoadables + if fileOffset >= h.Off && fileOffset < h.Off+h.Memsz { + if ph != nil { + // Assuming no other bugs, this can only happen if we have two or + // more small program segments that fit on the same page, and a + // segment other than the last one includes uninitialized data, or + // if the debug binary used for symbolization is stripped of some + // sections, so segment file sizes are smaller than memory sizes. + return nil, fmt.Errorf("found second program header (%#v) that matches file offset %x, first program header is %#v. Is this a stripped binary, or does the first program segment contain uninitialized data?", *h, fileOffset, *ph) + } + ph = h } - ph = h } if ph == nil { - // No matching header for the strict check. Return all previously identified - // headers. - return headers, hasLoadables + return nil, fmt.Errorf("no program header matches file offset %x", fileOffset) } - return []*elf.ProgHeader{ph}, hasLoadables + return ph, nil } |
