191eaf3e1SJohn Birrell /*
291eaf3e1SJohn Birrell * CDDL HEADER START
391eaf3e1SJohn Birrell *
491eaf3e1SJohn Birrell * The contents of this file are subject to the terms of the
591eaf3e1SJohn Birrell * Common Development and Distribution License (the "License").
691eaf3e1SJohn Birrell * You may not use this file except in compliance with the License.
791eaf3e1SJohn Birrell *
891eaf3e1SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
991eaf3e1SJohn Birrell * or http://www.opensolaris.org/os/licensing.
1091eaf3e1SJohn Birrell * See the License for the specific language governing permissions
1191eaf3e1SJohn Birrell * and limitations under the License.
1291eaf3e1SJohn Birrell *
1391eaf3e1SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each
1491eaf3e1SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1591eaf3e1SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the
1691eaf3e1SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying
1791eaf3e1SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner]
1891eaf3e1SJohn Birrell *
1991eaf3e1SJohn Birrell * CDDL HEADER END
2091eaf3e1SJohn Birrell *
2191eaf3e1SJohn Birrell * Portions Copyright 2006-2008 John Birrell jb@freebsd.org
2291eaf3e1SJohn Birrell *
2391eaf3e1SJohn Birrell */
2491eaf3e1SJohn Birrell
2591eaf3e1SJohn Birrell #include <sys/param.h>
2691eaf3e1SJohn Birrell #include <sys/systm.h>
2791eaf3e1SJohn Birrell #include <sys/conf.h>
28837610ebSMark Johnston #include <sys/ctype.h>
2991eaf3e1SJohn Birrell #include <sys/kernel.h>
3091eaf3e1SJohn Birrell #include <sys/malloc.h>
3191eaf3e1SJohn Birrell #include <sys/module.h>
3291eaf3e1SJohn Birrell
3391eaf3e1SJohn Birrell #include <sys/dtrace.h>
3491eaf3e1SJohn Birrell #include <sys/dtrace_bsd.h>
3591eaf3e1SJohn Birrell
367cd79421SMateusz Guzik extern bool dtrace_malloc_enabled;
377cd79421SMateusz Guzik static uint32_t dtrace_malloc_enabled_count;
387cd79421SMateusz Guzik
3991eaf3e1SJohn Birrell static int dtmalloc_unload(void);
4091eaf3e1SJohn Birrell static void dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
4191eaf3e1SJohn Birrell static void dtmalloc_provide(void *, dtrace_probedesc_t *);
4291eaf3e1SJohn Birrell static void dtmalloc_destroy(void *, dtrace_id_t, void *);
4391eaf3e1SJohn Birrell static void dtmalloc_enable(void *, dtrace_id_t, void *);
4491eaf3e1SJohn Birrell static void dtmalloc_disable(void *, dtrace_id_t, void *);
4591eaf3e1SJohn Birrell static void dtmalloc_load(void *);
4691eaf3e1SJohn Birrell
4791eaf3e1SJohn Birrell static dtrace_pattr_t dtmalloc_attr = {
4891eaf3e1SJohn Birrell { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
4991eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
5091eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
5191eaf3e1SJohn Birrell { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
5291eaf3e1SJohn Birrell { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
5391eaf3e1SJohn Birrell };
5491eaf3e1SJohn Birrell
5591eaf3e1SJohn Birrell static dtrace_pops_t dtmalloc_pops = {
5647f11baaSMark Johnston .dtps_provide = dtmalloc_provide,
5747f11baaSMark Johnston .dtps_provide_module = NULL,
5847f11baaSMark Johnston .dtps_enable = dtmalloc_enable,
5947f11baaSMark Johnston .dtps_disable = dtmalloc_disable,
6047f11baaSMark Johnston .dtps_suspend = NULL,
6147f11baaSMark Johnston .dtps_resume = NULL,
6247f11baaSMark Johnston .dtps_getargdesc = dtmalloc_getargdesc,
6347f11baaSMark Johnston .dtps_getargval = NULL,
6447f11baaSMark Johnston .dtps_usermode = NULL,
6547f11baaSMark Johnston .dtps_destroy = dtmalloc_destroy
6691eaf3e1SJohn Birrell };
6791eaf3e1SJohn Birrell
6891eaf3e1SJohn Birrell static dtrace_provider_id_t dtmalloc_id;
6991eaf3e1SJohn Birrell
7091eaf3e1SJohn Birrell static void
dtmalloc_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)7191eaf3e1SJohn Birrell dtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
7291eaf3e1SJohn Birrell {
7391eaf3e1SJohn Birrell const char *p = NULL;
7491eaf3e1SJohn Birrell
7591eaf3e1SJohn Birrell switch (desc->dtargd_ndx) {
7691eaf3e1SJohn Birrell case 0:
7791eaf3e1SJohn Birrell p = "struct malloc_type *";
7891eaf3e1SJohn Birrell break;
7991eaf3e1SJohn Birrell case 1:
8091eaf3e1SJohn Birrell p = "struct malloc_type_internal *";
8191eaf3e1SJohn Birrell break;
8291eaf3e1SJohn Birrell case 2:
8391eaf3e1SJohn Birrell p = "struct malloc_type_stats *";
8491eaf3e1SJohn Birrell break;
8591eaf3e1SJohn Birrell case 3:
8691eaf3e1SJohn Birrell p = "unsigned long";
8791eaf3e1SJohn Birrell break;
8891eaf3e1SJohn Birrell case 4:
8991eaf3e1SJohn Birrell p = "int";
9091eaf3e1SJohn Birrell break;
9191eaf3e1SJohn Birrell default:
9291eaf3e1SJohn Birrell desc->dtargd_ndx = DTRACE_ARGNONE;
9391eaf3e1SJohn Birrell break;
9491eaf3e1SJohn Birrell }
9591eaf3e1SJohn Birrell
9691eaf3e1SJohn Birrell if (p != NULL)
9791eaf3e1SJohn Birrell strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
9891eaf3e1SJohn Birrell
9991eaf3e1SJohn Birrell return;
10091eaf3e1SJohn Birrell }
10191eaf3e1SJohn Birrell
10291eaf3e1SJohn Birrell static void
dtmalloc_type_cb(struct malloc_type * mtp,void * arg __unused)10391eaf3e1SJohn Birrell dtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused)
10491eaf3e1SJohn Birrell {
10591eaf3e1SJohn Birrell char name[DTRACE_FUNCNAMELEN];
106bdcc2226SMateusz Guzik struct malloc_type_internal *mtip = &mtp->ks_mti;
107837610ebSMark Johnston int i;
10891eaf3e1SJohn Birrell
109837610ebSMark Johnston /*
110837610ebSMark Johnston * malloc_type descriptions are allowed to contain whitespace, but
111837610ebSMark Johnston * DTrace probe identifiers are not, so replace the whitespace with
112837610ebSMark Johnston * underscores.
113837610ebSMark Johnston */
11491eaf3e1SJohn Birrell strlcpy(name, mtp->ks_shortdesc, sizeof(name));
115837610ebSMark Johnston for (i = 0; name[i] != 0; i++)
116837610ebSMark Johnston if (isspace(name[i]))
117837610ebSMark Johnston name[i] = '_';
11891eaf3e1SJohn Birrell
11991eaf3e1SJohn Birrell if (dtrace_probe_lookup(dtmalloc_id, NULL, name, "malloc") != 0)
12091eaf3e1SJohn Birrell return;
12191eaf3e1SJohn Birrell
12291eaf3e1SJohn Birrell (void) dtrace_probe_create(dtmalloc_id, NULL, name, "malloc", 0,
12391eaf3e1SJohn Birrell &mtip->mti_probes[DTMALLOC_PROBE_MALLOC]);
12491eaf3e1SJohn Birrell (void) dtrace_probe_create(dtmalloc_id, NULL, name, "free", 0,
12591eaf3e1SJohn Birrell &mtip->mti_probes[DTMALLOC_PROBE_FREE]);
12691eaf3e1SJohn Birrell }
12791eaf3e1SJohn Birrell
12891eaf3e1SJohn Birrell static void
dtmalloc_provide(void * arg,dtrace_probedesc_t * desc)12991eaf3e1SJohn Birrell dtmalloc_provide(void *arg, dtrace_probedesc_t *desc)
13091eaf3e1SJohn Birrell {
13191eaf3e1SJohn Birrell if (desc != NULL)
13291eaf3e1SJohn Birrell return;
13391eaf3e1SJohn Birrell
13491eaf3e1SJohn Birrell malloc_type_list(dtmalloc_type_cb, desc);
13591eaf3e1SJohn Birrell }
13691eaf3e1SJohn Birrell
13791eaf3e1SJohn Birrell static void
dtmalloc_destroy(void * arg,dtrace_id_t id,void * parg)13891eaf3e1SJohn Birrell dtmalloc_destroy(void *arg, dtrace_id_t id, void *parg)
13991eaf3e1SJohn Birrell {
14091eaf3e1SJohn Birrell }
14191eaf3e1SJohn Birrell
14291eaf3e1SJohn Birrell static void
dtmalloc_enable(void * arg,dtrace_id_t id,void * parg)14391eaf3e1SJohn Birrell dtmalloc_enable(void *arg, dtrace_id_t id, void *parg)
14491eaf3e1SJohn Birrell {
14591eaf3e1SJohn Birrell uint32_t *p = parg;
14691eaf3e1SJohn Birrell *p = id;
1477cd79421SMateusz Guzik dtrace_malloc_enabled_count++;
1487cd79421SMateusz Guzik if (dtrace_malloc_enabled_count == 1)
1497cd79421SMateusz Guzik dtrace_malloc_enabled = true;
15091eaf3e1SJohn Birrell }
15191eaf3e1SJohn Birrell
15291eaf3e1SJohn Birrell static void
dtmalloc_disable(void * arg,dtrace_id_t id,void * parg)15391eaf3e1SJohn Birrell dtmalloc_disable(void *arg, dtrace_id_t id, void *parg)
15491eaf3e1SJohn Birrell {
15591eaf3e1SJohn Birrell uint32_t *p = parg;
15691eaf3e1SJohn Birrell *p = 0;
1577cd79421SMateusz Guzik dtrace_malloc_enabled_count--;
1587cd79421SMateusz Guzik if (dtrace_malloc_enabled_count == 0)
1597cd79421SMateusz Guzik dtrace_malloc_enabled = false;
16091eaf3e1SJohn Birrell }
16191eaf3e1SJohn Birrell
16291eaf3e1SJohn Birrell static void
dtmalloc_load(void * dummy)16391eaf3e1SJohn Birrell dtmalloc_load(void *dummy)
16491eaf3e1SJohn Birrell {
16591eaf3e1SJohn Birrell if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER,
16691eaf3e1SJohn Birrell NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0)
16791eaf3e1SJohn Birrell return;
16891eaf3e1SJohn Birrell
16991eaf3e1SJohn Birrell dtrace_malloc_probe = dtrace_probe;
17091eaf3e1SJohn Birrell }
17191eaf3e1SJohn Birrell
17291eaf3e1SJohn Birrell
17391eaf3e1SJohn Birrell static int
dtmalloc_unload(void)174*a0c55bacSDimitry Andric dtmalloc_unload(void)
17591eaf3e1SJohn Birrell {
17691eaf3e1SJohn Birrell int error = 0;
17791eaf3e1SJohn Birrell
17891eaf3e1SJohn Birrell dtrace_malloc_probe = NULL;
17991eaf3e1SJohn Birrell
18091eaf3e1SJohn Birrell if ((error = dtrace_unregister(dtmalloc_id)) != 0)
18191eaf3e1SJohn Birrell return (error);
18291eaf3e1SJohn Birrell
18391eaf3e1SJohn Birrell return (error);
18491eaf3e1SJohn Birrell }
18591eaf3e1SJohn Birrell
18691eaf3e1SJohn Birrell static int
dtmalloc_modevent(module_t mod __unused,int type,void * data __unused)18791eaf3e1SJohn Birrell dtmalloc_modevent(module_t mod __unused, int type, void *data __unused)
18891eaf3e1SJohn Birrell {
18991eaf3e1SJohn Birrell int error = 0;
19091eaf3e1SJohn Birrell
19191eaf3e1SJohn Birrell switch (type) {
19291eaf3e1SJohn Birrell case MOD_LOAD:
19391eaf3e1SJohn Birrell break;
19491eaf3e1SJohn Birrell
19591eaf3e1SJohn Birrell case MOD_UNLOAD:
19691eaf3e1SJohn Birrell break;
19791eaf3e1SJohn Birrell
19891eaf3e1SJohn Birrell case MOD_SHUTDOWN:
19991eaf3e1SJohn Birrell break;
20091eaf3e1SJohn Birrell
20191eaf3e1SJohn Birrell default:
20291eaf3e1SJohn Birrell error = EOPNOTSUPP;
20391eaf3e1SJohn Birrell break;
20491eaf3e1SJohn Birrell
20591eaf3e1SJohn Birrell }
20691eaf3e1SJohn Birrell
20791eaf3e1SJohn Birrell return (error);
20891eaf3e1SJohn Birrell }
20991eaf3e1SJohn Birrell
21091eaf3e1SJohn Birrell SYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL);
21191eaf3e1SJohn Birrell SYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL);
21291eaf3e1SJohn Birrell
21391eaf3e1SJohn Birrell DEV_MODULE(dtmalloc, dtmalloc_modevent, NULL);
21491eaf3e1SJohn Birrell MODULE_VERSION(dtmalloc, 1);
21591eaf3e1SJohn Birrell MODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1);
21691eaf3e1SJohn Birrell MODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1);
217