Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf symbols: add Java demangling support

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>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Carl Love <cel@us.ibm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: John McCutchan <johnmccutchan@google.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sonny Rao <sonnyrao@chromium.org>
Cc: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/1448874143-7269-2-git-send-email-eranian@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Stephane Eranian and committed by
Arnaldo Carvalho de Melo
e9c4bcdd 89fee59b

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