scallgraph.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * This is a very small gcc plugin to generate a function callgraph of the compiled source
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * These are the four essential freedoms with GNU GPL software:
  18. * 1: freedom to run the program, for any purpose
  19. * 2: freedom to study how the program works, and change it to make it do what you wish
  20. * 3: freedom to redistribute copies to help your Free Software friends
  21. * 4: freedom to distribute copies of your modified versions to your Free Software friends
  22. * , ,
  23. * / \
  24. * ((__-^^-,-^^-__))
  25. * `-_---' `---_-'
  26. * `--|o` 'o|--'
  27. * \ ` /
  28. * ): :(
  29. * :o_o:
  30. * "-"
  31. */
  32. #include "gcc-plugin.h"
  33. #include "plugin.h"
  34. #include "plugin-version.h"
  35. #include "tree.h"
  36. #include "cgraph.h"
  37. #include <string>
  38. #include <vector>
  39. #include <map>
  40. #define DEBUG(...) /**/
  41. /* #define DEBUG(...) fprintf(stderr, __VA_ARGS__) */
  42. int plugin_is_GPL_compatible;
  43. extern symbol_table *symtab;
  44. /* Define main structure. */
  45. typedef std::string Name;
  46. typedef std::vector<std::string> Callees;
  47. typedef std::map<Name, Callees> CallGraph;
  48. static CallGraph call_graph;
  49. #define FUNCTION_NAME(fun) (const char*) IDENTIFIER_POINTER \
  50. (DECL_ASSEMBLER_NAME ((fun) ->decl))
  51. /* Plugin callback function for PLUGIN_ALL_IPA_PASSES_START */
  52. void
  53. dump_callgraph (void * ARG_UNUSED (gcc_data),
  54. void * ARG_UNUSED (data))
  55. {
  56. FILE *f = NULL;
  57. const char *func = NULL;
  58. size_t namelen = 0;
  59. size_t extlen = 0;
  60. char *buf = NULL;
  61. int n = 0;
  62. const char *dump_base_name2 = NULL;
  63. for (cgraph_node* node = symtab->first_function ();
  64. node;
  65. node = symtab->next_function (node))
  66. {
  67. if (!node->callees)
  68. continue;
  69. for (cgraph_edge* edge = node->callees;
  70. edge;
  71. edge = edge->next_callee)
  72. {
  73. if (edge->caller->get_fun()) {
  74. std::string sfn (FUNCTION_NAME (edge->caller->get_fun ()));
  75. if (edge->callee->get_fun()) {
  76. std::string dfn (FUNCTION_NAME (edge->callee->get_fun ()));
  77. call_graph[sfn].push_back (dfn);
  78. n++;
  79. } else {
  80. /* std todo. this can happen and creates segv */
  81. }
  82. } else {
  83. /* sfn todo can be nil */
  84. }
  85. }
  86. }
  87. if(n == 0) {
  88. return;
  89. }
  90. for (CallGraph::iterator iter = call_graph.begin ();
  91. iter != call_graph.end ();
  92. ++iter)
  93. {
  94. // only create file when there is data
  95. if (!f) {
  96. if (dump_base_name) {
  97. dump_base_name2 = dump_base_name;
  98. } else {
  99. dump_base_name2 = "scallgraph";
  100. }
  101. namelen = strlen (dump_base_name2);
  102. extlen = strlen (".scallgraph.gv") + 1;
  103. buf = XALLOCAVEC (char, namelen + extlen);
  104. memcpy (buf, dump_base_name2, namelen);
  105. memcpy (buf + namelen, ".scallgraph.gv", extlen);
  106. f = fopen (buf,"w");
  107. fprintf (f,"// function callgraph generated with gcc scallgraph plugin running with gcc version %s\n",gcc_version.basever);
  108. fprintf (f, "digraph scallgraph {\n");
  109. }
  110. DEBUG ("%s\n", iter->first.c_str ());
  111. func = iter->first.c_str ();
  112. for (Callees::iterator citer = iter->second.begin ();
  113. citer != iter->second.end ();
  114. ++citer)
  115. {
  116. DEBUG ("\t-> %s\n", citer->c_str ());
  117. fprintf (f," \"%s\" -> \"%s\";\n", func, citer->c_str () );
  118. }
  119. }
  120. if(f) {
  121. fprintf (f, "}\n");
  122. fclose (f);
  123. f = NULL;
  124. }
  125. return;
  126. }
  127. int
  128. plugin_init (struct plugin_name_args *plugin_info,
  129. struct plugin_gcc_version *version)
  130. {
  131. /* Check the building plugin compiler and the executing compiler are the
  132. same. */
  133. if (!plugin_default_version_check (version, &gcc_version))
  134. return 1;
  135. /* Dump the callgraph before IPA passes. */
  136. register_callback (plugin_info -> base_name,
  137. PLUGIN_ALL_IPA_PASSES_START,
  138. dump_callgraph,
  139. NULL);
  140. return 0;
  141. }
  142. /* end. */