Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <sys/types.h>
0003 #include <stdio.h>
0004 #include <stdlib.h>
0005 #include <string.h>
0006 #include "symbol.h"
0007 
0008 #include "demangle-java.h"
0009 
0010 #include <linux/ctype.h>
0011 #include <linux/kernel.h>
0012 
0013 enum {
0014     MODE_PREFIX = 0,
0015     MODE_CLASS  = 1,
0016     MODE_FUNC   = 2,
0017     MODE_TYPE   = 3,
0018     MODE_CTYPE  = 4, /* class arg */
0019 };
0020 
0021 #define BASE_ENT(c, n)  [c - 'A']=n
0022 static const char *base_types['Z' - 'A' + 1] = {
0023     BASE_ENT('B', "byte" ),
0024     BASE_ENT('C', "char" ),
0025     BASE_ENT('D', "double" ),
0026     BASE_ENT('F', "float" ),
0027     BASE_ENT('I', "int" ),
0028     BASE_ENT('J', "long" ),
0029     BASE_ENT('S', "short" ),
0030     BASE_ENT('Z', "boolean" ),
0031 };
0032 
0033 /*
0034  * demangle Java symbol between str and end positions and stores
0035  * up to maxlen characters into buf. The parser starts in mode.
0036  *
0037  * Use MODE_PREFIX to process entire prototype till end position
0038  * Use MODE_TYPE to process return type if str starts on return type char
0039  *
0040  *  Return:
0041  *  success: buf
0042  *  error  : NULL
0043  */
0044 static char *
0045 __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
0046 {
0047     int rlen = 0;
0048     int array = 0;
0049     int narg = 0;
0050     const char *q;
0051 
0052     if (!end)
0053         end = str + strlen(str);
0054 
0055     for (q = str; q != end; q++) {
0056 
0057         if (rlen == (maxlen - 1))
0058             break;
0059 
0060         switch (*q) {
0061         case 'L':
0062             if (mode == MODE_PREFIX || mode == MODE_TYPE) {
0063                 if (mode == MODE_TYPE) {
0064                     if (narg)
0065                         rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
0066                     narg++;
0067                 }
0068                 if (mode == MODE_PREFIX)
0069                     mode = MODE_CLASS;
0070                 else
0071                     mode = MODE_CTYPE;
0072             } else
0073                 buf[rlen++] = *q;
0074             break;
0075         case 'B':
0076         case 'C':
0077         case 'D':
0078         case 'F':
0079         case 'I':
0080         case 'J':
0081         case 'S':
0082         case 'Z':
0083             if (mode == MODE_TYPE) {
0084                 if (narg)
0085                     rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
0086                 rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
0087                 while (array--)
0088                     rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
0089                 array = 0;
0090                 narg++;
0091             } else
0092                 buf[rlen++] = *q;
0093             break;
0094         case 'V':
0095             if (mode == MODE_TYPE) {
0096                 rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
0097                 while (array--)
0098                     rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
0099                 array = 0;
0100             } else
0101                 buf[rlen++] = *q;
0102             break;
0103         case '[':
0104             if (mode != MODE_TYPE)
0105                 goto error;
0106             array++;
0107             break;
0108         case '(':
0109             if (mode != MODE_FUNC)
0110                 goto error;
0111             buf[rlen++] = *q;
0112             mode = MODE_TYPE;
0113             break;
0114         case ')':
0115             if (mode != MODE_TYPE)
0116                 goto error;
0117             buf[rlen++] = *q;
0118             narg = 0;
0119             break;
0120         case ';':
0121             if (mode != MODE_CLASS && mode != MODE_CTYPE)
0122                 goto error;
0123             /* safe because at least one other char to process */
0124             if (isalpha(*(q + 1)) && mode == MODE_CLASS)
0125                 rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
0126             if (mode == MODE_CLASS)
0127                 mode = MODE_FUNC;
0128             else if (mode == MODE_CTYPE)
0129                 mode = MODE_TYPE;
0130             break;
0131         case '/':
0132             if (mode != MODE_CLASS && mode != MODE_CTYPE)
0133                 goto error;
0134             rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
0135             break;
0136         default :
0137             buf[rlen++] = *q;
0138         }
0139     }
0140     buf[rlen] = '\0';
0141     return buf;
0142 error:
0143     return NULL;
0144 }
0145 
0146 /*
0147  * Demangle Java function signature (openJDK, not GCJ)
0148  * input:
0149  *  str: string to parse. String is not modified
0150  *    flags: combination of JAVA_DEMANGLE_* flags to modify demangling
0151  * return:
0152  *  if input can be demangled, then a newly allocated string is returned.
0153  *  if input cannot be demangled, then NULL is returned
0154  *
0155  * Note: caller is responsible for freeing demangled string
0156  */
0157 char *
0158 java_demangle_sym(const char *str, int flags)
0159 {
0160     char *buf, *ptr;
0161     char *p;
0162     size_t len, l1 = 0;
0163 
0164     if (!str)
0165         return NULL;
0166 
0167     /* find start of return type */
0168     p = strrchr(str, ')');
0169     if (!p)
0170         return NULL;
0171 
0172     /*
0173      * expansion factor estimated to 3x
0174      */
0175     len = strlen(str) * 3 + 1;
0176     buf = malloc(len);
0177     if (!buf)
0178         return NULL;
0179 
0180     buf[0] = '\0';
0181     if (!(flags & JAVA_DEMANGLE_NORET)) {
0182         /*
0183          * get return type first
0184          */
0185         ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
0186         if (!ptr)
0187             goto error;
0188 
0189         /* add space between return type and function prototype */
0190         l1 = strlen(buf);
0191         buf[l1++] = ' ';
0192     }
0193 
0194     /* process function up to return type */
0195     ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
0196     if (!ptr)
0197         goto error;
0198 
0199     return buf;
0200 error:
0201     free(buf);
0202     return NULL;
0203 }