git: 2449fa9c4d8e - main - hwpmc: hwpmc: record page size to fix analysis in some case
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 23 Sep 2026 18:36:22 UTC
The branch main has been updated by gallatin:
URL: https://cgit.FreeBSD.org/src/commit/?id=2449fa9c4d8e60cca863396dc3c7d67cbc16359f
commit 2449fa9c4d8e60cca863396dc3c7d67cbc16359f
Author: Andrew Gallatin <gallatin@FreeBSD.org>
AuthorDate: 2026-09-22 11:52:39 +0000
Commit: Andrew Gallatin <gallatin@FreeBSD.org>
CommitDate: 2026-09-23 18:35:44 +0000
hwpmc: hwpmc: record page size to fix analysis in some case
This fixes a bug where a binary linked using max-page-size=0x200000
can result in a bogus relocation offset when running on a system
with a smaller page size. This causes samples to fall outside
the image mapping or be translated to the wrong address (resulting
in symbol resolution, or incorrect symbol resolution). We noticed
this at Netflix because we run a patchset enabling 16k pages on
amd64 and have been compiling userspace with a 2MB page size.
Since we started doing this profiling userspace binaries has been
wonky.
Reviewed by: ali_mashtizadeh.com
Differential Revision: https://reviews.freebsd.org/D59771
Sponsored by: Netflix
---
lib/libpmc/pmclog.c | 2 +-
lib/libpmc/pmclog.h | 7 +++++++
lib/libpmcstat/libpmcstat.h | 1 +
lib/libpmcstat/libpmcstat_image.c | 19 +++++++++++++++++--
lib/libpmcstat/libpmcstat_logging.c | 1 +
sys/dev/hwpmc/hwpmc_logging.c | 6 +++++-
sys/sys/pmclog.h | 8 +++++++-
usr.sbin/pmc/view.cc | 17 +++++++++++------
usr.sbin/pmc/view.hh | 3 ++-
9 files changed, 52 insertions(+), 12 deletions(-)
diff --git a/lib/libpmc/pmclog.c b/lib/libpmc/pmclog.c
index c3587af46c7b..05fb05ced505 100644
--- a/lib/libpmc/pmclog.c
+++ b/lib/libpmc/pmclog.c
@@ -338,7 +338,7 @@ pmclog_get_event(void *cookie, char **data, ssize_t *len,
case PMCLOG_TYPE_MAP_IN:
PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_map_in);
PMCLOG_READ32(le,ev->pl_u.pl_mi.pl_pid);
- PMCLOG_SKIP32(le);
+ PMCLOG_READ32(le,ev->pl_u.pl_mi.pl_u);
PMCLOG_READADDR(le,ev->pl_u.pl_mi.pl_start);
PMCLOG_READSTRING(le, ev->pl_u.pl_mi.pl_pathname, pathlen);
break;
diff --git a/lib/libpmc/pmclog.h b/lib/libpmc/pmclog.h
index a79d33529890..8612d7adf946 100644
--- a/lib/libpmc/pmclog.h
+++ b/lib/libpmc/pmclog.h
@@ -69,6 +69,13 @@ struct pmclog_ev_initialize {
struct pmclog_ev_map_in {
pid_t pl_pid;
+ union {
+ uint32_t pl_u;
+ struct {
+ uint8_t pl_pageshift;
+ uint8_t pl_pad[3];
+ };
+ };
uintfptr_t pl_start;
char pl_pathname[PATH_MAX];
};
diff --git a/lib/libpmcstat/libpmcstat.h b/lib/libpmcstat/libpmcstat.h
index 2ef64f33c00e..7a1712cd2fb3 100644
--- a/lib/libpmcstat/libpmcstat.h
+++ b/lib/libpmcstat/libpmcstat.h
@@ -132,6 +132,7 @@ struct pmcstat_args {
int pa_mergepmc; /* merge PMC with same name */
double pa_duration; /* time duration */
uint32_t pa_tid;
+ uint8_t pa_pageshift; /* page shift recorded in log */
int pa_argc;
char **pa_argv;
STAILQ_HEAD(, pmcstat_ev) pa_events;
diff --git a/lib/libpmcstat/libpmcstat_image.c b/lib/libpmcstat/libpmcstat_image.c
index 69274dca31e8..72410609d238 100644
--- a/lib/libpmcstat/libpmcstat_image.c
+++ b/lib/libpmcstat/libpmcstat_image.c
@@ -312,7 +312,7 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
const char *path, *elfbase;
char *p, *endp;
bool first_exec_segment;
- uintfptr_t minva, maxva;
+ uintfptr_t minva, maxva, pagesize;
Elf *e;
Elf_Scn *scn;
GElf_Ehdr eh;
@@ -330,6 +330,11 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
image->pi_dynlinkerpath = NULL;
image->pi_vaddr = 0;
+ if (args->pa_pageshift != 0)
+ pagesize = 1ULL << args->pa_pageshift;
+ else
+ pagesize = getpagesize();
+
path = pmcstat_string_unintern(image->pi_execpath);
assert(path != NULL);
@@ -421,7 +426,17 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
case PT_LOAD:
if ((ph.p_flags & PF_X) != 0 &&
first_exec_segment) {
- image->pi_vaddr = ph.p_vaddr & (-ph.p_align);
+ if (image->pi_iskernelmodule) {
+ image->pi_vaddr = ph.p_vaddr &
+ (-ph.p_align);
+ } else {
+ /*
+ * User MAP_IN records depend
+ * on page size.
+ */
+ image->pi_vaddr = rounddown2(
+ ph.p_vaddr, pagesize);
+ }
first_exec_segment = false;
}
break;
diff --git a/lib/libpmcstat/libpmcstat_logging.c b/lib/libpmcstat/libpmcstat_logging.c
index f30170cbbb9d..09b73a6091f1 100644
--- a/lib/libpmcstat/libpmcstat_logging.c
+++ b/lib/libpmcstat/libpmcstat_logging.c
@@ -235,6 +235,7 @@ pmcstat_analyze_log(struct pmcstat_args *args,
PMCSTAT_ALLOCATE);
assert(pp != NULL);
+ args->pa_pageshift = ev.pl_u.pl_mi.pl_pageshift;
image_path = pmcstat_string_intern(ev.pl_u.pl_mi.
pl_pathname);
diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c
index 4f507523b6ab..ad1f63b848e0 100644
--- a/sys/dev/hwpmc/hwpmc_logging.c
+++ b/sys/dev/hwpmc/hwpmc_logging.c
@@ -947,6 +947,7 @@ void
pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start,
const char *path)
{
+ struct pmclog_map_in *mi;
int pathlen, recordlen;
KASSERT(path != NULL, ("[pmclog,%d] map-in, null path", __LINE__));
@@ -956,8 +957,11 @@ pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start,
pathlen;
PMCLOG_RESERVE(po, PMCLOG_TYPE_MAP_IN, recordlen);
+ mi = (struct pmclog_map_in *)ph;
PMCLOG_EMIT32(pid);
- PMCLOG_EMIT32(0);
+ mi->pl_u = 0;
+ mi->pl_pageshift = PAGE_SHIFT;
+ PMCLOG_EMIT32(mi->pl_u);
PMCLOG_EMITADDR(start);
PMCLOG_EMITSTRING(path,pathlen);
PMCLOG_DESPATCH_SYNC(po);
diff --git a/sys/sys/pmclog.h b/sys/sys/pmclog.h
index 362792ae9ad1..2beb69562b97 100644
--- a/sys/sys/pmclog.h
+++ b/sys/sys/pmclog.h
@@ -159,7 +159,13 @@ struct pmclog_initialize {
struct pmclog_map_in {
PMCLOG_ENTRY_HEADER
uint32_t pl_pid;
- uint32_t pl_pad;
+ union {
+ uint32_t pl_u;
+ struct {
+ uint8_t pl_pageshift;
+ uint8_t pl_pad[3];
+ };
+ };
uintfptr_t pl_start; /* 8 byte aligned */
char pl_pathname[PATH_MAX];
} __packed;
diff --git a/usr.sbin/pmc/view.cc b/usr.sbin/pmc/view.cc
index d633b6737e34..3053833cdacb 100644
--- a/usr.sbin/pmc/view.cc
+++ b/usr.sbin/pmc/view.cc
@@ -89,8 +89,8 @@ syminfo::to_string(bool show_line)
return ss.str();
}
-pmcview::pmcview() : tscfreq(0), pmcid(), pmcinfo(), procs(), tidtopid(),
- images(), sysroot(""), filter()
+pmcview::pmcview() : tscfreq(0), pageshift(0), pmcid(), pmcinfo(), procs(),
+ tidtopid(), images(), sysroot(""), filter()
{
char *root;
@@ -436,7 +436,7 @@ pmcview::process(struct pmclog_ev_threadexit &p)
* if the dwarf symbols are available.
*/
image
-pmcview::loadimage(const std::string &path)
+pmcview::loadimage(const std::string &path, bool iskernel)
{
std::string fullpath;
image im;
@@ -519,7 +519,12 @@ pmcview::loadimage(const std::string &path)
if (ph.p_type == PT_LOAD) {
if ((ph.p_flags & PF_X) != 0 && !foundexec) {
- im.vaddr = ph.p_vaddr & ~(ph.p_align - 1);
+ uint64_t alignment;
+
+ alignment = iskernel ? ph.p_align :
+ (pageshift != 0 ? 1ULL << pageshift :
+ (uint64_t)getpagesize());
+ im.vaddr = rounddown2(ph.p_vaddr, alignment);
foundexec = true;
}
}
@@ -727,8 +732,9 @@ pmcview::process(struct pmclog_ev_map_in &p)
{
// Kernel map-in events should be mapped to pid 0
pid_t pid = (p.pl_pid == -1) ? 0 : p.pl_pid;
+ pageshift = p.pl_pageshift;
- image im = loadimage(p.pl_pathname);
+ image im = loadimage(p.pl_pathname, pid == 0);
mapimage(pid, im, p.pl_start);
}
@@ -958,4 +964,3 @@ pmcview::printvm(pid_t pid)
i.second.highpc, i.second.image.c_str());
}
}
-
diff --git a/usr.sbin/pmc/view.hh b/usr.sbin/pmc/view.hh
index b1e04a73e130..05904b3da53e 100644
--- a/usr.sbin/pmc/view.hh
+++ b/usr.sbin/pmc/view.hh
@@ -389,6 +389,7 @@ protected:
void printvm(pid_t pid);
// Fields available to views
uint64_t tscfreq;
+ uint8_t pageshift;
std::unordered_map<uint32_t, uint32_t> pmcid;
std::unordered_map<uint32_t, struct pmcinfo> pmcinfo;
std::unordered_map<pid_t, struct procinfo> procs;
@@ -404,7 +405,7 @@ protected:
std::vector<struct pmcinfox> extpmcinfo;
std::map<uint32_t, struct cpuidleaf> cpuid; // x86 Only
private:
- image loadimage(const std::string &path);
+ image loadimage(const std::string &path, bool iskernel = false);
void mapimage(pid_t pid, const image &im, uint64_t linkaddr);
void loadsymboltable(image *im, Elf *e, Elf_Scn *scn, GElf_Shdr *sh);
void loadsymbols(image *im);