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