]> git.karo-electronics.de Git - karo-tx-linux.git/blob - tools/perf/util/demangle-java.c
Merge tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso...
[karo-tx-linux.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 #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 }