aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/vendor/github.com/google/pprof/internal/elfexec
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/elfexec
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/elfexec')
-rw-r--r--src/cmd/vendor/github.com/google/pprof/internal/elfexec/elfexec.go81
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
+}