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 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, 94 * rip all of them out of dmp->dm_dem. 95 */ 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; 102 } 103 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; 111 } 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; 118 } 119 break; 120 } 121 } 122 123 /* 124 * If function arguments should not be displayed, remove everything 125 * between the outermost set of parentheses in dmp->dm_dem. 126 */ 127 if (!(dmp->dm_flags & MDB_DM_FUNCARG)) { 128 char *lp = strchr(dmp->dm_dem, '('); 129 char *rp = strrchr(dmp->dm_dem, ')'); 130 131 if (lp != NULL && rp != NULL) 132 bcopy(rp + 1, lp, strlen(rp) + 1); 133 } 134 135 /* 136 * If function scope specifiers should not be displayed, remove text 137 * from the leftmost space to the rightmost colon prior to any paren. 138 */ 139 if (!(dmp->dm_flags & MDB_DM_SCOPE)) { 140 char *c, *s, *lp = strchr(dmp->dm_dem, '('); 141 142 if (lp != NULL) 143 *lp = '\0'; 144 145 c = strrchr(dmp->dm_dem, ':'); 146 s = strchr(dmp->dm_dem, ' '); 147 148 if (lp != NULL) 149 *lp = '('; 150 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); 156 } 157 } 158 159 len = strlen(dmp->dm_dem); /* recompute length of buffer */ 160 161 /* 162 * Compute bytes remaining 163 */ 164 resid = (dmp->dm_buf + dmp->dm_len) - (dmp->dm_dem + len); 165 166 /* 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+"]". 169 */ 170 if ((dmp->dm_flags & MDB_DM_MANGLED) && resid > 3) { 171 char *p = dmp->dm_dem + len; 172 173 *p++ = '['; 174 (void) strncpy(p, name, resid - 3); 175 p[resid - 3] = '\0'; 176 p += strlen(p); 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", 299 "function arguments displayed", 300 "mangled name displayed" 301 }; 302 303 mdb_demangler_t *dmp = mdb.m_demangler; 304 int i; 305 306 if (argc > 0) 307 return (DCMD_USAGE); 308 309 if (dmp == NULL || !(mdb.m_flags & MDB_FL_DEMANGLE)) { 310 mdb_warn("C++ demangling facility is currently disabled\n"); 311 return (DCMD_ERR); 312 } 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 }