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