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 [email protected]
22 *
23 */
24
25 #include <sys/cdefs.h>
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/conf.h>
29 #include <sys/ctype.h>
30 #include <sys/kernel.h>
31 #include <sys/malloc.h>
32 #include <sys/module.h>
33
34 #include <sys/dtrace.h>
35 #include <sys/dtrace_bsd.h>
36
37 extern bool dtrace_malloc_enabled;
38 static uint32_t dtrace_malloc_enabled_count;
39
40 static int dtmalloc_unload(void);
41 static void dtmalloc_getargdesc(void *, dtrace_id_t, void *, dtrace_argdesc_t *);
42 static void dtmalloc_provide(void *, dtrace_probedesc_t *);
43 static void dtmalloc_destroy(void *, dtrace_id_t, void *);
44 static void dtmalloc_enable(void *, dtrace_id_t, void *);
45 static void dtmalloc_disable(void *, dtrace_id_t, void *);
46 static void dtmalloc_load(void *);
47
48 static dtrace_pattr_t dtmalloc_attr = {
49 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
50 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
51 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
52 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
53 { DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
54 };
55
56 static dtrace_pops_t dtmalloc_pops = {
57 .dtps_provide = dtmalloc_provide,
58 .dtps_provide_module = NULL,
59 .dtps_enable = dtmalloc_enable,
60 .dtps_disable = dtmalloc_disable,
61 .dtps_suspend = NULL,
62 .dtps_resume = NULL,
63 .dtps_getargdesc = dtmalloc_getargdesc,
64 .dtps_getargval = NULL,
65 .dtps_usermode = NULL,
66 .dtps_destroy = dtmalloc_destroy
67 };
68
69 static dtrace_provider_id_t dtmalloc_id;
70
71 static void
dtmalloc_getargdesc(void * arg,dtrace_id_t id,void * parg,dtrace_argdesc_t * desc)72 dtmalloc_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
73 {
74 const char *p = NULL;
75
76 switch (desc->dtargd_ndx) {
77 case 0:
78 p = "struct malloc_type *";
79 break;
80 case 1:
81 p = "struct malloc_type_internal *";
82 break;
83 case 2:
84 p = "struct malloc_type_stats *";
85 break;
86 case 3:
87 p = "unsigned long";
88 break;
89 case 4:
90 p = "int";
91 break;
92 default:
93 desc->dtargd_ndx = DTRACE_ARGNONE;
94 break;
95 }
96
97 if (p != NULL)
98 strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
99
100 return;
101 }
102
103 static void
dtmalloc_type_cb(struct malloc_type * mtp,void * arg __unused)104 dtmalloc_type_cb(struct malloc_type *mtp, void *arg __unused)
105 {
106 char name[DTRACE_FUNCNAMELEN];
107 struct malloc_type_internal *mtip = &mtp->ks_mti;
108 int i;
109
110 /*
111 * malloc_type descriptions are allowed to contain whitespace, but
112 * DTrace probe identifiers are not, so replace the whitespace with
113 * underscores.
114 */
115 strlcpy(name, mtp->ks_shortdesc, sizeof(name));
116 for (i = 0; name[i] != 0; i++)
117 if (isspace(name[i]))
118 name[i] = '_';
119
120 if (dtrace_probe_lookup(dtmalloc_id, NULL, name, "malloc") != 0)
121 return;
122
123 (void) dtrace_probe_create(dtmalloc_id, NULL, name, "malloc", 0,
124 &mtip->mti_probes[DTMALLOC_PROBE_MALLOC]);
125 (void) dtrace_probe_create(dtmalloc_id, NULL, name, "free", 0,
126 &mtip->mti_probes[DTMALLOC_PROBE_FREE]);
127 }
128
129 static void
dtmalloc_provide(void * arg,dtrace_probedesc_t * desc)130 dtmalloc_provide(void *arg, dtrace_probedesc_t *desc)
131 {
132 if (desc != NULL)
133 return;
134
135 malloc_type_list(dtmalloc_type_cb, desc);
136 }
137
138 static void
dtmalloc_destroy(void * arg,dtrace_id_t id,void * parg)139 dtmalloc_destroy(void *arg, dtrace_id_t id, void *parg)
140 {
141 }
142
143 static void
dtmalloc_enable(void * arg,dtrace_id_t id,void * parg)144 dtmalloc_enable(void *arg, dtrace_id_t id, void *parg)
145 {
146 uint32_t *p = parg;
147 *p = id;
148 dtrace_malloc_enabled_count++;
149 if (dtrace_malloc_enabled_count == 1)
150 dtrace_malloc_enabled = true;
151 }
152
153 static void
dtmalloc_disable(void * arg,dtrace_id_t id,void * parg)154 dtmalloc_disable(void *arg, dtrace_id_t id, void *parg)
155 {
156 uint32_t *p = parg;
157 *p = 0;
158 dtrace_malloc_enabled_count--;
159 if (dtrace_malloc_enabled_count == 0)
160 dtrace_malloc_enabled = false;
161 }
162
163 static void
dtmalloc_load(void * dummy)164 dtmalloc_load(void *dummy)
165 {
166 if (dtrace_register("dtmalloc", &dtmalloc_attr, DTRACE_PRIV_USER,
167 NULL, &dtmalloc_pops, NULL, &dtmalloc_id) != 0)
168 return;
169
170 dtrace_malloc_probe = dtrace_probe;
171 }
172
173
174 static int
dtmalloc_unload(void)175 dtmalloc_unload(void)
176 {
177 int error = 0;
178
179 dtrace_malloc_probe = NULL;
180
181 if ((error = dtrace_unregister(dtmalloc_id)) != 0)
182 return (error);
183
184 return (error);
185 }
186
187 static int
dtmalloc_modevent(module_t mod __unused,int type,void * data __unused)188 dtmalloc_modevent(module_t mod __unused, int type, void *data __unused)
189 {
190 int error = 0;
191
192 switch (type) {
193 case MOD_LOAD:
194 break;
195
196 case MOD_UNLOAD:
197 break;
198
199 case MOD_SHUTDOWN:
200 break;
201
202 default:
203 error = EOPNOTSUPP;
204 break;
205
206 }
207
208 return (error);
209 }
210
211 SYSINIT(dtmalloc_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_load, NULL);
212 SYSUNINIT(dtmalloc_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY, dtmalloc_unload, NULL);
213
214 DEV_MODULE(dtmalloc, dtmalloc_modevent, NULL);
215 MODULE_VERSION(dtmalloc, 1);
216 MODULE_DEPEND(dtmalloc, dtrace, 1, 1, 1);
217 MODULE_DEPEND(dtmalloc, opensolaris, 1, 1, 1);
218