mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-01 18:24:23 +08:00
3052ba56bc
We got the sane_ctype.h headers from git and kept using it so far, but since that code originally came from the kernel sources to the git sources, perhaps its better to just use the one in the kernel, so that we can leverage tools/perf/check_headers.sh to be notified when our copy gets out of sync, i.e. when fixes or goodies are added to the code we've copied. This will help with things like tools/lib/string.c where we want to have more things in common with the kernel, such as strim(), skip_spaces(), etc so as to go on removing the things that we have in tools/perf/util/ and instead using the code in the kernel, indirectly and removing things like EXPORT_SYMBOL(), etc, getting notified when fixes and improvements are made to the original code. Hopefully this also should help with reducing the difference of code hosted in tools/ to the one in the kernel proper. Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Link: https://lkml.kernel.org/n/tip-7k9868l713wqtgo01xxygn12@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
203 lines
4.2 KiB
C
203 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "util.h"
|
|
#include "debug.h"
|
|
#include "symbol.h"
|
|
|
|
#include "demangle-java.h"
|
|
|
|
#include <linux/ctype.h>
|
|
|
|
enum {
|
|
MODE_PREFIX = 0,
|
|
MODE_CLASS = 1,
|
|
MODE_FUNC = 2,
|
|
MODE_TYPE = 3,
|
|
MODE_CTYPE = 3, /* class arg */
|
|
};
|
|
|
|
#define BASE_ENT(c, n) [c - 'A']=n
|
|
static 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', "bool" ),
|
|
};
|
|
|
|
/*
|
|
* 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_CTYPE) {
|
|
if (mode == MODE_CTYPE) {
|
|
if (narg)
|
|
rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
|
|
narg++;
|
|
}
|
|
rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
|
|
if (mode == MODE_PREFIX)
|
|
mode = MODE_CLASS;
|
|
} 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)))
|
|
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: comobination 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 retunr 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;
|
|
}
|