diff --git a/FreeBSD/sys/dev/hwpmc/hwpmc_logging.c b/FreeBSD/sys/dev/hwpmc/hwpmc_logging.c --- a/FreeBSD/sys/dev/hwpmc/hwpmc_logging.c +++ b/FreeBSD/sys/dev/hwpmc/hwpmc_logging.c @@ -718,7 +718,10 @@ /* create a log initialization entry */ PMCLOG_RESERVE_WITH_ERROR(po, PMCLOG_TYPE_INITIALIZE, sizeof(struct pmclog_initialize)); - PMCLOG_EMIT32(PMC_VERSION); + if ((po->po_flags & PMC_PO_LEGACY) != 0) + PMCLOG_EMIT32(pmc_compat_version); + else + PMCLOG_EMIT32(PMC_VERSION); PMCLOG_EMIT32(md->pmd_cputype); #if defined(__i386__) || defined(__amd64__) PMCLOG_EMIT64(tsc_freq); @@ -1098,19 +1101,26 @@ void pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid, - uintptr_t baseaddr, uintptr_t dynaddr, char *path) + uintptr_t baseaddr, uintptr_t dynaddr, uintptr_t entryaddr, char *path) { - int pathlen, recordlen; + int pathlen, recordlen, legacy; PMCDBG3(LOG,EXC,1,"po=%p pid=%d path=\"%s\"", po, pid, path); pathlen = strlen(path) + 1; /* #bytes for the path */ recordlen = offsetof(struct pmclog_procexec, pl_pathname) + pathlen; + legacy = !!(po->po_flags & PMC_PO_LEGACY); + if (legacy) + recordlen -= sizeof (uintptr_t); PMCLOG_RESERVE(po, PMCLOG_TYPE_PROCEXEC, recordlen); PMCLOG_EMIT32(pid); PMCLOG_EMIT32(pmid); - PMCLOG_EMITADDR(baseaddr); - PMCLOG_EMITADDR(dynaddr); + if (legacy) { + PMCLOG_EMITADDR(entryaddr); + } else { + PMCLOG_EMITADDR(baseaddr); + PMCLOG_EMITADDR(dynaddr); + } PMCLOG_EMITSTRING(path,pathlen); PMCLOG_DESPATCH_SYNC(po); } diff --git a/FreeBSD/sys/dev/hwpmc/hwpmc_mod.c b/FreeBSD/sys/dev/hwpmc/hwpmc_mod.c --- a/FreeBSD/sys/dev/hwpmc/hwpmc_mod.c +++ b/FreeBSD/sys/dev/hwpmc/hwpmc_mod.c @@ -392,6 +392,15 @@ &pmc_unprivileged_syspmcs, 0, "allow unprivileged process to allocate system PMCs"); +/* + * Enable support for legacy profilers, like AMDuProf, that are + * built for older version of FreeBSD and use an older ABI. + */ +int pmc_compat_version = 0; +SYSCTL_INT(_kern_hwpmc, OID_AUTO, compat_verson, CTLFLAG_RWTUN, + &pmc_compat_version, 0, + "Emulate ABI from this older version when an older binary is run"); + /* * Hash function. Discard the lower 2 bits of the pointer since * these are always zero for our uses. The hash multiplier is @@ -1345,7 +1354,8 @@ CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext) { if ((po->po_flags & PMC_PO_OWNS_LOGFILE) != 0) { pmclog_process_procexec(po, PMC_ID_INVALID, p->p_pid, - pk->pm_baseaddr, pk->pm_dynaddr, fullpath); + pk->pm_baseaddr, pk->pm_dynaddr, pk->pm_entryaddr, + fullpath); } } PMC_EPOCH_EXIT(); @@ -1392,7 +1402,8 @@ if (po->po_sscount == 0 && (po->po_flags & PMC_PO_OWNS_LOGFILE) != 0) { pmclog_process_procexec(po, pm->pm_id, p->p_pid, - pk->pm_baseaddr, pk->pm_dynaddr, fullpath); + pk->pm_baseaddr, pk->pm_dynaddr, + pk->pm_entryaddr, fullpath); } } @@ -2306,6 +2317,8 @@ /* Allocate space for N pointers and one descriptor struct. */ po = malloc(sizeof(struct pmc_owner), M_PMC, M_WAITOK | M_ZERO); po->po_owner = p; + if (pmc_compat_version != 0 && p->p_osrel == 1200500) + po->po_flags |= PMC_PO_LEGACY; LIST_INSERT_HEAD(poh, po, po_next); /* insert into hash table */ TAILQ_INIT(&po->po_logbuffers); @@ -3418,6 +3431,8 @@ (pmc_pcpu[(cpu)]->pc_hwpmcs[(n)]->phw_pmc == NULL) if (PMC_IS_SYSTEM_MODE(mode)) { + if (pmc_compat_version != 0 && curproc->p_osrel == 1200500) + pa->pm_flags |= PMC_F_EV_PMU; pmc_select_cpu(cpu); for (n = pcd->pcd_ri; n < md->pmd_npmc; n++) { pcd = pmc_ri_to_classdep(md, n, &adjri); @@ -3819,6 +3834,10 @@ break; } + /* zero out flags on legacy apps */ + if (pmc_compat_version != 0 && curproc->p_osrel == 1200500) + cl.pm_flags = 0; + /* No flags currently implemented */ if (cl.pm_flags != 0) { pmclog_proc_ignite(pmclog_proc_handle, NULL); @@ -4011,6 +4030,13 @@ break; /* don't service clients newer than our driver */ modv = PMC_VERSION; + if (cv == 0 && pmc_compat_version != 0 && + curproc->p_osrel == 1200500) { + /* work around AMDuProf support ending at FreeBSD 13 */ + printf("%s %d: overriding hwpmc version to 0x%x\n", + curproc->p_comm, curproc->p_osrel, pmc_compat_version); + modv = pmc_compat_version; + } if ((cv & 0xFFFF0000) > (modv & 0xFFFF0000)) { error = EPROGMISMATCH; break; diff --git a/FreeBSD/sys/kern/kern_exec.c b/FreeBSD/sys/kern/kern_exec.c --- a/FreeBSD/sys/kern/kern_exec.c +++ b/FreeBSD/sys/kern/kern_exec.c @@ -932,6 +932,7 @@ pe.pm_credentialschanged = credential_changing; pe.pm_baseaddr = imgp->reloc_base; pe.pm_dynaddr = imgp->et_dyn_addr; + pe.pm_entryaddr = imgp->entry_addr; PMC_CALL_HOOK_X(td, PMC_FN_PROCESS_EXEC, (void *) &pe); vn_lock(imgp->vp, LK_SHARED | LK_RETRY); diff --git a/FreeBSD/sys/sys/pmc.h b/FreeBSD/sys/sys/pmc.h --- a/FreeBSD/sys/sys/pmc.h +++ b/FreeBSD/sys/sys/pmc.h @@ -874,6 +874,7 @@ #define PMC_PO_OWNS_LOGFILE 0x00000001 /* has a log file */ #define PMC_PO_SHUTDOWN 0x00000010 /* in the process of shutdown */ #define PMC_PO_INITIAL_MAPPINGS_DONE 0x00000020 +#define PMC_PO_LEGACY 0x00000040 /* * struct pmc_hw -- describe the state of the PMC hardware @@ -1072,6 +1073,9 @@ /* driver statistics */ extern struct pmc_driverstats pmc_stats; +/* compat version */ +extern int pmc_compat_version; + #if defined(HWPMC_DEBUG) /* HWPMC_DEBUG without KTR will compile but is a no-op. */ diff --git a/FreeBSD/sys/sys/pmckern.h b/FreeBSD/sys/sys/pmckern.h --- a/FreeBSD/sys/sys/pmckern.h +++ b/FreeBSD/sys/sys/pmckern.h @@ -76,6 +76,7 @@ int pm_credentialschanged; uintptr_t pm_baseaddr; uintptr_t pm_dynaddr; + uintptr_t pm_entryaddr; }; struct pmckern_map_in { diff --git a/FreeBSD/sys/sys/pmclog.h b/FreeBSD/sys/sys/pmclog.h --- a/FreeBSD/sys/sys/pmclog.h +++ b/FreeBSD/sys/sys/pmclog.h @@ -315,7 +315,7 @@ void pmclog_process_proccsw(struct pmc *_pm, struct pmc_process *_pp, pmc_value_t _v, struct thread *); void pmclog_process_procexec(struct pmc_owner *_po, pmc_id_t _pmid, pid_t _pid, - uintfptr_t _baseaddr, uintptr_t _dynaddr, char *_path); + uintfptr_t _baseaddr, uintptr_t _dynaddr, uintptr_t _entryaddr, char *_path); void pmclog_process_procexit(struct pmc *_pm, struct pmc_process *_pp); void pmclog_process_procfork(struct pmc_owner *_po, pid_t _oldpid, pid_t _newpid); void pmclog_process_sysexit(struct pmc_owner *_po, pid_t _pid);