linux/tools/perf/util/demangle-java.c
<<
>>
Prefs
   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
  10enum {
  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
  19static 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 */
  41static 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;
 138error:
 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 */
 153char *
 154java_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;
 196error:
 197        free(buf);
 198        return NULL;
 199}
 200