summaryrefslogtreecommitdiffstats
path: root/sys/dev/hwpmc
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hwpmc')
-rw-r--r--sys/dev/hwpmc/hwpmc_logging.c35
-rw-r--r--sys/dev/hwpmc/hwpmc_mod.c170
2 files changed, 189 insertions, 16 deletions
diff --git a/sys/dev/hwpmc/hwpmc_logging.c b/sys/dev/hwpmc/hwpmc_logging.c
index f901cbe..efa0c52 100644
--- a/sys/dev/hwpmc/hwpmc_logging.c
+++ b/sys/dev/hwpmc/hwpmc_logging.c
@@ -137,10 +137,11 @@ static struct mtx pmc_kthread_mtx; /* sleep lock */
CTASSERT(sizeof(struct pmclog_closelog) == 3*4);
CTASSERT(sizeof(struct pmclog_dropnotify) == 3*4);
-CTASSERT(sizeof(struct pmclog_mappingchange) == PATH_MAX +
- 5*4 + 2*sizeof(uintfptr_t));
-CTASSERT(offsetof(struct pmclog_mappingchange,pl_pathname) ==
- 5*4 + 2*sizeof(uintfptr_t));
+CTASSERT(sizeof(struct pmclog_map_in) == PATH_MAX +
+ 4*4 + sizeof(uintfptr_t));
+CTASSERT(offsetof(struct pmclog_map_in,pl_pathname) ==
+ 4*4 + sizeof(uintfptr_t));
+CTASSERT(sizeof(struct pmclog_map_out) == 4*4 + 2*sizeof(uintfptr_t));
CTASSERT(sizeof(struct pmclog_pcsample) == 6*4 + sizeof(uintfptr_t));
CTASSERT(sizeof(struct pmclog_pmcallocate) == 6*4);
CTASSERT(sizeof(struct pmclog_pmcattach) == 5*4 + PATH_MAX);
@@ -728,24 +729,36 @@ pmclog_process_dropnotify(struct pmc_owner *po)
}
void
-pmclog_process_mappingchange(struct pmc_owner *po, pid_t pid, int type,
- uintfptr_t start, uintfptr_t end, char *path)
+pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start,
+ const char *path)
{
int pathlen, recordlen;
+ KASSERT(path != NULL, ("[pmclog,%d] map-in, null path", __LINE__));
+
pathlen = strlen(path) + 1; /* #bytes for path name */
- recordlen = offsetof(struct pmclog_mappingchange, pl_pathname) +
+ recordlen = offsetof(struct pmclog_map_in, pl_pathname) +
pathlen;
- PMCLOG_RESERVE(po,MAPPINGCHANGE,recordlen);
- PMCLOG_EMIT32(type);
- PMCLOG_EMITADDR(start);
- PMCLOG_EMITADDR(end);
+ PMCLOG_RESERVE(po, MAP_IN, recordlen);
PMCLOG_EMIT32(pid);
+ PMCLOG_EMITADDR(start);
PMCLOG_EMITSTRING(path,pathlen);
PMCLOG_DESPATCH(po);
}
+void
+pmclog_process_map_out(struct pmc_owner *po, pid_t pid, uintfptr_t start,
+ uintfptr_t end)
+{
+ KASSERT(start <= end, ("[pmclog,%d] start > end", __LINE__));
+
+ PMCLOG_RESERVE(po, MAP_OUT, sizeof(struct pmclog_map_out));
+ PMCLOG_EMIT32(pid);
+ PMCLOG_EMITADDR(start);
+ PMCLOG_EMITADDR(end);
+ PMCLOG_DESPATCH(po);
+}
void
pmclog_process_pcsample(struct pmc *pm, struct pmc_sample *ps)
diff --git a/sys/dev/hwpmc/hwpmc_mod.c b/sys/dev/hwpmc/hwpmc_mod.c
index 0b6f72d..12d742a 100644
--- a/sys/dev/hwpmc/hwpmc_mod.c
+++ b/sys/dev/hwpmc/hwpmc_mod.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2003-2005 Joseph Koshy
+ * Copyright (c) 2003-2006 Joseph Koshy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/vnode.h>
+#include <sys/linker.h> /* needs to be after <sys/malloc.h> */
+
#include <machine/atomic.h>
#include <machine/md_var.h>
@@ -1411,19 +1413,138 @@ pmc_process_csw_out(struct thread *td)
}
/*
+ * Log a KLD operation.
+ */
+
+static void
+pmc_process_kld_load(struct pmckern_map_in *pkm)
+{
+ struct pmc_owner *po;
+
+ sx_assert(&pmc_sx, SX_LOCKED);
+
+ /*
+ * Notify owners of system sampling PMCs about KLD operations.
+ */
+
+ LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_map_in(po, (pid_t) -1, pkm->pm_address,
+ (char *) pkm->pm_file);
+
+ /*
+ * TODO: Notify owners of (all) process-sampling PMCs too.
+ */
+
+ return;
+}
+
+static void
+pmc_process_kld_unload(struct pmckern_map_out *pkm)
+{
+ struct pmc_owner *po;
+
+ sx_assert(&pmc_sx, SX_LOCKED);
+
+ LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_map_out(po, (pid_t) -1,
+ pkm->pm_address, pkm->pm_address + pkm->pm_size);
+
+ /*
+ * TODO: Notify owners of process-sampling PMCs.
+ */
+}
+
+/*
+ * A mapping change for a process.
+ */
+
+static void
+pmc_process_mmap(struct thread *td, struct pmckern_map_in *pkm)
+{
+ int ri;
+ pid_t pid;
+ char *fullpath, *freepath;
+ const struct pmc *pm;
+ struct pmc_owner *po;
+ const struct pmc_process *pp;
+
+ freepath = fullpath = NULL;
+ pmc_getfilename((struct vnode *) pkm->pm_file, &fullpath, &freepath);
+
+ pid = td->td_proc->p_pid;
+
+ /* Inform owners of all system-wide sampling PMCs. */
+ LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_map_in(po, pid, pkm->pm_address, fullpath);
+
+ if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL)
+ goto done;
+
+ /*
+ * Inform sampling PMC owners tracking this process.
+ */
+ for (ri = 0; ri < md->pmd_npmc; ri++)
+ if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL &&
+ PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ pmclog_process_map_in(pm->pm_owner,
+ pid, pkm->pm_address, fullpath);
+
+ done:
+ if (freepath)
+ FREE(freepath, M_TEMP);
+}
+
+
+/*
+ * Log an munmap request.
+ */
+
+static void
+pmc_process_munmap(struct thread *td, struct pmckern_map_out *pkm)
+{
+ int ri;
+ pid_t pid;
+ struct pmc_owner *po;
+ const struct pmc *pm;
+ const struct pmc_process *pp;
+
+ pid = td->td_proc->p_pid;
+
+ LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
+ if (po->po_flags & PMC_PO_OWNS_LOGFILE)
+ pmclog_process_map_out(po, pid, pkm->pm_address,
+ pkm->pm_address + pkm->pm_size);
+
+ if ((pp = pmc_find_process_descriptor(td->td_proc, 0)) == NULL)
+ return;
+
+ for (ri = 0; ri < md->pmd_npmc; ri++)
+ if ((pm = pp->pp_pmcs[ri].pp_pmc) != NULL &&
+ PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
+ pmclog_process_map_out(po, pid, pkm->pm_address,
+ pkm->pm_address + pkm->pm_size);
+}
+
+/*
* The 'hook' invoked from the kernel proper
*/
#ifdef DEBUG
const char *pmc_hooknames[] = {
+ /* these strings correspond to PMC_FN_* in <sys/pmckern.h> */
"",
- "EXIT",
"EXEC",
- "FORK",
"CSW-IN",
"CSW-OUT",
- "SAMPLE"
+ "SAMPLE",
+ "KLDLOAD",
+ "KLDUNLOAD",
+ "MMAP",
+ "MUNMAP"
};
#endif
@@ -1585,6 +1706,27 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
pmc_process_samples(PCPU_GET(cpuid));
break;
+
+ case PMC_FN_KLD_LOAD:
+ sx_assert(&pmc_sx, SX_LOCKED);
+ pmc_process_kld_load((struct pmckern_map_in *) arg);
+ break;
+
+ case PMC_FN_KLD_UNLOAD:
+ sx_assert(&pmc_sx, SX_LOCKED);
+ pmc_process_kld_unload((struct pmckern_map_out *) arg);
+ break;
+
+ case PMC_FN_MMAP:
+ sx_assert(&pmc_sx, SX_LOCKED);
+ pmc_process_mmap(td, (struct pmckern_map_in *) arg);
+ break;
+
+ case PMC_FN_MUNMAP:
+ sx_assert(&pmc_sx, SX_LOCKED);
+ pmc_process_munmap(td, (struct pmckern_map_out *) arg);
+ break;
+
default:
#ifdef DEBUG
KASSERT(0, ("[pmc,%d] unknown hook %d\n", __LINE__, function));
@@ -2237,6 +2379,8 @@ pmc_start(struct pmc *pm)
po->po_sscount++;
}
+ /* TODO: dump system wide process mappings to the log? */
+
/*
* Move to the CPU associated with this
* PMC, and start the hardware.
@@ -2408,10 +2552,11 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
case PMC_OP_CONFIGURELOG:
{
+ struct proc *p;
struct pmc *pm;
struct pmc_owner *po;
+ struct pmckern_map_in *km, *kmbase;
struct pmc_op_configurelog cl;
- struct proc *p;
sx_assert(&pmc_sx, SX_XLOCKED);
@@ -2446,6 +2591,21 @@ pmc_syscall_handler(struct thread *td, void *syscall_args)
}
} else
error = EINVAL;
+
+ if (error)
+ break;
+
+ /*
+ * Log the current set of kernel modules.
+ */
+ kmbase = linker_hwpmc_list_objects();
+ for (km = kmbase; km->pm_file != NULL; km++) {
+ PMCDBG(LOG,REG,1,"%s %p", (char *) km->pm_file,
+ (void *) km->pm_address);
+ pmclog_process_map_in(po, (pid_t) -1, km->pm_address,
+ km->pm_file);
+ }
+ FREE(kmbase, M_LINKER);
}
break;
OpenPOWER on IntegriCloud