/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1988 AT&T * All Rights Reserved * * * Copyright (c) 1998 by Sun Microsystems, Inc. * All rights reserved. */ #include #include #include #include #include #include "elf_dem.h" #include "String.h" #include "msg.h" /* * The variable "hold" contains the pointer to the array initially * handed to demangle. It is returned if it is not possible to * demangle the string. NULL is returned if a memory allocation * problem is encountered. Thus one can do the following: * * char *mn = "Some mangled name"; * char *dm = mangle(mn); * if (dm == NULL) * printf("allocation error\n"); * else if (dm == mn) * printf("name could not be demangled\n"); * else * printf("demangled name is: %s\n",dm); */ static char *hold; /* * this String is the working buffer for the demangle * routine. A pointer into this String is returned * from demangle when it is possible to demangle the * String. For this reason, the pointer should not * be saved between calls of demangle(), nor freed. */ static String *s = 0; static int getint(char **c) { return (strtol(*c, c, 10)); } /* * If a mangled name has a __ * that is not at the very beginning * of the string, then this routine * is called to demangle that part * of the name. All overloaded functions, * and class members fall into this category. * * c should start with two underscores followed by a non-zero digit or an F. */ static char * second(char *c) { int n; if (strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2)) return (hold); c += 2; if (!(isdigit(*c) || *c == 'F')) return (hold); if (isdigit(*c)) { /* a member */ n = getint(&c); if (n == 0 || (int)strlen(c) < n) return (hold); s = prep_String(MSG_ORIG(MSG_STR_DBLCOL), s); s = nprep_String(c, s, n); c += n; } if (*c == 'F') { /* an overloaded function */ switch (*++c) { case '\0': return (hold); case 'v': s = app_String(s, MSG_ORIG(MSG_STR_OPENCLOSEPAR)); break; default: if (demangle_doargs(&s, c) < 0) return (hold); } } return (PTR(s)); } char * demangle(char *c) { volatile int i = 0; extern jmp_buf jbuf; static mutex_t mlock = DEFAULTMUTEX; (void) mutex_lock(&mlock); if (setjmp(jbuf)) { (void) mutex_unlock(&mlock); return (0); } hold = c; s = mk_String(s); s = set_String(s, MSG_ORIG(MSG_STR_EMPTY)); if (c == 0 || *c == 0) { c = hold; (void) mutex_unlock(&mlock); return (c); } if (strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) != 0) { /* * If a name does not begin with a __ * but it does contain one, it is either * a member or an overloaded function. */ while (c[i] && strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2)) i++; if (c[i]) { /* Advance to first non-underscore */ while (c[i+2] == '_') i++; } if (strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) == 0) { /* Copy the simple name */ s = napp_String(s, c, i); /* Process the signature */ c = second(c+i); (void) mutex_unlock(&mlock); return (c); } else { c = hold; (void) mutex_unlock(&mlock); return (c); } } else { const char *x; int oplen; c += 2; /* * For automatic variables, or internal static * variables, a __(number) is prepended to the * name. If this is encountered, strip this off * and return. */ if (isdigit(*c)) { while (isdigit(*c)) c++; (void) mutex_unlock(&mlock); return (c); } /* * Handle operator functions -- this * automatically calls second, since * all operator functions are overloaded. */ x = findop(c, &oplen); if (x != NULL) { s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_1)); s = app_String(s, x); c += oplen; c = second(c); (void) mutex_unlock(&mlock); return (c); } /* * Operator cast does not fit the mould * of the other operators. Its type name * is encoded. The cast function must * take a void as an argument. */ if (strncmp(c, MSG_ORIG(MSG_STR_OP), 2) == 0) { int r; s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_2)); c += 2; r = demangle_doarg(&s, c); if (r < 0) { c = hold; (void) mutex_unlock(&mlock); return (c); } c += r; c = second(c); (void) mutex_unlock(&mlock); return (c); } /* * Constructors and Destructors are also * a special case of operator name. Note * that the destructor, while overloaded, * must always take the same arguments -- * none. */ if ((*c == 'c' || *c == 'd') && strncmp(c+1, MSG_ORIG(MSG_STR_TDBLUNDBAR), 3) == 0) { int n; char *c2 = c+2; char cx = c[0]; c += 4; n = getint(&c); if (n == 0) { c = hold; (void) mutex_unlock(&mlock); return (c); } s = napp_String(s, c, n); if (cx == 'd') s = prep_String(MSG_ORIG(MSG_STR_TILDE), s); c = second(c2); (void) mutex_unlock(&mlock); return (c); } c = hold; (void) mutex_unlock(&mlock); return (c); } }