5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_demangle.h>
31 #include <mdb/mdb_err.h>
32 #include <mdb/mdb.h>
33
34 #include <demangle.h>
35 #include <strings.h>
36 #include <unistd.h>
37 #include <dlfcn.h>
38 #include <link.h>
39
40 #ifdef _LP64
41 static const char LIB_DEMANGLE[] = "/usr/lib/64/libdemangle.so.1";
42 #else
43 static const char LIB_DEMANGLE[] = "/usr/lib/libdemangle.so.1";
44 #endif
45
46 mdb_demangler_t *
47 mdb_dem_load(const char *path)
48 {
49 mdb_demangler_t *dmp;
50 void *hdl, *func;
51
52 if (access(path, F_OK) == -1)
53 return (NULL);
54
55 if ((hdl = dlmopen(LM_ID_BASE, path, RTLD_LAZY | RTLD_LOCAL)) == NULL) {
56 (void) set_errno(EMDB_RTLD);
57 return (NULL);
58 }
59
60 if ((func = dlsym(hdl, "cplus_demangle")) == NULL) {
61 (void) dlclose(hdl);
62 (void) set_errno(EMDB_NODEM);
63 return (NULL);
64 }
65
66 dmp = mdb_alloc(sizeof (mdb_demangler_t), UM_SLEEP);
67 (void) strncpy(dmp->dm_pathname, path, MAXPATHLEN);
68 dmp->dm_pathname[MAXPATHLEN - 1] = '\0';
69 dmp->dm_handle = hdl;
70 dmp->dm_convert = (int (*)())func;
71 dmp->dm_len = MDB_SYM_NAMLEN * 2;
72 dmp->dm_buf = mdb_alloc(dmp->dm_len, UM_SLEEP);
73 dmp->dm_flags = MDB_DM_SCOPE;
74
75 return (dmp);
76 }
77
78 void
79 mdb_dem_unload(mdb_demangler_t *dmp)
80 {
81 (void) dlclose(dmp->dm_handle);
82 mdb_free(dmp->dm_buf, dmp->dm_len);
83 mdb_free(dmp, sizeof (mdb_demangler_t));
84 }
85
86 static const char *
87 mdb_dem_filter(mdb_demangler_t *dmp, const char *name)
88 {
89 static const char s_pref[] = "static ";
90 static const char c_suff[] = " const";
91 static const char v_suff[] = " volatile";
92
93 /*
94 * We process dm_dem, which skips the prefix in dm_buf (if any)
95 */
96 size_t len = strlen(dmp->dm_dem);
97 char *end = dmp->dm_dem + len;
98 size_t resid;
99
100 /*
101 * If static, const, and volatile qualifiers should not be displayed,
185 (void) strcpy(p, "]");
186 }
187
188 /*
189 * We return the whole string
190 */
191 return (dmp->dm_buf);
192 }
193
194 /*
195 * Take a name: (the foo`bar` is optional)
196 * foo`bar`__mangled_
197 * and put:
198 * foo`bar`demangled
199 * into dmp->dm_buf. Point dmp->dm_dem to the beginning of the
200 * demangled section of the result.
201 */
202 static int
203 mdb_dem_process(mdb_demangler_t *dmp, const char *name)
204 {
205 char *buf = dmp->dm_buf;
206 size_t len = dmp->dm_len;
207
208 char *prefix = strrchr(name, '`');
209 size_t prefixlen;
210
211 if (prefix) {
212 prefix++; /* the ` is part of the prefix */
213 prefixlen = prefix - name;
214
215 if (prefixlen >= len)
216 return (DEMANGLE_ESPACE);
217
218 (void) strncpy(buf, name, prefixlen);
219
220 /*
221 * Fix up the arguments to dmp->dm_convert()
222 */
223 name += prefixlen;
224 buf += prefixlen;
225 len -= prefixlen;
226 }
227
228 /*
229 * Save the position of the demangled string for mdb_dem_filter()
230 */
231 dmp->dm_dem = buf;
232
233 return (dmp->dm_convert(name, buf, len));
234 }
235
236 const char *
237 mdb_dem_convert(mdb_demangler_t *dmp, const char *name)
238 {
239 int err;
240
241 while ((err = mdb_dem_process(dmp, name)) == DEMANGLE_ESPACE) {
242 size_t len = dmp->dm_len * 2;
243 char *buf = mdb_alloc(len, UM_NOSLEEP);
244
245 if (buf == NULL) {
246 mdb_warn("failed to allocate memory for demangling");
247 return (name); /* just return original name */
248 }
249
250 mdb_free(dmp->dm_buf, dmp->dm_len);
251 dmp->dm_buf = buf;
252 dmp->dm_len = len;
253 }
254
255 if (err != 0 || strcmp(dmp->dm_buf, name) == 0)
256 return (name); /* return original name if not mangled */
257
258 return (mdb_dem_filter(dmp, name));
259 }
260
261 /*ARGSUSED*/
262 int
263 cmd_demangle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
264 {
265 mdb_demangler_t *dmp = mdb.m_demangler;
266 const char *path = LIB_DEMANGLE;
267
268 if (argc > 1 || (argc > 0 && argv->a_type != MDB_TYPE_STRING))
269 return (DCMD_USAGE);
270
271 if (argc > 0) {
272 if (dmp != NULL)
273 mdb_dem_unload(mdb.m_demangler);
274 path = argv->a_un.a_str;
275 }
276
277 if (dmp != NULL && argc == 0 && !(mdb.m_flags & MDB_FL_DEMANGLE)) {
278 mdb_printf("C++ symbol demangling enabled\n");
279 mdb.m_flags |= MDB_FL_DEMANGLE;
280
281 } else if (dmp == NULL || argc > 0) {
282 if ((mdb.m_demangler = mdb_dem_load(path)) != NULL) {
283 mdb_printf("C++ symbol demangling enabled\n");
284 mdb.m_flags |= MDB_FL_DEMANGLE;
285 } else {
286 mdb_warn("failed to load C++ demangler %s", path);
287 mdb.m_flags &= ~MDB_FL_DEMANGLE;
288 }
289
290 } else {
291 mdb_dem_unload(mdb.m_demangler);
292 mdb.m_flags &= ~MDB_FL_DEMANGLE;
293 mdb.m_demangler = NULL;
294 mdb_printf("C++ symbol demangling disabled\n");
295 }
296
297 return (DCMD_OK);
298 }
299
300 /*ARGSUSED*/
301 int
302 cmd_demflags(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
303 {
304 static const char *const dm_desc[] = {
305 "static/const/volatile member func qualifiers displayed",
306 "scope resolution specifiers displayed",
321
322 if (flags & DCMD_ADDRSPEC)
323 dmp->dm_flags = ((uint_t)addr & MDB_DM_ALL);
324
325 for (i = 0; i < sizeof (dm_desc) / sizeof (dm_desc[0]); i++) {
326 mdb_printf("0x%x\t%s\t%s\n", 1 << i,
327 (dmp->dm_flags & (1 << i)) ? "on" : "off", dm_desc[i]);
328 }
329
330 return (DCMD_OK);
331 }
332
333 /*ARGSUSED*/
334 int
335 cmd_demstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
336 {
337 if ((flags & DCMD_ADDRSPEC) || argc == 0)
338 return (DCMD_USAGE);
339
340 if (mdb.m_demangler == NULL && (mdb.m_demangler =
341 mdb_dem_load(LIB_DEMANGLE)) == NULL) {
342 mdb_warn("failed to load C++ demangler %s", LIB_DEMANGLE);
343 return (DCMD_ERR);
344 }
345
346 for (; argc != 0; argc--, argv++) {
347 mdb_printf("%s == %s\n", argv->a_un.a_str,
348 mdb_dem_convert(mdb.m_demangler, argv->a_un.a_str));
349 }
350
351 return (DCMD_OK);
352 }
|
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * Copyright 2018 Jason King
27 */
28
29 #include <mdb/mdb_modapi.h>
30 #include <mdb/mdb_demangle.h>
31 #include <mdb/mdb_err.h>
32 #include <mdb/mdb.h>
33
34 #include <strings.h>
35 #include <unistd.h>
36 #include <dlfcn.h>
37 #include <link.h>
38
39 static void *
40 mdb_dem_alloc(size_t len)
41 {
42 return (mdb_alloc(len, UM_SLEEP));
43 }
44
45 static void
46 mdb_dem_free(void *p, size_t len)
47 {
48 mdb_free(p, len);
49 }
50
51 static sysdem_ops_t mdb_dem_demops = {
52 .alloc = mdb_dem_alloc,
53 .free = mdb_dem_free
54 };
55
56 mdb_demangler_t *
57 mdb_dem_load(void)
58 {
59 mdb_demangler_t *dmp;
60
61 dmp = mdb_alloc(sizeof (mdb_demangler_t), UM_SLEEP);
62 dmp->dm_len = 0;
63 dmp->dm_buf = NULL;
64 dmp->dm_flags = MDB_DM_SCOPE;
65 /* stick with C++ for now to match old behavior */
66 dmp->dm_lang = SYSDEM_LANG_CPP;
67
68 return (dmp);
69 }
70
71 void
72 mdb_dem_unload(mdb_demangler_t *dmp)
73 {
74 mdb_free(dmp->dm_buf, dmp->dm_len);
75 mdb_free(dmp, sizeof (mdb_demangler_t));
76 }
77
78 static const char *
79 mdb_dem_filter(mdb_demangler_t *dmp, const char *name)
80 {
81 static const char s_pref[] = "static ";
82 static const char c_suff[] = " const";
83 static const char v_suff[] = " volatile";
84
85 /*
86 * We process dm_dem, which skips the prefix in dm_buf (if any)
87 */
88 size_t len = strlen(dmp->dm_dem);
89 char *end = dmp->dm_dem + len;
90 size_t resid;
91
92 /*
93 * If static, const, and volatile qualifiers should not be displayed,
177 (void) strcpy(p, "]");
178 }
179
180 /*
181 * We return the whole string
182 */
183 return (dmp->dm_buf);
184 }
185
186 /*
187 * Take a name: (the foo`bar` is optional)
188 * foo`bar`__mangled_
189 * and put:
190 * foo`bar`demangled
191 * into dmp->dm_buf. Point dmp->dm_dem to the beginning of the
192 * demangled section of the result.
193 */
194 static int
195 mdb_dem_process(mdb_demangler_t *dmp, const char *name)
196 {
197 char *res = NULL;
198 size_t reslen = 0;
199
200 char *prefix = strrchr(name, '`');
201 size_t prefixlen = 0;
202
203 if (prefix) {
204 prefix++; /* the ` is part of the prefix */
205 prefixlen = prefix - name;
206 }
207
208 res = sysdemangle(name + prefixlen, dmp->dm_lang, &mdb_dem_demops);
209 if (res == NULL) {
210 if (errno != EINVAL)
211 mdb_warn("Error while demangling");
212 return (-1);
213 }
214
215 reslen = (res != NULL) ? strlen(res) : 0;
216 reslen += prefixlen;
217 reslen += 1;
218
219 if (reslen > dmp->dm_len) {
220 mdb_free(dmp->dm_buf, dmp->dm_len);
221
222 dmp->dm_buf = mdb_zalloc(reslen, UM_SLEEP);
223 if (dmp->dm_buf == NULL) {
224 dmp->dm_len = 0;
225 mdb_warn("Unable to allocate memory for demangling");
226 return (-1);
227 }
228 dmp->dm_len = reslen;
229 }
230
231 if (prefixlen > 0)
232 (void) strlcpy(dmp->dm_buf, name, prefixlen + 1);
233 else
234 *dmp->dm_buf = '\0';
235
236 if (res != NULL) {
237 (void) strlcat(dmp->dm_buf, res, dmp->dm_len);
238 mdb_dem_free(res, strlen(res) + 1);
239 }
240
241 /*
242 * Save the position of the demangled string for mdb_dem_filter()
243 */
244 dmp->dm_dem = dmp->dm_buf + prefixlen;
245
246 return (0);
247 }
248
249 /* used by mdb_io.c:iob_addr2str */
250 const char *
251 mdb_dem_convert(mdb_demangler_t *dmp, const char *name)
252 {
253 if (mdb_dem_process(dmp, name) != 0 ||
254 strcmp(dmp->dm_buf, name) == 0)
255 return (name);
256
257 return (mdb_dem_filter(dmp, name));
258 }
259
260 /*ARGSUSED*/
261 int
262 cmd_demangle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
263 {
264 mdb_demangler_t *dmp = mdb.m_demangler;
265
266 if (argc > 0)
267 return (DCMD_USAGE);
268
269 if (dmp != NULL && !(mdb.m_flags & MDB_FL_DEMANGLE)) {
270 mdb_printf("C++ symbol demangling enabled\n");
271 mdb.m_flags |= MDB_FL_DEMANGLE;
272
273 } else if (dmp == NULL) {
274 if ((mdb.m_demangler = mdb_dem_load()) != NULL) {
275 mdb_printf("C++ symbol demangling enabled\n");
276 mdb.m_flags |= MDB_FL_DEMANGLE;
277 } else {
278 mdb_warn("no memory to load C++ demangler");
279 mdb.m_flags &= ~MDB_FL_DEMANGLE;
280 }
281
282 } else {
283 mdb_dem_unload(mdb.m_demangler);
284 mdb.m_flags &= ~MDB_FL_DEMANGLE;
285 mdb.m_demangler = NULL;
286 mdb_printf("C++ symbol demangling disabled\n");
287 }
288
289 return (DCMD_OK);
290 }
291
292 /*ARGSUSED*/
293 int
294 cmd_demflags(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
295 {
296 static const char *const dm_desc[] = {
297 "static/const/volatile member func qualifiers displayed",
298 "scope resolution specifiers displayed",
313
314 if (flags & DCMD_ADDRSPEC)
315 dmp->dm_flags = ((uint_t)addr & MDB_DM_ALL);
316
317 for (i = 0; i < sizeof (dm_desc) / sizeof (dm_desc[0]); i++) {
318 mdb_printf("0x%x\t%s\t%s\n", 1 << i,
319 (dmp->dm_flags & (1 << i)) ? "on" : "off", dm_desc[i]);
320 }
321
322 return (DCMD_OK);
323 }
324
325 /*ARGSUSED*/
326 int
327 cmd_demstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
328 {
329 if ((flags & DCMD_ADDRSPEC) || argc == 0)
330 return (DCMD_USAGE);
331
332 if (mdb.m_demangler == NULL && (mdb.m_demangler =
333 mdb_dem_load()) == NULL) {
334 mdb_warn("failed to load demangler");
335 return (DCMD_ERR);
336 }
337
338 for (; argc != 0; argc--, argv++) {
339 mdb_printf("%s == %s\n", argv->a_un.a_str,
340 mdb_dem_convert(mdb.m_demangler, argv->a_un.a_str));
341 }
342
343 return (DCMD_OK);
344 }
|