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/elfexec | |
| 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/elfexec')
| -rw-r--r-- | src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go | 81 |
1 files changed, 81 insertions, 0 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 d520765cc9..3b3c6ee89f 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 @@ -283,3 +283,84 @@ func FindTextProgHeader(f *elf.File) *elf.ProgHeader { } return nil } + +// FindProgHeaderForMapping returns the loadable program segment header that is +// fully contained in the runtime mapping with file offset pgoff and memory size +// memsz, or an error if the segment cannot be determined. The function returns +// a nil program header and no error if the ELF binary has no loadable segments. +func FindProgHeaderForMapping(f *elf.File, pgoff, memsz uint64) (*elf.ProgHeader, error) { + var headers []*elf.ProgHeader + loadables := 0 + for _, p := range f.Progs { + if p.Type == elf.PT_LOAD && pgoff <= p.Off && p.Off+p.Memsz <= pgoff+memsz { + headers = append(headers, &p.ProgHeader) + } + if p.Type == elf.PT_LOAD { + loadables++ + } + } + if len(headers) == 1 { + return headers[0], nil + } + // Some ELF files don't contain any program segments, e.g. .ko loadable kernel + // modules. Don't return an error in such cases. + if loadables == 0 { + return nil, nil + } + if len(headers) == 0 { + return nil, fmt.Errorf("no program header matches file offset %x and memory size %x", pgoff, memsz) + } + + // Segments are mapped page aligned. In some cases, segments may be smaller + // than a page, which causes the next segment to start at a file offset that + // is logically on the same page if we were to align file offsets by page. + // Example: + // LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 + // 0x00000000000006fc 0x00000000000006fc R E 0x200000 + // LOAD 0x0000000000000e10 0x0000000000600e10 0x0000000000600e10 + // 0x0000000000000230 0x0000000000000238 RW 0x200000 + // + // In this case, perf records the following mappings for this executable: + // 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x400000(0x1000) @ 0 00:3c 512041 0]: r-xp exename + // 0 0 [0xc0]: PERF_RECORD_MMAP2 87867/87867: [0x600000(0x2000) @ 0 00:3c 512041 0]: rw-p exename + // + // Both mappings have file offset 0. The first mapping is one page length and + // it can include only the first loadable segment. Due to page alignment, the + // second mapping starts also at file offset 0, and it spans two pages. It can + // include both the first and the second loadable segments. We must return the + // correct program header to compute the correct base offset. + // + // We cannot use the mapping protections to distinguish between segments, + // because protections are not passed through to this function. + // We cannot use the start address to differentiate between segments, because + // with ASLR, the mapping start address can be any value. + // + // We use a heuristic to compute the minimum mapping size required for a + // segment, assuming mappings are 4k page aligned, and return the segment that + // matches the given mapping size. + const pageSize = 4096 + + // The memory size based heuristic makes sense only if the mapping size is a + // multiple of 4k page size. + if memsz%pageSize != 0 { + return nil, fmt.Errorf("mapping size = %x and %d segments match the passed in mapping", memsz, len(headers)) + } + + // Return an error if no segment, or multiple segments match the size, so we can debug. + var ph *elf.ProgHeader + pageMask := ^uint64(pageSize - 1) + for _, h := range headers { + wantSize := (h.Vaddr+h.Memsz+pageSize-1)&pageMask - (h.Vaddr & pageMask) + if wantSize != memsz { + continue + } + if ph != nil { + return nil, fmt.Errorf("found second program header (%#v) that matches memsz %x, first program header is %#v", *h, memsz, *ph) + } + ph = h + } + if ph == nil { + return nil, fmt.Errorf("found %d matching program headers, but none matches mapping size %x", len(headers), memsz) + } + return ph, nil +} |
