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