linux/tools/perf/util/demangle-java.c
<<
>>
Prefs
   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}
 204