lkml.org 
[lkml]   [2015]   [Mar]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 2/4] perf tools: add Java demangling support
    Date
    Add Java function descriptor demangling support.
    Something bfd cannot do.

    Use the JAVA_DEMANGLE_NORET flag to avoid decoding the
    return type of functions.

    Signed-off-by: Stephane Eranian <eranian@google.com>
    ---
    tools/perf/util/Build | 1 +
    tools/perf/util/demangle-java.c | 199 ++++++++++++++++++++++++++++++++++++++++
    tools/perf/util/demangle-java.h | 10 ++
    tools/perf/util/symbol-elf.c | 3 +
    4 files changed, 213 insertions(+)
    create mode 100644 tools/perf/util/demangle-java.c
    create mode 100644 tools/perf/util/demangle-java.h

    diff --git a/tools/perf/util/Build b/tools/perf/util/Build
    index 797490a..9bff65e 100644
    --- a/tools/perf/util/Build
    +++ b/tools/perf/util/Build
    @@ -74,6 +74,7 @@ libperf-y += data.o
    libperf-$(CONFIG_X86) += tsc.o
    libperf-y += cloexec.o
    libperf-y += thread-stack.o
    +libperf-y += demangle-java.o

    libperf-$(CONFIG_LIBELF) += symbol-elf.o
    libperf-$(CONFIG_LIBELF) += probe-event.o
    diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
    new file mode 100644
    index 0000000..79d5484
    --- /dev/null
    +++ b/tools/perf/util/demangle-java.c
    @@ -0,0 +1,199 @@
    +#include <sys/types.h>
    +#include <stdio.h>
    +#include <string.h>
    +#include "util.h"
    +#include "debug.h"
    +#include "symbol.h"
    +
    +#include "demangle-java.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 += snprintf(buf+rlen, maxlen - rlen, ", ");
    + narg++;
    + }
    + rlen += snprintf(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 += snprintf(buf+rlen, maxlen - rlen, ", ");
    + rlen += snprintf(buf+rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
    + while(array--)
    + rlen += snprintf(buf+rlen, maxlen - rlen, "[]");
    + array = 0;
    + narg++;
    + } else
    + buf[rlen++] = *q;
    + break;
    + case 'V':
    + if (mode == MODE_TYPE) {
    + rlen += snprintf(buf+rlen, maxlen - rlen, "void");
    + while(array--)
    + rlen += snprintf(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 += snprintf(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 += snprintf(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;
    +}
    diff --git a/tools/perf/util/demangle-java.h b/tools/perf/util/demangle-java.h
    new file mode 100644
    index 0000000..a981c1f
    --- /dev/null
    +++ b/tools/perf/util/demangle-java.h
    @@ -0,0 +1,10 @@
    +#ifndef __PERF_DEMANGLE_JAVA
    +#define __PERF_DEMANGLE_JAVA 1
    +/*
    + * demangle function flags
    + */
    +#define JAVA_DEMANGLE_NORET 0x1 /* do not process return type */
    +
    +char * java_demangle_sym(const char *str, int flags);
    +
    +#endif /* __PERF_DEMANGLE_JAVA */
    diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
    index 476268c..2174bf4 100644
    --- a/tools/perf/util/symbol-elf.c
    +++ b/tools/perf/util/symbol-elf.c
    @@ -6,6 +6,7 @@
    #include <inttypes.h>

    #include "symbol.h"
    +#include "demangle-java.h"
    #include "machine.h"
    #include "vdso.h"
    #include <symbol/kallsyms.h>
    @@ -1046,6 +1047,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
    demangle_flags = DMGL_PARAMS | DMGL_ANSI;

    demangled = bfd_demangle(NULL, elf_name, demangle_flags);
    + if (demangled == NULL)
    + demangled = java_demangle_sym(elf_name, JAVA_DEMANGLE_NORET);
    if (demangled != NULL)
    elf_name = demangled;
    }
    --
    1.9.1


    \
     
     \ /
      Last update: 2015-03-25 00:01    [W:4.148 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site