GNU Linux-libre 4.19.211-gnu1
[releases.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 <string.h>
5 #include "util.h"
6 #include "debug.h"
7 #include "symbol.h"
8
9 #include "demangle-java.h"
10
11 #include "sane_ctype.h"
12
13 enum {
14         MODE_PREFIX = 0,
15         MODE_CLASS  = 1,
16         MODE_FUNC   = 2,
17         MODE_TYPE   = 3,
18         MODE_CTYPE  = 3, /* 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', "bool" ),
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_CTYPE) {
63                                 if (mode == MODE_CTYPE) {
64                                         if (narg)
65                                                 rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
66                                         narg++;
67                                 }
68                                 rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
69                                 if (mode == MODE_PREFIX)
70                                         mode = MODE_CLASS;
71                         } else
72                                 buf[rlen++] = *q;
73                         break;
74                 case 'B':
75                 case 'C':
76                 case 'D':
77                 case 'F':
78                 case 'I':
79                 case 'J':
80                 case 'S':
81                 case 'Z':
82                         if (mode == MODE_TYPE) {
83                                 if (narg)
84                                         rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
85                                 rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
86                                 while (array--)
87                                         rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
88                                 array = 0;
89                                 narg++;
90                         } else
91                                 buf[rlen++] = *q;
92                         break;
93                 case 'V':
94                         if (mode == MODE_TYPE) {
95                                 rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
96                                 while (array--)
97                                         rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
98                                 array = 0;
99                         } else
100                                 buf[rlen++] = *q;
101                         break;
102                 case '[':
103                         if (mode != MODE_TYPE)
104                                 goto error;
105                         array++;
106                         break;
107                 case '(':
108                         if (mode != MODE_FUNC)
109                                 goto error;
110                         buf[rlen++] = *q;
111                         mode = MODE_TYPE;
112                         break;
113                 case ')':
114                         if (mode != MODE_TYPE)
115                                 goto error;
116                         buf[rlen++] = *q;
117                         narg = 0;
118                         break;
119                 case ';':
120                         if (mode != MODE_CLASS && mode != MODE_CTYPE)
121                                 goto error;
122                         /* safe because at least one other char to process */
123                         if (isalpha(*(q + 1)))
124                                 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
125                         if (mode == MODE_CLASS)
126                                 mode = MODE_FUNC;
127                         else if (mode == MODE_CTYPE)
128                                 mode = MODE_TYPE;
129                         break;
130                 case '/':
131                         if (mode != MODE_CLASS && mode != MODE_CTYPE)
132                                 goto error;
133                         rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
134                         break;
135                 default :
136                         buf[rlen++] = *q;
137                 }
138         }
139         buf[rlen] = '\0';
140         return buf;
141 error:
142         return NULL;
143 }
144
145 /*
146  * Demangle Java function signature (openJDK, not GCJ)
147  * input:
148  *      str: string to parse. String is not modified
149  *    flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
150  * return:
151  *      if input can be demangled, then a newly allocated string is returned.
152  *      if input cannot be demangled, then NULL is returned
153  *
154  * Note: caller is responsible for freeing demangled string
155  */
156 char *
157 java_demangle_sym(const char *str, int flags)
158 {
159         char *buf, *ptr;
160         char *p;
161         size_t len, l1 = 0;
162
163         if (!str)
164                 return NULL;
165
166         /* find start of retunr type */
167         p = strrchr(str, ')');
168         if (!p)
169                 return NULL;
170
171         /*
172          * expansion factor estimated to 3x
173          */
174         len = strlen(str) * 3 + 1;
175         buf = malloc(len);
176         if (!buf)
177                 return NULL;
178
179         buf[0] = '\0';
180         if (!(flags & JAVA_DEMANGLE_NORET)) {
181                 /*
182                  * get return type first
183                  */
184                 ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
185                 if (!ptr)
186                         goto error;
187
188                 /* add space between return type and function prototype */
189                 l1 = strlen(buf);
190                 buf[l1++] = ' ';
191         }
192
193         /* process function up to return type */
194         ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
195         if (!ptr)
196                 goto error;
197
198         return buf;
199 error:
200         free(buf);
201         return NULL;
202 }