Loading...
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
13enum {
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
22static 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 */
44static 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;
141error:
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 */
156char *
157java_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;
199error:
200 free(buf);
201 return NULL;
202}
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
10enum {
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
19static 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 */
41static 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;
138error:
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 */
153char *
154java_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;
196error:
197 free(buf);
198 return NULL;
199}