xref: /freebsd/sys/cddl/dev/dtmalloc/dtmalloc.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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