18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <sys/types.h> 38c2ecf20Sopenharmony_ci#include <stdio.h> 48c2ecf20Sopenharmony_ci#include <stdlib.h> 58c2ecf20Sopenharmony_ci#include <string.h> 68c2ecf20Sopenharmony_ci#include "symbol.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "demangle-java.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/ctype.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cienum { 148c2ecf20Sopenharmony_ci MODE_PREFIX = 0, 158c2ecf20Sopenharmony_ci MODE_CLASS = 1, 168c2ecf20Sopenharmony_ci MODE_FUNC = 2, 178c2ecf20Sopenharmony_ci MODE_TYPE = 3, 188c2ecf20Sopenharmony_ci MODE_CTYPE = 4, /* class arg */ 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define BASE_ENT(c, n) [c - 'A']=n 228c2ecf20Sopenharmony_cistatic const char *base_types['Z' - 'A' + 1] = { 238c2ecf20Sopenharmony_ci BASE_ENT('B', "byte" ), 248c2ecf20Sopenharmony_ci BASE_ENT('C', "char" ), 258c2ecf20Sopenharmony_ci BASE_ENT('D', "double" ), 268c2ecf20Sopenharmony_ci BASE_ENT('F', "float" ), 278c2ecf20Sopenharmony_ci BASE_ENT('I', "int" ), 288c2ecf20Sopenharmony_ci BASE_ENT('J', "long" ), 298c2ecf20Sopenharmony_ci BASE_ENT('S', "short" ), 308c2ecf20Sopenharmony_ci BASE_ENT('Z', "boolean" ), 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * demangle Java symbol between str and end positions and stores 358c2ecf20Sopenharmony_ci * up to maxlen characters into buf. The parser starts in mode. 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * Use MODE_PREFIX to process entire prototype till end position 388c2ecf20Sopenharmony_ci * Use MODE_TYPE to process return type if str starts on return type char 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * Return: 418c2ecf20Sopenharmony_ci * success: buf 428c2ecf20Sopenharmony_ci * error : NULL 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_cistatic char * 458c2ecf20Sopenharmony_ci__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci int rlen = 0; 488c2ecf20Sopenharmony_ci int array = 0; 498c2ecf20Sopenharmony_ci int narg = 0; 508c2ecf20Sopenharmony_ci const char *q; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (!end) 538c2ecf20Sopenharmony_ci end = str + strlen(str); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci for (q = str; q != end; q++) { 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (rlen == (maxlen - 1)) 588c2ecf20Sopenharmony_ci break; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci switch (*q) { 618c2ecf20Sopenharmony_ci case 'L': 628c2ecf20Sopenharmony_ci if (mode == MODE_PREFIX || mode == MODE_TYPE) { 638c2ecf20Sopenharmony_ci if (mode == MODE_TYPE) { 648c2ecf20Sopenharmony_ci if (narg) 658c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, ", "); 668c2ecf20Sopenharmony_ci narg++; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci if (mode == MODE_PREFIX) 698c2ecf20Sopenharmony_ci mode = MODE_CLASS; 708c2ecf20Sopenharmony_ci else 718c2ecf20Sopenharmony_ci mode = MODE_CTYPE; 728c2ecf20Sopenharmony_ci } else 738c2ecf20Sopenharmony_ci buf[rlen++] = *q; 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci case 'B': 768c2ecf20Sopenharmony_ci case 'C': 778c2ecf20Sopenharmony_ci case 'D': 788c2ecf20Sopenharmony_ci case 'F': 798c2ecf20Sopenharmony_ci case 'I': 808c2ecf20Sopenharmony_ci case 'J': 818c2ecf20Sopenharmony_ci case 'S': 828c2ecf20Sopenharmony_ci case 'Z': 838c2ecf20Sopenharmony_ci if (mode == MODE_TYPE) { 848c2ecf20Sopenharmony_ci if (narg) 858c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, ", "); 868c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']); 878c2ecf20Sopenharmony_ci while (array--) 888c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "[]"); 898c2ecf20Sopenharmony_ci array = 0; 908c2ecf20Sopenharmony_ci narg++; 918c2ecf20Sopenharmony_ci } else 928c2ecf20Sopenharmony_ci buf[rlen++] = *q; 938c2ecf20Sopenharmony_ci break; 948c2ecf20Sopenharmony_ci case 'V': 958c2ecf20Sopenharmony_ci if (mode == MODE_TYPE) { 968c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "void"); 978c2ecf20Sopenharmony_ci while (array--) 988c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "[]"); 998c2ecf20Sopenharmony_ci array = 0; 1008c2ecf20Sopenharmony_ci } else 1018c2ecf20Sopenharmony_ci buf[rlen++] = *q; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case '[': 1048c2ecf20Sopenharmony_ci if (mode != MODE_TYPE) 1058c2ecf20Sopenharmony_ci goto error; 1068c2ecf20Sopenharmony_ci array++; 1078c2ecf20Sopenharmony_ci break; 1088c2ecf20Sopenharmony_ci case '(': 1098c2ecf20Sopenharmony_ci if (mode != MODE_FUNC) 1108c2ecf20Sopenharmony_ci goto error; 1118c2ecf20Sopenharmony_ci buf[rlen++] = *q; 1128c2ecf20Sopenharmony_ci mode = MODE_TYPE; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci case ')': 1158c2ecf20Sopenharmony_ci if (mode != MODE_TYPE) 1168c2ecf20Sopenharmony_ci goto error; 1178c2ecf20Sopenharmony_ci buf[rlen++] = *q; 1188c2ecf20Sopenharmony_ci narg = 0; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci case ';': 1218c2ecf20Sopenharmony_ci if (mode != MODE_CLASS && mode != MODE_CTYPE) 1228c2ecf20Sopenharmony_ci goto error; 1238c2ecf20Sopenharmony_ci /* safe because at least one other char to process */ 1248c2ecf20Sopenharmony_ci if (isalpha(*(q + 1)) && mode == MODE_CLASS) 1258c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "."); 1268c2ecf20Sopenharmony_ci if (mode == MODE_CLASS) 1278c2ecf20Sopenharmony_ci mode = MODE_FUNC; 1288c2ecf20Sopenharmony_ci else if (mode == MODE_CTYPE) 1298c2ecf20Sopenharmony_ci mode = MODE_TYPE; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case '/': 1328c2ecf20Sopenharmony_ci if (mode != MODE_CLASS && mode != MODE_CTYPE) 1338c2ecf20Sopenharmony_ci goto error; 1348c2ecf20Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "."); 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci default : 1378c2ecf20Sopenharmony_ci buf[rlen++] = *q; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci buf[rlen] = '\0'; 1418c2ecf20Sopenharmony_ci return buf; 1428c2ecf20Sopenharmony_cierror: 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Demangle Java function signature (openJDK, not GCJ) 1488c2ecf20Sopenharmony_ci * input: 1498c2ecf20Sopenharmony_ci * str: string to parse. String is not modified 1508c2ecf20Sopenharmony_ci * flags: comobination of JAVA_DEMANGLE_* flags to modify demangling 1518c2ecf20Sopenharmony_ci * return: 1528c2ecf20Sopenharmony_ci * if input can be demangled, then a newly allocated string is returned. 1538c2ecf20Sopenharmony_ci * if input cannot be demangled, then NULL is returned 1548c2ecf20Sopenharmony_ci * 1558c2ecf20Sopenharmony_ci * Note: caller is responsible for freeing demangled string 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cichar * 1588c2ecf20Sopenharmony_cijava_demangle_sym(const char *str, int flags) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci char *buf, *ptr; 1618c2ecf20Sopenharmony_ci char *p; 1628c2ecf20Sopenharmony_ci size_t len, l1 = 0; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (!str) 1658c2ecf20Sopenharmony_ci return NULL; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* find start of retunr type */ 1688c2ecf20Sopenharmony_ci p = strrchr(str, ')'); 1698c2ecf20Sopenharmony_ci if (!p) 1708c2ecf20Sopenharmony_ci return NULL; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* 1738c2ecf20Sopenharmony_ci * expansion factor estimated to 3x 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci len = strlen(str) * 3 + 1; 1768c2ecf20Sopenharmony_ci buf = malloc(len); 1778c2ecf20Sopenharmony_ci if (!buf) 1788c2ecf20Sopenharmony_ci return NULL; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci buf[0] = '\0'; 1818c2ecf20Sopenharmony_ci if (!(flags & JAVA_DEMANGLE_NORET)) { 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * get return type first 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_ci ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE); 1868c2ecf20Sopenharmony_ci if (!ptr) 1878c2ecf20Sopenharmony_ci goto error; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* add space between return type and function prototype */ 1908c2ecf20Sopenharmony_ci l1 = strlen(buf); 1918c2ecf20Sopenharmony_ci buf[l1++] = ' '; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* process function up to return type */ 1958c2ecf20Sopenharmony_ci ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX); 1968c2ecf20Sopenharmony_ci if (!ptr) 1978c2ecf20Sopenharmony_ci goto error; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return buf; 2008c2ecf20Sopenharmony_cierror: 2018c2ecf20Sopenharmony_ci free(buf); 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci} 204