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