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