Page MenuHomeFreeBSD

D59367.1794528374.diff
No OneTemporary

Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None

D59367.1794528374.diff

diff --git a/tools/regression/pmc/Makefile b/tools/regression/pmc/Makefile
--- a/tools/regression/pmc/Makefile
+++ b/tools/regression/pmc/Makefile
@@ -36,7 +36,7 @@
# Kernel ABI tests (need hwpmc(4) loaded and root to run).
KTESTS= pmc_group_test pmc_mux_test pmc_mux_works_test \
- pmc_mux_rotation_test pmc_mux_drain_test
+ pmc_mux_rotation_test pmc_mux_drain_test pmc_group_fuzz
# Userland-only tests (no PMU access).
UTESTS= test_libpmcstat_group
@@ -73,6 +73,9 @@
pmc_mux_drain_test: ${.CURDIR}/pmc_mux_drain_test.c
${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC} -lpmc -lpthread
+pmc_group_fuzz: ${.CURDIR}/pmc_group_fuzz.c
+ ${CC} ${CFLAGS} -o ${.TARGET} ${.ALLSRC} -lpmc
+
# These are userland-only checks: parsers and pmcstat warning policy.
check: ${UTESTS}
./test_libpmcstat_group
@@ -89,6 +92,8 @@
./pmc_mux_rotation_test
@echo "==> pmc_mux_drain_test"
./pmc_mux_drain_test
+ @echo "==> pmc_group_fuzz"
+ ./pmc_group_fuzz 20000
clean:
rm -f ${ALL} *.o *.core
diff --git a/tools/regression/pmc/pmc_group_fuzz.c b/tools/regression/pmc/pmc_group_fuzz.c
new file mode 100644
--- /dev/null
+++ b/tools/regression/pmc/pmc_group_fuzz.c
@@ -0,0 +1,259 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Fuzz test for hwpmc group system calls.
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/module.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pmc.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int pmc_sc = -1;
+
+#define CALL(op, arg) syscall(pmc_sc, (op), (arg))
+
+static unsigned long calls, errs, oks;
+static unsigned int seed = 12345;
+
+/* This PRNG makes the test runs repeatable. */
+static uint32_t
+rnd(void)
+{
+ seed = seed * 1103515245u + 12345u;
+ return (seed >> 8);
+}
+
+static uint32_t
+pick_capacity(void)
+{
+ switch (rnd() % 8) {
+ case 0: return (0);
+ case 1: return (1);
+ case 2: return (32);
+ case 3: return (33);
+ case 4: return (UINT32_MAX);
+ case 5: return (rnd());
+ case 6: return (rnd() % 64);
+ default: return (2);
+ }
+}
+
+static void
+note(long rv)
+{
+ calls++;
+ if (rv == 0)
+ oks++;
+ else
+ errs++;
+}
+
+/* Test PMCGROUPREAD with any capacity value. */
+static void
+fuzz_read(pmc_id_t leader, uint32_t claim, uint32_t alloc)
+{
+ struct pmc_op_pmcgroupread *gr;
+ size_t sz;
+
+ /* Allocate memory. Add guard bytes. */
+ if (alloc > 64)
+ alloc = 64;
+ if (alloc < claim && claim <= 64)
+ alloc = claim;
+ if (claim > 64)
+ alloc = 64;
+ sz = sizeof(*gr) + (size_t)alloc * sizeof(gr->pm_members[0]);
+ gr = calloc(1, sz + 4096); /* This is the guard zone. */
+ if (gr == NULL)
+ return;
+ memset((char *)gr + sz, 0xA5, 4096);
+ gr->pm_leader = leader;
+ gr->pm_nmembers = claim;
+ errno = 0;
+ note(CALL(PMC_OP_PMCGROUPREAD, gr));
+
+ /* Check that the guard zone did not change. */
+ for (size_t i = 0; i < 4096; i++) {
+ if (((unsigned char *)gr)[sz + i] != 0xA5) {
+ printf(" *** RED ZONE CLOBBERED at +%zu "
+ "(claim=%u alloc=%u)\n", i, claim, alloc);
+ break;
+ }
+ }
+ free(gr);
+}
+
+static void
+fuzz_add(uint32_t gid, pmc_id_t pmcid, uint32_t flags)
+{
+ struct pmc_op_pmcgroupadd ga;
+
+ memset(&ga, 0, sizeof(ga));
+ ga.pm_groupid = gid;
+ ga.pm_pmcid = pmcid;
+ ga.pm_flags = flags;
+ errno = 0;
+ note(CALL(PMC_OP_PMCGROUPADD, &ga));
+}
+
+static void
+fuzz_commit(uint32_t gid)
+{
+ struct pmc_op_pmcgroupcommit gc;
+
+ memset(&gc, 0, sizeof(gc));
+ gc.pm_groupid = gid;
+ errno = 0;
+ note(CALL(PMC_OP_PMCGROUPCOMMIT, &gc));
+}
+
+int
+main(int argc, char **argv)
+{
+ struct module_stat ms;
+ pmc_id_t real_ids[4], released_id;
+ uint32_t real_gid, released_gid, uncommitted_gid;
+ long iters = 20000;
+ int i, nreal = 0, modid;
+
+ if (argc > 1)
+ iters = atol(argv[1]);
+
+ if (pmc_init() < 0)
+ errx(77, "pmc_init: %s", strerror(errno));
+
+ if ((modid = modfind(PMC_MODULE_NAME)) < 0)
+ errx(77, "modfind %s: %s", PMC_MODULE_NAME, strerror(errno));
+ memset(&ms, 0, sizeof(ms));
+ ms.version = sizeof(ms);
+ if (modstat(modid, &ms) < 0)
+ errx(77, "modstat: %s", strerror(errno));
+ pmc_sc = ms.data.intval;
+ printf("hwpmc syscall=%d, %ld iterations, seed=%u\n", pmc_sc, iters,
+ seed);
+
+ /* Create the committed test group. */
+ if (pmc_group_create(&real_gid) < 0)
+ errx(77, "group_create: %s", strerror(errno));
+ {
+ const char *ev[] = { "instructions", "unhalted-cycles",
+ "branches" };
+ for (i = 0; i < 3; i++) {
+ if (pmc_allocate_group(ev[i], PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &real_ids[nreal], 0) < 0)
+ continue;
+ if (pmc_group_add(real_gid, real_ids[nreal],
+ nreal == 0) < 0) {
+ (void)pmc_release(real_ids[nreal]);
+ continue;
+ }
+ nreal++;
+ }
+ }
+ if (nreal < 2)
+ errx(77, "could not build a 2-member group");
+ if (pmc_group_commit(real_gid) < 0)
+ errx(77, "commit: %s", strerror(errno));
+ if (pmc_attach(real_ids[0], getpid()) < 0)
+ errx(77, "attach: %s", strerror(errno));
+ if (pmc_start(real_ids[0]) < 0)
+ errx(77, "start: %s", strerror(errno));
+
+ /* Create the uncommitted test group. */
+ if (pmc_group_create(&uncommitted_gid) < 0)
+ errx(77, "group_create 2");
+
+ /* Create the released test group. */
+ if (pmc_group_create(&released_gid) == 0) {
+ pmc_id_t tmp;
+
+ if (pmc_allocate_group("instructions", PMC_MODE_TC, 0,
+ PMC_CPU_ANY, &tmp, 0) == 0) {
+ (void)pmc_group_add(released_gid, tmp, 1);
+ released_id = tmp;
+ (void)pmc_release(tmp);
+ } else {
+ released_id = 0xdeadbeef;
+ }
+ } else {
+ released_gid = 0xdead;
+ released_id = 0xdeadbeef;
+ }
+
+ printf("real gid=%u (%d members), uncommitted gid=%u, "
+ "released gid=%u\n", real_gid, nreal, uncommitted_gid,
+ released_gid);
+
+ for (i = 0; i < iters; i++) {
+ uint32_t gid;
+ pmc_id_t pid_;
+
+ /* Pick a group ID. */
+ switch (rnd() % 6) {
+ case 0: gid = real_gid; break;
+ case 1: gid = uncommitted_gid; break;
+ case 2: gid = released_gid; break;
+ case 3: gid = rnd(); break;
+ case 4: gid = 0; break;
+ default: gid = UINT32_MAX; break;
+ }
+
+ /* Pick a PMC ID. */
+ switch (rnd() % 6) {
+ case 0: pid_ = real_ids[0]; break;
+ case 1: pid_ = real_ids[nreal - 1]; break;
+ case 2: pid_ = released_id; break;
+ case 3: pid_ = rnd(); break;
+ case 4: pid_ = 0; break;
+ default: pid_ = UINT32_MAX; break;
+ }
+
+ switch (rnd() % 3) {
+ case 0:
+ fuzz_add(gid, pid_, rnd() % 4);
+ break;
+ case 1:
+ fuzz_commit(gid);
+ break;
+ default:
+ fuzz_read(pid_, pick_capacity(), rnd() % 40);
+ break;
+ }
+
+ if ((i % 5000) == 0 && i > 0)
+ printf(" %d iterations, %lu calls, %lu errno, "
+ "%lu ok\n", i, calls, errs, oks);
+ }
+
+ printf("done: %lu calls, %lu returned an errno, %lu returned 0\n",
+ calls, errs, oks);
+
+ /* Check that the group is still readable. */
+ {
+ struct pmc_group_times t;
+ uint32_t n = 0;
+
+ memset(&t, 0, sizeof(t));
+ if (pmc_group_read(real_ids[0], &n, NULL, &t) < 0) {
+ printf(" *** real group unreadable after fuzz: %s\n",
+ strerror(errno));
+ return (1);
+ }
+ printf("real group still live: %u members, enabled=%llu\n",
+ n, (unsigned long long)t.pgt_enabled);
+ }
+
+ (void)pmc_release(real_ids[0]);
+ return (0);
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 13, 12:06 AM (16 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41686795
Default Alt Text
D59367.1794528374.diff (7 KB)

Event Timeline