demangle-java.c 4.2 KB

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