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 } 203