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/param.h> 26#include <sys/systm.h> 27#include <sys/conf.h> 28#include <sys/ctype.h> 29#include <sys/kernel.h> 30#include <sys/malloc.h> 31#include <sys/module.h> 32 33#include <sys/dtrace.h> 34#include <sys/dtrace_bsd.h> 35 36extern bool dtrace_malloc_enabled; 37static uint32_t dtrace_malloc_enabled_count; 38 39static int dtmalloc_unload(void); 40static void dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 41static void dtmalloc_provide(void *, dtrace_probedesc_t *); 42static void dtmalloc_destroy(void *, dtrace_id_t, void *); 43static void dtmalloc_enable(void *, dtrace_id_t, void *); 44static void dtmalloc_disable(void *, dtrace_id_t, void *); 45static void dtmalloc_load(void *); 46 47static dtrace_pattr_t dtmalloc_attr = { 48{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 49{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 50{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 51{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 52{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 53}; 54 55static dtrace_pops_t dtmalloc_pops = { 56 .dtps_provide = dtmalloc_provide, 57 .dtps_provide_module = NULL, 58 .dtps_enable = dtmalloc_enable, 59 .dtps_disable = dtmalloc_disable, 60 .dtps_suspend = NULL, 61 .dtps_resume = NULL, 62 .dtps_getargdesc = dtmalloc_getargdesc, 63 .dtps_getargval = NULL, 64 .dtps_usermode = NULL, 65 .dtps_destroy = dtmalloc_destroy 66}; 67 68static dtrace_provider_id_t dtmalloc_id; 69 70static void 71dtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) 72{ 73 const char *p = NULL; 74 75 switch (desc->dtargd_ndx) { 76 case 0: 77 p = "struct malloc_type *"; 78 break; 79 case 1: 80 p = "struct malloc_type_internal *"; 81 break; 82 case 2: 83 p = "struct malloc_type_stats *"; 84 break; 85 case 3: 86 p = "unsigned long"; 87 break; 88 case 4: 89 p = "int"; 90 break; 91 default: 92 desc->dtargd_ndx = DTRACE_ARGNONE; 93 break; 94 } 95 96 if (p != NULL) 97 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native)); 98 99 return; 100} 101 102static void 103dtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused) 104{ 105 char name[DTRACE_FUNCNAMELEN]; 106 struct malloc_type_internal *mtip = &mtp->ks_mti; 107 int i; 108 109 /* 110 * malloc_type descriptions are allowed to contain whitespace, but 111 * DTrace probe identifiers are not, so replace the whitespace with 112 * underscores. 113 */ 114 strlcpy(name, mtp->ks_shortdesc, sizeof(name)); 115 for (i = 0; name[i] != 0; i++) 116 if (isspace(name[i])) 117 name[i] = '_'; 118 119 if (dtrace_probe_lookup(dtmalloc_id, NULL, name, "malloc") != 0) 120 return; 121 122 (void) dtrace_probe_create(dtmalloc_id, NULL, name, "malloc", 0, 123 &mtip->mti_probes[DTMALLOC_PROBE_MALLOC]); 124 (void) dtrace_probe_create(dtmalloc_id, NULL, name, "free", 0, 125 &mtip->mti_probes[DTMALLOC_PROBE_FREE]); 126} 127 128static void 129dtmalloc_provide(void *arg, dtrace_probedesc_t *desc) 130{ 131 if (desc != NULL) 132 return; 133 134 malloc_type_list(dtmalloc_type_cb, desc); 135} 136 137static void 138dtmalloc_destroy(void *arg, dtrace_id_t id, void *parg) 139{ 140} 141 142static void 143dtmalloc_enable(void *arg, dtrace_id_t id, void *parg) 144{ 145 uint32_t *p = parg; 146 *p = id; 147 dtrace_malloc_enabled_count++; 148 if (dtrace_malloc_enabled_count == 1) 149 dtrace_malloc_enabled = true; 150} 151 152static void 153dtmalloc_disable(void *arg, dtrace_id_t id, void *parg) 154{ 155 uint32_t *p = parg; 156 *p = 0; 157 dtrace_malloc_enabled_count--; 158 if (dtrace_malloc_enabled_count == 0) 159 dtrace_malloc_enabled = false; 160} 161 162static void 163dtmalloc_load(void *dummy) 164{ 165 if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER, 166 NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0) 167 return; 168 169 dtrace_malloc_probe = dtrace_probe; 170} 171 172 173static int 174dtmalloc_unload(void) 175{ 176 int error = 0; 177 178 dtrace_malloc_probe = NULL; 179 180 if ((error = dtrace_unregister(dtmalloc_id)) != 0) 181 return (error); 182 183 return (error); 184} 185 186static int 187dtmalloc_modevent(module_t mod __unused, int type, void *data __unused) 188{ 189 int error = 0; 190 191 switch (type) { 192 case MOD_LOAD: 193 break; 194 195 case MOD_UNLOAD: 196 break; 197 198 case MOD_SHUTDOWN: 199 break; 200 201 default: 202 error = EOPNOTSUPP; 203 break; 204 205 } 206 207 return (error); 208} 209 210SYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL); 211SYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL); 212 213DEV_MODULE(dtmalloc, dtmalloc_modevent, NULL); 214MODULE_VERSION(dtmalloc, 1); 215MODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1); 216MODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1); 217