Page MenuHomeFreeBSD

D37619.id113899.diff
No OneTemporary

D37619.id113899.diff

diff --git a/sys/cddl/dev/kinst/amd64/kinst_isa.c b/sys/cddl/dev/kinst/amd64/kinst_isa.c
--- a/sys/cddl/dev/kinst/amd64/kinst_isa.c
+++ b/sys/cddl/dev/kinst/amd64/kinst_isa.c
@@ -6,6 +6,7 @@
*/
#include <sys/param.h>
+#include <sys/pcpu.h>
#include <machine/cpufunc.h>
#include <machine/md_var.h>
@@ -39,6 +40,14 @@
#define KINST_F_JMP 0x0008 /* instruction is a %rip-relative jmp */
#define KINST_F_MOD_DIRECT 0x0010 /* operand is not a memory address */
+/*
+ * Per-CPU trampolines used when the interrupted thread is executing with
+ * interrupts disabled. If an interrupt is raised while executing a trampoline,
+ * the interrupt thread cannot safely overwrite its trampoline if it hits a
+ * kinst probe while executing the interrupt handler.
+ */
+DPCPU_DEFINE_STATIC(uint8_t *, intr_tramp);
+
/*
* Map ModR/M register bits to a trapframe offset.
*/
@@ -185,7 +194,10 @@
}
return (DTRACE_INVOP_CALL);
} else {
- tramp = curthread->t_kinst;
+ if ((frame->tf_rflags & PSL_I) == 0)
+ tramp = DPCPU_GET(intr_tramp);
+ else
+ tramp = curthread->t_kinst;
if (tramp == NULL) {
/*
* A trampoline allocation failed, so this probe is
@@ -495,7 +507,7 @@
struct kinst_probe *kp;
dtrace_kinst_probedesc_t *pd;
const char *func;
- int error, n, off;
+ int error, instrsize, n, off;
uint8_t *instr, *limit;
pd = opaque;
@@ -510,17 +522,37 @@
/*
* Ignore functions not beginning with the usual function prologue.
- * These might correspond to assembly routines with which we should not
- * meddle.
+ * These might correspond to exception handlers with which we should not
+ * meddle. This does however exclude functions which can be safely
+ * traced, such as cpu_switch().
*/
if (*instr != KINST_PUSHL_RBP)
return (0);
n = 0;
while (instr < limit) {
+ instrsize = dtrace_instr_size(instr);
off = (int)(instr - (uint8_t *)symval->value);
if (pd->kpd_off != -1 && off != pd->kpd_off) {
- instr += dtrace_instr_size(instr);
+ instr += instrsize;
+ continue;
+ }
+
+ /*
+ * Check for instructions which may enable interrupts. Such
+ * instructions are tricky to trace since it is unclear whether
+ * to use the per-thread or per-CPU trampolines. Since they are
+ * rare, we don't bother to implement special handling for them.
+ *
+ * If the caller specified an offset, return an error, otherwise
+ * silently ignore the instruction so that it remains possible
+ * to enable all instructions in a function.
+ */
+ if (instrsize == 1 &&
+ (instr[0] == KINST_POPF || instr[0] == KINST_STI)) {
+ if (pd->kpd_off != -1)
+ return (EINVAL);
+ instr += instrsize;
continue;
}
@@ -554,3 +586,30 @@
return (0);
}
+
+int
+kinst_md_init(void)
+{
+ uint8_t *tramp;
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ tramp = kinst_trampoline_alloc(M_WAITOK);
+ if (tramp == NULL)
+ return (ENOMEM);
+ DPCPU_ID_SET(cpu, intr_tramp, tramp);
+ }
+
+ return (0);
+}
+
+void
+kinst_md_deinit(void)
+{
+ int cpu;
+
+ CPU_FOREACH(cpu) {
+ kinst_trampoline_dealloc(DPCPU_ID_GET(cpu, intr_tramp));
+ DPCPU_ID_SET(cpu, intr_tramp, NULL);
+ }
+}
diff --git a/sys/cddl/dev/kinst/kinst.h b/sys/cddl/dev/kinst/kinst.h
--- a/sys/cddl/dev/kinst/kinst.h
+++ b/sys/cddl/dev/kinst/kinst.h
@@ -57,6 +57,9 @@
uint8_t *kinst_trampoline_alloc(int);
void kinst_trampoline_dealloc(uint8_t *);
+int kinst_md_init(void);
+void kinst_md_deinit(void);
+
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_KINST);
#endif /* MALLOC_DECLARE */
diff --git a/sys/cddl/dev/kinst/kinst.c b/sys/cddl/dev/kinst/kinst.c
--- a/sys/cddl/dev/kinst/kinst.c
+++ b/sys/cddl/dev/kinst/kinst.c
@@ -180,10 +180,16 @@
error = kinst_trampoline_init();
if (error != 0)
return (error);
+ error = kinst_md_init();
+ if (error != 0) {
+ kinst_trampoline_deinit();
+ return (error);
+ }
error = dtrace_register("kinst", &kinst_attr, DTRACE_PRIV_USER, NULL,
&kinst_pops, NULL, &kinst_id);
if (error != 0) {
+ kinst_md_deinit();
kinst_trampoline_deinit();
return (error);
}
@@ -201,6 +207,7 @@
kinst_unload(void *dummy)
{
free(kinst_probetab, M_KINST);
+ kinst_md_deinit();
kinst_trampoline_deinit();
dtrace_invop_remove(kinst_invop);
destroy_dev(kinst_cdev);

File Metadata

Mime Type
text/plain
Expires
Sat, Feb 1, 8:15 PM (19 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16390081
Default Alt Text
D37619.id113899.diff (4 KB)

Event Timeline