xref: /freebsd-13.1/sys/cddl/dev/dtmalloc/dtmalloc.c (revision bdcc2226)
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 [email protected]
2291eaf3e1SJohn Birrell  *
2391eaf3e1SJohn Birrell  * $FreeBSD$
2491eaf3e1SJohn Birrell  *
2591eaf3e1SJohn Birrell  */
2691eaf3e1SJohn Birrell 
2791eaf3e1SJohn Birrell #include <sys/cdefs.h>
2891eaf3e1SJohn Birrell #include <sys/param.h>
2991eaf3e1SJohn Birrell #include <sys/systm.h>
3091eaf3e1SJohn Birrell #include <sys/conf.h>
31837610ebSMark Johnston #include <sys/ctype.h>
3291eaf3e1SJohn Birrell #include <sys/kernel.h>
3391eaf3e1SJohn Birrell #include <sys/malloc.h>
3491eaf3e1SJohn Birrell #include <sys/module.h>
3591eaf3e1SJohn Birrell 
3691eaf3e1SJohn Birrell #include <sys/dtrace.h>
3791eaf3e1SJohn Birrell #include <sys/dtrace_bsd.h>
3891eaf3e1SJohn Birrell 
397cd79421SMateusz Guzik extern bool dtrace_malloc_enabled;
407cd79421SMateusz Guzik static uint32_t dtrace_malloc_enabled_count;
417cd79421SMateusz Guzik 
4291eaf3e1SJohn Birrell static d_open_t	dtmalloc_open;
4391eaf3e1SJohn Birrell static int	dtmalloc_unload(void);
4491eaf3e1SJohn Birrell static void	dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
4591eaf3e1SJohn Birrell static void	dtmalloc_provide(void *, dtrace_probedesc_t *);
4691eaf3e1SJohn Birrell static void	dtmalloc_destroy(void *, dtrace_id_t, void *);
4791eaf3e1SJohn Birrell static void	dtmalloc_enable(void *, dtrace_id_t, void *);
4891eaf3e1SJohn Birrell static void	dtmalloc_disable(void *, dtrace_id_t, void *);
4991eaf3e1SJohn Birrell static void	dtmalloc_load(void *);
5091eaf3e1SJohn Birrell 
5191eaf3e1SJohn Birrell static struct cdevsw dtmalloc_cdevsw = {
5291eaf3e1SJohn Birrell 	.d_version	= D_VERSION,
5391eaf3e1SJohn Birrell 	.d_open		= dtmalloc_open,
5491eaf3e1SJohn Birrell 	.d_name		= "dtmalloc",
5591eaf3e1SJohn Birrell };
5691eaf3e1SJohn Birrell 
5791eaf3e1SJohn Birrell static dtrace_pattr_t dtmalloc_attr = {
5891eaf3e1SJohn Birrell { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
5991eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
6091eaf3e1SJohn Birrell { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
6191eaf3e1SJohn Birrell { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
6291eaf3e1SJohn Birrell { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
6391eaf3e1SJohn Birrell };
6491eaf3e1SJohn Birrell 
6591eaf3e1SJohn Birrell static dtrace_pops_t dtmalloc_pops = {
6647f11baaSMark Johnston 	.dtps_provide =		dtmalloc_provide,
6747f11baaSMark Johnston 	.dtps_provide_module =	NULL,
6847f11baaSMark Johnston 	.dtps_enable =		dtmalloc_enable,
6947f11baaSMark Johnston 	.dtps_disable =		dtmalloc_disable,
7047f11baaSMark Johnston 	.dtps_suspend =		NULL,
7147f11baaSMark Johnston 	.dtps_resume =		NULL,
7247f11baaSMark Johnston 	.dtps_getargdesc =	dtmalloc_getargdesc,
7347f11baaSMark Johnston 	.dtps_getargval =	NULL,
7447f11baaSMark Johnston 	.dtps_usermode =	NULL,
7547f11baaSMark Johnston 	.dtps_destroy =		dtmalloc_destroy
7691eaf3e1SJohn Birrell };
7791eaf3e1SJohn Birrell 
7891eaf3e1SJohn Birrell static struct cdev		*dtmalloc_cdev;
7991eaf3e1SJohn Birrell static dtrace_provider_id_t	dtmalloc_id;
8091eaf3e1SJohn Birrell 
8191eaf3e1SJohn Birrell static void
dtmalloc_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)8291eaf3e1SJohn Birrell dtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
8391eaf3e1SJohn Birrell {
8491eaf3e1SJohn Birrell 	const char *p = NULL;
8591eaf3e1SJohn Birrell 
8691eaf3e1SJohn Birrell 	switch (desc->dtargd_ndx) {
8791eaf3e1SJohn Birrell 	case 0:
8891eaf3e1SJohn Birrell 		p = "struct malloc_type *";
8991eaf3e1SJohn Birrell 		break;
9091eaf3e1SJohn Birrell 	case 1:
9191eaf3e1SJohn Birrell 		p = "struct malloc_type_internal *";
9291eaf3e1SJohn Birrell 		break;
9391eaf3e1SJohn Birrell 	case 2:
9491eaf3e1SJohn Birrell 		p = "struct malloc_type_stats *";
9591eaf3e1SJohn Birrell 		break;
9691eaf3e1SJohn Birrell 	case 3:
9791eaf3e1SJohn Birrell 		p = "unsigned long";
9891eaf3e1SJohn Birrell 		break;
9991eaf3e1SJohn Birrell 	case 4:
10091eaf3e1SJohn Birrell 		p = "int";
10191eaf3e1SJohn Birrell 		break;
10291eaf3e1SJohn Birrell 	default:
10391eaf3e1SJohn Birrell 		desc->dtargd_ndx = DTRACE_ARGNONE;
10491eaf3e1SJohn Birrell 		break;
10591eaf3e1SJohn Birrell 	}
10691eaf3e1SJohn Birrell 
10791eaf3e1SJohn Birrell 	if (p != NULL)
10891eaf3e1SJohn Birrell 		strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
10991eaf3e1SJohn Birrell 
11091eaf3e1SJohn Birrell 	return;
11191eaf3e1SJohn Birrell }
11291eaf3e1SJohn Birrell 
11391eaf3e1SJohn Birrell static void
dtmalloc_type_cb(struct malloc_type * mtp,void * arg __unused)11491eaf3e1SJohn Birrell dtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused)
11591eaf3e1SJohn Birrell {
11691eaf3e1SJohn Birrell 	char name[DTRACE_FUNCNAMELEN];
117*bdcc2226SMateusz Guzik 	struct malloc_type_internal *mtip = &mtp->ks_mti;
118837610ebSMark Johnston 	int i;
11991eaf3e1SJohn Birrell 
120837610ebSMark Johnston 	/*
121837610ebSMark Johnston 	 * malloc_type descriptions are allowed to contain whitespace, but
122837610ebSMark Johnston 	 * DTrace probe identifiers are not, so replace the whitespace with
123837610ebSMark Johnston 	 * underscores.
124837610ebSMark Johnston 	 */
12591eaf3e1SJohn Birrell 	strlcpy(name, mtp->ks_shortdesc, sizeof(name));
126837610ebSMark Johnston 	for (i = 0; name[i] != 0; i++)
127837610ebSMark Johnston 		if (isspace(name[i]))
128837610ebSMark Johnston 			name[i] = '_';
12991eaf3e1SJohn Birrell 
13091eaf3e1SJohn Birrell 	if (dtrace_probe_lookup(dtmalloc_id, NULL, name, "malloc") != 0)
13191eaf3e1SJohn Birrell 		return;
13291eaf3e1SJohn Birrell 
13391eaf3e1SJohn Birrell 	(void) dtrace_probe_create(dtmalloc_id, NULL, name, "malloc", 0,
13491eaf3e1SJohn Birrell 	    &mtip->mti_probes[DTMALLOC_PROBE_MALLOC]);
13591eaf3e1SJohn Birrell 	(void) dtrace_probe_create(dtmalloc_id, NULL, name, "free", 0,
13691eaf3e1SJohn Birrell 	    &mtip->mti_probes[DTMALLOC_PROBE_FREE]);
13791eaf3e1SJohn Birrell }
13891eaf3e1SJohn Birrell 
13991eaf3e1SJohn Birrell static void
dtmalloc_provide(void * arg,dtrace_probedesc_t * desc)14091eaf3e1SJohn Birrell dtmalloc_provide(void *arg, dtrace_probedesc_t *desc)
14191eaf3e1SJohn Birrell {
14291eaf3e1SJohn Birrell 	if (desc != NULL)
14391eaf3e1SJohn Birrell 		return;
14491eaf3e1SJohn Birrell 
14591eaf3e1SJohn Birrell 	malloc_type_list(dtmalloc_type_cb, desc);
14691eaf3e1SJohn Birrell }
14791eaf3e1SJohn Birrell 
14891eaf3e1SJohn Birrell static void
dtmalloc_destroy(void * arg,dtrace_id_t id,void * parg)14991eaf3e1SJohn Birrell dtmalloc_destroy(void *arg, dtrace_id_t id, void *parg)
15091eaf3e1SJohn Birrell {
15191eaf3e1SJohn Birrell }
15291eaf3e1SJohn Birrell 
15391eaf3e1SJohn Birrell static void
dtmalloc_enable(void * arg,dtrace_id_t id,void * parg)15491eaf3e1SJohn Birrell dtmalloc_enable(void *arg, dtrace_id_t id, void *parg)
15591eaf3e1SJohn Birrell {
15691eaf3e1SJohn Birrell 	uint32_t *p = parg;
15791eaf3e1SJohn Birrell 	*p = id;
1587cd79421SMateusz Guzik 	dtrace_malloc_enabled_count++;
1597cd79421SMateusz Guzik 	if (dtrace_malloc_enabled_count == 1)
1607cd79421SMateusz Guzik 		dtrace_malloc_enabled = true;
16191eaf3e1SJohn Birrell }
16291eaf3e1SJohn Birrell 
16391eaf3e1SJohn Birrell static void
dtmalloc_disable(void * arg,dtrace_id_t id,void * parg)16491eaf3e1SJohn Birrell dtmalloc_disable(void *arg, dtrace_id_t id, void *parg)
16591eaf3e1SJohn Birrell {
16691eaf3e1SJohn Birrell 	uint32_t *p = parg;
16791eaf3e1SJohn Birrell 	*p = 0;
1687cd79421SMateusz Guzik 	dtrace_malloc_enabled_count--;
1697cd79421SMateusz Guzik 	if (dtrace_malloc_enabled_count == 0)
1707cd79421SMateusz Guzik 		dtrace_malloc_enabled = false;
17191eaf3e1SJohn Birrell }
17291eaf3e1SJohn Birrell 
17391eaf3e1SJohn Birrell static void
dtmalloc_load(void * dummy)17491eaf3e1SJohn Birrell dtmalloc_load(void *dummy)
17591eaf3e1SJohn Birrell {
17691eaf3e1SJohn Birrell 	/* Create the /dev/dtrace/dtmalloc entry. */
17791eaf3e1SJohn Birrell 	dtmalloc_cdev = make_dev(&dtmalloc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
17891eaf3e1SJohn Birrell 	    "dtrace/dtmalloc");
17991eaf3e1SJohn Birrell 
18091eaf3e1SJohn Birrell 	if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER,
18191eaf3e1SJohn Birrell 	    NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0)
18291eaf3e1SJohn Birrell 		return;
18391eaf3e1SJohn Birrell 
18491eaf3e1SJohn Birrell 	dtrace_malloc_probe = dtrace_probe;
18591eaf3e1SJohn Birrell }
18691eaf3e1SJohn Birrell 
18791eaf3e1SJohn Birrell 
18891eaf3e1SJohn Birrell static int
dtmalloc_unload()18991eaf3e1SJohn Birrell dtmalloc_unload()
19091eaf3e1SJohn Birrell {
19191eaf3e1SJohn Birrell 	int error = 0;
19291eaf3e1SJohn Birrell 
19391eaf3e1SJohn Birrell 	dtrace_malloc_probe = NULL;
19491eaf3e1SJohn Birrell 
19591eaf3e1SJohn Birrell 	if ((error = dtrace_unregister(dtmalloc_id)) != 0)
19691eaf3e1SJohn Birrell 		return (error);
19791eaf3e1SJohn Birrell 
19891eaf3e1SJohn Birrell 	destroy_dev(dtmalloc_cdev);
19991eaf3e1SJohn Birrell 
20091eaf3e1SJohn Birrell 	return (error);
20191eaf3e1SJohn Birrell }
20291eaf3e1SJohn Birrell 
20391eaf3e1SJohn Birrell static int
dtmalloc_modevent(module_t mod __unused,int type,void * data __unused)20491eaf3e1SJohn Birrell dtmalloc_modevent(module_t mod __unused, int type, void *data __unused)
20591eaf3e1SJohn Birrell {
20691eaf3e1SJohn Birrell 	int error = 0;
20791eaf3e1SJohn Birrell 
20891eaf3e1SJohn Birrell 	switch (type) {
20991eaf3e1SJohn Birrell 	case MOD_LOAD:
21091eaf3e1SJohn Birrell 		break;
21191eaf3e1SJohn Birrell 
21291eaf3e1SJohn Birrell 	case MOD_UNLOAD:
21391eaf3e1SJohn Birrell 		break;
21491eaf3e1SJohn Birrell 
21591eaf3e1SJohn Birrell 	case MOD_SHUTDOWN:
21691eaf3e1SJohn Birrell 		break;
21791eaf3e1SJohn Birrell 
21891eaf3e1SJohn Birrell 	default:
21991eaf3e1SJohn Birrell 		error = EOPNOTSUPP;
22091eaf3e1SJohn Birrell 		break;
22191eaf3e1SJohn Birrell 
22291eaf3e1SJohn Birrell 	}
22391eaf3e1SJohn Birrell 
22491eaf3e1SJohn Birrell 	return (error);
22591eaf3e1SJohn Birrell }
22691eaf3e1SJohn Birrell 
22791eaf3e1SJohn Birrell static int
dtmalloc_open(struct cdev * dev __unused,int oflags __unused,int devtype __unused,struct thread * td __unused)22891eaf3e1SJohn Birrell dtmalloc_open(struct cdev *dev __unused, int oflags __unused, int devtype __unused, struct thread *td __unused)
22991eaf3e1SJohn Birrell {
23091eaf3e1SJohn Birrell 	return (0);
23191eaf3e1SJohn Birrell }
23291eaf3e1SJohn Birrell 
23391eaf3e1SJohn Birrell SYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL);
23491eaf3e1SJohn Birrell SYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL);
23591eaf3e1SJohn Birrell 
23691eaf3e1SJohn Birrell DEV_MODULE(dtmalloc, dtmalloc_modevent, NULL);
23791eaf3e1SJohn Birrell MODULE_VERSION(dtmalloc, 1);
23891eaf3e1SJohn Birrell MODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1);
23991eaf3e1SJohn Birrell MODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1);
240