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