dis: use libdemangle-sys for symbol demangling
[unleashed.git] / usr / src / cmd / mdb / common / mdb / mdb_demangle.cc
blobc42f98aa55349cf920076f647c34e4b85cebf583
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <mdb/mdb_modapi.h>
28 #include <mdb/mdb_demangle.h>
29 #include <mdb/mdb_err.h>
30 #include <mdb/mdb.h>
32 #include <cxxabi.h>
33 #include <strings.h>
34 #include <unistd.h>
35 #include <dlfcn.h>
36 #include <link.h>
38 #define LIB_DEMANGLE "libstdc++.so.6"
40 mdb_demangler_t *
41 mdb_dem_load(const char *path)
43 mdb_demangler_t *dmp;
44 void *hdl, *func;
46 if ((hdl = dlmopen(LM_ID_BASE, path, RTLD_LAZY | RTLD_LOCAL)) == NULL) {
47 (void) set_errno(EMDB_RTLD);
48 return (NULL);
51 if ((func = dlsym(hdl, "__cxa_demangle")) == NULL) {
52 (void) dlclose(hdl);
53 (void) set_errno(EMDB_NODEM);
54 return (NULL);
57 dmp = (mdb_demangler_t *)mdb_alloc(sizeof (mdb_demangler_t), UM_SLEEP);
58 (void) strncpy(dmp->dm_pathname, path, MAXPATHLEN);
59 dmp->dm_pathname[MAXPATHLEN - 1] = '\0';
60 dmp->dm_handle = hdl;
61 dmp->dm_convert = (char *(*)(const char *, char *, size_t *, int *))
62 func;
63 dmp->dm_len = MDB_SYM_NAMLEN * 2;
64 dmp->dm_buf = (char *)mdb_alloc(dmp->dm_len, UM_SLEEP);
65 dmp->dm_flags = MDB_DM_SCOPE;
67 return (dmp);
70 void
71 mdb_dem_unload(mdb_demangler_t *dmp)
73 (void) dlclose(dmp->dm_handle);
74 mdb_free(dmp->dm_buf, dmp->dm_len);
75 mdb_free(dmp, sizeof (mdb_demangler_t));
78 static const char *
79 mdb_dem_filter(mdb_demangler_t *dmp, const char *name)
81 static const char s_pref[] = "static ";
82 static const char c_suff[] = " const";
83 static const char v_suff[] = " volatile";
86 * We process dm_dem, which skips the prefix in dm_buf (if any)
88 size_t len = strlen(dmp->dm_dem);
89 char *end = dmp->dm_dem + len;
90 size_t resid;
93 * If static, const, and volatile qualifiers should not be displayed,
94 * rip all of them out of dmp->dm_dem.
96 if (!(dmp->dm_flags & MDB_DM_QUAL)) {
97 if (strncmp(dmp->dm_dem, s_pref, sizeof (s_pref) - 1) == 0) {
98 bcopy(dmp->dm_dem + sizeof (s_pref) - 1, dmp->dm_dem,
99 len - (sizeof (s_pref) - 1) + 1);
100 end -= sizeof (s_pref) - 1;
101 len -= sizeof (s_pref) - 1;
104 for (;;) {
105 if (len > sizeof (c_suff) - 1 &&
106 strcmp(end - (sizeof (c_suff) - 1), c_suff) == 0) {
107 end -= sizeof (c_suff) - 1;
108 len -= sizeof (c_suff) - 1;
109 *end = '\0';
110 continue;
112 if (len > sizeof (v_suff) - 1 &&
113 strcmp(end - (sizeof (v_suff) - 1), v_suff) == 0) {
114 end -= sizeof (v_suff) - 1;
115 len -= sizeof (v_suff) - 1;
116 *end = '\0';
117 continue;
119 break;
124 * If function arguments should not be displayed, remove everything
125 * between the outermost set of parentheses in dmp->dm_dem.
127 if (!(dmp->dm_flags & MDB_DM_FUNCARG)) {
128 char *lp = strchr(dmp->dm_dem, '(');
129 char *rp = strrchr(dmp->dm_dem, ')');
131 if (lp != NULL && rp != NULL)
132 bcopy(rp + 1, lp, strlen(rp) + 1);
136 * If function scope specifiers should not be displayed, remove text
137 * from the leftmost space to the rightmost colon prior to any paren.
139 if (!(dmp->dm_flags & MDB_DM_SCOPE)) {
140 char *c, *s, *lp = strchr(dmp->dm_dem, '(');
142 if (lp != NULL)
143 *lp = '\0';
145 c = strrchr(dmp->dm_dem, ':');
146 s = strchr(dmp->dm_dem, ' ');
148 if (lp != NULL)
149 *lp = '(';
151 if (c != NULL) {
152 if (s == NULL || s > c)
153 bcopy(c + 1, dmp->dm_dem, strlen(c + 1) + 1);
154 else
155 bcopy(c + 1, s + 1, strlen(c + 1) + 1);
159 len = strlen(dmp->dm_dem); /* recompute length of buffer */
162 * Compute bytes remaining
164 resid = (dmp->dm_buf + dmp->dm_len) - (dmp->dm_dem + len);
167 * If we want to append the mangled name as well and there is enough
168 * space for "[]\0" and at least one character, append "["+name+"]".
170 if ((dmp->dm_flags & MDB_DM_MANGLED) && resid > 3) {
171 char *p = dmp->dm_dem + len;
173 *p++ = '[';
174 (void) strncpy(p, name, resid - 3);
175 p[resid - 3] = '\0';
176 p += strlen(p);
177 (void) strcpy(p, "]");
181 * We return the whole string
183 return (dmp->dm_buf);
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.
194 static int
195 mdb_dem_process(mdb_demangler_t *dmp, const char *name)
197 char *buf = dmp->dm_buf;
198 size_t len = dmp->dm_len;
200 const char *prefix = strrchr(name, '`');
201 size_t prefixlen;
202 int ret;
204 if (prefix) {
205 prefix++; /* the ` is part of the prefix */
206 prefixlen = prefix - name;
208 if (prefixlen >= len)
209 return (-1);
211 (void) strncpy(buf, name, prefixlen);
214 * Fix up the arguments to dmp->dm_convert()
216 name += prefixlen;
217 buf += prefixlen;
218 len -= prefixlen;
222 * Save the position of the demangled string for mdb_dem_filter()
224 dmp->dm_dem = buf;
226 dmp->dm_convert(name, buf, &len, &ret);
227 return (ret);
230 const char *
231 mdb_dem_convert(mdb_demangler_t *dmp, const char *name)
233 int err;
235 while ((err = mdb_dem_process(dmp, name)) == -1) {
236 size_t len = dmp->dm_len * 2;
237 char *buf = (char *)mdb_alloc(len, UM_NOSLEEP);
239 if (buf == NULL) {
240 mdb_warn("failed to allocate memory for demangling");
241 return (name); /* just return original name */
244 mdb_free(dmp->dm_buf, dmp->dm_len);
245 dmp->dm_buf = buf;
246 dmp->dm_len = len;
249 if (err != 0 || strcmp(dmp->dm_buf, name) == 0)
250 return (name); /* return original name if not mangled */
252 return (mdb_dem_filter(dmp, name));
255 /*ARGSUSED*/
257 cmd_demangle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
259 mdb_demangler_t *dmp = mdb.m_demangler;
260 const char *path = LIB_DEMANGLE;
262 if (argc > 1 || (argc > 0 && argv->a_type != MDB_TYPE_STRING))
263 return (DCMD_USAGE);
265 if (argc > 0) {
266 if (dmp != NULL)
267 mdb_dem_unload(mdb.m_demangler);
268 path = argv->a_un.a_str;
271 if (dmp != NULL && argc == 0 && !(mdb.m_flags & MDB_FL_DEMANGLE)) {
272 mdb_printf("C++ symbol demangling enabled\n");
273 mdb.m_flags |= MDB_FL_DEMANGLE;
275 } else if (dmp == NULL || argc > 0) {
276 if ((mdb.m_demangler = mdb_dem_load(path)) != NULL) {
277 mdb_printf("C++ symbol demangling enabled\n");
278 mdb.m_flags |= MDB_FL_DEMANGLE;
279 } else {
280 mdb_warn("failed to load C++ demangler %s", path);
281 mdb.m_flags &= ~MDB_FL_DEMANGLE;
284 } else {
285 mdb_dem_unload(mdb.m_demangler);
286 mdb.m_flags &= ~MDB_FL_DEMANGLE;
287 mdb.m_demangler = NULL;
288 mdb_printf("C++ symbol demangling disabled\n");
291 return (DCMD_OK);
294 /*ARGSUSED*/
296 cmd_demflags(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
298 static const char *const dm_desc[] = {
299 "static/const/volatile member func qualifiers displayed",
300 "scope resolution specifiers displayed",
301 "function arguments displayed",
302 "mangled name displayed"
305 mdb_demangler_t *dmp = mdb.m_demangler;
306 int i;
308 if (argc > 0)
309 return (DCMD_USAGE);
311 if (dmp == NULL || !(mdb.m_flags & MDB_FL_DEMANGLE)) {
312 mdb_warn("C++ demangling facility is currently disabled\n");
313 return (DCMD_ERR);
316 if (flags & DCMD_ADDRSPEC)
317 dmp->dm_flags = ((uint_t)addr & MDB_DM_ALL);
319 for (i = 0; i < sizeof (dm_desc) / sizeof (dm_desc[0]); i++) {
320 mdb_printf("0x%x\t%s\t%s\n", 1 << i,
321 (dmp->dm_flags & (1 << i)) ? "on" : "off", dm_desc[i]);
324 return (DCMD_OK);
327 /*ARGSUSED*/
329 cmd_demstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
331 if ((flags & DCMD_ADDRSPEC) || argc == 0)
332 return (DCMD_USAGE);
334 if (mdb.m_demangler == NULL && (mdb.m_demangler =
335 mdb_dem_load(LIB_DEMANGLE)) == NULL) {
336 mdb_warn("failed to load C++ demangler " LIB_DEMANGLE);
337 return (DCMD_ERR);
340 for (; argc != 0; argc--, argv++) {
341 mdb_printf("%s == %s\n", argv->a_un.a_str,
342 mdb_dem_convert(mdb.m_demangler, argv->a_un.a_str));
345 return (DCMD_OK);