Linux Perf
demangle-java.c
Go to the documentation of this file.
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 {
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 }
#define isalpha(x)
Definition: sane_ctype.h:37
static const char * base_types['Z' - 'A'+1]
Definition: demangle-java.c:22
#define JAVA_DEMANGLE_NORET
Definition: demangle-java.h:7
void * malloc(YYSIZE_T)
static char * __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
Definition: demangle-java.c:45
char * java_demangle_sym(const char *str, int flags)
static int str(yyscan_t scanner, int token)
int * ptr
Definition: debug.c:177
#define BASE_ENT(c, n)
Definition: demangle-java.c:21
#define array
u32 flags
void free(void *)