xref: /illumos-gate/usr/src/cmd/sgs/libelf/misc/demangle.c (revision 7dbbfe7762f9eabac3999ee1a8b38311d428f7a8)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
247c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  *
277c478bd9Sstevel@tonic-gate  *	Copyright (c) 1998 by Sun Microsystems, Inc.
287c478bd9Sstevel@tonic-gate  *	All rights reserved.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <ctype.h>
327c478bd9Sstevel@tonic-gate #include <setjmp.h>
337c478bd9Sstevel@tonic-gate #include <stdlib.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <thread.h>
367c478bd9Sstevel@tonic-gate #include "elf_dem.h"
377c478bd9Sstevel@tonic-gate #include "String.h"
387c478bd9Sstevel@tonic-gate #include "msg.h"
397c478bd9Sstevel@tonic-gate 
4037f60115SToomas Soome /*
4137f60115SToomas Soome  * The variable "hold" contains the pointer to the array initially
427c478bd9Sstevel@tonic-gate  * handed to demangle.  It is returned if it is not possible to
437c478bd9Sstevel@tonic-gate  * demangle the string.  NULL is returned if a memory allocation
447c478bd9Sstevel@tonic-gate  * problem is encountered.  Thus one can do the following:
457c478bd9Sstevel@tonic-gate  *
467c478bd9Sstevel@tonic-gate  * char *mn = "Some mangled name";
477c478bd9Sstevel@tonic-gate  * char *dm = mangle(mn);
487c478bd9Sstevel@tonic-gate  * if (dm == NULL)
497c478bd9Sstevel@tonic-gate  *	printf("allocation error\n");
507c478bd9Sstevel@tonic-gate  * else if (dm == mn)
517c478bd9Sstevel@tonic-gate  *	printf("name could not be demangled\n");
527c478bd9Sstevel@tonic-gate  * else
537c478bd9Sstevel@tonic-gate  *	printf("demangled name is: %s\n",dm);
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate static char *hold;
567c478bd9Sstevel@tonic-gate 
5737f60115SToomas Soome /*
5837f60115SToomas Soome  * this String is the working buffer for the demangle
597c478bd9Sstevel@tonic-gate  * routine.  A pointer into this String is returned
607c478bd9Sstevel@tonic-gate  * from demangle when it is possible to demangle the
617c478bd9Sstevel@tonic-gate  * String.  For this reason, the pointer should not
627c478bd9Sstevel@tonic-gate  * be saved between calls of demangle(), nor freed.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate static String *s = 0;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate static int
getint(char ** c)6737f60115SToomas Soome getint(char **c)
687c478bd9Sstevel@tonic-gate {
6937f60115SToomas Soome 	return (strtol(*c, c, 10));
707c478bd9Sstevel@tonic-gate }
717c478bd9Sstevel@tonic-gate 
7237f60115SToomas Soome /*
7337f60115SToomas Soome  * If a mangled name has a __
747c478bd9Sstevel@tonic-gate  * that is not at the very beginning
757c478bd9Sstevel@tonic-gate  * of the string, then this routine
767c478bd9Sstevel@tonic-gate  * is called to demangle that part
777c478bd9Sstevel@tonic-gate  * of the name.  All overloaded functions,
787c478bd9Sstevel@tonic-gate  * and class members fall into this category.
797c478bd9Sstevel@tonic-gate  *
807c478bd9Sstevel@tonic-gate  * c should start with two underscores followed by a non-zero digit or an F.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate static char *
second(char * c)8337f60115SToomas Soome second(char *c)
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate 	int n;
867c478bd9Sstevel@tonic-gate 	if (strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2))
8737f60115SToomas Soome 		return (hold);
887c478bd9Sstevel@tonic-gate 	c += 2;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if (!(isdigit(*c) || *c == 'F'))
9137f60115SToomas Soome 		return (hold);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	if (isdigit(*c)) {
947c478bd9Sstevel@tonic-gate 		/* a member */
957c478bd9Sstevel@tonic-gate 		n = getint(&c);
967c478bd9Sstevel@tonic-gate 		if (n == 0 || (int)strlen(c) < n)
9737f60115SToomas Soome 			return (hold);
987c478bd9Sstevel@tonic-gate 		s = prep_String(MSG_ORIG(MSG_STR_DBLCOL), s);
997c478bd9Sstevel@tonic-gate 		s = nprep_String(c, s, n);
1007c478bd9Sstevel@tonic-gate 		c += n;
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 	if (*c == 'F') {
1037c478bd9Sstevel@tonic-gate 		/* an overloaded function */
1047c478bd9Sstevel@tonic-gate 		switch (*++c) {
1057c478bd9Sstevel@tonic-gate 		case '\0':
10637f60115SToomas Soome 			return (hold);
1077c478bd9Sstevel@tonic-gate 		case 'v':
1087c478bd9Sstevel@tonic-gate 			s = app_String(s, MSG_ORIG(MSG_STR_OPENCLOSEPAR));
1097c478bd9Sstevel@tonic-gate 			break;
1107c478bd9Sstevel@tonic-gate 		default:
1117c478bd9Sstevel@tonic-gate 			if (demangle_doargs(&s, c) < 0)
11237f60115SToomas Soome 				return (hold);
1137c478bd9Sstevel@tonic-gate 		}
1147c478bd9Sstevel@tonic-gate 	}
11537f60115SToomas Soome 	return (PTR(s));
1167c478bd9Sstevel@tonic-gate }
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate char *
demangle(char * c)11937f60115SToomas Soome demangle(char *c)
1207c478bd9Sstevel@tonic-gate {
12137f60115SToomas Soome 	volatile int i = 0;
1227c478bd9Sstevel@tonic-gate 	extern jmp_buf jbuf;
1237c478bd9Sstevel@tonic-gate 	static mutex_t	mlock = DEFAULTMUTEX;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&mlock);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if (setjmp(jbuf)) {
1287c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mlock);
12937f60115SToomas Soome 		return (0);
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	hold = c;
1337c478bd9Sstevel@tonic-gate 	s = mk_String(s);
1347c478bd9Sstevel@tonic-gate 	s = set_String(s, MSG_ORIG(MSG_STR_EMPTY));
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate 	if (c == 0 || *c == 0) {
1377c478bd9Sstevel@tonic-gate 		c = hold;
1387c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mlock);
13937f60115SToomas Soome 		return (c);
1407c478bd9Sstevel@tonic-gate 	}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	if (strncmp(c, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) != 0) {
14337f60115SToomas Soome 		/*
14437f60115SToomas Soome 		 * If a name does not begin with a __
1457c478bd9Sstevel@tonic-gate 		 * but it does contain one, it is either
1467c478bd9Sstevel@tonic-gate 		 * a member or an overloaded function.
1477c478bd9Sstevel@tonic-gate 		 */
1487c478bd9Sstevel@tonic-gate 		while (c[i] && strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2))
1497c478bd9Sstevel@tonic-gate 			i++;
1507c478bd9Sstevel@tonic-gate 		if (c[i]) {
1517c478bd9Sstevel@tonic-gate 			/* Advance to first non-underscore */
1527c478bd9Sstevel@tonic-gate 			while (c[i+2] == '_')
1537c478bd9Sstevel@tonic-gate 				i++;
1547c478bd9Sstevel@tonic-gate 		}
1557c478bd9Sstevel@tonic-gate 		if (strncmp(c+i, MSG_ORIG(MSG_STR_DBLUNDBAR), 2) == 0) {
1567c478bd9Sstevel@tonic-gate 			/* Copy the simple name */
1577c478bd9Sstevel@tonic-gate 			s = napp_String(s, c, i);
1587c478bd9Sstevel@tonic-gate 			/* Process the signature */
1597c478bd9Sstevel@tonic-gate 			c = second(c+i);
1607c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&mlock);
16137f60115SToomas Soome 			return (c);
1627c478bd9Sstevel@tonic-gate 		} else {
1637c478bd9Sstevel@tonic-gate 			c = hold;
1647c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&mlock);
16537f60115SToomas Soome 			return (c);
1667c478bd9Sstevel@tonic-gate 		}
1677c478bd9Sstevel@tonic-gate 	} else {
1687c478bd9Sstevel@tonic-gate 		const char	*x;
1697c478bd9Sstevel@tonic-gate 		int		oplen;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		c += 2;
1727c478bd9Sstevel@tonic-gate 
17337f60115SToomas Soome 		/*
17437f60115SToomas Soome 		 * For automatic variables, or internal static
1757c478bd9Sstevel@tonic-gate 		 * variables, a __(number) is prepended to the
1767c478bd9Sstevel@tonic-gate 		 * name.  If this is encountered, strip this off
1777c478bd9Sstevel@tonic-gate 		 * and return.
1787c478bd9Sstevel@tonic-gate 		 */
1797c478bd9Sstevel@tonic-gate 		if (isdigit(*c)) {
1807c478bd9Sstevel@tonic-gate 			while (isdigit(*c))
1817c478bd9Sstevel@tonic-gate 				c++;
1827c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&mlock);
18337f60115SToomas Soome 			return (c);
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 
18637f60115SToomas Soome 		/*
18737f60115SToomas Soome 		 * Handle operator functions -- this
1887c478bd9Sstevel@tonic-gate 		 * automatically calls second, since
1897c478bd9Sstevel@tonic-gate 		 * all operator functions are overloaded.
1907c478bd9Sstevel@tonic-gate 		 */
191*7dbbfe77SToomas Soome 		x = findop(c, &oplen);
192*7dbbfe77SToomas Soome 		if (x != NULL) {
1937c478bd9Sstevel@tonic-gate 			s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_1));
1947c478bd9Sstevel@tonic-gate 			s = app_String(s, x);
1957c478bd9Sstevel@tonic-gate 			c += oplen;
1967c478bd9Sstevel@tonic-gate 			c = second(c);
1977c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&mlock);
19837f60115SToomas Soome 			return (c);
1997c478bd9Sstevel@tonic-gate 		}
2007c478bd9Sstevel@tonic-gate 
20137f60115SToomas Soome 		/*
20237f60115SToomas Soome 		 * Operator cast does not fit the mould
2037c478bd9Sstevel@tonic-gate 		 * of the other operators.  Its type name
2047c478bd9Sstevel@tonic-gate 		 * is encoded.  The cast function must
2057c478bd9Sstevel@tonic-gate 		 * take a void as an argument.
2067c478bd9Sstevel@tonic-gate 		 */
2077c478bd9Sstevel@tonic-gate 		if (strncmp(c, MSG_ORIG(MSG_STR_OP), 2) == 0) {
2087c478bd9Sstevel@tonic-gate 			int r;
2097c478bd9Sstevel@tonic-gate 			s = app_String(s, MSG_ORIG(MSG_STR_OPERATOR_2));
2107c478bd9Sstevel@tonic-gate 			c += 2;
2117c478bd9Sstevel@tonic-gate 			r = demangle_doarg(&s, c);
2127c478bd9Sstevel@tonic-gate 			if (r < 0) {
2137c478bd9Sstevel@tonic-gate 				c = hold;
2147c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&mlock);
21537f60115SToomas Soome 				return (c);
2167c478bd9Sstevel@tonic-gate 			}
2177c478bd9Sstevel@tonic-gate 			c += r;
2187c478bd9Sstevel@tonic-gate 			c = second(c);
2197c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&mlock);
22037f60115SToomas Soome 			return (c);
2217c478bd9Sstevel@tonic-gate 		}
2227c478bd9Sstevel@tonic-gate 
22337f60115SToomas Soome 		/*
22437f60115SToomas Soome 		 * Constructors and Destructors are also
2257c478bd9Sstevel@tonic-gate 		 * a special case of operator name.  Note
2267c478bd9Sstevel@tonic-gate 		 * that the destructor, while overloaded,
2277c478bd9Sstevel@tonic-gate 		 * must always take the same arguments --
2287c478bd9Sstevel@tonic-gate 		 * none.
2297c478bd9Sstevel@tonic-gate 		 */
23037f60115SToomas Soome 		if ((*c == 'c' || *c == 'd') &&
23137f60115SToomas Soome 		    strncmp(c+1, MSG_ORIG(MSG_STR_TDBLUNDBAR), 3) == 0) {
2327c478bd9Sstevel@tonic-gate 			int n;
2337c478bd9Sstevel@tonic-gate 			char *c2 = c+2;
2347c478bd9Sstevel@tonic-gate 			char cx = c[0];
2357c478bd9Sstevel@tonic-gate 			c += 4;
2367c478bd9Sstevel@tonic-gate 			n = getint(&c);
2377c478bd9Sstevel@tonic-gate 			if (n == 0) {
2387c478bd9Sstevel@tonic-gate 				c = hold;
2397c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&mlock);
24037f60115SToomas Soome 				return (c);
2417c478bd9Sstevel@tonic-gate 			}
2427c478bd9Sstevel@tonic-gate 			s = napp_String(s, c, n);
2437c478bd9Sstevel@tonic-gate 			if (cx == 'd')
2447c478bd9Sstevel@tonic-gate 				s = prep_String(MSG_ORIG(MSG_STR_TILDE), s);
2457c478bd9Sstevel@tonic-gate 			c = second(c2);
2467c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&mlock);
24737f60115SToomas Soome 			return (c);
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 		c = hold;
2507c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&mlock);
25137f60115SToomas Soome 		return (c);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate }
254