1179237Sjb/* 2179237Sjb * CDDL HEADER START 3179237Sjb * 4179237Sjb * The contents of this file are subject to the terms of the 5179237Sjb * Common Development and Distribution License (the "License"). 6179237Sjb * You may not use this file except in compliance with the License. 7179237Sjb * 8179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9179237Sjb * or http://www.opensolaris.org/os/licensing. 10179237Sjb * See the License for the specific language governing permissions 11179237Sjb * and limitations under the License. 12179237Sjb * 13179237Sjb * When distributing Covered Code, include this CDDL HEADER in each 14179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15179237Sjb * If applicable, add the following below this CDDL HEADER, with the 16179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying 17179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner] 18179237Sjb * 19179237Sjb * CDDL HEADER END 20179237Sjb * 21179237Sjb * Portions Copyright 2006-2008 John Birrell jb@freebsd.org 22179237Sjb * 23179237Sjb * $FreeBSD$ 24179237Sjb * 25179237Sjb */ 26179237Sjb 27179237Sjb#include <sys/cdefs.h> 28179237Sjb#include <sys/param.h> 29179237Sjb#include <sys/systm.h> 30179237Sjb#include <sys/conf.h> 31252325Smarkj#include <sys/ctype.h> 32179237Sjb#include <sys/kernel.h> 33179237Sjb#include <sys/malloc.h> 34179237Sjb#include <sys/module.h> 35179237Sjb 36179237Sjb#include <sys/dtrace.h> 37179237Sjb#include <sys/dtrace_bsd.h> 38179237Sjb 39179237Sjbstatic d_open_t dtmalloc_open; 40179237Sjbstatic int dtmalloc_unload(void); 41179237Sjbstatic void dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *); 42179237Sjbstatic void dtmalloc_provide(void *, dtrace_probedesc_t *); 43179237Sjbstatic void dtmalloc_destroy(void *, dtrace_id_t, void *); 44179237Sjbstatic void dtmalloc_enable(void *, dtrace_id_t, void *); 45179237Sjbstatic void dtmalloc_disable(void *, dtrace_id_t, void *); 46179237Sjbstatic void dtmalloc_load(void *); 47179237Sjb 48179237Sjbstatic struct cdevsw dtmalloc_cdevsw = { 49179237Sjb .d_version = D_VERSION, 50179237Sjb .d_open = dtmalloc_open, 51179237Sjb .d_name = "dtmalloc", 52179237Sjb}; 53179237Sjb 54179237Sjbstatic dtrace_pattr_t dtmalloc_attr = { 55179237Sjb{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 56179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 57179237Sjb{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, 58179237Sjb{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 59179237Sjb{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, 60179237Sjb}; 61179237Sjb 62179237Sjbstatic dtrace_pops_t dtmalloc_pops = { 63179237Sjb dtmalloc_provide, 64179237Sjb NULL, 65179237Sjb dtmalloc_enable, 66179237Sjb dtmalloc_disable, 67179237Sjb NULL, 68179237Sjb NULL, 69179237Sjb dtmalloc_getargdesc, 70179237Sjb NULL, 71179237Sjb NULL, 72179237Sjb dtmalloc_destroy 73179237Sjb}; 74179237Sjb 75179237Sjbstatic struct cdev *dtmalloc_cdev; 76179237Sjbstatic dtrace_provider_id_t dtmalloc_id; 77179237Sjb 78179237Sjbstatic void 79179237Sjbdtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc) 80179237Sjb{ 81179237Sjb const char *p = NULL; 82179237Sjb 83179237Sjb switch (desc->dtargd_ndx) { 84179237Sjb case 0: 85179237Sjb p = "struct malloc_type *"; 86179237Sjb break; 87179237Sjb case 1: 88179237Sjb p = "struct malloc_type_internal *"; 89179237Sjb break; 90179237Sjb case 2: 91179237Sjb p = "struct malloc_type_stats *"; 92179237Sjb break; 93179237Sjb case 3: 94179237Sjb p = "unsigned long"; 95179237Sjb break; 96179237Sjb case 4: 97179237Sjb p = "int"; 98179237Sjb break; 99179237Sjb default: 100179237Sjb desc->dtargd_ndx = DTRACE_ARGNONE; 101179237Sjb break; 102179237Sjb } 103179237Sjb 104179237Sjb if (p != NULL) 105179237Sjb strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native)); 106179237Sjb 107179237Sjb return; 108179237Sjb} 109179237Sjb 110179237Sjbstatic void 111179237Sjbdtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused) 112179237Sjb{ 113179237Sjb char name[DTRACE_FUNCNAMELEN]; 114179237Sjb struct malloc_type_internal *mtip = mtp->ks_handle; 115252325Smarkj int i; 116179237Sjb 117252325Smarkj /* 118252325Smarkj * malloc_type descriptions are allowed to contain whitespace, but 119252325Smarkj * DTrace probe identifiers are not, so replace the whitespace with 120252325Smarkj * underscores. 121252325Smarkj */ 122179237Sjb strlcpy(name, mtp->ks_shortdesc, sizeof(name)); 123252325Smarkj for (i = 0; name[i] != 0; i++) 124252325Smarkj if (isspace(name[i])) 125252325Smarkj name[i] = '_'; 126179237Sjb 127179237Sjb if (dtrace_probe_lookup(dtmalloc_id, NULL, name, "malloc") != 0) 128179237Sjb return; 129179237Sjb 130179237Sjb (void) dtrace_probe_create(dtmalloc_id, NULL, name, "malloc", 0, 131179237Sjb &mtip->mti_probes[DTMALLOC_PROBE_MALLOC]); 132179237Sjb (void) dtrace_probe_create(dtmalloc_id, NULL, name, "free", 0, 133179237Sjb &mtip->mti_probes[DTMALLOC_PROBE_FREE]); 134179237Sjb} 135179237Sjb 136179237Sjbstatic void 137179237Sjbdtmalloc_provide(void *arg, dtrace_probedesc_t *desc) 138179237Sjb{ 139179237Sjb if (desc != NULL) 140179237Sjb return; 141179237Sjb 142179237Sjb malloc_type_list(dtmalloc_type_cb, desc); 143179237Sjb} 144179237Sjb 145179237Sjbstatic void 146179237Sjbdtmalloc_destroy(void *arg, dtrace_id_t id, void *parg) 147179237Sjb{ 148179237Sjb} 149179237Sjb 150179237Sjbstatic void 151179237Sjbdtmalloc_enable(void *arg, dtrace_id_t id, void *parg) 152179237Sjb{ 153179237Sjb uint32_t *p = parg; 154179237Sjb *p = id; 155179237Sjb} 156179237Sjb 157179237Sjbstatic void 158179237Sjbdtmalloc_disable(void *arg, dtrace_id_t id, void *parg) 159179237Sjb{ 160179237Sjb uint32_t *p = parg; 161179237Sjb *p = 0; 162179237Sjb} 163179237Sjb 164179237Sjbstatic void 165179237Sjbdtmalloc_load(void *dummy) 166179237Sjb{ 167179237Sjb /* Create the /dev/dtrace/dtmalloc entry. */ 168179237Sjb dtmalloc_cdev = make_dev(&dtmalloc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, 169179237Sjb "dtrace/dtmalloc"); 170179237Sjb 171179237Sjb if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER, 172179237Sjb NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0) 173179237Sjb return; 174179237Sjb 175179237Sjb dtrace_malloc_probe = dtrace_probe; 176179237Sjb} 177179237Sjb 178179237Sjb 179179237Sjbstatic int 180179237Sjbdtmalloc_unload() 181179237Sjb{ 182179237Sjb int error = 0; 183179237Sjb 184179237Sjb dtrace_malloc_probe = NULL; 185179237Sjb 186179237Sjb if ((error = dtrace_unregister(dtmalloc_id)) != 0) 187179237Sjb return (error); 188179237Sjb 189179237Sjb destroy_dev(dtmalloc_cdev); 190179237Sjb 191179237Sjb return (error); 192179237Sjb} 193179237Sjb 194179237Sjbstatic int 195179237Sjbdtmalloc_modevent(module_t mod __unused, int type, void *data __unused) 196179237Sjb{ 197179237Sjb int error = 0; 198179237Sjb 199179237Sjb switch (type) { 200179237Sjb case MOD_LOAD: 201179237Sjb break; 202179237Sjb 203179237Sjb case MOD_UNLOAD: 204179237Sjb break; 205179237Sjb 206179237Sjb case MOD_SHUTDOWN: 207179237Sjb break; 208179237Sjb 209179237Sjb default: 210179237Sjb error = EOPNOTSUPP; 211179237Sjb break; 212179237Sjb 213179237Sjb } 214179237Sjb 215179237Sjb return (error); 216179237Sjb} 217179237Sjb 218179237Sjbstatic int 219179237Sjbdtmalloc_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused) 220179237Sjb{ 221179237Sjb return (0); 222179237Sjb} 223179237Sjb 224179237SjbSYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL); 225179237SjbSYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL); 226179237Sjb 227179237SjbDEV_MODULE(dtmalloc, dtmalloc_modevent, NULL); 228179237SjbMODULE_VERSION(dtmalloc, 1); 229179237SjbMODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1); 230179237SjbMODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1); 231