diff options
author | Jasper Lievisse Adriaanse <jasper@cvs.openbsd.org> | 2021-09-03 16:45:46 +0000 |
---|---|---|
committer | Jasper Lievisse Adriaanse <jasper@cvs.openbsd.org> | 2021-09-03 16:45:46 +0000 |
commit | fce04b0e80489062d30507672c4c064fbab3538c (patch) | |
tree | d6f516ec863b671ee396c63daaaae1bfcfff5a8a /sys/dev | |
parent | 562bd13c16f2bafe89c42489d0ec06b2b02c5e32 (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')
-rw-r--r-- | sys/dev/dt/dt_dev.c | 43 | ||||
-rw-r--r-- | sys/dev/dt/dt_prov_kprobe.c | 464 | ||||
-rw-r--r-- | sys/dev/dt/dt_prov_profile.c | 14 | ||||
-rw-r--r-- | sys/dev/dt/dt_prov_static.c | 14 | ||||
-rw-r--r-- | sys/dev/dt/dt_prov_syscall.c | 12 | ||||
-rw-r--r-- | sys/dev/dt/dtvar.h | 19 |
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 *); |