Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102665043
D44483.id140007.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D44483.id140007.diff
View Options
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d
--- a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/sdt/tst.sdtargs.d
@@ -27,7 +27,7 @@
#pragma ident "%Z%%M% %I% %E% SMI"
/*
- * ASSERTION: Verify that argN (1..7) variables are properly remapped.
+ * ASSERTION: Verify that argN (1..6) variables are properly remapped.
*/
BEGIN
@@ -44,13 +44,12 @@
}
test:::sdttest
-/arg0 != 1 || arg1 != 2 || arg2 != 3 || arg3 != 4 || arg4 != 5 || arg5 != 6 ||
- arg6 != 7/
+/arg0 != 1 || arg1 != 2 || arg2 != 3 || arg3 != 4 || arg4 != 5 || arg5 != 6/
{
printf("sdt arg mismatch\n\n");
- printf("args are : %d, %d, %d, %d, %d, %d, %d\n", arg0, arg1, arg2,
- arg3, arg4, arg5, arg6);
- printf("should be : 1, 2, 3, 4, 5, 6, 7\n");
+ printf("args are : %d, %d, %d, %d, %d, %d\n", arg0, arg1, arg2,
+ arg3, arg4, arg5);
+ printf("should be : 1, 2, 3, 4, 5, 6\n");
exit(1);
}
diff --git a/sys/amd64/include/sdt_machdep.h b/sys/amd64/include/sdt_machdep.h
new file mode 100644
--- /dev/null
+++ b/sys/amd64/include/sdt_machdep.h
@@ -0,0 +1,12 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#ifndef _SYS_SDT_MACHDEP_H_
+#define _SYS_SDT_MACHDEP_H_
+
+#define _SDT_ASM_PATCH_INSTR "nop; nop; nop; nop; nop"
+
+#endif
diff --git a/sys/arm/arm/sdt_machdep.c b/sys/arm/arm/sdt_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/arm/arm/sdt_machdep.c
@@ -0,0 +1,63 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <sys/systm.h>
+#include <sys/sdt.h>
+
+#include <machine/cpu.h>
+
+/*
+ * Return true if we can overwrite a nop at "patchpoint" with a jump to the
+ * target address.
+ */
+bool
+sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
+{
+ int32_t offset;
+
+ if (patchpoint == target ||
+ (patchpoint & (INSN_SIZE - 1)) != 0 ||
+ (target & (INSN_SIZE - 1)) != 0 ||
+ patchpoint + 2 * INSN_SIZE < patchpoint)
+ return (false);
+ offset = target - (patchpoint + 2 * INSN_SIZE);
+ if (offset < -(1 << 24) || offset > (1 >> 24))
+ return (false);
+ return (true);
+}
+
+/*
+ * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
+ * the target address.
+ */
+void
+sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
+{
+ uint32_t instr;
+
+ KASSERT(sdt_tracepoint_valid(patchpoint, target),
+ ("%s: invalid tracepoint %#x -> %#x",
+ __func__, patchpoint, target));
+
+ instr =
+ (((target - (patchpoint + 2 * INSN_SIZE)) >> 2) & ((1 << 24) - 1)) |
+ 0xea000000;
+ memcpy((void *)patchpoint, &instr, sizeof(instr));
+ icache_sync(patchpoint, sizeof(instr));
+}
+
+/*
+ * Overwrite the patchpoint with a nop instruction.
+ */
+void
+sdt_tracepoint_restore(uintptr_t patchpoint)
+{
+ uint32_t instr;
+
+ instr = 0xe320f000u;
+ memcpy((void *)patchpoint, &instr, sizeof(instr));
+ icache_sync(patchpoint, sizeof(instr));
+}
diff --git a/sys/arm/include/sdt_machdep.h b/sys/arm/include/sdt_machdep.h
new file mode 100644
--- /dev/null
+++ b/sys/arm/include/sdt_machdep.h
@@ -0,0 +1,12 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#ifndef _SYS_SDT_MACHDEP_H_
+#define _SYS_SDT_MACHDEP_H_
+
+#define _SDT_ASM_PATCH_INSTR "nop"
+
+#endif /* _SYS_SDT_MACHDEP_H_ */
diff --git a/sys/arm64/arm64/sdt_machdep.c b/sys/arm64/arm64/sdt_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/arm64/arm64/sdt_machdep.c
@@ -0,0 +1,77 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <sys/systm.h>
+#include <sys/sdt.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/cpufunc.h>
+#include <machine/md_var.h>
+#include <machine/vmparam.h>
+
+/*
+ * Return true if we can overwrite a nop at "patchpoint" with a jump to the
+ * target address.
+ */
+bool
+sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
+{
+ void *addr;
+ int64_t offset;
+
+ if (!arm64_get_writable_addr((void *)patchpoint, &addr))
+ return (false);
+
+ if (patchpoint == target ||
+ (patchpoint & (INSN_SIZE - 1)) != 0 ||
+ (target & (INSN_SIZE - 1)) != 0)
+ return (false);
+ offset = target - patchpoint;
+ if (offset < -(1 << 26) || offset > (1 << 26))
+ return (false);
+ return (true);
+}
+
+/*
+ * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to the
+ * target address.
+ */
+void
+sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
+{
+ void *addr;
+ uint32_t instr;
+
+ KASSERT(sdt_tracepoint_valid(patchpoint, target),
+ ("%s: invalid tracepoint %#lx -> %#lx",
+ __func__, patchpoint, target));
+
+ if (!arm64_get_writable_addr((void *)patchpoint, &addr))
+ panic("%s: Unable to write new instruction", __func__);
+
+ instr = (((target - patchpoint) >> 2) & 0x3fffffful) | 0x14000000;
+ memcpy(addr, &instr, sizeof(instr));
+ cpu_icache_sync_range((void *)patchpoint, INSN_SIZE);
+}
+
+/*
+ * Overwrite the patchpoint with a nop instruction.
+ */
+void
+sdt_tracepoint_restore(uintptr_t patchpoint)
+{
+ void *addr;
+ uint32_t instr;
+
+ if (!arm64_get_writable_addr((void *)patchpoint, &addr))
+ panic("%s: Unable to write new instruction", __func__);
+
+ instr = 0xd503201f;
+ memcpy(addr, &instr, sizeof(instr));
+ cpu_icache_sync_range((void *)patchpoint, INSN_SIZE);
+}
diff --git a/sys/arm64/include/sdt_machdep.h b/sys/arm64/include/sdt_machdep.h
new file mode 100644
--- /dev/null
+++ b/sys/arm64/include/sdt_machdep.h
@@ -0,0 +1,12 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#ifndef _SYS_SDT_MACHDEP_H_
+#define _SYS_SDT_MACHDEP_H_
+
+#define _SDT_ASM_PATCH_INSTR "nop"
+
+#endif /* _SYS_SDT_MACHDEP_H_ */
diff --git a/sys/cddl/dev/dtrace/dtrace_test.c b/sys/cddl/dev/dtrace/dtrace_test.c
--- a/sys/cddl/dev/dtrace/dtrace_test.c
+++ b/sys/cddl/dev/dtrace/dtrace_test.c
@@ -37,8 +37,8 @@
SDT_PROVIDER_DEFINE(test);
-SDT_PROBE_DEFINE7(test, , , sdttest, "int", "int", "int", "int", "int",
- "int", "int");
+SDT_PROBE_DEFINE6(test, , , sdttest, "int", "int", "int", "int", "int",
+ "int");
/*
* These are variables that the DTrace test suite references in the
@@ -68,7 +68,7 @@
else if (val == 0)
return (0);
- SDT_PROBE7(test, , , sdttest, 1, 2, 3, 4, 5, 6, 7);
+ SDT_PROBE6(test, , , sdttest, 1, 2, 3, 4, 5, 6);
return (error);
}
diff --git a/sys/cddl/dev/sdt/sdt.c b/sys/cddl/dev/sdt/sdt.c
--- a/sys/cddl/dev/sdt/sdt.c
+++ b/sys/cddl/dev/sdt/sdt.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*
* Portions Copyright 2006-2008 John Birrell jb@freebsd.org
- *
+ * Copyright 2024 Mark Johnston <markj@FreeBSD.org>
*/
/*
@@ -187,7 +187,7 @@
if (dtrace_probe_lookup(prov->id, mod, func, name) != DTRACE_IDNONE)
return;
- (void)dtrace_probe_create(prov->id, mod, func, name, 1, probe);
+ (void)dtrace_probe_create(prov->id, mod, func, name, 0, probe);
}
/*
@@ -200,10 +200,62 @@
{
}
+struct sdt_enable_cb_arg {
+ struct sdt_probe *probe;
+ int cpu;
+ int arrived;
+ int done;
+ bool enable;
+};
+
+static void
+sdt_probe_update_cb(void *_arg)
+{
+ struct sdt_enable_cb_arg *arg;
+ struct sdt_tracepoint *tp;
+
+ arg = _arg;
+ if (arg->cpu != curcpu) {
+ atomic_add_rel_int(&arg->arrived, 1);
+ while (atomic_load_acq_int(&arg->done) == 0)
+ cpu_spinwait();
+ return;
+ } else {
+ while (atomic_load_acq_int(&arg->arrived) != mp_ncpus - 1)
+ cpu_spinwait();
+ }
+
+ STAILQ_FOREACH(tp, &arg->probe->tracepoint_list, tracepoint_entry) {
+ if (arg->enable)
+ sdt_tracepoint_patch(tp->patchpoint, tp->target);
+ else
+ sdt_tracepoint_restore(tp->patchpoint);
+ }
+
+ atomic_store_rel_int(&arg->done, 1);
+}
+
+static void
+sdt_probe_update(struct sdt_probe *probe, bool enable)
+{
+ struct sdt_enable_cb_arg cbarg;
+
+ sched_pin();
+ cbarg.probe = probe;
+ cbarg.cpu = curcpu;
+ atomic_store_rel_int(&cbarg.arrived, 0);
+ atomic_store_rel_int(&cbarg.done, 0);
+ cbarg.enable = enable;
+ smp_rendezvous(NULL, sdt_probe_update_cb, NULL, &cbarg);
+ sched_unpin();
+}
+
static void
sdt_enable(void *arg __unused, dtrace_id_t id, void *parg)
{
- struct sdt_probe *probe = parg;
+ struct sdt_probe *probe;
+
+ probe = parg;
probe->id = id;
probe->sdtp_lf->nenabled++;
@@ -215,15 +267,20 @@
sdt_probes_enabled_count++;
if (sdt_probes_enabled_count == 1)
sdt_probes_enabled = true;
+
+ sdt_probe_update(probe, true);
}
static void
sdt_disable(void *arg __unused, dtrace_id_t id, void *parg)
{
- struct sdt_probe *probe = parg;
+ struct sdt_probe *probe;
+ probe = parg;
KASSERT(probe->sdtp_lf->nenabled > 0, ("no probes enabled"));
+ sdt_probe_update(probe, false);
+
sdt_probes_enabled_count--;
if (sdt_probes_enabled_count == 0)
sdt_probes_enabled = false;
@@ -284,26 +341,47 @@
static void
sdt_kld_load_probes(struct linker_file *lf)
{
- struct sdt_probe **probe, **p_begin, **p_end;
- struct sdt_argtype **argtype, **a_begin, **a_end;
+ struct sdt_probe **p_begin, **p_end;
+ struct sdt_argtype **a_begin, **a_end;
+ struct sdt_tracepoint *tp_begin, *tp_end;
if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
NULL) == 0) {
- for (probe = p_begin; probe < p_end; probe++) {
+ for (struct sdt_probe **probe = p_begin; probe < p_end;
+ probe++) {
(*probe)->sdtp_lf = lf;
sdt_create_probe(*probe);
TAILQ_INIT(&(*probe)->argtype_list);
+ STAILQ_INIT(&(*probe)->tracepoint_list);
}
}
if (linker_file_lookup_set(lf, "sdt_argtypes_set", &a_begin, &a_end,
NULL) == 0) {
- for (argtype = a_begin; argtype < a_end; argtype++) {
+ for (struct sdt_argtype **argtype = a_begin; argtype < a_end;
+ argtype++) {
(*argtype)->probe->n_args++;
TAILQ_INSERT_TAIL(&(*argtype)->probe->argtype_list,
*argtype, argtype_entry);
}
}
+
+ if (linker_file_lookup_set(lf, __XSTRING(_SDT_TRACEPOINT_SET),
+ &tp_begin, &tp_end, NULL) == 0) {
+ for (struct sdt_tracepoint *tp = tp_begin; tp < tp_end; tp++) {
+ if (!sdt_tracepoint_valid(tp->patchpoint, tp->target)) {
+ printf(
+ "invalid tracepoint %#jx->%#jx for %s:%s:%s:%s\n",
+ (uintmax_t)tp->patchpoint,
+ (uintmax_t)tp->target,
+ tp->probe->prov->name, tp->probe->mod,
+ tp->probe->func, tp->probe->name);
+ continue;
+ }
+ STAILQ_INSERT_TAIL(&tp->probe->tracepoint_list, tp,
+ tracepoint_entry);
+ }
+ }
}
/*
@@ -378,6 +456,7 @@
TAILQ_INIT(&sdt_prov_list);
sdt_probe_func = dtrace_probe;
+ sdt_probe6_func = (sdt_probe6_func_t)dtrace_probe;
sdt_kld_load_tag = EVENTHANDLER_REGISTER(kld_load, sdt_kld_load, NULL,
EVENTHANDLER_PRI_ANY);
@@ -403,6 +482,7 @@
EVENTHANDLER_DEREGISTER(kld_unload_try, sdt_kld_unload_try_tag);
sdt_probe_func = sdt_probe_stub;
+ sdt_probe6_func = (sdt_probe6_func_t)sdt_probe_stub;
TAILQ_FOREACH_SAFE(prov, &sdt_prov_list, prov_entry, tmp) {
ret = dtrace_unregister(prov->id);
@@ -419,7 +499,6 @@
static int
sdt_modevent(module_t mod __unused, int type, void *data __unused)
{
-
switch (type) {
case MOD_LOAD:
case MOD_UNLOAD:
diff --git a/sys/conf/files.arm b/sys/conf/files.arm
--- a/sys/conf/files.arm
+++ b/sys/conf/files.arm
@@ -58,6 +58,7 @@
arm/arm/pmu_fdt.c optional fdt pmu | fdt hwpmc
arm/arm/ptrace_machdep.c standard
arm/arm/sc_machdep.c optional sc
+arm/arm/sdt_machdep.c optional kdtrace_hooks
arm/arm/setcpsr.S standard
arm/arm/setstack.S standard
arm/arm/stack_machdep.c optional ddb | stack
diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -68,6 +68,7 @@
compile-with "${NORMAL_C:N-mbranch-protection*} -mbranch-protection=bti"
arm64/arm64/pmap.c standard
arm64/arm64/ptrace_machdep.c standard
+arm64/arm64/sdt_machdep.c optional kdtrace_hooks
arm64/arm64/sigtramp.S standard
arm64/arm64/stack_machdep.c optional ddb | stack
arm64/arm64/strcmp.S standard
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc
--- a/sys/conf/files.powerpc
+++ b/sys/conf/files.powerpc
@@ -336,6 +336,7 @@
powerpc/powerpc/platform_if.m standard
powerpc/powerpc/ptrace_machdep.c standard
powerpc/powerpc/sc_machdep.c optional sc
+powerpc/powerpc/sdt_machdep.c optional powerpc64 kdtrace_hooks
powerpc/powerpc/setjmp.S standard
powerpc/powerpc/sigcode32.S optional powerpc | powerpcspe | compat_freebsd32
powerpc/powerpc/sigcode64.S optional powerpc64 | powerpc64le
diff --git a/sys/conf/files.riscv b/sys/conf/files.riscv
--- a/sys/conf/files.riscv
+++ b/sys/conf/files.riscv
@@ -61,6 +61,7 @@
riscv/riscv/sigtramp.S standard
riscv/riscv/sbi.c standard
riscv/riscv/sbi_ipi.c optional smp
+riscv/riscv/sdt_machdep.c optional kdtrace_hooks
riscv/riscv/stack_machdep.c optional ddb | stack
riscv/riscv/support.S standard
riscv/riscv/swtch.S standard
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -377,6 +377,7 @@
x86/x86/mp_x86.c optional smp
x86/x86/nexus.c standard
x86/x86/pvclock.c optional kvm_clock | xenhvm
+x86/x86/sdt_machdep.c optional kdtrace_hooks
x86/x86/stack_machdep.c optional ddb | stack
x86/x86/tsc.c standard
x86/x86/ucode.c standard
diff --git a/sys/i386/include/sdt_machdep.h b/sys/i386/include/sdt_machdep.h
new file mode 100644
--- /dev/null
+++ b/sys/i386/include/sdt_machdep.h
@@ -0,0 +1,19 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#ifndef _SYS_SDT_MACHDEP_H_
+#define _SYS_SDT_MACHDEP_H_
+
+#define _SDT_ASM_PATCH_INSTR "nop; nop; nop; nop; nop"
+
+/*
+ * Work around an apparent clang bug or limitation which prevents the use of the
+ * "i" (immediate) constraint with the probe structure.
+ */
+#define _SDT_ASM_PROBE_CONSTRAINT "Ws"
+#define _SDT_ASM_PROBE_OPERAND "p"
+
+#endif
diff --git a/sys/kern/kern_sdt.c b/sys/kern/kern_sdt.c
--- a/sys/kern/kern_sdt.c
+++ b/sys/kern/kern_sdt.c
@@ -37,6 +37,7 @@
* dtrace_probe() when it loads.
*/
sdt_probe_func_t sdt_probe_func = sdt_probe_stub;
+sdt_probe6_func_t sdt_probe6_func = (sdt_probe6_func_t)sdt_probe_stub;
volatile bool __read_frequently sdt_probes_enabled;
/*
@@ -45,10 +46,24 @@
* to enable it.
*/
void
-sdt_probe_stub(uint32_t id, uintptr_t arg0, uintptr_t arg1,
- uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
+sdt_probe_stub(uint32_t id __unused, uintptr_t arg0 __unused,
+ uintptr_t arg1 __unused, uintptr_t arg2 __unused, uintptr_t arg3 __unused,
+ uintptr_t arg4 __unused)
{
-
printf("sdt_probe_stub: unexpectedly called\n");
kdb_backtrace();
}
+
+void
+sdt_probe(uint32_t id, uintptr_t arg0, uintptr_t arg1,
+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4)
+{
+ sdt_probe_func(id, arg0, arg1, arg2, arg3, arg4);
+}
+
+void
+sdt_probe6(uint32_t id, uintptr_t arg0, uintptr_t arg1,
+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5)
+{
+ sdt_probe6_func(id, arg0, arg1, arg2, arg3, arg4, arg5);
+}
diff --git a/sys/modules/dtrace/Makefile b/sys/modules/dtrace/Makefile
--- a/sys/modules/dtrace/Makefile
+++ b/sys/modules/dtrace/Makefile
@@ -10,7 +10,6 @@
fbt \
profile \
prototype \
- sdt \
systrace
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
@@ -31,5 +30,8 @@
${MACHINE_ARCH} == "powerpc64"
SUBDIR+= systrace_freebsd32
.endif
+.if ${MACHINE_CPUARCH} != "powerpc" || ${MACHINE_ARCH} == "powerpc64"
+SUBDIR+= sdt
+.endif
.include <bsd.subdir.mk>
diff --git a/sys/powerpc/include/sdt_machdep.h b/sys/powerpc/include/sdt_machdep.h
new file mode 100644
--- /dev/null
+++ b/sys/powerpc/include/sdt_machdep.h
@@ -0,0 +1,12 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#ifndef _SYS_SDT_MACHDEP_H_
+#define _SYS_SDT_MACHDEP_H_
+
+#define _SDT_ASM_PATCH_INSTR "nop"
+
+#endif
diff --git a/sys/powerpc/powerpc/sdt_machdep.c b/sys/powerpc/powerpc/sdt_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/powerpc/powerpc/sdt_machdep.c
@@ -0,0 +1,59 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <sys/systm.h>
+#include <sys/sdt.h>
+
+#include <machine/md_var.h>
+
+/*
+ * Return true if we can overwrite a nop at "patchpoint" with a jump to the
+ * target address.
+ */
+bool
+sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
+{
+ int64_t offset;
+
+ if (patchpoint == target ||
+ (patchpoint & 3) != 0 || (target & 3) != 0)
+ return (false);
+ offset = target - patchpoint;
+ if (offset < -(1 << 26) || offset > (1 << 26))
+ return (false);
+ return (true);
+}
+
+/*
+ * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
+ * the target address.
+ */
+void
+sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
+{
+ uint32_t instr;
+
+ KASSERT(sdt_tracepoint_valid(patchpoint, target),
+ ("%s: invalid tracepoint %#lx -> %#lx",
+ __func__, patchpoint, target));
+
+ instr = ((target - patchpoint) & 0x7fffffful) | 0x48000000;
+ memcpy((void *)patchpoint, &instr, sizeof(instr));
+ __syncicache((void *)patchpoint, sizeof(instr));
+}
+
+/*
+ * Overwrite the patchpoint with a nop instruction.
+ */
+void
+sdt_tracepoint_restore(uintptr_t patchpoint)
+{
+ uint32_t instr;
+
+ instr = 0x60000000;
+ memcpy((void *)patchpoint, &instr, sizeof(instr));
+ __syncicache((void *)patchpoint, sizeof(instr));
+}
diff --git a/sys/riscv/include/sdt_machdep.h b/sys/riscv/include/sdt_machdep.h
new file mode 100644
--- /dev/null
+++ b/sys/riscv/include/sdt_machdep.h
@@ -0,0 +1,12 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#ifndef _SYS_SDT_MACHDEP_H_
+#define _SYS_SDT_MACHDEP_H_
+
+#define _SDT_ASM_PATCH_INSTR ".option push; .option norvc; nop; .option pop"
+
+#endif /* _SYS_SDT_MACHDEP_H_ */
diff --git a/sys/riscv/riscv/sdt_machdep.c b/sys/riscv/riscv/sdt_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/riscv/riscv/sdt_machdep.c
@@ -0,0 +1,68 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <sys/systm.h>
+#include <sys/sdt.h>
+
+#include <machine/encoding.h>
+
+/*
+ * Return true if we can overwrite a nop at "patchpoint" with a jump to the
+ * target address.
+ */
+bool
+sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
+{
+ int64_t offset;
+
+ if (patchpoint == target ||
+ (patchpoint & (INSN_C_SIZE - 1)) != 0 ||
+ (target & (INSN_C_SIZE - 1)) != 0)
+ return (false);
+ offset = target - patchpoint;
+ if (offset < -(1 << 19) || offset > (1 << 19))
+ return (false);
+ return (true);
+}
+
+/*
+ * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
+ * the target address.
+ */
+void
+sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
+{
+ int32_t imm;
+ uint32_t instr;
+
+ KASSERT(sdt_tracepoint_valid(patchpoint, target),
+ ("%s: invalid tracepoint %#lx -> %#lx",
+ __func__, patchpoint, target));
+
+ imm = target - patchpoint;
+ imm = (imm & 0x100000) |
+ ((imm & 0x7fe) << 8) |
+ ((imm & 0x800) >> 2) |
+ ((imm & 0xff000) >> 12);
+ instr = (imm << 12) | MATCH_JAL;
+
+ memcpy((void *)patchpoint, &instr, sizeof(instr));
+ fence_i();
+}
+
+/*
+ * Overwrite the patchpoint with a nop instruction.
+ */
+void
+sdt_tracepoint_restore(uintptr_t patchpoint)
+{
+ uint32_t instr;
+
+ instr = 0x13; /* uncompressed nop */
+
+ memcpy((void *)patchpoint, &instr, sizeof(instr));
+ fence_i();
+}
diff --git a/sys/sys/sdt.h b/sys/sys/sdt.h
--- a/sys/sys/sdt.h
+++ b/sys/sys/sdt.h
@@ -77,8 +77,8 @@
#else /* _KERNEL */
-#include <sys/cdefs.h>
#include <sys/linker_set.h>
+#include <machine/sdt_machdep.h>
extern volatile bool sdt_probes_enabled;
@@ -102,8 +102,6 @@
#define SDT_PROBE_DEFINE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4)
#define SDT_PROBE_DEFINE6(prov, mod, func, name, arg0, arg1, arg2, \
arg3, arg4, arg5)
-#define SDT_PROBE_DEFINE7(prov, mod, func, name, arg0, arg1, arg2, \
- arg3, arg4, arg5, arg6)
#define SDT_PROBE0(prov, mod, func, name)
#define SDT_PROBE1(prov, mod, func, name, arg0)
@@ -112,8 +110,6 @@
#define SDT_PROBE4(prov, mod, func, name, arg0, arg1, arg2, arg3)
#define SDT_PROBE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4)
#define SDT_PROBE6(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5)
-#define SDT_PROBE7(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5, \
- arg6)
#define MIB_SDT_PROBE1(...)
#define MIB_SDT_PROBE2(...)
@@ -130,9 +126,6 @@
arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4)
#define SDT_PROBE_DEFINE6_XLATE(prov, mod, func, name, arg0, xarg0, \
arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5)
-#define SDT_PROBE_DEFINE7_XLATE(prov, mod, func, name, arg0, xarg0, \
- arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5, arg6, \
- xarg6)
#define DTRACE_PROBE(name)
#define DTRACE_PROBE1(name, type0, arg0)
@@ -144,6 +137,18 @@
#else
+void sdt_probe(uint32_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t);
+void sdt_probe6(uint32_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t, uintptr_t);
+
+#define _SDT_TRACEPOINT_SET sdt_tracepoint_set
+#define _SDT_TRACEPOINT_SECTION "set_sdt_tracepoint_set"
+
+bool sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target);
+void sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target);
+void sdt_tracepoint_restore(uintptr_t patchpoint);
+
#define __sdt_used
SET_DECLARE(sdt_providers_set, struct sdt_provider);
@@ -181,14 +186,58 @@
#define SDT_PROBES_ENABLED() __predict_false(sdt_probes_enabled)
-#define SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) do { \
- if (SDT_PROBES_ENABLED()) { \
- if (__predict_false(_SDT_PROBE_NAME(prov, mod, func, name)->id)) \
- (*sdt_probe_func)(_SDT_PROBE_NAME(prov, mod, func, name)->id, \
- (uintptr_t) arg0, (uintptr_t) arg1, (uintptr_t) arg2, \
- (uintptr_t) arg3, (uintptr_t) arg4); \
- } \
+#ifdef _ILP32
+#define _SDT_ASM_WORD ".long"
+#else
+#define _SDT_ASM_WORD ".quad"
+#endif
+
+#ifndef _SDT_ASM_PROBE_CONSTRAINT
+#define _SDT_ASM_PROBE_CONSTRAINT "i"
+#endif
+#ifndef _SDT_ASM_PROBE_OPERAND
+#define _SDT_ASM_PROBE_OPERAND "c"
+#endif
+
+/*
+ * The asm below generates records corresponding to the structure's layout, so
+ * the two must be kept in sync.
+ */
+struct sdt_tracepoint {
+ struct sdt_probe *probe;
+ uintptr_t patchpoint;
+ uintptr_t target;
+ STAILQ_ENTRY(sdt_tracepoint) tracepoint_entry;
+};
+
+#define __SDT_PROBE(prov, mod, func, name, uniq, f, ...) do { \
+ __WEAK(__CONCAT(__start_set_, _SDT_TRACEPOINT_SET)); \
+ __WEAK(__CONCAT(__stop_set_, _SDT_TRACEPOINT_SET)); \
+ asm goto( \
+ "0:\n" \
+ _SDT_ASM_PATCH_INSTR "\n" \
+ ".pushsection " _SDT_TRACEPOINT_SECTION ", \"aw\"\n" \
+ _SDT_ASM_WORD " %" _SDT_ASM_PROBE_OPERAND "0\n" \
+ _SDT_ASM_WORD " 0b\n" \
+ _SDT_ASM_WORD " %l1\n" \
+ _SDT_ASM_WORD " 0\n" \
+ ".popsection\n" \
+ : \
+ : _SDT_ASM_PROBE_CONSTRAINT (_SDT_PROBE_NAME(prov, mod, \
+ func, name)) \
+ : \
+ : __sdt_probe##uniq); \
+ if (0) { \
+__sdt_probe##uniq:; \
+ f(_SDT_PROBE_NAME(prov, mod, func, name)->id, __VA_ARGS__); \
+ } \
} while (0)
+#define _SDT_PROBE(prov, mod, func, name, uniq, f, ...) \
+ __SDT_PROBE(prov, mod, func, name, uniq, f, __VA_ARGS__)
+#define SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) \
+ _SDT_PROBE(prov, mod, func, name, __COUNTER__, sdt_probe, \
+ (uintptr_t)arg0, (uintptr_t)arg1, (uintptr_t)arg2, \
+ (uintptr_t)arg3, (uintptr_t)arg4)
#define SDT_PROBE_ARGTYPE(_prov, _mod, _func, _name, _num, _type, _xtype) \
static struct sdt_argtype \
@@ -246,17 +295,6 @@
SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, NULL); \
SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, NULL)
-#define SDT_PROBE_DEFINE7(prov, mod, func, name, arg0, arg1, arg2, arg3,\
- arg4, arg5, arg6) \
- SDT_PROBE_DEFINE(prov, mod, func, name); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, NULL); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, NULL); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, NULL); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, NULL); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, NULL); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, NULL); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 6, arg6, NULL)
-
#define SDT_PROBE_DEFINE0_XLATE(prov, mod, func, name) \
SDT_PROBE_DEFINE(prov, mod, func, name)
@@ -304,18 +342,6 @@
SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, xarg4); \
SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, xarg5)
-#define SDT_PROBE_DEFINE7_XLATE(prov, mod, func, name, arg0, xarg0, \
- arg1, xarg1, arg2, xarg2, arg3, xarg3, arg4, xarg4, arg5, xarg5, arg6, \
- xarg6) \
- SDT_PROBE_DEFINE(prov, mod, func, name); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 0, arg0, xarg0); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 1, arg1, xarg1); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 2, arg2, xarg2); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 3, arg3, xarg3); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 4, arg4, xarg4); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 5, arg5, xarg5); \
- SDT_PROBE_ARGTYPE(prov, mod, func, name, 6, arg6, xarg6)
-
#define SDT_PROBE0(prov, mod, func, name) \
SDT_PROBE(prov, mod, func, name, 0, 0, 0, 0, 0)
#define SDT_PROBE1(prov, mod, func, name, arg0) \
@@ -328,27 +354,10 @@
SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, 0)
#define SDT_PROBE5(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4) \
SDT_PROBE(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4)
-#define SDT_PROBE6(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5) \
- do { \
- if (_SDT_PROBE_NAME(prov, mod, func, name)->id) \
- (*(void (*)(uint32_t, uintptr_t, uintptr_t, uintptr_t, \
- uintptr_t, uintptr_t, uintptr_t))sdt_probe_func)( \
- _SDT_PROBE_NAME(prov, mod, func, name)->id, \
- (uintptr_t)arg0, (uintptr_t)arg1, (uintptr_t)arg2, \
- (uintptr_t)arg3, (uintptr_t)arg4, (uintptr_t)arg5);\
- } while (0)
-#define SDT_PROBE7(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5, \
- arg6) \
- do { \
- if (_SDT_PROBE_NAME(prov, mod, func, name)->id) \
- (*(void (*)(uint32_t, uintptr_t, uintptr_t, uintptr_t, \
- uintptr_t, uintptr_t, uintptr_t, uintptr_t)) \
- sdt_probe_func)( \
- _SDT_PROBE_NAME(prov, mod, func, name)->id, \
- (uintptr_t)arg0, (uintptr_t)arg1, (uintptr_t)arg2, \
- (uintptr_t)arg3, (uintptr_t)arg4, (uintptr_t)arg5, \
- (uintptr_t)arg6); \
- } while (0)
+#define SDT_PROBE6(prov, mod, func, name, arg0, arg1, arg2, arg3, arg4, arg5) \
+ _SDT_PROBE(prov, mod, func, name, __COUNTER__, sdt_probe6, \
+ (uintptr_t)arg0, (uintptr_t)arg1, (uintptr_t)arg2, \
+ (uintptr_t)arg3, (uintptr_t)arg4, (uintptr_t)arg5)
#ifndef KDTRACE_NO_MIB_SDT
#define MIB_SDT_PROBE1(...) SDT_PROBE1(mib, __VA_ARGS__)
@@ -411,11 +420,14 @@
*/
typedef void (*sdt_probe_func_t)(uint32_t, uintptr_t arg0, uintptr_t arg1,
uintptr_t arg2, uintptr_t arg3, uintptr_t arg4);
+typedef void (*sdt_probe6_func_t)(uint32_t, uintptr_t arg0, uintptr_t arg1,
+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, uintptr_t arg5);
/*
* The 'sdt' provider will set it to dtrace_probe when it loads.
*/
-extern sdt_probe_func_t sdt_probe_func;
+extern sdt_probe_func_t sdt_probe_func;
+extern sdt_probe6_func_t sdt_probe6_func;
struct sdt_probe;
struct sdt_provider;
@@ -436,6 +448,7 @@
TAILQ_ENTRY(sdt_probe)
probe_entry; /* SDT probe list entry. */
TAILQ_HEAD(, sdt_argtype) argtype_list;
+ STAILQ_HEAD(, sdt_tracepoint) tracepoint_list;
const char *mod;
const char *func;
const char *name;
diff --git a/sys/x86/x86/sdt_machdep.c b/sys/x86/x86/sdt_machdep.c
new file mode 100644
--- /dev/null
+++ b/sys/x86/x86/sdt_machdep.c
@@ -0,0 +1,84 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <sys/systm.h>
+#include <sys/sdt.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/md_var.h>
+#include <machine/vmparam.h>
+
+#define SDT_PATCH_SIZE 5
+
+/*
+ * Return true if we can overwrite a nop at "patchpoint" with a jump to the
+ * target address.
+ */
+bool
+sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
+{
+#ifdef __amd64__
+ if (patchpoint < KERNSTART || target < KERNSTART)
+ return (false);
+#endif
+ if (patchpoint == target ||
+ patchpoint + SDT_PATCH_SIZE < patchpoint)
+ return (false);
+#ifdef __amd64__
+ int64_t offset = target - (patchpoint + SDT_PATCH_SIZE);
+ if (offset < -(1l << 31) || offset > (1l << 31))
+ return (false);
+#endif
+ return (true);
+}
+
+/*
+ * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
+ * the target address.
+ */
+void
+sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
+{
+ uint8_t instr[SDT_PATCH_SIZE];
+ int32_t disp;
+ bool old_wp;
+
+ KASSERT(sdt_tracepoint_valid(patchpoint, target),
+ ("%s: invalid tracepoint %#jx -> %#jx",
+ __func__, (uintmax_t)patchpoint, (uintmax_t)target));
+
+ instr[0] = 0xe9;
+ disp = target - (patchpoint + SDT_PATCH_SIZE);
+ memcpy(&instr[1], &disp, sizeof(disp));
+
+ old_wp = disable_wp();
+ memcpy((void *)patchpoint, instr, sizeof(instr));
+ restore_wp(old_wp);
+}
+
+/*
+ * Overwrite the patchpoint with a nop instruction.
+ */
+void
+sdt_tracepoint_restore(uintptr_t patchpoint)
+{
+ uint8_t instr[SDT_PATCH_SIZE];
+ bool old_wp;
+
+#ifdef __amd64__
+ KASSERT(patchpoint >= KERNSTART,
+ ("%s: invalid patchpoint %#lx", __func__, patchpoint));
+#endif
+
+ for (int i = 0; i < SDT_PATCH_SIZE; i++)
+ instr[i] = 0x90;
+
+ old_wp = disable_wp();
+ memcpy((void *)patchpoint, instr, sizeof(instr));
+ restore_wp(old_wp);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 16, 1:45 PM (21 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14659433
Default Alt Text
D44483.id140007.diff (29 KB)
Attached To
Mode
D44483: sdt: Prototype implementation of SDT probes using hot-patching
Attached
Detach File
Event Timeline
Log In to Comment