demangle-java.c 4.1 KB

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