1 /* $OpenBSD: dtvar.h,v 1.20 2024/11/02 16:59:22 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Martin Pieuchot <mpi@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #ifndef _DT_H_ 20 #define _DT_H_ 21 22 #include <sys/ioccom.h> 23 #include <sys/stacktrace.h> 24 #include <sys/time.h> 25 26 /* 27 * Length of provider/probe/function names, including NUL. 28 */ 29 #define DTNAMESIZE 16 30 31 /* 32 * Length of process name, including NUL. 33 */ 34 #define DTMAXCOMLEN _MAXCOMLEN 35 36 /* 37 * Maximum number of arguments passed to a function. 38 */ 39 #define DTMAXFUNCARGS 10 40 #define DTMAXARGTYPES 5 41 42 /* 43 * Event state: where to store information when a probe fires. 44 */ 45 struct dt_evt { 46 unsigned int dtev_pbn; /* Probe number */ 47 unsigned int dtev_cpu; /* CPU id */ 48 pid_t dtev_pid; /* ID of current process */ 49 pid_t dtev_tid; /* ID of current thread */ 50 struct timespec dtev_tsp; /* timestamp (nsecs) */ 51 52 /* 53 * Recorded if the corresponding flag is set. 54 */ 55 struct stacktrace dtev_kstack; /* kernel stack frame */ 56 struct stacktrace dtev_ustack; /* userland stack frame */ 57 char dtev_comm[DTMAXCOMLEN]; /* current pr. name */ 58 union { 59 register_t E_entry[DTMAXFUNCARGS]; 60 struct { 61 register_t __retval[2]; 62 int __error; 63 } E_return; 64 } _args; 65 #define dtev_args _args.E_entry /* function args. */ 66 #define dtev_retval _args.E_return.__retval /* function retval */ 67 #define dtev_error _args.E_return.__error /* function error */ 68 }; 69 70 /* 71 * States to record when a probe fires. 72 */ 73 #define DTEVT_EXECNAME (1 << 0) /* current process name */ 74 #define DTEVT_USTACK (1 << 1) /* userland stack */ 75 #define DTEVT_KSTACK (1 << 2) /* kernel stack */ 76 #define DTEVT_FUNCARGS (1 << 3) /* function arguments */ 77 78 #define DTEVT_FLAG_BITS \ 79 "\020" \ 80 "\001EXECNAME" \ 81 "\002USTACK" \ 82 "\003KSTACK" \ 83 "\004FUNCARGS" \ 84 85 struct dtioc_probe_info { 86 uint32_t dtpi_pbn; /* probe number */ 87 uint8_t dtpi_nargs; /* # of arguments */ 88 char dtpi_prov[DTNAMESIZE]; 89 char dtpi_func[DTNAMESIZE]; 90 char dtpi_name[DTNAMESIZE]; 91 }; 92 93 struct dtioc_probe { 94 size_t dtpr_size; /* size of the buffer */ 95 struct dtioc_probe_info *dtpr_probes; /* array of probe info */ 96 }; 97 98 struct dtioc_arg_info { 99 uint32_t dtai_pbn; /* probe number */ 100 uint8_t dtai_argn; /* arguments number */ 101 char dtai_argtype[DTNAMESIZE]; 102 }; 103 104 struct dtioc_arg { 105 uint32_t dtar_pbn; /* probe number */ 106 size_t dtar_size; /* size of the buffer */ 107 struct dtioc_arg_info *dtar_args; /* array of arg info */ 108 }; 109 110 struct dtioc_req { 111 uint32_t dtrq_pbn; /* probe number */ 112 uint32_t dtrq_rate; /* number of ticks */ 113 uint64_t dtrq_evtflags; /* states to record */ 114 }; 115 116 struct dtioc_stat { 117 uint64_t dtst_readevt; /* events read */ 118 uint64_t dtst_dropevt; /* events dropped */ 119 }; 120 121 struct dtioc_getaux { 122 pid_t dtga_pid; /* process to inspect */ 123 unsigned long dtga_auxbase; /* AUX_base value */ 124 }; 125 126 #define DTIOCGPLIST _IOWR('D', 1, struct dtioc_probe) 127 #define DTIOCGSTATS _IOR('D', 2, struct dtioc_stat) 128 #define DTIOCRECORD _IOW('D', 3, int) 129 #define DTIOCPRBENABLE _IOW('D', 4, struct dtioc_req) 130 #define DTIOCPRBDISABLE _IOW('D', 5, struct dtioc_req) 131 #define DTIOCGARGS _IOWR('D', 6, struct dtioc_arg) 132 #define DTIOCGETAUXBASE _IOWR('D', 7, struct dtioc_getaux) 133 134 #ifdef _KERNEL 135 136 #include <sys/mutex.h> 137 #include <sys/queue.h> 138 #include <sys/smr.h> 139 140 /* Flags that make sense for all providers. */ 141 #define DTEVT_COMMON (DTEVT_EXECNAME|DTEVT_KSTACK|DTEVT_USTACK) 142 143 #define M_DT M_DEVBUF /* XXX FIXME */ 144 145 struct dt_softc; 146 147 /* 148 * Probe control block, possibly per-CPU. 149 * 150 * At least a PCB is allocated for each probe enabled via the DTIOCPRBENABLE 151 * ioctl(2). It will hold the events written when the probe fires until 152 * userland read(2)s them. 153 * 154 * Locks used to protect struct members in this file: 155 * D dt_lock 156 * I immutable after creation 157 * K kernel lock 158 * K,S kernel lock for writing and SMR for reading 159 * m per-pcb mutex 160 * c owned (read & modified) by a single CPU 161 */ 162 struct dt_pcb { 163 SMR_SLIST_ENTRY(dt_pcb) dp_pnext; /* [K,S] next PCB per probe */ 164 TAILQ_ENTRY(dt_pcb) dp_snext; /* [K] next PCB per softc */ 165 166 struct dt_softc *dp_sc; /* [I] related softc */ 167 struct dt_probe *dp_dtp; /* [I] related probe */ 168 uint64_t dp_evtflags; /* [I] event states to record */ 169 170 /* Provider specific fields. */ 171 struct clockintr dp_clockintr; /* [D] profiling handle */ 172 uint64_t dp_nsecs; /* [I] profiling period */ 173 struct cpu_info *dp_cpu; /* [I] on which CPU */ 174 }; 175 176 TAILQ_HEAD(dt_pcb_list, dt_pcb); 177 178 struct dt_pcb *dt_pcb_alloc(struct dt_probe *, struct dt_softc *); 179 void dt_pcb_free(struct dt_pcb *); 180 void dt_pcb_purge(struct dt_pcb_list *); 181 182 struct dt_evt *dt_pcb_ring_get(struct dt_pcb *, int); 183 void dt_pcb_ring_consume(struct dt_pcb *, struct dt_evt *); 184 185 /* 186 * Probes are entry points in the system where events can be recorded. 187 * 188 * Locks used to protect struct members in this file: 189 * I immutable after creation 190 * K kernel lock 191 * D dt_lock 192 * D,S dt_lock for writing and SMR for reading 193 * M dtp mutex 194 */ 195 struct dt_probe { 196 SIMPLEQ_ENTRY(dt_probe) dtp_next; /* [K] global list of probes */ 197 SMR_SLIST_HEAD(, dt_pcb) dtp_pcbs; /* [D,S] list of enabled PCBs */ 198 struct dt_provider *dtp_prov; /* [I] its to provider */ 199 const char *dtp_func; /* [I] probe function */ 200 const char *dtp_name; /* [I] probe name */ 201 uint32_t dtp_pbn; /* [I] unique ID */ 202 volatile uint32_t dtp_recording; /* [d] is it recording? */ 203 unsigned dtp_ref; /* [m] # of PCBs referencing the probe */ 204 205 /* Provider specific fields. */ 206 int dtp_sysnum; /* [I] related # of syscall */ 207 const char *dtp_argtype[DTMAXARGTYPES]; 208 /* [I] type of arguments */ 209 int dtp_nargs; /* [I] # of arguments */ 210 vaddr_t dtp_addr; /* [I] address of breakpoint */ 211 }; 212 213 214 /* 215 * Providers expose a set of probes and a method to record events. 216 */ 217 struct dt_provider { 218 const char *dtpv_name; /* [I] provider name */ 219 volatile uint32_t dtpv_recording;/* [D] # of recording PCBs */ 220 221 int (*dtpv_alloc)(struct dt_probe *, struct dt_softc *, 222 struct dt_pcb_list *, struct dtioc_req *); 223 int (*dtpv_enter)(struct dt_provider *, ...); 224 void (*dtpv_leave)(struct dt_provider *, ...); 225 int (*dtpv_dealloc)(struct dt_probe *, struct dt_softc *, 226 struct dtioc_req *); 227 }; 228 229 extern struct dt_provider dt_prov_kprobe; 230 231 int dt_prov_profile_init(void); 232 int dt_prov_syscall_init(void); 233 int dt_prov_static_init(void); 234 int dt_prov_kprobe_init(void); 235 236 struct dt_probe *dt_dev_alloc_probe(const char *, const char *, 237 struct dt_provider *); 238 void dt_dev_register_probe(struct dt_probe *); 239 240 void dt_clock(struct clockrequest *, void *, void *); 241 242 extern volatile uint32_t dt_tracing; /* currently tracing? */ 243 244 #define DT_ENTER(provname, args...) do { \ 245 extern struct dt_provider dt_prov_ ## provname ; \ 246 struct dt_provider *dtpv = &dt_prov_ ## provname ; \ 247 \ 248 if (__predict_false(dt_tracing) && \ 249 __predict_false(dtpv->dtpv_recording)) { \ 250 dtpv->dtpv_enter(dtpv, args); \ 251 } \ 252 } while (0) 253 254 #define DT_LEAVE(provname, args...) do { \ 255 extern struct dt_provider dt_prov_ ## provname ; \ 256 struct dt_provider *dtpv = &dt_prov_ ## provname ; \ 257 \ 258 if (__predict_false(dt_tracing) && \ 259 __predict_false(dtpv->dtpv_recording)) { \ 260 dtpv->dtpv_leave(dtpv, args); \ 261 } \ 262 } while (0) 263 264 #define _DT_STATIC_P(func, name) (dt_static_##func##_##name) 265 266 /* 267 * Probe definition for the static provider. 268 */ 269 #define _DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, arg4, n) \ 270 struct dt_probe _DT_STATIC_P(func, name) = { \ 271 .dtp_next = { NULL }, \ 272 .dtp_pcbs = { NULL }, \ 273 .dtp_prov = &dt_prov_static, \ 274 .dtp_func = #func, \ 275 .dtp_name = #name, \ 276 .dtp_pbn = 0, \ 277 .dtp_sysnum = 0, \ 278 .dtp_argtype = { arg0, arg1, arg2, arg3, arg4 }, \ 279 .dtp_nargs = n, \ 280 } \ 281 282 #define DT_STATIC_PROBE0(func, name) \ 283 _DT_STATIC_PROBEN(func, name, NULL, NULL, NULL, NULL, NULL, 0) 284 285 #define DT_STATIC_PROBE1(func, name, arg0) \ 286 _DT_STATIC_PROBEN(func, name, arg0, NULL, NULL, NULL, NULL, 1) 287 288 #define DT_STATIC_PROBE2(func, name, arg0, arg1) \ 289 _DT_STATIC_PROBEN(func, name, arg0, arg1, NULL, NULL, NULL, 2) 290 291 #define DT_STATIC_PROBE3(func, name, arg0, arg1, arg2) \ 292 _DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, NULL, NULL, 3) 293 294 #define DT_STATIC_PROBE4(func, name, arg0, arg1, arg2, arg3) \ 295 _DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, NULL, 4) 296 297 #define DT_STATIC_PROBE5(func, name, arg0, arg1, arg2, arg3, arg4) \ 298 _DT_STATIC_PROBEN(func, name, arg0, arg1, arg2, arg3, arg4, 5) 299 300 #define DT_STATIC_ENTER(func, name, args...) do { \ 301 extern struct dt_probe _DT_STATIC_P(func, name); \ 302 struct dt_probe *dtp = &_DT_STATIC_P(func, name); \ 303 \ 304 if (__predict_false(dt_tracing) && \ 305 __predict_false(dtp->dtp_recording)) { \ 306 struct dt_provider *dtpv = dtp->dtp_prov; \ 307 \ 308 dtpv->dtpv_enter(dtpv, dtp, args); \ 309 } \ 310 } while (0) 311 312 #define _DT_INDEX_P(func) (dtps_index_##func) 313 314 #define DT_INDEX_ENTER(func, index, args...) do { \ 315 extern struct dt_probe **_DT_INDEX_P(func); \ 316 \ 317 if (__predict_false(dt_tracing) && \ 318 __predict_false(index > 0) && \ 319 __predict_true(_DT_INDEX_P(func) != NULL)) { \ 320 struct dt_probe *dtp = _DT_INDEX_P(func)[index]; \ 321 \ 322 if(__predict_false(dtp->dtp_recording)) { \ 323 struct dt_provider *dtpv = dtp->dtp_prov; \ 324 \ 325 dtpv->dtpv_enter(dtpv, dtp, args); \ 326 } \ 327 } \ 328 } while (0) 329 330 #endif /* !_KERNEL */ 331 #endif /* !_DT_H_ */ 332