demangle-java.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. #include "demangle-java.h"
  8. #include <linux/ctype.h>
  9. #include <linux/kernel.h>
  10. enum {
  11. MODE_PREFIX = 0,
  12. MODE_CLASS = 1,
  13. MODE_FUNC = 2,
  14. MODE_TYPE = 3,
  15. MODE_CTYPE = 4, /* class arg */
  16. };
  17. #define BASE_ENT(c, n) [c - 'A']=n
  18. static const char *base_types['Z' - 'A' + 1] = {
  19. BASE_ENT('B', "byte" ),
  20. BASE_ENT('C', "char" ),
  21. BASE_ENT('D', "double" ),
  22. BASE_ENT('F', "float" ),
  23. BASE_ENT('I', "int" ),
  24. BASE_ENT('J', "long" ),
  25. BASE_ENT('S', "short" ),
  26. BASE_ENT('Z', "boolean" ),
  27. };
  28. /*
  29. * demangle Java symbol between str and end positions and stores
  30. * up to maxlen characters into buf. The parser starts in mode.
  31. *
  32. * Use MODE_PREFIX to process entire prototype till end position
  33. * Use MODE_TYPE to process return type if str starts on return type char
  34. *
  35. * Return:
  36. * success: buf
  37. * error : NULL
  38. */
  39. static char *
  40. __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int mode)
  41. {
  42. int rlen = 0;
  43. int array = 0;
  44. int narg = 0;
  45. const char *q;
  46. if (!end)
  47. end = str + strlen(str);
  48. for (q = str; q != end; q++) {
  49. if (rlen == (maxlen - 1))
  50. break;
  51. switch (*q) {
  52. case 'L':
  53. if (mode == MODE_PREFIX || mode == MODE_TYPE) {
  54. if (mode == MODE_TYPE) {
  55. if (narg)
  56. rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
  57. narg++;
  58. }
  59. if (mode == MODE_PREFIX)
  60. mode = MODE_CLASS;
  61. else
  62. mode = MODE_CTYPE;
  63. } else
  64. buf[rlen++] = *q;
  65. break;
  66. case 'B':
  67. case 'C':
  68. case 'D':
  69. case 'F':
  70. case 'I':
  71. case 'J':
  72. case 'S':
  73. case 'Z':
  74. if (mode == MODE_TYPE) {
  75. if (narg)
  76. rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
  77. rlen += scnprintf(buf + rlen, maxlen - rlen, "%s", base_types[*q - 'A']);
  78. while (array--)
  79. rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
  80. array = 0;
  81. narg++;
  82. } else
  83. buf[rlen++] = *q;
  84. break;
  85. case 'V':
  86. if (mode == MODE_TYPE) {
  87. rlen += scnprintf(buf + rlen, maxlen - rlen, "void");
  88. while (array--)
  89. rlen += scnprintf(buf + rlen, maxlen - rlen, "[]");
  90. array = 0;
  91. } else
  92. buf[rlen++] = *q;
  93. break;
  94. case '[':
  95. if (mode != MODE_TYPE)
  96. goto error;
  97. array++;
  98. break;
  99. case '(':
  100. if (mode != MODE_FUNC)
  101. goto error;
  102. buf[rlen++] = *q;
  103. mode = MODE_TYPE;
  104. break;
  105. case ')':
  106. if (mode != MODE_TYPE)
  107. goto error;
  108. buf[rlen++] = *q;
  109. narg = 0;
  110. break;
  111. case ';':
  112. if (mode != MODE_CLASS && mode != MODE_CTYPE)
  113. goto error;
  114. /* safe because at least one other char to process */
  115. if (isalpha(*(q + 1)) && mode == MODE_CLASS)
  116. rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
  117. if (mode == MODE_CLASS)
  118. mode = MODE_FUNC;
  119. else if (mode == MODE_CTYPE)
  120. mode = MODE_TYPE;
  121. break;
  122. case '/':
  123. if (mode != MODE_CLASS && mode != MODE_CTYPE)
  124. goto error;
  125. rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
  126. break;
  127. default :
  128. buf[rlen++] = *q;
  129. }
  130. }
  131. buf[rlen] = '\0';
  132. return buf;
  133. error:
  134. return NULL;
  135. }
  136. /*
  137. * Demangle Java function signature (openJDK, not GCJ)
  138. * input:
  139. * str: string to parse. String is not modified
  140. * flags: comobination of JAVA_DEMANGLE_* flags to modify demangling
  141. * return:
  142. * if input can be demangled, then a newly allocated string is returned.
  143. * if input cannot be demangled, then NULL is returned
  144. *
  145. * Note: caller is responsible for freeing demangled string
  146. */
  147. char *
  148. java_demangle_sym(const char *str, int flags)
  149. {
  150. char *buf, *ptr;
  151. char *p;
  152. size_t len, l1 = 0;
  153. if (!str)
  154. return NULL;
  155. /* find start of retunr type */
  156. p = strrchr(str, ')');
  157. if (!p)
  158. return NULL;
  159. /*
  160. * expansion factor estimated to 3x
  161. */
  162. len = strlen(str) * 3 + 1;
  163. buf = malloc(len);
  164. if (!buf)
  165. return NULL;
  166. buf[0] = '\0';
  167. if (!(flags & JAVA_DEMANGLE_NORET)) {
  168. /*
  169. * get return type first
  170. */
  171. ptr = __demangle_java_sym(p + 1, NULL, buf, len, MODE_TYPE);
  172. if (!ptr)
  173. goto error;
  174. /* add space between return type and function prototype */
  175. l1 = strlen(buf);
  176. buf[l1++] = ' ';
  177. }
  178. /* process function up to return type */
  179. ptr = __demangle_java_sym(str, p + 1, buf + l1, len - l1, MODE_PREFIX);
  180. if (!ptr)
  181. goto error;
  182. return buf;
  183. error:
  184. free(buf);
  185. return NULL;
  186. }