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, 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 2017 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 <demangle.h> 35 #include <strings.h> 36 #include <unistd.h> 37 #include <dlfcn.h> 38 #include <link.h> 39 #include <sysdemangle.h> 40 41 static void * 42 mdb_dem_alloc(size_t len) 43 { 44 return (mdb_alloc(len, UM_SLEEP)); 45 } 46 47 static void 48 mdb_dem_free(void *p, size_t len) 49 { 50 mdb_free(p, len); 51 } 52 53 static sysdem_ops_t mdb_dem_demops = { 54 .alloc = mdb_dem_alloc, 55 .free = mdb_dem_free 56 }; 57 58 mdb_demangler_t * 59 mdb_dem_load(void) 60 { 61 mdb_demangler_t *dmp; 62 63 dmp = mdb_alloc(sizeof (mdb_demangler_t), UM_SLEEP); 64 dmp->dm_len = 0; 65 dmp->dm_buf = NULL; 66 dmp->dm_flags = MDB_DM_SCOPE; 67 /* stick with C++ for now to match old behavior */ 68 dmp->dm_lang = SYSDEM_LANG_CPP; 69 70 return (dmp); 71 } 72 73 void 74 mdb_dem_unload(mdb_demangler_t *dmp) 75 { 76 mdb_free(dmp->dm_buf, dmp->dm_len); 77 mdb_free(dmp, sizeof (mdb_demangler_t)); 78 } 79 80 static const char * 81 mdb_dem_filter(mdb_demangler_t *dmp, const char *name) 82 { 83 static const char s_pref[] = "static "; 84 static const char c_suff[] = " const"; 85 static const char v_suff[] = " volatile"; 86 87 /* 88 * We process dm_dem, which skips the prefix in dm_buf (if any) 89 */ 90 size_t len = strlen(dmp->dm_dem); 91 char *end = dmp->dm_dem + len; 92 size_t resid; 93 94 /* 95 * If static, const, and volatile qualifiers should not be displayed, 96 * rip all of them out of dmp->dm_dem. 97 */ 98 if (!(dmp->dm_flags & MDB_DM_QUAL)) { 99 if (strncmp(dmp->dm_dem, s_pref, sizeof (s_pref) - 1) == 0) { 100 bcopy(dmp->dm_dem + sizeof (s_pref) - 1, dmp->dm_dem, 101 len - (sizeof (s_pref) - 1) + 1); 102 end -= sizeof (s_pref) - 1; 103 len -= sizeof (s_pref) - 1; 104 } 105 106 for (;;) { 107 if (len > sizeof (c_suff) - 1 && 108 strcmp(end - (sizeof (c_suff) - 1), c_suff) == 0) { 109 end -= sizeof (c_suff) - 1; 110 len -= sizeof (c_suff) - 1; 111 *end = '\0'; 112 continue; 113 } 114 if (len > sizeof (v_suff) - 1 && 115 strcmp(end - (sizeof (v_suff) - 1), v_suff) == 0) { 116 end -= sizeof (v_suff) - 1; 117 len -= sizeof (v_suff) - 1; 118 *end = '\0'; 119 continue; 120 } 121 break; 122 } 123 } 124 125 /* 126 * If function arguments should not be displayed, remove everything 127 * between the outermost set of parentheses in dmp->dm_dem. 128 */ 129 if (!(dmp->dm_flags & MDB_DM_FUNCARG)) { 130 char *lp = strchr(dmp->dm_dem, '('); 131 char *rp = strrchr(dmp->dm_dem, ')'); 132 133 if (lp != NULL && rp != NULL) 134 bcopy(rp + 1, lp, strlen(rp) + 1); 135 } 136 137 /* 138 * If function scope specifiers should not be displayed, remove text 139 * from the leftmost space to the rightmost colon prior to any paren. 140 */ 141 if (!(dmp->dm_flags & MDB_DM_SCOPE)) { 142 char *c, *s, *lp = strchr(dmp->dm_dem, '('); 143 144 if (lp != NULL) 145 *lp = '\0'; 146 147 c = strrchr(dmp->dm_dem, ':'); 148 s = strchr(dmp->dm_dem, ' '); 149 150 if (lp != NULL) 151 *lp = '('; 152 153 if (c != NULL) { 154 if (s == NULL || s > c) 155 bcopy(c + 1, dmp->dm_dem, strlen(c + 1) + 1); 156 else 157 bcopy(c + 1, s + 1, strlen(c + 1) + 1); 158 } 159 } 160 161 len = strlen(dmp->dm_dem); /* recompute length of buffer */ 162 163 /* 164 * Compute bytes remaining 165 */ 166 resid = (dmp->dm_buf + dmp->dm_len) - (dmp->dm_dem + len); 167 168 /* 169 * If we want to append the mangled name as well and there is enough 170 * space for "[]\0" and at least one character, append "["+name+"]". 171 */ 172 if ((dmp->dm_flags & MDB_DM_MANGLED) && resid > 3) { 173 char *p = dmp->dm_dem + len; 174 175 *p++ = '['; 176 (void) strncpy(p, name, resid - 3); 177 p[resid - 3] = '\0'; 178 p += strlen(p); 179 (void) strcpy(p, "]"); 180 } 181 182 /* 183 * We return the whole string 184 */ 185 return (dmp->dm_buf); 186 } 187 188 /* 189 * Take a name: (the foo`bar` is optional) 190 * foo`bar`__mangled_ 191 * and put: 192 * foo`bar`demangled 193 * into dmp->dm_buf. Point dmp->dm_dem to the beginning of the 194 * demangled section of the result. 195 */ 196 static int 197 mdb_dem_process(mdb_demangler_t *dmp, const char *name) 198 { 199 char *res = NULL; 200 size_t reslen = 0; 201 202 char *prefix = strrchr(name, '`'); 203 size_t prefixlen = 0; 204 205 if (prefix) { 206 prefix++; /* the ` is part of the prefix */ 207 prefixlen = prefix - name; 208 } 209 210 res = sysdemangle(name + prefixlen, dmp->dm_lang, &mdb_dem_demops); 211 if (res == NULL && errno != EINVAL) 212 mdb_warn("Error while demangling"); 213 214 reslen = (res != NULL) ? strlen(res) : 0; 215 reslen += prefixlen; 216 reslen += 1; 217 218 if (reslen > dmp->dm_len) { 219 mdb_free(dmp->dm_buf, dmp->dm_len); 220 221 dmp->dm_buf = mdb_zalloc(reslen, UM_SLEEP); 222 if (dmp->dm_buf == NULL) { 223 dmp->dm_len = 0; 224 mdb_warn("Unable to allocate memory for demangling"); 225 return (-1); 226 } 227 dmp->dm_len = reslen; 228 } 229 230 if (prefixlen > 0) 231 (void) strlcpy(dmp->dm_buf, name, prefixlen); 232 if (res != NULL) 233 (void) strlcat(dmp->dm_buf, res, dmp->dm_len); 234 235 /* 236 * Save the position of the demangled string for mdb_dem_filter() 237 */ 238 dmp->dm_dem = dmp->dm_buf + prefixlen; 239 240 return (0); 241 } 242 243 /* used by mdb_io.c:iob_addr2str */ 244 const char * 245 mdb_dem_convert(mdb_demangler_t *dmp, const char *name) 246 { 247 if (mdb_dem_process(dmp, name) != 0 || 248 strcmp(dmp->dm_buf, name) == 0) 249 return (name); 250 251 return (mdb_dem_filter(dmp, name)); 252 } 253 254 /*ARGSUSED*/ 255 int 256 cmd_demangle(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 257 { 258 mdb_demangler_t *dmp = mdb.m_demangler; 259 260 if (argc > 0) 261 return (DCMD_USAGE); 262 263 if (dmp != NULL && !(mdb.m_flags & MDB_FL_DEMANGLE)) { 264 mdb_printf("C++ symbol demangling enabled\n"); 265 mdb.m_flags |= MDB_FL_DEMANGLE; 266 267 } else if (dmp == NULL) { 268 if ((mdb.m_demangler = mdb_dem_load()) != NULL) { 269 mdb_printf("C++ symbol demangling enabled\n"); 270 mdb.m_flags |= MDB_FL_DEMANGLE; 271 } else { 272 mdb_warn("no memory to load C++ demangler"); 273 mdb.m_flags &= ~MDB_FL_DEMANGLE; 274 } 275 276 } else { 277 mdb_dem_unload(mdb.m_demangler); 278 mdb.m_flags &= ~MDB_FL_DEMANGLE; 279 mdb.m_demangler = NULL; 280 mdb_printf("C++ symbol demangling disabled\n"); 281 } 282 283 return (DCMD_OK); 284 } 285 286 /*ARGSUSED*/ 287 int 288 cmd_demflags(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 289 { 290 static const char *const dm_desc[] = { 291 "static/const/volatile member func qualifiers displayed", 292 "scope resolution specifiers displayed", 293 "function arguments displayed", 294 "mangled name displayed" 295 }; 296 297 mdb_demangler_t *dmp = mdb.m_demangler; 298 int i; 299 300 if (argc > 0) 301 return (DCMD_USAGE); 302 303 if (dmp == NULL || !(mdb.m_flags & MDB_FL_DEMANGLE)) { 304 mdb_warn("C++ demangling facility is currently disabled\n"); 305 return (DCMD_ERR); 306 } 307 308 if (flags & DCMD_ADDRSPEC) 309 dmp->dm_flags = ((uint_t)addr & MDB_DM_ALL); 310 311 for (i = 0; i < sizeof (dm_desc) / sizeof (dm_desc[0]); i++) { 312 mdb_printf("0x%x\t%s\t%s\n", 1 << i, 313 (dmp->dm_flags & (1 << i)) ? "on" : "off", dm_desc[i]); 314 } 315 316 return (DCMD_OK); 317 } 318 319 /*ARGSUSED*/ 320 int 321 cmd_demstr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 322 { 323 if ((flags & DCMD_ADDRSPEC) || argc == 0) 324 return (DCMD_USAGE); 325 326 for (; argc != 0; argc--, argv++) { 327 mdb_printf("%s == %s\n", argv->a_un.a_str, 328 mdb_dem_convert(mdb.m_demangler, argv->a_un.a_str)); 329 } 330 331 return (DCMD_OK); 332 }