1 /* $NetBSD: dtmalloc.c,v 1.3 2018/05/28 21:05:03 chs Exp $ */ 2 3 /* 4 * CDDL HEADER START 5 * 6 * The contents of this file are subject to the terms of the 7 * Common Development and Distribution License (the "License"). 8 * You may not use this file except in compliance with the License. 9 * 10 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 11 * or http://www.opensolaris.org/os/licensing. 12 * See the License for the specific language governing permissions 13 * and limitations under the License. 14 * 15 * When distributing Covered Code, include this CDDL HEADER in each 16 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 17 * If applicable, add the following below this CDDL HEADER, with the 18 * fields enclosed by brackets "[]" replaced with your own identifying 19 * information: Portions Copyright [yyyy] [name of copyright owner] 20 * 21 * CDDL HEADER END 22 * 23 * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 24 * 25 * $FreeBSD: head/sys/cddl/dev/dtmalloc/dtmalloc.c 252325 2013-06-28 03:14:40Z markj $ 26 * 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/conf.h> 33 #include <sys/ctype.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/module.h> 37 38 #include <sys/dtrace.h> 39 #include <sys/dtrace_bsd.h> 40 41 static d_open_t dtmalloc_open; 42 static int dtmalloc_unload(void); 43 static void dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 44 static void dtmalloc_provide(void *, dtrace_probedesc_t *); 45 static void dtmalloc_destroy(void *, dtrace_id_t, void *); 46 static void dtmalloc_enable(void *, dtrace_id_t, void *); 47 static void dtmalloc_disable(void *, dtrace_id_t, void *); 48 static void dtmalloc_load(void *); 49 50 static struct cdevsw dtmalloc_cdevsw = { 51 .d_version = D_VERSION, 52 .d_open = dtmalloc_open, 53 .d_name = "dtmalloc", 54 }; 55 56 static dtrace_pattr_t dtmalloc_attr = { 57 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 58 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 59 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 60 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 61 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 62 }; 63 64 static dtrace_pops_t dtmalloc_pops = { 65 dtmalloc_provide, 66 NULL, 67 dtmalloc_enable, 68 dtmalloc_disable, 69 NULL, 70 NULL, 71 dtmalloc_getargdesc, 72 NULL, 73 NULL, 74 dtmalloc_destroy 75 }; 76 77 static struct cdev *dtmalloc_cdev; 78 static dtrace_provider_id_t dtmalloc_id; 79 80 static void 81 dtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) 82 { 83 const char *p = NULL; 84 85 switch (desc->dtargd_ndx) { 86 case 0: 87 p = "struct malloc_type *"; 88 break; 89 case 1: 90 p = "struct malloc_type_internal *"; 91 break; 92 case 2: 93 p = "struct malloc_type_stats *"; 94 break; 95 case 3: 96 p = "unsigned long"; 97 break; 98 case 4: 99 p = "int"; 100 break; 101 default: 102 desc->dtargd_ndx = DTRACE_ARGNONE; 103 break; 104 } 105 106 if (p != NULL) 107 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native)); 108 109 return; 110 } 111 112 static void 113 dtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused) 114 { 115 char name[DTRACE_FUNCNAMELEN]; 116 struct malloc_type_internal *mtip = mtp->ks_handle; 117 int i; 118 119 /* 120 * malloc_type descriptions are allowed to contain whitespace, but 121 * DTrace probe identifiers are not, so replace the whitespace with 122 * underscores. 123 */ 124 strlcpy(name, mtp->ks_shortdesc, sizeof(name)); 125 for (i = 0; name[i] != 0; i++) 126 if (isspace(name[i])) 127 name[i] = '_'; 128 129 if (dtrace_probe_lookup(dtmalloc_id, NULL, name, "malloc") != 0) 130 return; 131 132 (void) dtrace_probe_create(dtmalloc_id, NULL, name, "malloc", 0, 133 &mtip->mti_probes[DTMALLOC_PROBE_MALLOC]); 134 (void) dtrace_probe_create(dtmalloc_id, NULL, name, "free", 0, 135 &mtip->mti_probes[DTMALLOC_PROBE_FREE]); 136 } 137 138 static void 139 dtmalloc_provide(void *arg, dtrace_probedesc_t *desc) 140 { 141 if (desc != NULL) 142 return; 143 144 malloc_type_list(dtmalloc_type_cb, desc); 145 } 146 147 static void 148 dtmalloc_destroy(void *arg, dtrace_id_t id, void *parg) 149 { 150 } 151 152 static void 153 dtmalloc_enable(void *arg, dtrace_id_t id, void *parg) 154 { 155 uint32_t *p = parg; 156 *p = id; 157 } 158 159 static void 160 dtmalloc_disable(void *arg, dtrace_id_t id, void *parg) 161 { 162 uint32_t *p = parg; 163 *p = 0; 164 } 165 166 static void 167 dtmalloc_load(void *dummy) 168 { 169 /* Create the /dev/dtrace/dtmalloc entry. */ 170 dtmalloc_cdev = make_dev(&dtmalloc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 171 "dtrace/dtmalloc"); 172 173 if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER, 174 NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0) 175 return; 176 177 dtrace_malloc_probe = dtrace_probe; 178 } 179 180 181 static int 182 dtmalloc_unload() 183 { 184 int error = 0; 185 186 dtrace_malloc_probe = NULL; 187 188 if ((error = dtrace_unregister(dtmalloc_id)) != 0) 189 return (error); 190 191 destroy_dev(dtmalloc_cdev); 192 193 return (error); 194 } 195 196 static int 197 dtmalloc_modevent(module_t mod __unused, int type, void *data __unused) 198 { 199 int error = 0; 200 201 switch (type) { 202 case MOD_LOAD: 203 break; 204 205 case MOD_UNLOAD: 206 break; 207 208 case MOD_SHUTDOWN: 209 break; 210 211 default: 212 error = EOPNOTSUPP; 213 break; 214 215 } 216 217 return (error); 218 } 219 220 static int 221 dtmalloc_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 222 { 223 return (0); 224 } 225 226 SYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL); 227 SYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL); 228 229 DEV_MODULE(dtmalloc, dtmalloc_modevent, NULL); 230 MODULE_VERSION(dtmalloc, 1); 231 MODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1); 232 MODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1); 233