search.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Prototype search and parsing functions
  3. *
  4. * Copyright 2000 Jon Griffiths
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include "config.h"
  21. #include "winedump.h"
  22. static char *grep_buff = NULL;
  23. static char *fgrep_buff = NULL;
  24. static BOOL symbol_from_prototype (parsed_symbol *sym, const char *prototype);
  25. static const char *get_type (parsed_symbol *sym, const char *proto, int arg);
  26. /*******************************************************************
  27. * symbol_search
  28. *
  29. * Call Patrik Stridvall's 'function_grep.pl' script to retrieve a
  30. * function prototype from include file(s)
  31. */
  32. BOOL symbol_search (parsed_symbol *sym)
  33. {
  34. static const size_t MAX_RESULT_LEN = 1024;
  35. FILE *grep;
  36. int attempt = 0;
  37. assert (globals.do_code);
  38. assert (globals.directory);
  39. assert (sym && sym->symbol);
  40. if (!symbol_is_valid_c (sym))
  41. return FALSE;
  42. if (!grep_buff)
  43. grep_buff = xmalloc (MAX_RESULT_LEN);
  44. if (!fgrep_buff)
  45. fgrep_buff = xmalloc (MAX_RESULT_LEN);
  46. /* Use 'grep' to tell us which possible files the function is in,
  47. * then use 'function_grep.pl' to get the prototype. If this fails the
  48. * first time then give grep a more general query (that doesn't
  49. * require an opening argument brace on the line with the function name).
  50. */
  51. while (attempt < 2)
  52. {
  53. FILE *f_grep;
  54. char *cmd = strmake( "grep -d recurse -l \"%s%s\" %s", sym->symbol,
  55. !attempt ? "[:blank:]*(" : "", globals.directory);
  56. if (VERBOSE)
  57. puts (cmd);
  58. fflush (NULL); /* See 'man popen' */
  59. if (!(grep = popen (cmd, "r")))
  60. fatal ("Cannot execute grep -l");
  61. free (cmd);
  62. while (fgets (grep_buff, MAX_RESULT_LEN, grep))
  63. {
  64. int i;
  65. const char *extension = grep_buff;
  66. for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++) {
  67. if (grep_buff[i] == '.')
  68. extension = &grep_buff[i];
  69. }
  70. grep_buff[i] = '\0';
  71. /* Definitely not in these: */
  72. if (strcmp(extension,".dll") == 0 ||
  73. strcmp(extension,".lib") == 0 ||
  74. strcmp(extension,".so") == 0 ||
  75. strcmp(extension,".o") == 0)
  76. continue;
  77. if (VERBOSE)
  78. puts (grep_buff);
  79. cmd = strmake( "function_grep.pl %s \"%s\"", sym->symbol, grep_buff );
  80. if (VERBOSE)
  81. puts (cmd);
  82. fflush (NULL); /* See 'man popen' */
  83. if (!(f_grep = popen (cmd, "r")))
  84. fatal ("Cannot execute function_grep.pl");
  85. free (cmd);
  86. while (fgets (grep_buff, MAX_RESULT_LEN, f_grep))
  87. {
  88. char *iter = grep_buff;
  89. /* Keep only the first line */
  90. symbol_clean_string(grep_buff);
  91. for (i = 0; grep_buff[i] && grep_buff[i] != '\n' ; i++)
  92. ;
  93. grep_buff[i] = '\0';
  94. if (VERBOSE)
  95. puts (grep_buff);
  96. while ((iter = strstr (iter, sym->symbol)))
  97. {
  98. if (iter > grep_buff && (iter[-1] == ' ' || iter[-1] == '*') &&
  99. (iter[strlen (sym->symbol)] == ' ' ||
  100. iter[strlen (sym->symbol)] == '('))
  101. {
  102. if (VERBOSE)
  103. printf ("Prototype '%s' looks OK, processing\n", grep_buff);
  104. if (symbol_from_prototype (sym, grep_buff))
  105. {
  106. pclose (f_grep);
  107. pclose (grep);
  108. return TRUE; /* OK */
  109. }
  110. if (VERBOSE)
  111. puts ("Failed, trying next");
  112. }
  113. else
  114. iter += strlen (sym->symbol);
  115. }
  116. }
  117. pclose (f_grep);
  118. }
  119. pclose (grep);
  120. attempt++;
  121. }
  122. return FALSE; /* Not found */
  123. }
  124. /*******************************************************************
  125. * symbol_from_prototype
  126. *
  127. * Convert a C prototype into a symbol
  128. */
  129. static BOOL symbol_from_prototype (parsed_symbol *sym, const char *proto)
  130. {
  131. const char *iter;
  132. BOOL found;
  133. proto = get_type (sym, proto, -1); /* Get return type */
  134. if (!proto)
  135. return FALSE;
  136. iter = str_match (proto, sym->symbol, &found);
  137. if (!found)
  138. {
  139. char *call;
  140. /* Calling Convention */
  141. iter = strchr (iter, ' ');
  142. if (!iter)
  143. return FALSE;
  144. call = str_substring (proto, iter);
  145. if (!strcasecmp (call, "cdecl") || !strcasecmp (call, "__cdecl"))
  146. sym->flags |= SYM_CDECL;
  147. else
  148. sym->flags |= SYM_STDCALL;
  149. free (call);
  150. iter = str_match (iter, sym->symbol, &found);
  151. if (!found)
  152. return FALSE;
  153. if (VERBOSE)
  154. printf ("Using %s calling convention\n",
  155. sym->flags & SYM_CDECL ? "cdecl" : "stdcall");
  156. }
  157. else
  158. sym->flags = CALLING_CONVENTION;
  159. sym->function_name = xstrdup (sym->symbol);
  160. proto = iter;
  161. /* Now should be the arguments */
  162. if (*proto++ != '(')
  163. return FALSE;
  164. for (; *proto == ' '; proto++);
  165. if (!strncmp (proto, "void", 4))
  166. return TRUE;
  167. do
  168. {
  169. /* Process next argument */
  170. str_match (proto, "...", &sym->varargs);
  171. if (sym->varargs)
  172. return TRUE;
  173. if (!(proto = get_type (sym, proto, sym->argc)))
  174. return FALSE;
  175. sym->argc++;
  176. if (*proto == ',')
  177. proto++;
  178. else if (*proto != ')')
  179. return FALSE;
  180. } while (*proto != ')');
  181. return TRUE;
  182. }
  183. /*******************************************************************
  184. * get_type
  185. *
  186. * Read a type from a prototype
  187. */
  188. static const char *get_type (parsed_symbol *sym, const char *proto, int arg)
  189. {
  190. BOOL is_const, is_volatile, is_struct, is_signed, is_unsigned;
  191. int ptrs = 0;
  192. const char *iter, *base_type, *catch_unsigned, *proto_str;
  193. char dest_type, *type_str;
  194. assert (sym && sym->symbol);
  195. assert (proto && *proto);
  196. assert (arg < 0 || (unsigned)arg == sym->argc);
  197. proto_str = str_match (proto, "const", &is_const);
  198. proto_str = str_match (proto_str, "volatile", &is_volatile);
  199. proto_str = str_match (proto_str, "struct", &is_struct);
  200. if (!is_struct)
  201. proto_str = str_match (proto_str, "union", &is_struct);
  202. catch_unsigned = proto_str;
  203. proto_str = str_match (proto_str, "unsigned", &is_unsigned);
  204. proto_str = str_match (proto_str, "signed", &is_signed);
  205. /* Can have 'unsigned const' or 'const unsigned' etc */
  206. if (!is_const)
  207. proto_str = str_match (proto_str, "const", &is_const);
  208. if (!is_volatile)
  209. proto_str = str_match (proto_str, "volatile", &is_volatile);
  210. base_type = proto_str;
  211. iter = str_find_set (proto_str, " ,*)");
  212. if (!iter)
  213. return NULL;
  214. if (arg < 0 && (is_signed || is_unsigned))
  215. {
  216. /* Prevent calling convention from being swallowed by 'un/signed' alone */
  217. if (strncmp (base_type, "int", 3) && strncmp (base_type, "long", 4) &&
  218. strncmp (base_type, "short", 5) && strncmp (base_type, "char", 4))
  219. {
  220. iter = proto_str;
  221. base_type = catch_unsigned;
  222. } else
  223. catch_unsigned = NULL;
  224. }
  225. else
  226. catch_unsigned = NULL;
  227. /* FIXME: skip const/volatile here too */
  228. for (proto_str = iter; *proto_str; proto_str++)
  229. if (*proto_str == '*')
  230. ptrs++;
  231. else if (*proto_str != ' ')
  232. break;
  233. if (!*proto_str)
  234. return NULL;
  235. type_str = str_substring (proto, proto_str);
  236. if (iter == base_type || catch_unsigned)
  237. {
  238. /* 'unsigned' with no type */
  239. type_str = strmake( "%s int", type_str );
  240. }
  241. symbol_clean_string (type_str);
  242. dest_type = symbol_get_type (type_str);
  243. if (arg < 0)
  244. {
  245. sym->return_text = type_str;
  246. sym->return_type = dest_type;
  247. }
  248. else
  249. {
  250. sym->arg_type [arg] = dest_type;
  251. sym->arg_flag [arg] = is_const ? CT_CONST : is_volatile ? CT_VOLATILE : 0;
  252. if (*proto_str == ',' || *proto_str == ')')
  253. sym->arg_name [arg] = strmake( "arg%u", arg );
  254. else
  255. {
  256. iter = str_find_set (proto_str, " ,)");
  257. if (!iter)
  258. {
  259. free (type_str);
  260. return NULL;
  261. }
  262. sym->arg_name [arg] = str_substring (proto_str, iter);
  263. proto_str = iter;
  264. }
  265. sym->arg_text [arg] = type_str;
  266. }
  267. return proto_str;
  268. }