xref: /openbmc/linux/tools/perf/util/demangle-java.c (revision 4d39c89f)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2e9c4bcddSStephane Eranian #include <sys/types.h>
3e9c4bcddSStephane Eranian #include <stdio.h>
4215a0d30SArnaldo Carvalho de Melo #include <stdlib.h>
5e9c4bcddSStephane Eranian #include <string.h>
6e9c4bcddSStephane Eranian #include "symbol.h"
7e9c4bcddSStephane Eranian 
8e9c4bcddSStephane Eranian #include "demangle-java.h"
9e9c4bcddSStephane Eranian 
103052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h>
11215a0d30SArnaldo Carvalho de Melo #include <linux/kernel.h>
123d689ed6SArnaldo Carvalho de Melo 
13e9c4bcddSStephane Eranian enum {
14e9c4bcddSStephane Eranian 	MODE_PREFIX = 0,
15e9c4bcddSStephane Eranian 	MODE_CLASS  = 1,
16e9c4bcddSStephane Eranian 	MODE_FUNC   = 2,
17e9c4bcddSStephane Eranian 	MODE_TYPE   = 3,
180bdf3181SNick Gasson 	MODE_CTYPE  = 4, /* class arg */
19e9c4bcddSStephane Eranian };
20e9c4bcddSStephane Eranian 
21e9c4bcddSStephane Eranian #define BASE_ENT(c, n)	[c - 'A']=n
22e9c4bcddSStephane Eranian static const char *base_types['Z' - 'A' + 1] = {
23e9c4bcddSStephane Eranian 	BASE_ENT('B', "byte" ),
24e9c4bcddSStephane Eranian 	BASE_ENT('C', "char" ),
25e9c4bcddSStephane Eranian 	BASE_ENT('D', "double" ),
26e9c4bcddSStephane Eranian 	BASE_ENT('F', "float" ),
27e9c4bcddSStephane Eranian 	BASE_ENT('I', "int" ),
28e9c4bcddSStephane Eranian 	BASE_ENT('J', "long" ),
29e9c4bcddSStephane Eranian 	BASE_ENT('S', "short" ),
300bdf3181SNick Gasson 	BASE_ENT('Z', "boolean" ),
31e9c4bcddSStephane Eranian };
32e9c4bcddSStephane Eranian 
33e9c4bcddSStephane Eranian /*
34e9c4bcddSStephane Eranian  * demangle Java symbol between str and end positions and stores
35e9c4bcddSStephane Eranian  * up to maxlen characters into buf. The parser starts in mode.
36e9c4bcddSStephane Eranian  *
37e9c4bcddSStephane Eranian  * Use MODE_PREFIX to process entire prototype till end position
38e9c4bcddSStephane Eranian  * Use MODE_TYPE to process return type if str starts on return type char
39e9c4bcddSStephane Eranian  *
40e9c4bcddSStephane Eranian  *  Return:
41e9c4bcddSStephane Eranian  *	success: buf
42e9c4bcddSStephane Eranian  *	error  : NULL
43e9c4bcddSStephane Eranian  */
44e9c4bcddSStephane Eranian static char *
__demangle_java_sym(const char * str,const char * end,char * buf,int maxlen,int mode)45e9c4bcddSStephane Eranian __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
46e9c4bcddSStephane Eranian {
47e9c4bcddSStephane Eranian 	int rlen = 0;
48e9c4bcddSStephane Eranian 	int array = 0;
49e9c4bcddSStephane Eranian 	int narg = 0;
50e9c4bcddSStephane Eranian 	const char *q;
51e9c4bcddSStephane Eranian 
52e9c4bcddSStephane Eranian 	if (!end)
53e9c4bcddSStephane Eranian 		end = str + strlen(str);
54e9c4bcddSStephane Eranian 
55e9c4bcddSStephane Eranian 	for (q = str; q != end; q++) {
56e9c4bcddSStephane Eranian 
57e9c4bcddSStephane Eranian 		if (rlen == (maxlen - 1))
58e9c4bcddSStephane Eranian 			break;
59e9c4bcddSStephane Eranian 
60e9c4bcddSStephane Eranian 		switch (*q) {
61e9c4bcddSStephane Eranian 		case 'L':
620bdf3181SNick Gasson 			if (mode == MODE_PREFIX || mode == MODE_TYPE) {
630bdf3181SNick Gasson 				if (mode == MODE_TYPE) {
64e9c4bcddSStephane Eranian 					if (narg)
65e9c4bcddSStephane Eranian 						rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
66e9c4bcddSStephane Eranian 					narg++;
67e9c4bcddSStephane Eranian 				}
68e9c4bcddSStephane Eranian 				if (mode == MODE_PREFIX)
69e9c4bcddSStephane Eranian 					mode = MODE_CLASS;
700bdf3181SNick Gasson 				else
710bdf3181SNick Gasson 					mode = MODE_CTYPE;
72e9c4bcddSStephane Eranian 			} else
73e9c4bcddSStephane Eranian 				buf[rlen++] = *q;
74e9c4bcddSStephane Eranian 			break;
75e9c4bcddSStephane Eranian 		case 'B':
76e9c4bcddSStephane Eranian 		case 'C':
77e9c4bcddSStephane Eranian 		case 'D':
78e9c4bcddSStephane Eranian 		case 'F':
79e9c4bcddSStephane Eranian 		case 'I':
80e9c4bcddSStephane Eranian 		case 'J':
81e9c4bcddSStephane Eranian 		case 'S':
82e9c4bcddSStephane Eranian 		case 'Z':
83e9c4bcddSStephane Eranian 			if (mode == MODE_TYPE) {
84e9c4bcddSStephane Eranian 				if (narg)
85e9c4bcddSStephane Eranian 					rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
86e9c4bcddSStephane Eranian 				rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
87e9c4bcddSStephane Eranian 				while (array--)
88e9c4bcddSStephane Eranian 					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
89e9c4bcddSStephane Eranian 				array = 0;
90e9c4bcddSStephane Eranian 				narg++;
91e9c4bcddSStephane Eranian 			} else
92e9c4bcddSStephane Eranian 				buf[rlen++] = *q;
93e9c4bcddSStephane Eranian 			break;
94e9c4bcddSStephane Eranian 		case 'V':
95e9c4bcddSStephane Eranian 			if (mode == MODE_TYPE) {
96e9c4bcddSStephane Eranian 				rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
97e9c4bcddSStephane Eranian 				while (array--)
98e9c4bcddSStephane Eranian 					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
99e9c4bcddSStephane Eranian 				array = 0;
100e9c4bcddSStephane Eranian 			} else
101e9c4bcddSStephane Eranian 				buf[rlen++] = *q;
102e9c4bcddSStephane Eranian 			break;
103e9c4bcddSStephane Eranian 		case '[':
104e9c4bcddSStephane Eranian 			if (mode != MODE_TYPE)
105e9c4bcddSStephane Eranian 				goto error;
106e9c4bcddSStephane Eranian 			array++;
107e9c4bcddSStephane Eranian 			break;
108e9c4bcddSStephane Eranian 		case '(':
109e9c4bcddSStephane Eranian 			if (mode != MODE_FUNC)
110e9c4bcddSStephane Eranian 				goto error;
111e9c4bcddSStephane Eranian 			buf[rlen++] = *q;
112e9c4bcddSStephane Eranian 			mode = MODE_TYPE;
113e9c4bcddSStephane Eranian 			break;
114e9c4bcddSStephane Eranian 		case ')':
115e9c4bcddSStephane Eranian 			if (mode != MODE_TYPE)
116e9c4bcddSStephane Eranian 				goto error;
117e9c4bcddSStephane Eranian 			buf[rlen++] = *q;
118e9c4bcddSStephane Eranian 			narg = 0;
119e9c4bcddSStephane Eranian 			break;
120e9c4bcddSStephane Eranian 		case ';':
121e9c4bcddSStephane Eranian 			if (mode != MODE_CLASS && mode != MODE_CTYPE)
122e9c4bcddSStephane Eranian 				goto error;
123e9c4bcddSStephane Eranian 			/* safe because at least one other char to process */
1240bdf3181SNick Gasson 			if (isalpha(*(q + 1)) && mode == MODE_CLASS)
125e9c4bcddSStephane Eranian 				rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
126e9c4bcddSStephane Eranian 			if (mode == MODE_CLASS)
127e9c4bcddSStephane Eranian 				mode = MODE_FUNC;
128e9c4bcddSStephane Eranian 			else if (mode == MODE_CTYPE)
129e9c4bcddSStephane Eranian 				mode = MODE_TYPE;
130e9c4bcddSStephane Eranian 			break;
131e9c4bcddSStephane Eranian 		case '/':
132e9c4bcddSStephane Eranian 			if (mode != MODE_CLASS && mode != MODE_CTYPE)
133e9c4bcddSStephane Eranian 				goto error;
134e9c4bcddSStephane Eranian 			rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
135e9c4bcddSStephane Eranian 			break;
136e9c4bcddSStephane Eranian 		default :
137e9c4bcddSStephane Eranian 			buf[rlen++] = *q;
138e9c4bcddSStephane Eranian 		}
139e9c4bcddSStephane Eranian 	}
140e9c4bcddSStephane Eranian 	buf[rlen] = '\0';
141e9c4bcddSStephane Eranian 	return buf;
142e9c4bcddSStephane Eranian error:
143e9c4bcddSStephane Eranian 	return NULL;
144e9c4bcddSStephane Eranian }
145e9c4bcddSStephane Eranian 
146e9c4bcddSStephane Eranian /*
147e9c4bcddSStephane Eranian  * Demangle Java function signature (openJDK, not GCJ)
148e9c4bcddSStephane Eranian  * input:
149e9c4bcddSStephane Eranian  * 	str: string to parse. String is not modified
150*4d39c89fSIngo Molnar  *    flags: combination of JAVA_DEMANGLE_* flags to modify demangling
151e9c4bcddSStephane Eranian  * return:
152e9c4bcddSStephane Eranian  *	if input can be demangled, then a newly allocated string is returned.
153e9c4bcddSStephane Eranian  *	if input cannot be demangled, then NULL is returned
154e9c4bcddSStephane Eranian  *
155e9c4bcddSStephane Eranian  * Note: caller is responsible for freeing demangled string
156e9c4bcddSStephane Eranian  */
157e9c4bcddSStephane Eranian char *
java_demangle_sym(const char * str,int flags)158e9c4bcddSStephane Eranian java_demangle_sym(const char *str, int flags)
159e9c4bcddSStephane Eranian {
160e9c4bcddSStephane Eranian 	char *buf, *ptr;
161e9c4bcddSStephane Eranian 	char *p;
162e9c4bcddSStephane Eranian 	size_t len, l1 = 0;
163e9c4bcddSStephane Eranian 
164e9c4bcddSStephane Eranian 	if (!str)
165e9c4bcddSStephane Eranian 		return NULL;
166e9c4bcddSStephane Eranian 
167*4d39c89fSIngo Molnar 	/* find start of return type */
168e9c4bcddSStephane Eranian 	p = strrchr(str, ')');
169e9c4bcddSStephane Eranian 	if (!p)
170e9c4bcddSStephane Eranian 		return NULL;
171e9c4bcddSStephane Eranian 
172e9c4bcddSStephane Eranian 	/*
173e9c4bcddSStephane Eranian 	 * expansion factor estimated to 3x
174e9c4bcddSStephane Eranian 	 */
175e9c4bcddSStephane Eranian 	len = strlen(str) * 3 + 1;
176e9c4bcddSStephane Eranian 	buf = malloc(len);
177e9c4bcddSStephane Eranian 	if (!buf)
178e9c4bcddSStephane Eranian 		return NULL;
179e9c4bcddSStephane Eranian 
180e9c4bcddSStephane Eranian 	buf[0] = '\0';
181e9c4bcddSStephane Eranian 	if (!(flags & JAVA_DEMANGLE_NORET)) {
182e9c4bcddSStephane Eranian 		/*
183e9c4bcddSStephane Eranian 		 * get return type first
184e9c4bcddSStephane Eranian 		 */
185e9c4bcddSStephane Eranian 		ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
186e9c4bcddSStephane Eranian 		if (!ptr)
187e9c4bcddSStephane Eranian 			goto error;
188e9c4bcddSStephane Eranian 
189e9c4bcddSStephane Eranian 		/* add space between return type and function prototype */
190e9c4bcddSStephane Eranian 		l1 = strlen(buf);
191e9c4bcddSStephane Eranian 		buf[l1++] = ' ';
192e9c4bcddSStephane Eranian 	}
193e9c4bcddSStephane Eranian 
194e9c4bcddSStephane Eranian 	/* process function up to return type */
195e9c4bcddSStephane Eranian 	ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
196e9c4bcddSStephane Eranian 	if (!ptr)
197e9c4bcddSStephane Eranian 		goto error;
198e9c4bcddSStephane Eranian 
199e9c4bcddSStephane Eranian 	return buf;
200e9c4bcddSStephane Eranian error:
201e9c4bcddSStephane Eranian 	free(buf);
202e9c4bcddSStephane Eranian 	return NULL;
203e9c4bcddSStephane Eranian }
204