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