cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

demangle-java.c (4285B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <sys/types.h>
      3#include <stdio.h>
      4#include <stdlib.h>
      5#include <string.h>
      6#include "symbol.h"
      7
      8#include "demangle-java.h"
      9
     10#include <linux/ctype.h>
     11#include <linux/kernel.h>
     12
     13enum {
     14	MODE_PREFIX = 0,
     15	MODE_CLASS  = 1,
     16	MODE_FUNC   = 2,
     17	MODE_TYPE   = 3,
     18	MODE_CTYPE  = 4, /* class arg */
     19};
     20
     21#define BASE_ENT(c, n)	[c - 'A']=n
     22static const char *base_types['Z' - 'A' + 1] = {
     23	BASE_ENT('B', "byte" ),
     24	BASE_ENT('C', "char" ),
     25	BASE_ENT('D', "double" ),
     26	BASE_ENT('F', "float" ),
     27	BASE_ENT('I', "int" ),
     28	BASE_ENT('J', "long" ),
     29	BASE_ENT('S', "short" ),
     30	BASE_ENT('Z', "boolean" ),
     31};
     32
     33/*
     34 * demangle Java symbol between str and end positions and stores
     35 * up to maxlen characters into buf. The parser starts in mode.
     36 *
     37 * Use MODE_PREFIX to process entire prototype till end position
     38 * Use MODE_TYPE to process return type if str starts on return type char
     39 *
     40 *  Return:
     41 *	success: buf
     42 *	error  : NULL
     43 */
     44static char *
     45__demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
     46{
     47	int rlen = 0;
     48	int array = 0;
     49	int narg = 0;
     50	const char *q;
     51
     52	if (!end)
     53		end = str + strlen(str);
     54
     55	for (q = str; q != end; q++) {
     56
     57		if (rlen == (maxlen - 1))
     58			break;
     59
     60		switch (*q) {
     61		case 'L':
     62			if (mode == MODE_PREFIX || mode == MODE_TYPE) {
     63				if (mode == MODE_TYPE) {
     64					if (narg)
     65						rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
     66					narg++;
     67				}
     68				if (mode == MODE_PREFIX)
     69					mode = MODE_CLASS;
     70				else
     71					mode = MODE_CTYPE;
     72			} else
     73				buf[rlen++] = *q;
     74			break;
     75		case 'B':
     76		case 'C':
     77		case 'D':
     78		case 'F':
     79		case 'I':
     80		case 'J':
     81		case 'S':
     82		case 'Z':
     83			if (mode == MODE_TYPE) {
     84				if (narg)
     85					rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
     86				rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
     87				while (array--)
     88					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
     89				array = 0;
     90				narg++;
     91			} else
     92				buf[rlen++] = *q;
     93			break;
     94		case 'V':
     95			if (mode == MODE_TYPE) {
     96				rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
     97				while (array--)
     98					rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
     99				array = 0;
    100			} else
    101				buf[rlen++] = *q;
    102			break;
    103		case '[':
    104			if (mode != MODE_TYPE)
    105				goto error;
    106			array++;
    107			break;
    108		case '(':
    109			if (mode != MODE_FUNC)
    110				goto error;
    111			buf[rlen++] = *q;
    112			mode = MODE_TYPE;
    113			break;
    114		case ')':
    115			if (mode != MODE_TYPE)
    116				goto error;
    117			buf[rlen++] = *q;
    118			narg = 0;
    119			break;
    120		case ';':
    121			if (mode != MODE_CLASS && mode != MODE_CTYPE)
    122				goto error;
    123			/* safe because at least one other char to process */
    124			if (isalpha(*(q + 1)) && mode == MODE_CLASS)
    125				rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
    126			if (mode == MODE_CLASS)
    127				mode = MODE_FUNC;
    128			else if (mode == MODE_CTYPE)
    129				mode = MODE_TYPE;
    130			break;
    131		case '/':
    132			if (mode != MODE_CLASS && mode != MODE_CTYPE)
    133				goto error;
    134			rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
    135			break;
    136		default :
    137			buf[rlen++] = *q;
    138		}
    139	}
    140	buf[rlen] = '\0';
    141	return buf;
    142error:
    143	return NULL;
    144}
    145
    146/*
    147 * Demangle Java function signature (openJDK, not GCJ)
    148 * input:
    149 * 	str: string to parse. String is not modified
    150 *    flags: combination of JAVA_DEMANGLE_* flags to modify demangling
    151 * return:
    152 *	if input can be demangled, then a newly allocated string is returned.
    153 *	if input cannot be demangled, then NULL is returned
    154 *
    155 * Note: caller is responsible for freeing demangled string
    156 */
    157char *
    158java_demangle_sym(const char *str, int flags)
    159{
    160	char *buf, *ptr;
    161	char *p;
    162	size_t len, l1 = 0;
    163
    164	if (!str)
    165		return NULL;
    166
    167	/* find start of return type */
    168	p = strrchr(str, ')');
    169	if (!p)
    170		return NULL;
    171
    172	/*
    173	 * expansion factor estimated to 3x
    174	 */
    175	len = strlen(str) * 3 + 1;
    176	buf = malloc(len);
    177	if (!buf)
    178		return NULL;
    179
    180	buf[0] = '\0';
    181	if (!(flags & JAVA_DEMANGLE_NORET)) {
    182		/*
    183		 * get return type first
    184		 */
    185		ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
    186		if (!ptr)
    187			goto error;
    188
    189		/* add space between return type and function prototype */
    190		l1 = strlen(buf);
    191		buf[l1++] = ' ';
    192	}
    193
    194	/* process function up to return type */
    195	ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
    196	if (!ptr)
    197		goto error;
    198
    199	return buf;
    200error:
    201	free(buf);
    202	return NULL;
    203}