1 /* $NetBSD: dtmalloc.c,v 1.2 2010/02/21 01:46:33 darran 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: src/sys/cddl/dev/dtmalloc/dtmalloc.c,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $ 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/kernel.h> 34 #include <sys/malloc.h> 35 #include <sys/module.h> 36 37 #include <sys/dtrace.h> 38 #include <sys/dtrace_bsd.h> 39 40 static d_open_t dtmalloc_open; 41 static int dtmalloc_unload(void); 42 static void dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 43 static void dtmalloc_provide(void *, dtrace_probedesc_t *); 44 static void dtmalloc_destroy(void *, dtrace_id_t, void *); 45 static void dtmalloc_enable(void *, dtrace_id_t, void *); 46 static void dtmalloc_disable(void *, dtrace_id_t, void *); 47 static void dtmalloc_load(void *); 48 49 static struct cdevsw dtmalloc_cdevsw = { 50 .d_version = D_VERSION, 51 .d_open = dtmalloc_open, 52 .d_name = "dtmalloc", 53 }; 54 55 static dtrace_pattr_t dtmalloc_attr = { 56 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 57 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 58 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 59 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 60 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 61 }; 62 63 static dtrace_pops_t dtmalloc_pops = { 64 dtmalloc_provide, 65 NULL, 66 dtmalloc_enable, 67 dtmalloc_disable, 68 NULL, 69 NULL, 70 dtmalloc_getargdesc, 71 NULL, 72 NULL, 73 dtmalloc_destroy 74 }; 75 76 static struct cdev *dtmalloc_cdev; 77 static dtrace_provider_id_t dtmalloc_id; 78 79 static void 80 dtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) 81 { 82 const char *p = NULL; 83 84 switch (desc->dtargd_ndx) { 85 case 0: 86 p = "struct malloc_type *"; 87 break; 88 case 1: 89 p = "struct malloc_type_internal *"; 90 break; 91 case 2: 92 p = "struct malloc_type_stats *"; 93 break; 94 case 3: 95 p = "unsigned long"; 96 break; 97 case 4: 98 p = "int"; 99 break; 100 default: 101 desc->dtargd_ndx = DTRACE_ARGNONE; 102 break; 103 } 104 105 if (p != NULL) 106 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native)); 107 108 return; 109 } 110 111 static void 112 dtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused) 113 { 114 char name[DTRACE_FUNCNAMELEN]; 115 struct malloc_type_internal *mtip = mtp->ks_handle; 116 117 strlcpy(name, mtp->ks_shortdesc, sizeof(name)); 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 128 static void 129 dtmalloc_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 137 static void 138 dtmalloc_destroy(void *arg, dtrace_id_t id, void *parg) 139 { 140 } 141 142 static void 143 dtmalloc_enable(void *arg, dtrace_id_t id, void *parg) 144 { 145 uint32_t *p = parg; 146 *p = id; 147 } 148 149 static void 150 dtmalloc_disable(void *arg, dtrace_id_t id, void *parg) 151 { 152 uint32_t *p = parg; 153 *p = 0; 154 } 155 156 static void 157 dtmalloc_load(void *dummy) 158 { 159 /* Create the /dev/dtrace/dtmalloc entry. */ 160 dtmalloc_cdev = make_dev(&dtmalloc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 161 "dtrace/dtmalloc"); 162 163 if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER, 164 NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0) 165 return; 166 167 dtrace_malloc_probe = dtrace_probe; 168 } 169 170 171 static int 172 dtmalloc_unload() 173 { 174 int error = 0; 175 176 dtrace_malloc_probe = NULL; 177 178 if ((error = dtrace_unregister(dtmalloc_id)) != 0) 179 return (error); 180 181 destroy_dev(dtmalloc_cdev); 182 183 return (error); 184 } 185 186 static int 187 dtmalloc_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 210 static int 211 dtmalloc_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 212 { 213 return (0); 214 } 215 216 SYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL); 217 SYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL); 218 219 DEV_MODULE(dtmalloc, dtmalloc_modevent, NULL); 220 MODULE_VERSION(dtmalloc, 1); 221 MODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1); 222 MODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1); 223