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