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