From: claudio Date: Wed, 26 Apr 2023 16:53:58 +0000 (+0000) Subject: Implement dt(4) utrace support on amd64 and i386. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=a28bb56f1e3b6564881b3d3de68367d380458694;p=openbsd Implement dt(4) utrace support on amd64 and i386. This adds stacktrace_save_utrace() to extract and save the userland stack which is stubbed out on most archs. alpha and riscv64 do not even implement dt(4) and stacktrace_save_at() so the stubs are excluded there. Additionally add a new ioctl DTIOCGETAUXBASE which allows btrace to fetch the AUX_BASE vallue from the AUX vector of a process. OK mpi@ (some time ago) discussed with kettenis@ --- diff --git a/sys/arch/amd64/amd64/db_trace.c b/sys/arch/amd64/amd64/db_trace.c index e9209c348eb..eed87fee1a2 100644 --- a/sys/arch/amd64/amd64/db_trace.c +++ b/sys/arch/amd64/amd64/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.54 2021/09/04 07:13:14 jasper Exp $ */ +/* $OpenBSD: db_trace.c,v 1.55 2023/04/26 16:53:58 claudio Exp $ */ /* $NetBSD: db_trace.c,v 1.1 2003/04/26 18:39:27 fvdl Exp $ */ /* @@ -287,6 +287,43 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) } } +void +stacktrace_save_utrace(struct stacktrace *st) +{ + struct callframe f, *frame, *lastframe; + struct pcb *pcb = curpcb; + + st->st_count = 0; + + if (pcb == NULL) + return; + + frame = __builtin_frame_address(0); + KASSERT(INKERNEL(frame)); + f = *frame; + + while (st->st_count < STACKTRACE_MAX) { + if (f.f_retaddr != 0 && !INKERNEL(f.f_retaddr)) + st->st_pc[st->st_count++] = f.f_retaddr; + + lastframe = frame; + frame = f.f_frame; + + if (frame == NULL) + break; + if (INKERNEL(f.f_retaddr)) { + if (frame <= lastframe) + break; + f = *frame; + continue; + } + if (!INKERNEL(lastframe) && frame <= lastframe) + break; + if (copyin(frame, &f, sizeof(f)) != 0) + break; + } +} + vaddr_t db_get_pc(struct trapframe *tf) { diff --git a/sys/arch/arm64/arm64/db_trace.c b/sys/arch/arm64/arm64/db_trace.c index d36db66c6ad..f0c0bd5b0a0 100644 --- a/sys/arch/arm64/arm64/db_trace.c +++ b/sys/arch/arm64/arm64/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.13 2021/07/09 20:59:51 jasper Exp $ */ +/* $OpenBSD: db_trace.c,v 1.14 2023/04/26 16:53:58 claudio Exp $ */ /* $NetBSD: db_trace.c,v 1.8 2003/01/17 22:28:48 thorpej Exp $ */ /* @@ -183,3 +183,9 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) break; } } + +void +stacktrace_save_utrace(struct stacktrace *st) +{ + st->st_count = 0; +} diff --git a/sys/arch/hppa/hppa/db_interface.c b/sys/arch/hppa/hppa/db_interface.c index 4fdc05da415..2d278b03568 100644 --- a/sys/arch/hppa/hppa/db_interface.c +++ b/sys/arch/hppa/hppa/db_interface.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_interface.c,v 1.48 2020/04/18 04:45:20 visa Exp $ */ +/* $OpenBSD: db_interface.c,v 1.49 2023/04/26 16:53:58 claudio Exp $ */ /* * Copyright (c) 1999-2003 Michael Shalayeff @@ -341,3 +341,9 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) fp = (register_t *)fp[0]; } } + +void +stacktrace_save_utrace(struct stacktrace *st) +{ + st->st_count = 0; +} diff --git a/sys/arch/i386/i386/db_trace.c b/sys/arch/i386/i386/db_trace.c index 8242374ab97..5f73dabee4d 100644 --- a/sys/arch/i386/i386/db_trace.c +++ b/sys/arch/i386/i386/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.43 2023/01/30 10:49:05 jsg Exp $ */ +/* $OpenBSD: db_trace.c,v 1.44 2023/04/26 16:53:58 claudio Exp $ */ /* $NetBSD: db_trace.c,v 1.18 1996/05/03 19:42:01 christos Exp $ */ /* @@ -292,6 +292,43 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) } } +void +stacktrace_save_utrace(struct stacktrace *st) +{ + struct callframe f, *frame, *lastframe; + struct pcb *pcb = curpcb; + + st->st_count = 0; + + if (pcb == NULL) + return; + + frame = __builtin_frame_address(0); + KASSERT(INKERNEL(frame)); + f = *frame; + + while (st->st_count < STACKTRACE_MAX) { + if (f.f_retaddr != 0 && !INKERNEL(f.f_retaddr)) + st->st_pc[st->st_count++] = f.f_retaddr; + + lastframe = frame; + frame = f.f_frame; + + if (frame == NULL) + break; + if (INKERNEL(f.f_retaddr)) { + if (frame <= lastframe) + break; + f = *frame; + continue; + } + if (!INKERNEL(lastframe) && frame <= lastframe) + break; + if (copyin(frame, &f, sizeof(f)) != 0) + break; + } +} + vaddr_t db_get_pc(struct trapframe *tf) { diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c index ba018dd9f48..df4d2adebe5 100644 --- a/sys/arch/mips64/mips64/trap.c +++ b/sys/arch/mips64/mips64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.166 2023/02/11 23:07:27 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.167 2023/04/26 16:53:59 claudio Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -1479,6 +1479,12 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) sp += framesize; } } + +void +stacktrace_save_utrace(struct stacktrace *st) +{ + st->st_count = 0; +} #endif #undef VALID_ADDRESS diff --git a/sys/arch/powerpc/ddb/db_trace.c b/sys/arch/powerpc/ddb/db_trace.c index e9351e93f6c..46cba9b61e4 100644 --- a/sys/arch/powerpc/ddb/db_trace.c +++ b/sys/arch/powerpc/ddb/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.19 2022/02/07 22:28:15 gkoehler Exp $ */ +/* $OpenBSD: db_trace.c,v 1.20 2023/04/26 16:53:59 claudio Exp $ */ /* $NetBSD: db_trace.c,v 1.15 1996/02/22 23:23:41 gwr Exp $ */ /* @@ -268,3 +268,9 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) break; } } + +void +stacktrace_save_utrace(struct stacktrace *st) +{ + st->st_count = 0; +} diff --git a/sys/arch/powerpc64/powerpc64/db_trace.c b/sys/arch/powerpc64/powerpc64/db_trace.c index 9dc63224f93..f70d5200e1f 100644 --- a/sys/arch/powerpc64/powerpc64/db_trace.c +++ b/sys/arch/powerpc64/powerpc64/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.8 2022/01/28 18:37:40 gkoehler Exp $ */ +/* $OpenBSD: db_trace.c,v 1.9 2023/04/26 16:53:59 claudio Exp $ */ /* $NetBSD: db_trace.c,v 1.15 1996/02/22 23:23:41 gwr Exp $ */ /* @@ -232,3 +232,9 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) break; } } + +void +stacktrace_save_utrace(struct stacktrace *st) +{ + st->st_count = 0; +} diff --git a/sys/arch/sparc64/sparc64/db_trace.c b/sys/arch/sparc64/sparc64/db_trace.c index 70d8f90df14..88e40b0c2ae 100644 --- a/sys/arch/sparc64/sparc64/db_trace.c +++ b/sys/arch/sparc64/sparc64/db_trace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: db_trace.c,v 1.24 2022/10/25 06:00:34 guenther Exp $ */ +/* $OpenBSD: db_trace.c,v 1.25 2023/04/26 16:53:59 claudio Exp $ */ /* $NetBSD: db_trace.c,v 1.23 2001/07/10 06:06:16 eeh Exp $ */ /* @@ -188,6 +188,12 @@ stacktrace_save_at(struct stacktrace *st, unsigned int skip) } } +void +stacktrace_save_utrace(struct stacktrace *st) +{ + st->st_count = 0; +} + void db_dump_window(db_expr_t addr, int have_addr, db_expr_t count, char *modif) { diff --git a/sys/dev/dt/dt_dev.c b/sys/dev/dt/dt_dev.c index 4f84e5dd4fc..96c4709f2f7 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.25 2023/03/10 22:14:32 bluhm Exp $ */ +/* $OpenBSD: dt_dev.c,v 1.26 2023/04/26 16:53:59 claudio Exp $ */ /* * Copyright (c) 2019 Martin Pieuchot @@ -20,8 +20,10 @@ #include #include #include +#include #include #include +#include #include @@ -135,6 +137,7 @@ 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 *); int dt_ioctl_probe_disable(struct dt_softc *, struct dtioc_req *); +int dt_ioctl_get_auxbase(struct dt_softc *, struct dtioc_getaux *); int dt_pcb_ring_copy(struct dt_pcb *, struct dt_evt *, size_t, uint64_t *); @@ -289,6 +292,7 @@ dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) case DTIOCRECORD: case DTIOCPRBENABLE: case DTIOCPRBDISABLE: + case DTIOCGETAUXBASE: /* root only ioctl(2) */ break; default: @@ -312,6 +316,9 @@ dtioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) case DTIOCPRBDISABLE: error = dt_ioctl_probe_disable(sc, (struct dtioc_req *)addr); break; + case DTIOCGETAUXBASE: + error = dt_ioctl_get_auxbase(sc, (struct dtioc_getaux *)addr); + break; default: KASSERT(0); } @@ -575,6 +582,42 @@ dt_ioctl_probe_disable(struct dt_softc *sc, struct dtioc_req *dtrq) return 0; } +int +dt_ioctl_get_auxbase(struct dt_softc *sc, struct dtioc_getaux *dtga) +{ + struct uio uio; + struct iovec iov; + struct process *pr; + struct proc *p = curproc; + AuxInfo auxv[ELF_AUX_ENTRIES]; + int i, error; + + dtga->dtga_auxbase = 0; + + if ((pr = prfind(dtga->dtga_pid)) == NULL) + return ESRCH; + + iov.iov_base = auxv; + iov.iov_len = sizeof(auxv); + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = pr->ps_auxinfo; + uio.uio_resid = sizeof(auxv); + uio.uio_segflg = UIO_SYSSPACE; + uio.uio_procp = p; + uio.uio_rw = UIO_READ; + + error = process_domem(p, pr, &uio, PT_READ_D); + if (error) + return error; + + for (i = 0; i < ELF_AUX_ENTRIES; i++) + if (auxv[i].au_id == AUX_base) + dtga->dtga_auxbase = auxv[i].au_v; + + return 0; +} + struct dt_probe * dt_dev_alloc_probe(const char *func, const char *name, struct dt_provider *dtpv) { @@ -725,12 +768,14 @@ dt_pcb_ring_get(struct dt_pcb *dp, int profiling) if (ISSET(dp->dp_evtflags, DTEVT_EXECNAME)) strlcpy(dtev->dtev_comm, p->p_p->ps_comm, sizeof(dtev->dtev_comm)); - if (ISSET(dp->dp_evtflags, DTEVT_KSTACK|DTEVT_USTACK)) { + if (ISSET(dp->dp_evtflags, DTEVT_KSTACK)) { if (profiling) stacktrace_save_at(&dtev->dtev_kstack, DT_FA_PROFILE); else stacktrace_save_at(&dtev->dtev_kstack, DT_FA_STATIC); } + if (ISSET(dp->dp_evtflags, DTEVT_USTACK)) + stacktrace_save_utrace(&dtev->dtev_ustack); return dtev; } diff --git a/sys/dev/dt/dt_prov_profile.c b/sys/dev/dt/dt_prov_profile.c index 502e99828f3..d6db0797bf0 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.4 2021/09/03 16:45:45 jasper Exp $ */ +/* $OpenBSD: dt_prov_profile.c,v 1.5 2023/04/26 16:53:59 claudio Exp $ */ /* * Copyright (c) 2019 Martin Pieuchot @@ -27,7 +27,7 @@ struct dt_probe *dtpp_profile; /* per-CPU profile probe */ struct dt_probe *dtpp_interval; /* global periodic probe */ /* Flags that make sense for this provider */ -#define DTEVT_PROV_PROFILE DTEVT_KSTACK +#define DTEVT_PROV_PROFILE DTEVT_COMMON int dt_prov_profile_alloc(struct dt_probe *, struct dt_softc *, struct dt_pcb_list *, struct dtioc_req *); diff --git a/sys/dev/dt/dtvar.h b/sys/dev/dt/dtvar.h index 5d4aeac21a9..9b5d3de08ee 100644 --- a/sys/dev/dt/dtvar.h +++ b/sys/dev/dt/dtvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dtvar.h,v 1.16 2023/04/10 04:21:20 jsg Exp $ */ +/* $OpenBSD: dtvar.h,v 1.17 2023/04/26 16:53:59 claudio Exp $ */ /* * Copyright (c) 2019 Martin Pieuchot @@ -53,6 +53,7 @@ struct dt_evt { * Recorded if the corresponding flag is set. */ struct stacktrace dtev_kstack; /* kernel stack frame */ + struct stacktrace dtev_ustack; /* userland stack frame */ char dtev_comm[DTMAXCOMLEN]; /* current pr. name */ union { register_t E_entry[DTMAXFUNCARGS]; @@ -80,7 +81,6 @@ struct dt_evt { "\002USTACK" \ "\003KSTACK" \ "\004FUNCARGS" \ - "\005RETVAL" \ /* * Each PCB can have a filter attached to itself. A filter do not @@ -139,12 +139,18 @@ struct dtioc_stat { uint64_t dtst_dropevt; /* events dropped */ }; +struct dtioc_getaux { + pid_t dtga_pid; /* process to inspect */ + unsigned long dtga_auxbase; /* AUX_base value */ +}; + #define DTIOCGPLIST _IOWR('D', 1, struct dtioc_probe) #define DTIOCGSTATS _IOR('D', 2, 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) #define DTIOCGARGS _IOWR('D', 6, struct dtioc_arg) +#define DTIOCGETAUXBASE _IOWR('D', 7, struct dtioc_getaux) #ifdef _KERNEL diff --git a/sys/sys/stacktrace.h b/sys/sys/stacktrace.h index 5d78b757a16..1348b715db2 100644 --- a/sys/sys/stacktrace.h +++ b/sys/sys/stacktrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: stacktrace.h,v 1.3 2020/04/18 04:45:20 visa Exp $ */ +/* $OpenBSD: stacktrace.h,v 1.4 2023/04/26 16:53:59 claudio Exp $ */ /* * Copyright (c) 2017 Visa Hankala @@ -29,6 +29,7 @@ struct stacktrace { #ifdef _KERNEL void stacktrace_print(struct stacktrace *, int (*)(const char *, ...)); void stacktrace_save_at(struct stacktrace *, unsigned int); +void stacktrace_save_utrace(struct stacktrace *); static inline void stacktrace_save(struct stacktrace *st)