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