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