162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <sys/types.h> 362306a36Sopenharmony_ci#include <stdio.h> 462306a36Sopenharmony_ci#include <stdlib.h> 562306a36Sopenharmony_ci#include <string.h> 662306a36Sopenharmony_ci#include "symbol.h" 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "demangle-java.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/ctype.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cienum { 1462306a36Sopenharmony_ci MODE_PREFIX = 0, 1562306a36Sopenharmony_ci MODE_CLASS = 1, 1662306a36Sopenharmony_ci MODE_FUNC = 2, 1762306a36Sopenharmony_ci MODE_TYPE = 3, 1862306a36Sopenharmony_ci MODE_CTYPE = 4, /* class arg */ 1962306a36Sopenharmony_ci}; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define BASE_ENT(c, n) [c - 'A']=n 2262306a36Sopenharmony_cistatic const char *base_types['Z' - 'A' + 1] = { 2362306a36Sopenharmony_ci BASE_ENT('B', "byte" ), 2462306a36Sopenharmony_ci BASE_ENT('C', "char" ), 2562306a36Sopenharmony_ci BASE_ENT('D', "double" ), 2662306a36Sopenharmony_ci BASE_ENT('F', "float" ), 2762306a36Sopenharmony_ci BASE_ENT('I', "int" ), 2862306a36Sopenharmony_ci BASE_ENT('J', "long" ), 2962306a36Sopenharmony_ci BASE_ENT('S', "short" ), 3062306a36Sopenharmony_ci BASE_ENT('Z', "boolean" ), 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * demangle Java symbol between str and end positions and stores 3562306a36Sopenharmony_ci * up to maxlen characters into buf. The parser starts in mode. 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * Use MODE_PREFIX to process entire prototype till end position 3862306a36Sopenharmony_ci * Use MODE_TYPE to process return type if str starts on return type char 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Return: 4162306a36Sopenharmony_ci * success: buf 4262306a36Sopenharmony_ci * error : NULL 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistatic char * 4562306a36Sopenharmony_ci__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode) 4662306a36Sopenharmony_ci{ 4762306a36Sopenharmony_ci int rlen = 0; 4862306a36Sopenharmony_ci int array = 0; 4962306a36Sopenharmony_ci int narg = 0; 5062306a36Sopenharmony_ci const char *q; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (!end) 5362306a36Sopenharmony_ci end = str + strlen(str); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci for (q = str; q != end; q++) { 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (rlen == (maxlen - 1)) 5862306a36Sopenharmony_ci break; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci switch (*q) { 6162306a36Sopenharmony_ci case 'L': 6262306a36Sopenharmony_ci if (mode == MODE_PREFIX || mode == MODE_TYPE) { 6362306a36Sopenharmony_ci if (mode == MODE_TYPE) { 6462306a36Sopenharmony_ci if (narg) 6562306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, ", "); 6662306a36Sopenharmony_ci narg++; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci if (mode == MODE_PREFIX) 6962306a36Sopenharmony_ci mode = MODE_CLASS; 7062306a36Sopenharmony_ci else 7162306a36Sopenharmony_ci mode = MODE_CTYPE; 7262306a36Sopenharmony_ci } else 7362306a36Sopenharmony_ci buf[rlen++] = *q; 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci case 'B': 7662306a36Sopenharmony_ci case 'C': 7762306a36Sopenharmony_ci case 'D': 7862306a36Sopenharmony_ci case 'F': 7962306a36Sopenharmony_ci case 'I': 8062306a36Sopenharmony_ci case 'J': 8162306a36Sopenharmony_ci case 'S': 8262306a36Sopenharmony_ci case 'Z': 8362306a36Sopenharmony_ci if (mode == MODE_TYPE) { 8462306a36Sopenharmony_ci if (narg) 8562306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, ", "); 8662306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']); 8762306a36Sopenharmony_ci while (array--) 8862306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "[]"); 8962306a36Sopenharmony_ci array = 0; 9062306a36Sopenharmony_ci narg++; 9162306a36Sopenharmony_ci } else 9262306a36Sopenharmony_ci buf[rlen++] = *q; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case 'V': 9562306a36Sopenharmony_ci if (mode == MODE_TYPE) { 9662306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "void"); 9762306a36Sopenharmony_ci while (array--) 9862306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "[]"); 9962306a36Sopenharmony_ci array = 0; 10062306a36Sopenharmony_ci } else 10162306a36Sopenharmony_ci buf[rlen++] = *q; 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci case '[': 10462306a36Sopenharmony_ci if (mode != MODE_TYPE) 10562306a36Sopenharmony_ci goto error; 10662306a36Sopenharmony_ci array++; 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci case '(': 10962306a36Sopenharmony_ci if (mode != MODE_FUNC) 11062306a36Sopenharmony_ci goto error; 11162306a36Sopenharmony_ci buf[rlen++] = *q; 11262306a36Sopenharmony_ci mode = MODE_TYPE; 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci case ')': 11562306a36Sopenharmony_ci if (mode != MODE_TYPE) 11662306a36Sopenharmony_ci goto error; 11762306a36Sopenharmony_ci buf[rlen++] = *q; 11862306a36Sopenharmony_ci narg = 0; 11962306a36Sopenharmony_ci break; 12062306a36Sopenharmony_ci case ';': 12162306a36Sopenharmony_ci if (mode != MODE_CLASS && mode != MODE_CTYPE) 12262306a36Sopenharmony_ci goto error; 12362306a36Sopenharmony_ci /* safe because at least one other char to process */ 12462306a36Sopenharmony_ci if (isalpha(*(q + 1)) && mode == MODE_CLASS) 12562306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "."); 12662306a36Sopenharmony_ci if (mode == MODE_CLASS) 12762306a36Sopenharmony_ci mode = MODE_FUNC; 12862306a36Sopenharmony_ci else if (mode == MODE_CTYPE) 12962306a36Sopenharmony_ci mode = MODE_TYPE; 13062306a36Sopenharmony_ci break; 13162306a36Sopenharmony_ci case '/': 13262306a36Sopenharmony_ci if (mode != MODE_CLASS && mode != MODE_CTYPE) 13362306a36Sopenharmony_ci goto error; 13462306a36Sopenharmony_ci rlen += scnprintf(buf + rlen, maxlen - rlen, "."); 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default : 13762306a36Sopenharmony_ci buf[rlen++] = *q; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci buf[rlen] = '\0'; 14162306a36Sopenharmony_ci return buf; 14262306a36Sopenharmony_cierror: 14362306a36Sopenharmony_ci return NULL; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* 14762306a36Sopenharmony_ci * Demangle Java function signature (openJDK, not GCJ) 14862306a36Sopenharmony_ci * input: 14962306a36Sopenharmony_ci * str: string to parse. String is not modified 15062306a36Sopenharmony_ci * flags: combination of JAVA_DEMANGLE_* flags to modify demangling 15162306a36Sopenharmony_ci * return: 15262306a36Sopenharmony_ci * if input can be demangled, then a newly allocated string is returned. 15362306a36Sopenharmony_ci * if input cannot be demangled, then NULL is returned 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * Note: caller is responsible for freeing demangled string 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cichar * 15862306a36Sopenharmony_cijava_demangle_sym(const char *str, int flags) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci char *buf, *ptr; 16162306a36Sopenharmony_ci char *p; 16262306a36Sopenharmony_ci size_t len, l1 = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!str) 16562306a36Sopenharmony_ci return NULL; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* find start of return type */ 16862306a36Sopenharmony_ci p = strrchr(str, ')'); 16962306a36Sopenharmony_ci if (!p) 17062306a36Sopenharmony_ci return NULL; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * expansion factor estimated to 3x 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci len = strlen(str) * 3 + 1; 17662306a36Sopenharmony_ci buf = malloc(len); 17762306a36Sopenharmony_ci if (!buf) 17862306a36Sopenharmony_ci return NULL; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci buf[0] = '\0'; 18162306a36Sopenharmony_ci if (!(flags & JAVA_DEMANGLE_NORET)) { 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * get return type first 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_ci ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE); 18662306a36Sopenharmony_ci if (!ptr) 18762306a36Sopenharmony_ci goto error; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* add space between return type and function prototype */ 19062306a36Sopenharmony_ci l1 = strlen(buf); 19162306a36Sopenharmony_ci buf[l1++] = ' '; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* process function up to return type */ 19562306a36Sopenharmony_ci ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX); 19662306a36Sopenharmony_ci if (!ptr) 19762306a36Sopenharmony_ci goto error; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return buf; 20062306a36Sopenharmony_cierror: 20162306a36Sopenharmony_ci free(buf); 20262306a36Sopenharmony_ci return NULL; 20362306a36Sopenharmony_ci} 204