summaryrefslogtreecommitdiff
path: root/sys/ddb
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/ddb
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/ddb')
-rw-r--r--sys/ddb/db_prof.c168
1 files changed, 20 insertions, 148 deletions
diff --git a/sys/ddb/db_prof.c b/sys/ddb/db_prof.c
index 7d8190f41bc..fe77f927f65 100644
--- a/sys/ddb/db_prof.c
+++ b/sys/ddb/db_prof.c
@@ -1,20 +1,5 @@
-/* $OpenBSD: db_prof.c,v 1.4 2017/08/11 15:14:23 nayden Exp $ */
+/* $OpenBSD: db_prof.c,v 1.5 2021/09/03 16:45:45 jasper Exp $ */
-/*
- * Copyright (c) 2016 Martin Pieuchot
- *
- * 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.
- */
/*-
* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -43,7 +28,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
@@ -54,173 +38,58 @@
#include <machine/db_machdep.h>
#include <ddb/db_extern.h>
-#include <ddb/db_access.h> /* for db_write_bytes() */
#include <ddb/db_sym.h>
-extern char etext[];
-
-struct prof_probe {
- const char *pp_name;
- Elf_Sym *pp_symb;
- SLIST_ENTRY(prof_probe) pp_next;
- vaddr_t pp_inst;
- int pp_on;
-};
+#include "dt.h" /* for NDT */
-#define PPTSIZE PAGE_SIZE
-#define PPTMASK ((PPTSIZE / sizeof(struct prof_probe)) - 1)
-#define INSTTOIDX(inst) ((((unsigned long)(inst)) >> 4) & PPTMASK)
-SLIST_HEAD(, prof_probe) *pp_table;
+#if NDT > 0
+#include <dev/dt/dtvar.h>
+#endif
extern int db_profile; /* Allow dynamic profiling */
int db_prof_on; /* Profiling state On/Off */
-vaddr_t db_get_pc(struct trapframe *);
-vaddr_t db_get_probe_addr(struct trapframe *);
-
-void db_prof_forall(Elf_Sym *, char *, char *, int, void *);
-void db_prof_count(unsigned long, unsigned long);
-
-void
-db_prof_init(void)
-{
- unsigned long nentries;
-
- pp_table = malloc(PPTSIZE, M_TEMP, M_NOWAIT|M_ZERO);
- if (pp_table == NULL)
- return;
-
- db_elf_sym_forall(db_prof_forall, &nentries);
- printf("ddb probe table references %lu entry points\n", nentries);
-}
-
-void
-db_prof_forall(Elf_Sym *sym, char *name, char *suff, int pre, void *xarg)
-{
- Elf_Sym *symb = sym;
- unsigned long *nentries = xarg;
- struct prof_probe *pp;
- vaddr_t inst;
-
- if (ELF_ST_TYPE(symb->st_info) != STT_FUNC)
- return;
-
- inst = symb->st_value;
- if (inst < KERNBASE || inst >= (vaddr_t)&etext)
- return;
-
- if (*((uint8_t *)inst) != SSF_INST)
- return;
-
- if (strncmp(name, "db_", 3) == 0 || strncmp(name, "trap", 4) == 0)
- return;
-
-#ifdef __i386__
- /* Avoid a recursion in db_write_text(). */
- if (strncmp(name, "pmap_pte", 8) == 0)
- return;
-#endif
-
- pp = malloc(sizeof(struct prof_probe), M_TEMP, M_NOWAIT|M_ZERO);
- if (pp == NULL)
- return;
-
- pp->pp_name = name;
- pp->pp_inst = inst;
- pp->pp_symb = symb;
-
- SLIST_INSERT_HEAD(&pp_table[INSTTOIDX(pp->pp_inst)], pp, pp_next);
+void dt_prov_kprobe_patch_all_entry(void);
+void dt_prov_kprobe_depatch_all_entry(void);
- (*nentries)++;
-}
+vaddr_t db_get_probe_addr(struct trapframe *);
+vaddr_t db_get_pc(struct trapframe *);
int
db_prof_enable(void)
{
-#if defined(__amd64__) || defined(__i386__)
- struct prof_probe *pp;
- uint8_t patch = BKPT_INST;
- unsigned long s;
- int i;
-
+#if NDT > 0
if (!db_profile)
return EPERM;
- if (pp_table == NULL)
- return ENOENT;
-
- KASSERT(BKPT_SIZE == SSF_SIZE);
-
- s = intr_disable();
- for (i = 0; i < (PPTSIZE / sizeof(*pp)); i++) {
- SLIST_FOREACH(pp, &pp_table[i], pp_next) {
- pp->pp_on = 1;
- db_write_bytes(pp->pp_inst, BKPT_SIZE, &patch);
- }
- }
- intr_restore(s);
-
+ dt_prov_kprobe_patch_all_entry();
db_prof_on = 1;
-
return 0;
#else
return ENOENT;
-#endif
+#endif /* NDT > 0 */
}
void
db_prof_disable(void)
{
- struct prof_probe *pp;
- uint8_t patch = SSF_INST;
- unsigned long s;
- int i;
-
+#if NDT > 0
db_prof_on = 0;
-
- s = intr_disable();
- for (i = 0; i < (PPTSIZE / sizeof(*pp)); i++) {
- SLIST_FOREACH(pp, &pp_table[i], pp_next) {
- db_write_bytes(pp->pp_inst, SSF_SIZE, &patch);
- pp->pp_on = 0;
- }
- }
- intr_restore(s);
-}
-
-int
-db_prof_hook(struct trapframe *frame)
-{
- struct prof_probe *pp;
- vaddr_t pc, inst;
-
- if (pp_table == NULL)
- return 0;
-
- pc = db_get_pc(frame);
- inst = db_get_probe_addr(frame);
-
- SLIST_FOREACH(pp, &pp_table[INSTTOIDX(inst)], pp_next) {
- if (pp->pp_on && pp->pp_inst == inst) {
- if (db_prof_on)
- db_prof_count(pc, inst);
- return 1;
- }
- }
-
- return 0;
+ dt_prov_kprobe_depatch_all_entry();
+#endif /* NDT > 0 */
}
/*
* Equivalent to mcount(), must be called with interrupt disabled.
*/
void
-db_prof_count(unsigned long frompc, unsigned long selfpc)
+db_prof_count(struct trapframe *frame)
{
unsigned short *frompcindex;
struct tostruct *top, *prevtop;
struct gmonparam *p;
long toindex;
+ unsigned long frompc, selfpc;
if ((p = curcpu()->ci_gmon) == NULL)
return;
@@ -232,6 +101,9 @@ db_prof_count(unsigned long frompc, unsigned long selfpc)
if (p->state != GMON_PROF_ON)
return;
+ frompc = db_get_pc(frame);
+ selfpc = db_get_probe_addr(frame);
+
/*
* check that frompcindex is a reasonable pc value.
* for example: signal catchers get called from the stack,