203 lines · 4.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <sys/types.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include "symbol.h" #include "demangle-java.h" #include <linux/ctype.h>#include <linux/kernel.h> enum {	MODE_PREFIX = 0,	MODE_CLASS  = 1,	MODE_FUNC   = 2,	MODE_TYPE   = 3,	MODE_CTYPE  = 4, /* class arg */}; #define BASE_ENT(c, n)	[c - 'A']=nstatic const char *base_types['Z' - 'A' + 1] = {	BASE_ENT('B', "byte" ),	BASE_ENT('C', "char" ),	BASE_ENT('D', "double" ),	BASE_ENT('F', "float" ),	BASE_ENT('I', "int" ),	BASE_ENT('J', "long" ),	BASE_ENT('S', "short" ),	BASE_ENT('Z', "boolean" ),}; /* * demangle Java symbol between str and end positions and stores * up to maxlen characters into buf. The parser starts in mode. * * Use MODE_PREFIX to process entire prototype till end position * Use MODE_TYPE to process return type if str starts on return type char * *  Return: *	success: buf *	error  : NULL */static char *__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode){	int rlen = 0;	int array = 0;	int narg = 0;	const char *q; 	if (!end)		end = str + strlen(str); 	for (q = str; q != end; q++) { 		if (rlen == (maxlen - 1))			break; 		switch (*q) {		case 'L':			if (mode == MODE_PREFIX || mode == MODE_TYPE) {				if (mode == MODE_TYPE) {					if (narg)						rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");					narg++;				}				if (mode == MODE_PREFIX)					mode = MODE_CLASS;				else					mode = MODE_CTYPE;			} else				buf[rlen++] = *q;			break;		case 'B':		case 'C':		case 'D':		case 'F':		case 'I':		case 'J':		case 'S':		case 'Z':			if (mode == MODE_TYPE) {				if (narg)					rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");				rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);				while (array--)					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");				array = 0;				narg++;			} else				buf[rlen++] = *q;			break;		case 'V':			if (mode == MODE_TYPE) {				rlen += scnprintf(buf + rlen, maxlen - rlen, "void");				while (array--)					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");				array = 0;			} else				buf[rlen++] = *q;			break;		case '[':			if (mode != MODE_TYPE)				goto error;			array++;			break;		case '(':			if (mode != MODE_FUNC)				goto error;			buf[rlen++] = *q;			mode = MODE_TYPE;			break;		case ')':			if (mode != MODE_TYPE)				goto error;			buf[rlen++] = *q;			narg = 0;			break;		case ';':			if (mode != MODE_CLASS && mode != MODE_CTYPE)				goto error;			/* safe because at least one other char to process */			if (isalpha(*(q + 1)) && mode == MODE_CLASS)				rlen += scnprintf(buf + rlen, maxlen - rlen, ".");			if (mode == MODE_CLASS)				mode = MODE_FUNC;			else if (mode == MODE_CTYPE)				mode = MODE_TYPE;			break;		case '/':			if (mode != MODE_CLASS && mode != MODE_CTYPE)				goto error;			rlen += scnprintf(buf + rlen, maxlen - rlen, ".");			break;		default :			buf[rlen++] = *q;		}	}	buf[rlen] = '\0';	return buf;error:	return NULL;} /* * Demangle Java function signature (openJDK, not GCJ) * input: * 	str: string to parse. String is not modified *    flags: combination of JAVA_DEMANGLE_* flags to modify demangling * return: *	if input can be demangled, then a newly allocated string is returned. *	if input cannot be demangled, then NULL is returned * * Note: caller is responsible for freeing demangled string */char *java_demangle_sym(const char *str, int flags){	char *buf, *ptr;	char *p;	size_t len, l1 = 0; 	if (!str)		return NULL; 	/* find start of return type */	p = strrchr(str, ')');	if (!p)		return NULL; 	/*	 * expansion factor estimated to 3x	 */	len = strlen(str) * 3 + 1;	buf = malloc(len);	if (!buf)		return NULL; 	buf[0] = '\0';	if (!(flags & JAVA_DEMANGLE_NORET)) {		/*		 * get return type first		 */		ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);		if (!ptr)			goto error; 		/* add space between return type and function prototype */		l1 = strlen(buf);		buf[l1++] = ' ';	} 	/* process function up to return type */	ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);	if (!ptr)		goto error; 	return buf;error:	free(buf);	return NULL;}