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 <string.h>
   5#include "util.h"
   6#include "debug.h"
   7#include "symbol.h"
   8
   9#include "demangle-java.h"
  10
  11#include "sane_ctype.h"
  12
  13enum {
  14        MODE_PREFIX = 0,
  15        MODE_CLASS  = 1,
  16        MODE_FUNC   = 2,
  17        MODE_TYPE   = 3,
  18        MODE_CTYPE  = 3, /* 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', "bool" ),
  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_CTYPE) {
  63                                if (mode == MODE_CTYPE) {
  64                                        if (narg)
  65                                                rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
  66                                        narg++;
  67                                }
  68                                rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
  69                                if (mode == MODE_PREFIX)
  70                                        mode = MODE_CLASS;
  71                        } else
  72                                buf[rlen++] = *q;
  73                        break;
  74                case 'B':
  75                case 'C':
  76                case 'D':
  77                case 'F':
  78                case 'I':
  79                case 'J':
  80                case 'S':
  81                case 'Z':
  82                        if (mode == MODE_TYPE) {
  83                                if (narg)
  84                                        rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
  85                                rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
  86                                while (array--)
  87                                        rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
  88                                array = 0;
  89                                narg++;
  90                        } else
  91                                buf[rlen++] = *q;
  92                        break;
  93                case 'V':
  94                        if (mode == MODE_TYPE) {
  95                                rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
  96                                while (array--)
  97                                        rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
  98                                array = 0;
  99                        } else
 100                                buf[rlen++] = *q;
 101                        break;
 102                case '[':
 103                        if (mode != MODE_TYPE)
 104                                goto error;
 105                        array++;
 106                        break;
 107                case '(':
 108                        if (mode != MODE_FUNC)
 109                                goto error;
 110                        buf[rlen++] = *q;
 111                        mode = MODE_TYPE;
 112                        break;
 113                case ')':
 114                        if (mode != MODE_TYPE)
 115                                goto error;
 116                        buf[rlen++] = *q;
 117                        narg = 0;
 118                        break;
 119                case ';':
 120                        if (mode != MODE_CLASS && mode != MODE_CTYPE)
 121                                goto error;
 122                        /* safe because at least one other char to process */
 123                        if (isalpha(*(q + 1)))
 124                                rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
 125                        if (mode == MODE_CLASS)
 126                                mode = MODE_FUNC;
 127                        else if (mode == MODE_CTYPE)
 128                                mode = MODE_TYPE;
 129                        break;
 130                case '/':
 131                        if (mode != MODE_CLASS && mode != MODE_CTYPE)
 132                                goto error;
 133                        rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
 134                        break;
 135                default :
 136                        buf[rlen++] = *q;
 137                }
 138        }
 139        buf[rlen] = '\0';
 140        return buf;
 141error:
 142        return NULL;
 143}
 144
 145/*
 146 * Demangle Java function signature (openJDK, not GCJ)
 147 * input:
 148 *      str: string to parse. String is not modified
 149 *    flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
 150 * return:
 151 *      if input can be demangled, then a newly allocated string is returned.
 152 *      if input cannot be demangled, then NULL is returned
 153 *
 154 * Note: caller is responsible for freeing demangled string
 155 */
 156char *
 157java_demangle_sym(const char *str, int flags)
 158{
 159        char *buf, *ptr;
 160        char *p;
 161        size_t len, l1 = 0;
 162
 163        if (!str)
 164                return NULL;
 165
 166        /* find start of retunr type */
 167        p = strrchr(str, ')');
 168        if (!p)
 169                return NULL;
 170
 171        /*
 172         * expansion factor estimated to 3x
 173         */
 174        len = strlen(str) * 3 + 1;
 175        buf = malloc(len);
 176        if (!buf)
 177                return NULL;
 178
 179        buf[0] = '\0';
 180        if (!(flags & JAVA_DEMANGLE_NORET)) {
 181                /*
 182                 * get return type first
 183                 */
 184                ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
 185                if (!ptr)
 186                        goto error;
 187
 188                /* add space between return type and function prototype */
 189                l1 = strlen(buf);
 190                buf[l1++] = ' ';
 191        }
 192
 193        /* process function up to return type */
 194        ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
 195        if (!ptr)
 196                goto error;
 197
 198        return buf;
 199error:
 200        free(buf);
 201        return NULL;
 202}
 203