1 /* 2 * SPDX-License-Identifier: CDDL 1.0 3 * 4 * Copyright 2022 Christos Margiolis <christos@FreeBSD.org> 5 */ 6 7 #include <sys/param.h> 8 #include <sys/systm.h> 9 #include <sys/conf.h> 10 #include <sys/kernel.h> 11 #include <sys/linker.h> 12 #include <sys/module.h> 13 14 #include <sys/dtrace.h> 15 16 #include "kinst.h" 17 18 MALLOC_DEFINE(M_KINST, "kinst", "Kernel Instruction Tracing"); 19 20 static d_open_t kinst_open; 21 static d_close_t kinst_close; 22 static d_ioctl_t kinst_ioctl; 23 24 static void kinst_provide_module(void *, modctl_t *); 25 static void kinst_getargdesc(void *, dtrace_id_t, void *, 26 dtrace_argdesc_t *); 27 static void kinst_destroy(void *, dtrace_id_t, void *); 28 static void kinst_enable(void *, dtrace_id_t, void *); 29 static void kinst_disable(void *, dtrace_id_t, void *); 30 static int kinst_load(void *); 31 static int kinst_unload(void *); 32 static int kinst_modevent(module_t, int, void *); 33 34 static dtrace_pattr_t kinst_attr = { 35 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 36 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 37 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 38 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, 39 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, 40 }; 41 42 static const dtrace_pops_t kinst_pops = { 43 .dtps_provide = NULL, 44 .dtps_provide_module = kinst_provide_module, 45 .dtps_enable = kinst_enable, 46 .dtps_disable = kinst_disable, 47 .dtps_suspend = NULL, 48 .dtps_resume = NULL, 49 .dtps_getargdesc = kinst_getargdesc, 50 .dtps_getargval = NULL, 51 .dtps_usermode = NULL, 52 .dtps_destroy = kinst_destroy 53 }; 54 55 static struct cdevsw kinst_cdevsw = { 56 .d_name = "kinst", 57 .d_version = D_VERSION, 58 .d_flags = D_TRACKCLOSE, 59 .d_open = kinst_open, 60 .d_close = kinst_close, 61 .d_ioctl = kinst_ioctl, 62 }; 63 64 static dtrace_provider_id_t kinst_id; 65 struct kinst_probe_list *kinst_probetab; 66 static struct cdev *kinst_cdev; 67 68 int 69 kinst_excluded(const char *name) 70 { 71 if (kinst_md_excluded(name)) 72 return (1); 73 74 /* 75 * Anything beginning with "dtrace_" may be called from probe context 76 * unless it explicitly indicates that it won't be called from probe 77 * context by using the prefix "dtrace_safe_". 78 */ 79 if (strncmp(name, "dtrace_", strlen("dtrace_")) == 0 && 80 strncmp(name, "dtrace_safe_", strlen("dtrace_safe_")) != 0) 81 return (1); 82 83 /* 84 * Omit instrumentation of functions that are probably in DDB. It 85 * makes it too hard to debug broken kinst. 86 * 87 * NB: kdb_enter() can be excluded, but its call to printf() can't be. 88 * This is generally OK since we're not yet in debugging context. 89 */ 90 if (strncmp(name, "db_", strlen("db_")) == 0 || 91 strncmp(name, "kdb_", strlen("kdb_")) == 0) 92 return (1); 93 94 /* 95 * Lock owner methods may be called from probe context. 96 */ 97 if (strcmp(name, "owner_mtx") == 0 || 98 strcmp(name, "owner_rm") == 0 || 99 strcmp(name, "owner_rw") == 0 || 100 strcmp(name, "owner_sx") == 0) 101 return (1); 102 103 /* 104 * When DTrace is built into the kernel we need to exclude the kinst 105 * functions from instrumentation. 106 */ 107 #ifndef _KLD_MODULE 108 if (strncmp(name, "kinst_", strlen("kinst_")) == 0) 109 return (1); 110 #endif 111 112 if (strcmp(name, "trap_check") == 0) 113 return (1); 114 115 return (0); 116 } 117 118 void 119 kinst_probe_create(struct kinst_probe *kp, linker_file_t lf) 120 { 121 kp->kp_id = dtrace_probe_create(kinst_id, lf->filename, 122 kp->kp_func, kp->kp_name, 3, kp); 123 124 LIST_INSERT_HEAD(KINST_GETPROBE(kp->kp_patchpoint), kp, kp_hashnext); 125 } 126 127 static int 128 kinst_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, 129 struct thread *td __unused) 130 { 131 return (0); 132 } 133 134 static int 135 kinst_close(struct cdev *dev __unused, int fflag __unused, int devtype __unused, 136 struct thread *td __unused) 137 { 138 dtrace_condense(kinst_id); 139 return (0); 140 } 141 142 static int 143 kinst_linker_file_cb(linker_file_t lf, void *arg) 144 { 145 dtrace_kinst_probedesc_t *pd; 146 147 pd = arg; 148 if (pd->kpd_mod[0] != '\0' && strcmp(pd->kpd_mod, lf->filename) != 0) 149 return (0); 150 151 /* 152 * Invoke kinst_make_probe_function() once for each function symbol in 153 * the module "lf". 154 */ 155 return (linker_file_function_listall(lf, kinst_make_probe, arg)); 156 } 157 158 static int 159 kinst_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, 160 int flags __unused, struct thread *td __unused) 161 { 162 dtrace_kinst_probedesc_t *pd; 163 int error = 0; 164 165 switch (cmd) { 166 case KINSTIOC_MAKEPROBE: 167 pd = (dtrace_kinst_probedesc_t *)addr; 168 pd->kpd_func[sizeof(pd->kpd_func) - 1] = '\0'; 169 pd->kpd_mod[sizeof(pd->kpd_mod) - 1] = '\0'; 170 171 /* Loop over all functions in the kernel and loaded modules. */ 172 error = linker_file_foreach(kinst_linker_file_cb, pd); 173 break; 174 default: 175 error = ENOTTY; 176 break; 177 } 178 179 return (error); 180 } 181 182 static void 183 kinst_provide_module(void *arg, modctl_t *lf) 184 { 185 } 186 187 static void 188 kinst_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) 189 { 190 desc->dtargd_ndx = DTRACE_ARGNONE; 191 } 192 193 static void 194 kinst_destroy(void *arg, dtrace_id_t id, void *parg) 195 { 196 struct kinst_probe *kp = parg; 197 198 LIST_REMOVE(kp, kp_hashnext); 199 free(kp, M_KINST); 200 } 201 202 static void 203 kinst_enable(void *arg, dtrace_id_t id, void *parg) 204 { 205 struct kinst_probe *kp = parg; 206 static bool warned = false; 207 208 if (!warned) { 209 KINST_LOG( 210 "kinst: This provider is experimental, exercise caution"); 211 warned = true; 212 } 213 214 kinst_patch_tracepoint(kp, kp->kp_patchval); 215 } 216 217 static void 218 kinst_disable(void *arg, dtrace_id_t id, void *parg) 219 { 220 struct kinst_probe *kp = parg; 221 222 kinst_patch_tracepoint(kp, kp->kp_savedval); 223 } 224 225 static int 226 kinst_load(void *dummy) 227 { 228 int error; 229 230 error = kinst_trampoline_init(); 231 if (error != 0) 232 return (error); 233 error = kinst_md_init(); 234 if (error != 0) { 235 kinst_trampoline_deinit(); 236 return (error); 237 } 238 239 error = dtrace_register("kinst", &kinst_attr, DTRACE_PRIV_USER, NULL, 240 &kinst_pops, NULL, &kinst_id); 241 if (error != 0) { 242 kinst_md_deinit(); 243 kinst_trampoline_deinit(); 244 return (error); 245 } 246 kinst_probetab = malloc(KINST_PROBETAB_MAX * 247 sizeof(struct kinst_probe_list), M_KINST, M_WAITOK | M_ZERO); 248 for (int i = 0; i < KINST_PROBETAB_MAX; i++) 249 LIST_INIT(&kinst_probetab[i]); 250 kinst_cdev = make_dev(&kinst_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 251 "dtrace/kinst"); 252 dtrace_invop_add(kinst_invop); 253 return (0); 254 } 255 256 static int 257 kinst_unload(void *dummy) 258 { 259 free(kinst_probetab, M_KINST); 260 kinst_md_deinit(); 261 kinst_trampoline_deinit(); 262 dtrace_invop_remove(kinst_invop); 263 destroy_dev(kinst_cdev); 264 265 return (dtrace_unregister(kinst_id)); 266 } 267 268 static int 269 kinst_modevent(module_t mod __unused, int type, void *data __unused) 270 { 271 int error = 0; 272 273 switch (type) { 274 case MOD_LOAD: 275 break; 276 case MOD_UNLOAD: 277 break; 278 case MOD_SHUTDOWN: 279 break; 280 default: 281 error = EOPNOTSUPP; 282 break; 283 } 284 285 return (error); 286 } 287 288 SYSINIT(kinst_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, kinst_load, NULL); 289 SYSUNINIT(kinst_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, kinst_unload, 290 NULL); 291 292 DEV_MODULE(kinst, kinst_modevent, NULL); 293 MODULE_VERSION(kinst, 1); 294 MODULE_DEPEND(kinst, dtrace, 1, 1, 1); 295 MODULE_DEPEND(kinst, opensolaris, 1, 1, 1); 296