summaryrefslogtreecommitdiff
path: root/sys/dev/dt
diff options
context:
space:
mode:
authorJasper Lievisse Adriaanse <jasper@cvs.openbsd.org>2021-09-03 16:45:46 +0000
committerJasper Lievisse Adriaanse <jasper@cvs.openbsd.org>2021-09-03 16:45:46 +0000
commitfce04b0e80489062d30507672c4c064fbab3538c (patch)
treed6f516ec863b671ee396c63daaaae1bfcfff5a8a /sys/dev/dt
parent562bd13c16f2bafe89c42489d0ec06b2b02c5e32 (diff)
add kprobes provider for dt
this allows us to dynamically trace function boundaries with btrace by patching prologues and epilogues with a breakpoint upon which the handler records the data, sends it back to userland for btrace to consume. currently it's hidden behind DDBPROF, and there is still a lot to cleanup and improve, but basic scripts that observe return codes from a probed function work. from Tom Rollet, with various changes by me feedback and ok mpi@
Diffstat (limited to 'sys/dev/dt')
-rw-r--r--sys/dev/dt/dt_dev.c43
-rw-r--r--sys/dev/dt/dt_prov_kprobe.c464
-rw-r--r--sys/dev/dt/dt_prov_profile.c14
-rw-r--r--sys/dev/dt/dt_prov_static.c14
-rw-r--r--sys/dev/dt/dt_prov_syscall.c12
-rw-r--r--sys/dev/dt/dtvar.h19
6 files changed, 543 insertions, 23 deletions
diff --git a/sys/dev/dt/dt_dev.c b/sys/dev/dt/dt_dev.c
index 03f2658ecc9..7c781df0d0f 100644
--- a/sys/dev/dt/dt_dev.c
+++ b/sys/dev/dt/dt_dev.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dt_dev.c,v 1.14 2021/05/22 21:25:38 bluhm Exp $ */
+/* $OpenBSD: dt_dev.c,v 1.15 2021/09/03 16:45:45 jasper Exp $ */
/*
* Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
@@ -124,7 +124,7 @@ int dt_ioctl_get_stats(struct dt_softc *, struct dtioc_stat *);
int dt_ioctl_record_start(struct dt_softc *);
void dt_ioctl_record_stop(struct dt_softc *);
int dt_ioctl_probe_enable(struct dt_softc *, struct dtioc_req *);
-void dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *);
+int dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *);
int dt_pcb_ring_copy(struct dt_pcb *, struct dt_evt *, size_t, uint64_t *);
@@ -138,6 +138,9 @@ dtattach(struct device *parent, struct device *self, void *aux)
dt_nprobes += dt_prov_profile_init();
dt_nprobes += dt_prov_syscall_init();
dt_nprobes += dt_prov_static_init();
+#ifdef DDBPROF
+ dt_nprobes += dt_prov_kprobe_init();
+#endif
printf("dt: %u probes\n", dt_nprobes);
}
@@ -275,6 +278,7 @@ dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
return dt_ioctl_get_stats(sc, (struct dtioc_stat *)addr);
case DTIOCRECORD:
case DTIOCPRBENABLE:
+ case DTIOCPRBDISABLE:
/* root only ioctl(2) */
break;
default:
@@ -295,6 +299,9 @@ dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
case DTIOCPRBENABLE:
error = dt_ioctl_probe_enable(sc, (struct dtioc_req *)addr);
break;
+ case DTIOCPRBDISABLE:
+ error = dt_ioctl_probe_disable(sc, (struct dtioc_req *)addr);
+ break;
default:
KASSERT(0);
}
@@ -478,6 +485,35 @@ dt_ioctl_probe_enable(struct dt_softc *sc, struct dtioc_req *dtrq)
return 0;
}
+int
+dt_ioctl_probe_disable(struct dt_softc *sc, struct dtioc_req *dtrq)
+{
+ struct dt_probe *dtp;
+ int error;
+
+ KASSERT(suser(curproc) == 0);
+ if (!dtioc_req_isvalid(dtrq))
+ return EINVAL;
+
+ SIMPLEQ_FOREACH(dtp, &dt_probe_list, dtp_next) {
+ if (dtp->dtp_pbn == dtrq->dtrq_pbn)
+ break;
+ }
+ if (dtp == NULL)
+ return ENOENT;
+
+ if (dtp->dtp_prov->dtpv_dealloc) {
+ error = dtp->dtp_prov->dtpv_dealloc(dtp, sc, dtrq);
+ if (error)
+ return error;
+ }
+
+ DPRINTF("dt%d: pid %d dealloc\n", sc->ds_unit, sc->ds_pid,
+ dtrq->dtrq_pbn);
+
+ return 0;
+}
+
struct dt_probe *
dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv)
{
@@ -492,6 +528,9 @@ dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv)
dtp->dtp_func = func;
dtp->dtp_name = name;
dtp->dtp_sysnum = -1;
+ dtp->dtp_ref = 0;
+
+ mtx_init(&dtp->dtp_mtx, IPL_HIGH);
return dtp;
}
diff --git a/sys/dev/dt/dt_prov_kprobe.c b/sys/dev/dt/dt_prov_kprobe.c
new file mode 100644
index 00000000000..f239ad15e9c
--- /dev/null
+++ b/sys/dev/dt/dt_prov_kprobe.c
@@ -0,0 +1,464 @@
+/* $OpenBSD: dt_prov_kprobe.c,v 1.1 2021/09/03 16:45:45 jasper Exp $ */
+
+/*
+ * Copyright (c) 2020 Tom Rollet <tom.rollet@epita.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#if defined(DDBPROF) && (defined(__amd64__) || defined(__i386__))
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/atomic.h>
+#include <sys/exec_elf.h>
+
+#include <ddb/db_elf.h>
+#include <machine/db_machdep.h>
+#include <ddb/db_extern.h>
+#include <ddb/db_access.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_interface.h>
+
+#include <dev/dt/dtvar.h>
+
+int dt_prov_kprobe_alloc(struct dt_probe *dtp, struct dt_softc *sc,
+ struct dt_pcb_list *plist, struct dtioc_req *dtrq);
+int dt_prov_kprobe_hook(struct dt_provider *dtpv, ...);
+int dt_prov_kprobe_dealloc(struct dt_probe *dtp, struct dt_softc *sc,
+ struct dtioc_req *dtrq);
+
+void db_prof_count(struct trapframe *frame);
+
+struct kprobe_probe {
+ struct dt_probe* dtp;
+ SLIST_ENTRY(kprobe_probe) kprobe_next;
+};
+
+/* Bob Jenkin's public domain 32-bit integer hashing function.
+ * Original at https://burtleburtle.net/bob/hash/integer.html.
+ */
+uint32_t
+ptr_hash(uint32_t a) {
+ a = (a + 0x7ed55d16) + (a<<12);
+ a = (a ^ 0xc761c23c) ^ (a>>19);
+ a = (a + 0x165667b1) + (a<<5);
+ a = (a + 0xd3a2646c) ^ (a<<9);
+ a = (a + 0xfd7046c5) + (a<<3);
+ a = (a ^ 0xb55a4f09) ^ (a>>16);
+ return a;
+}
+
+#define PPTSIZE PAGE_SIZE * 30
+#define PPTMASK ((PPTSIZE / sizeof(struct kprobe_probe)) - 1)
+#define INSTTOIDX(inst) (ptr_hash(inst) & PPTMASK)
+
+SLIST_HEAD(, kprobe_probe) *dtpf_entry;
+SLIST_HEAD(, kprobe_probe) *dtpf_return;
+int nb_probes_entry = 0;
+int nb_probes_return = 0;
+
+#define DTEVT_PROV_KPROBE (DTEVT_COMMON|DTEVT_FUNCARGS)
+
+#define KPROBE_ENTRY "entry"
+#define KPROBE_RETURN "return"
+
+#if defined(__amd64__)
+#define KPROBE_RETGUARD_MOV_1 0x4c
+#define KPROBE_RETGUARD_MOV_2 0x8b
+#define KPROBE_RETGUARD_MOV_3 0x1d
+
+#define KPROBE_RETGUARD_MOV_SIZE 7
+
+#define KPROBE_RETGUARD_XOR_1 0x4c
+#define KPROBE_RETGUARD_XOR_2 0x33
+#define KPROBE_RETGUARD_XOR_3 0x1c
+
+#define KPROBE_RETGUARD_XOR_SIZE 4
+
+#define RET 0xc3
+#define RET_SIZE 1
+#elif defined(__i386__)
+#define POP_RBP 0x5d
+#define POP_RBP_SIZE 1
+#endif
+
+struct dt_provider dt_prov_kprobe = {
+ .dtpv_name = "kprobe",
+ .dtpv_alloc = dt_prov_kprobe_alloc,
+ .dtpv_enter = dt_prov_kprobe_hook,
+ .dtpv_leave = NULL,
+ .dtpv_dealloc = dt_prov_kprobe_dealloc,
+};
+
+extern db_symtab_t db_symtab;
+extern char __kutext_end[];
+extern int db_prof_on;
+
+/* Initialize all entry and return probes and store them in global arrays */
+int
+dt_prov_kprobe_init(void)
+{
+ struct dt_probe *dtp;
+ struct kprobe_probe *kprobe_dtp;
+ Elf_Sym *symp, *symtab_start, *symtab_end;
+ char *strtab, *name;
+ vaddr_t inst, limit;
+ int nb_sym, nb_probes;
+
+ nb_sym = (db_symtab.end - db_symtab.start) / sizeof (Elf_Sym);
+ nb_probes = nb_probes_entry = nb_probes_return = 0;
+
+ dtpf_entry = malloc(PPTSIZE, M_DT, M_NOWAIT|M_ZERO);
+ if (dtpf_entry == NULL)
+ goto end;
+
+ dtpf_return = malloc(PPTSIZE, M_DT, M_NOWAIT|M_ZERO);
+ if (dtpf_return == NULL)
+ goto end;
+
+ db_symtab_t *stab = &db_symtab;
+
+ symtab_start = STAB_TO_SYMSTART(stab);
+ symtab_end = STAB_TO_SYMEND(stab);
+
+ strtab = db_elf_find_strtab(stab);
+
+ for (symp = symtab_start; symp < symtab_end; symp++) {
+ if (ELF_ST_TYPE(symp->st_info) != STT_FUNC)
+ continue;
+
+ inst = symp->st_value;
+ name = strtab + symp->st_name;
+ limit = symp->st_value + symp->st_size;
+
+ /* Filter function that are not mapped in memory */
+ if (inst < KERNBASE || inst >= (vaddr_t)&__kutext_end)
+ continue;
+
+ /* Remove some function to avoid recursive tracing */
+ if (strncmp(name, "dt_", 3) == 0 || strncmp(name, "trap", 4) == 0 ||
+ strncmp(name, "db_", 3) == 0)
+ continue;
+
+#if defined(__amd64__)
+ /* Find if there is a retguard, if so move the inst pointer to the later 'push rbp' */
+ if (*((uint8_t *)inst) != SSF_INST) {
+ /* No retguards in i386 */
+ if (((uint8_t *)inst)[0] != KPROBE_RETGUARD_MOV_1 ||
+ ((uint8_t *)inst)[1] != KPROBE_RETGUARD_MOV_2 ||
+ ((uint8_t *)inst)[2] != KPROBE_RETGUARD_MOV_3 ||
+ ((uint8_t *)inst)[KPROBE_RETGUARD_MOV_SIZE] != KPROBE_RETGUARD_XOR_1 ||
+ ((uint8_t *)inst)[KPROBE_RETGUARD_MOV_SIZE + 1] != KPROBE_RETGUARD_XOR_2 ||
+ ((uint8_t *)inst)[KPROBE_RETGUARD_MOV_SIZE + 2] != KPROBE_RETGUARD_XOR_3 ||
+ ((uint8_t *)inst)[KPROBE_RETGUARD_MOV_SIZE + KPROBE_RETGUARD_XOR_SIZE] != SSF_INST)
+ continue;
+ inst = (vaddr_t)&(((uint8_t *)inst)[KPROBE_RETGUARD_MOV_SIZE + KPROBE_RETGUARD_XOR_SIZE]);
+ }
+#elif defined(__i386__)
+ if (*((uint8_t *)inst) != SSF_INST)
+ continue;
+#endif
+
+ dtp = dt_dev_alloc_probe(name, KPROBE_ENTRY, &dt_prov_kprobe);
+ if (dtp == NULL)
+ goto end;
+
+ kprobe_dtp = malloc(sizeof(struct kprobe_probe), M_TEMP, M_NOWAIT|M_ZERO);
+ if (kprobe_dtp == NULL)
+ goto end;
+ kprobe_dtp->dtp = dtp;
+
+ dtp->dtp_addr = inst;
+ dtp->dtp_nargs = db_ctf_func_numargs(symp);
+ dt_dev_register_probe(dtp);
+
+ SLIST_INSERT_HEAD(&dtpf_entry[INSTTOIDX(dtp->dtp_addr)], kprobe_dtp, kprobe_next);
+
+ nb_probes++;
+ nb_probes_entry++;
+
+ /*
+ * Poor method to find the return point
+ * => we would need a disassembler to find all return points
+ * For now we start from the end of the function, iterate on
+ * int3 inserted for retguard until we find a ret
+ */
+#if defined(__amd64__)
+ if (*(uint8_t *)(limit - 1) != RET)
+ continue;
+ inst = limit - 1;
+#elif defined(__i386__)
+ /*
+ * Little temporary hack to find some return probe
+ * => always int3 after 'pop %rpb; ret'
+ */
+ while(*((uint8_t *)inst) == 0xcc)
+ (*(uint8_t *)inst) -= 1;
+ if (*(uint8_t *)(limit - 2) != POP_RBP)
+ continue;
+ inst = limit - 2;
+#endif
+
+ dtp = dt_dev_alloc_probe(name, KPROBE_RETURN, &dt_prov_kprobe);
+ if (dtp == NULL)
+ goto end;
+
+ kprobe_dtp = malloc(sizeof(struct kprobe_probe), M_TEMP, M_NOWAIT|M_ZERO);
+ if (kprobe_dtp == NULL)
+ goto end;
+ kprobe_dtp->dtp = dtp;
+
+ dtp->dtp_addr = inst;
+ dt_dev_register_probe(dtp);
+ SLIST_INSERT_HEAD(&dtpf_return[INSTTOIDX(dtp->dtp_addr)], kprobe_dtp, kprobe_next);
+ nb_probes++;
+ nb_probes_return++;
+ }
+end:
+ return nb_probes;
+}
+
+int
+dt_prov_kprobe_alloc(struct dt_probe *dtp, struct dt_softc *sc,
+ struct dt_pcb_list *plist, struct dtioc_req *dtrq)
+{
+ uint8_t patch = BKPT_INST;
+ struct dt_pcb *dp;
+ unsigned s;
+
+ dp = dt_pcb_alloc(dtp, sc);
+ if (dp == NULL)
+ return ENOMEM;
+
+ /* Patch only if it's first pcb referencing this probe */
+ mtx_enter(&dtp->dtp_mtx);
+ dtp->dtp_ref++;
+ KASSERT(dtp->dtp_ref != 0);
+
+ if (dtp->dtp_ref == 1) {
+ s = intr_disable();
+ db_write_bytes(dtp->dtp_addr, BKPT_SIZE, &patch);
+ intr_restore(s);
+ }
+ mtx_leave(&dtp->dtp_mtx);
+
+ dp->dp_filter = dtrq->dtrq_filter;
+ dp->dp_evtflags = dtrq->dtrq_evtflags & DTEVT_PROV_KPROBE;
+ TAILQ_INSERT_HEAD(plist, dp, dp_snext);
+ return 0;
+}
+
+int
+dt_prov_kprobe_dealloc(struct dt_probe *dtp, struct dt_softc *sc,
+ struct dtioc_req *dtrq)
+{
+ uint8_t patch;
+ int size;
+ unsigned s;
+
+ if (strcmp(dtp->dtp_name, KPROBE_ENTRY) == 0) {
+ patch = SSF_INST;
+ size = SSF_SIZE;
+ } else if (strcmp(dtp->dtp_name, KPROBE_RETURN) == 0) {
+#if defined(__amd64__)
+ patch = RET;
+ size = RET_SIZE;
+#elif defined(__i386__)
+ patch = POP_RBP;
+ size = POP_RBP_SIZE;
+#endif
+ } else
+ KASSERT(0 && "Trying to dealloc not yet implemented probe type");
+
+ mtx_enter(&dtp->dtp_mtx);
+ dtp->dtp_ref--;
+
+ if (dtp->dtp_ref == 0) {
+ s = intr_disable();
+ db_write_bytes(dtp->dtp_addr, size, &patch);
+ intr_restore(s);
+ }
+
+ mtx_leave(&dtp->dtp_mtx);
+
+ /* Deallocation of PCB is done by dt_pcb_purge when closing the dev */
+ return 0;
+}
+
+int
+dt_prov_kprobe_hook(struct dt_provider *dtpv, ...)
+{
+ struct dt_probe *dtp;
+ struct dt_pcb *dp;
+ struct trapframe *tf;
+ struct kprobe_probe *kprobe_dtp;
+ va_list ap;
+ int is_dt_bkpt = 0;
+ int error; /* Return values for return probes*/
+ vaddr_t *args;
+ size_t argsize;
+ register_t retval[2];
+
+ KASSERT(dtpv == &dt_prov_kprobe);
+
+ va_start(ap, dtpv);
+ tf = va_arg(ap, struct trapframe*);
+ va_end(ap);
+
+#if defined(__amd64__)
+ vaddr_t addr = tf->tf_rip - BKPT_SIZE;
+#elif defined(__i386)
+ vaddr_t addr = tf->tf_eip - BKPT_SIZE;
+#endif
+
+ SLIST_FOREACH(kprobe_dtp, &dtpf_entry[INSTTOIDX(addr)], kprobe_next) {
+ dtp = kprobe_dtp->dtp;
+
+ if (dtp->dtp_addr != addr)
+ continue;
+
+ is_dt_bkpt = 1;
+ if (db_prof_on)
+ db_prof_count(tf);
+
+ if (!dtp->dtp_recording)
+ continue;
+
+ smr_read_enter();
+ SMR_SLIST_FOREACH(dp, &dtp->dtp_pcbs, dp_pnext) {
+ struct dt_evt *dtev;
+
+ dtev = dt_pcb_ring_get(dp, 0);
+ if (dtev == NULL)
+ continue;
+
+#if defined(__amd64__)
+ args = (vaddr_t *)tf->tf_rdi;
+ /* XXX: use CTF to get the number of arguments. */
+ argsize = 6;
+#elif defined(__i386__)
+ /* All args on stack */
+ args = (vaddr_t *)(tf->tf_esp + 4);
+ argsize = 10;
+#endif
+
+ if (ISSET(dp->dp_evtflags, DTEVT_FUNCARGS))
+ memcpy(dtev->dtev_args, args, argsize);
+
+ dt_pcb_ring_consume(dp, dtev);
+ }
+ smr_read_leave();
+ }
+
+ if (is_dt_bkpt)
+ return is_dt_bkpt;
+
+ SLIST_FOREACH(kprobe_dtp, &dtpf_return[INSTTOIDX(addr)], kprobe_next) {
+ dtp = kprobe_dtp->dtp;
+
+ if (dtp->dtp_addr != addr)
+ continue;
+
+ is_dt_bkpt = 2;
+
+ if (!dtp->dtp_recording)
+ continue;
+
+ smr_read_enter();
+ SMR_SLIST_FOREACH(dp, &dtp->dtp_pcbs, dp_pnext) {
+ struct dt_evt *dtev;
+
+ dtev = dt_pcb_ring_get(dp, 0);
+ if (dtev == NULL)
+ continue;
+
+#if defined(__amd64__)
+ retval[0] = tf->tf_rax;
+ retval[1] = 0;
+ error = 0;
+#elif defined(__i386)
+ retval[0] = tf->tf_eax;
+ retval[1] = 0;
+ error = 0;
+#endif
+
+ dtev->dtev_retval[0] = retval[0];
+ dtev->dtev_retval[1] = retval[1];
+ dtev->dtev_error = error;
+
+ dt_pcb_ring_consume(dp, dtev);
+ }
+ smr_read_leave();
+ }
+ return is_dt_bkpt;
+}
+
+/* Function called by ddb to patch all functions without allocating 1 pcb per probe */
+void
+dt_prov_kprobe_patch_all_entry(void)
+{
+ uint8_t patch = BKPT_INST;
+ struct dt_probe *dtp;
+ struct kprobe_probe *kprobe_dtp;
+ size_t i;
+
+ for (i = 0; i < PPTMASK; ++i) {
+ SLIST_FOREACH(kprobe_dtp, &dtpf_entry[i], kprobe_next) {
+ dtp = kprobe_dtp->dtp;
+
+ mtx_enter(&dtp->dtp_mtx);
+ dtp->dtp_ref++;
+
+ if (dtp->dtp_ref == 1) {
+ unsigned s;
+ s = intr_disable();
+ db_write_bytes(dtp->dtp_addr, BKPT_SIZE, &patch);
+ intr_restore(s);
+ }
+
+ mtx_leave(&dtp->dtp_mtx);
+ }
+ }
+}
+
+/* Function called by ddb to patch all functions without allocating 1 pcb per probe */
+void
+dt_prov_kprobe_depatch_all_entry(void)
+{
+ uint8_t patch = SSF_INST;
+ struct dt_probe *dtp;
+ struct kprobe_probe *kprobe_dtp;
+ size_t i;
+
+ for (i = 0; i < PPTMASK; ++i) {
+ SLIST_FOREACH(kprobe_dtp, &dtpf_entry[i], kprobe_next) {
+ dtp = kprobe_dtp->dtp;
+
+ mtx_enter(&dtp->dtp_mtx);
+ dtp->dtp_ref--;
+
+ if (dtp->dtp_ref == 0) {
+ unsigned s;
+ s = intr_disable();
+ db_write_bytes(dtp->dtp_addr, SSF_SIZE, &patch);
+ intr_restore(s);
+ }
+
+ mtx_leave(&dtp->dtp_mtx);
+ }
+
+ }
+}
+#endif /* __amd64__ || __i386__ */
diff --git a/sys/dev/dt/dt_prov_profile.c b/sys/dev/dt/dt_prov_profile.c
index 60d59af54f7..502e99828f3 100644
--- a/sys/dev/dt/dt_prov_profile.c
+++ b/sys/dev/dt/dt_prov_profile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dt_prov_profile.c,v 1.3 2020/06/26 13:11:23 mpi Exp $ */
+/* $OpenBSD: dt_prov_profile.c,v 1.4 2021/09/03 16:45:45 jasper Exp $ */
/*
* Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
@@ -31,14 +31,15 @@ struct dt_probe *dtpp_interval; /* global periodic probe */
int dt_prov_profile_alloc(struct dt_probe *, struct dt_softc *,
struct dt_pcb_list *, struct dtioc_req *);
-void dt_prov_profile_enter(struct dt_provider *, ...);
-void dt_prov_interval_enter(struct dt_provider *, ...);
+int dt_prov_profile_enter(struct dt_provider *, ...);
+int dt_prov_interval_enter(struct dt_provider *, ...);
struct dt_provider dt_prov_profile = {
.dtpv_name = "profile",
.dtpv_alloc = dt_prov_profile_alloc,
.dtpv_enter = dt_prov_profile_enter,
.dtpv_leave = NULL,
+ .dtpv_dealloc = NULL,
};
struct dt_provider dt_prov_interval = {
@@ -46,6 +47,7 @@ struct dt_provider dt_prov_interval = {
.dtpv_alloc = dt_prov_profile_alloc,
.dtpv_enter = dt_prov_interval_enter,
.dtpv_leave = NULL,
+ .dtpv_dealloc = NULL,
};
int
@@ -114,7 +116,7 @@ dt_prov_profile_fire(struct dt_pcb *dp)
dp->dp_nticks = 0;
}
-void
+int
dt_prov_profile_enter(struct dt_provider *dtpv, ...)
{
struct cpu_info *ci = curcpu();
@@ -130,9 +132,10 @@ dt_prov_profile_enter(struct dt_provider *dtpv, ...)
dt_prov_profile_fire(dp);
}
smr_read_leave();
+ return 0;
}
-void
+int
dt_prov_interval_enter(struct dt_provider *dtpv, ...)
{
struct dt_pcb *dp;
@@ -144,4 +147,5 @@ dt_prov_interval_enter(struct dt_provider *dtpv, ...)
dt_prov_profile_fire(dp);
}
smr_read_leave();
+ return 0;
}
diff --git a/sys/dev/dt/dt_prov_static.c b/sys/dev/dt/dt_prov_static.c
index 789c2246e14..9c052abf731 100644
--- a/sys/dev/dt/dt_prov_static.c
+++ b/sys/dev/dt/dt_prov_static.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dt_prov_static.c,v 1.9 2021/09/02 17:21:39 jasper Exp $ */
+/* $OpenBSD: dt_prov_static.c,v 1.10 2021/09/03 16:45:45 jasper Exp $ */
/*
* Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
@@ -25,12 +25,13 @@
int dt_prov_static_alloc(struct dt_probe *, struct dt_softc *,
struct dt_pcb_list *, struct dtioc_req *);
-void dt_prov_static_hook(struct dt_provider *, ...);
+int dt_prov_static_hook(struct dt_provider *, ...);
struct dt_provider dt_prov_static = {
- .dtpv_name = "tracepoint",
- .dtpv_alloc = dt_prov_static_alloc,
- .dtpv_enter = dt_prov_static_hook,
+ .dtpv_name = "tracepoint",
+ .dtpv_alloc = dt_prov_static_alloc,
+ .dtpv_enter = dt_prov_static_hook,
+ .dtpv_dealloc = NULL,
};
/*
@@ -137,7 +138,7 @@ dt_prov_static_alloc(struct dt_probe *dtp, struct dt_softc *sc,
return 0;
}
-void
+int
dt_prov_static_hook(struct dt_provider *dtpv, ...)
{
struct dt_probe *dtp;
@@ -172,4 +173,5 @@ dt_prov_static_hook(struct dt_provider *dtpv, ...)
dt_pcb_ring_consume(dp, dtev);
}
smr_read_leave();
+ return 1;
}
diff --git a/sys/dev/dt/dt_prov_syscall.c b/sys/dev/dt/dt_prov_syscall.c
index 0db59ef1c9a..33822dade1b 100644
--- a/sys/dev/dt/dt_prov_syscall.c
+++ b/sys/dev/dt/dt_prov_syscall.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dt_prov_syscall.c,v 1.5 2021/09/02 17:21:39 jasper Exp $ */
+/* $OpenBSD: dt_prov_syscall.c,v 1.6 2021/09/03 16:45:45 jasper Exp $ */
/*
* Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
@@ -37,7 +37,7 @@ unsigned int dtps_nsysent = SYS_MAXSYSCALL;
int dt_prov_syscall_alloc(struct dt_probe *, struct dt_softc *,
struct dt_pcb_list *, struct dtioc_req *);
-void dt_prov_syscall_entry(struct dt_provider *, ...);
+int dt_prov_syscall_entry(struct dt_provider *, ...);
void dt_prov_syscall_return(struct dt_provider *, ...);
struct dt_provider dt_prov_syscall = {
@@ -45,6 +45,7 @@ struct dt_provider dt_prov_syscall = {
.dtpv_alloc = dt_prov_syscall_alloc,
.dtpv_enter = dt_prov_syscall_entry,
.dtpv_leave = dt_prov_syscall_return,
+ .dtpv_dealloc = NULL,
};
int
@@ -119,7 +120,7 @@ dt_prov_syscall_alloc(struct dt_probe *dtp, struct dt_softc *sc,
return 0;
}
-void
+int
dt_prov_syscall_entry(struct dt_provider *dtpv, ...)
{
struct dt_probe *dtp;
@@ -139,11 +140,11 @@ dt_prov_syscall_entry(struct dt_provider *dtpv, ...)
KASSERT((argsize / sizeof(register_t)) <= DTMAXFUNCARGS);
if (sysnum < 0 || sysnum >= dtps_nsysent)
- return;
+ return 0;
dtp = dtps_entry[sysnum];
if (!dtp->dtp_recording)
- return;
+ return 0;
smr_read_enter();
SMR_SLIST_FOREACH(dp, &dtp->dtp_pcbs, dp_pnext) {
@@ -159,6 +160,7 @@ dt_prov_syscall_entry(struct dt_provider *dtpv, ...)
dt_pcb_ring_consume(dp, dtev);
}
smr_read_leave();
+ return 0;
}
void
diff --git a/sys/dev/dt/dtvar.h b/sys/dev/dt/dtvar.h
index 83ad3d22923..db47cfd4ea5 100644
--- a/sys/dev/dt/dtvar.h
+++ b/sys/dev/dt/dtvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dtvar.h,v 1.7 2021/09/02 19:41:48 jasper Exp $ */
+/* $OpenBSD: dtvar.h,v 1.8 2021/09/03 16:45:45 jasper Exp $ */
/*
* Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org>
@@ -63,7 +63,6 @@ struct dt_evt {
#define dtev_args _args.E_entry /* function args. */
#define dtev_retval _args.E_return.__retval /* function retval */
#define dtev_error _args.E_return.__error /* function error */
-
};
/*
@@ -132,6 +131,7 @@ struct dtioc_stat {
#define DTIOCRECORD _IOW('D', 3, int)
#define DTIOCPRBENABLE _IOW('D', 4, struct dtioc_req)
+#define DTIOCPRBDISABLE _IOW('D', 5, struct dtioc_req)
#ifdef _KERNEL
@@ -205,6 +205,7 @@ void dt_pcb_ring_consume(struct dt_pcb *, struct dt_evt *);
* K kernel lock
* D dt_lock
* D,S dt_lock for writting and SMR for reading
+ * M dtp mutex
*/
struct dt_probe {
SIMPLEQ_ENTRY(dt_probe) dtp_next; /* [K] global list of probes */
@@ -213,12 +214,15 @@ struct dt_probe {
const char *dtp_func; /* [I] probe function */
const char *dtp_name; /* [I] probe name */
uint32_t dtp_pbn; /* [I] unique ID */
- volatile uint32_t dtp_recording; /* [D] is it recording? */
- uint8_t dtp_nargs; /* [I] # of arguments */
+ volatile uint32_t dtp_recording; /* [d] is it recording? */
+ struct mutex dtp_mtx;
+ unsigned dtp_ref; /* [m] # of PCBs referencing the probe */
/* Provider specific fields. */
int dtp_sysnum; /* [I] related # of syscall */
const char *dtp_argtype[5];/* [I] type of arguments */
+ int dtp_nargs; /* [I] # of arguments */
+ vaddr_t dtp_addr; /* [I] address of breakpint */
};
@@ -231,13 +235,18 @@ struct dt_provider {
int (*dtpv_alloc)(struct dt_probe *, struct dt_softc *,
struct dt_pcb_list *, struct dtioc_req *);
- void (*dtpv_enter)(struct dt_provider *, ...);
+ int (*dtpv_enter)(struct dt_provider *, ...);
void (*dtpv_leave)(struct dt_provider *, ...);
+ int (*dtpv_dealloc)(struct dt_probe *, struct dt_softc *,
+ struct dtioc_req *);
};
+extern struct dt_provider dt_prov_kprobe;
+
int dt_prov_profile_init(void);
int dt_prov_syscall_init(void);
int dt_prov_static_init(void);
+int dt_prov_kprobe_init(void);
struct dt_probe *dt_dev_alloc_probe(const char *, const char *,
struct dt_provider *);