204 lines · c
1// SPDX-License-Identifier: GPL-2.02#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']=n22static 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 stores35 * up to maxlen characters into buf. The parser starts in mode.36 *37 * Use MODE_PREFIX to process entire prototype till end position38 * Use MODE_TYPE to process return type if str starts on return type char39 *40 * Return:41 * success: buf42 * error : NULL43 */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 else71 mode = MODE_CTYPE;72 } else73 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 } else92 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 } else101 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 modified150 * flags: combination of JAVA_DEMANGLE_* flags to modify demangling151 * return:152 * if input can be demangled, then a newly allocated string is returned.153 * if input cannot be demangled, then NULL is returned154 *155 * Note: caller is responsible for freeing demangled string156 */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 3x174 */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 first184 */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