123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- /*
- * This is a very small gcc plugin to generate a function callgraph of the compiled source
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * These are the four essential freedoms with GNU GPL software:
- * 1: freedom to run the program, for any purpose
- * 2: freedom to study how the program works, and change it to make it do what you wish
- * 3: freedom to redistribute copies to help your Free Software friends
- * 4: freedom to distribute copies of your modified versions to your Free Software friends
- * , ,
- * / \
- * ((__-^^-,-^^-__))
- * `-_---' `---_-'
- * `--|o` 'o|--'
- * \ ` /
- * ): :(
- * :o_o:
- * "-"
- */
- #include "gcc-plugin.h"
- #include "plugin.h"
- #include "plugin-version.h"
- #include "tree.h"
- #include "cgraph.h"
- #include <string>
- #include <vector>
- #include <map>
- #define DEBUG(...) /**/
- /* #define DEBUG(...) fprintf(stderr, __VA_ARGS__) */
- int plugin_is_GPL_compatible;
- extern symbol_table *symtab;
- /* Define main structure. */
- typedef std::string Name;
- typedef std::vector<std::string> Callees;
- typedef std::map<Name, Callees> CallGraph;
- static CallGraph call_graph;
- #define FUNCTION_NAME(fun) (const char*) IDENTIFIER_POINTER \
- (DECL_ASSEMBLER_NAME ((fun) ->decl))
- /* Plugin callback function for PLUGIN_ALL_IPA_PASSES_START */
- void
- dump_callgraph (void * ARG_UNUSED (gcc_data),
- void * ARG_UNUSED (data))
- {
- FILE *f = NULL;
- const char *func = NULL;
- size_t namelen = 0;
- size_t extlen = 0;
- char *buf = NULL;
- int n = 0;
- const char *dump_base_name2 = NULL;
- for (cgraph_node* node = symtab->first_function ();
- node;
- node = symtab->next_function (node))
- {
- if (!node->callees)
- continue;
- for (cgraph_edge* edge = node->callees;
- edge;
- edge = edge->next_callee)
- {
- if (edge->caller->get_fun()) {
- std::string sfn (FUNCTION_NAME (edge->caller->get_fun ()));
- if (edge->callee->get_fun()) {
- std::string dfn (FUNCTION_NAME (edge->callee->get_fun ()));
- call_graph[sfn].push_back (dfn);
- n++;
- } else {
- /* std todo. this can happen and creates segv */
- }
- } else {
- /* sfn todo can be nil */
- }
- }
- }
- if(n == 0) {
- return;
- }
- for (CallGraph::iterator iter = call_graph.begin ();
- iter != call_graph.end ();
- ++iter)
- {
- // only create file when there is data
- if (!f) {
- if (dump_base_name) {
- dump_base_name2 = dump_base_name;
- } else {
- dump_base_name2 = "scallgraph";
- }
- namelen = strlen (dump_base_name2);
- extlen = strlen (".scallgraph.gv") + 1;
- buf = XALLOCAVEC (char, namelen + extlen);
- memcpy (buf, dump_base_name2, namelen);
- memcpy (buf + namelen, ".scallgraph.gv", extlen);
- f = fopen (buf,"w");
- fprintf (f,"// function callgraph generated with gcc scallgraph plugin running with gcc version %s\n",gcc_version.basever);
- fprintf (f, "digraph scallgraph {\n");
- }
- DEBUG ("%s\n", iter->first.c_str ());
- func = iter->first.c_str ();
- for (Callees::iterator citer = iter->second.begin ();
- citer != iter->second.end ();
- ++citer)
- {
- DEBUG ("\t-> %s\n", citer->c_str ());
- fprintf (f," \"%s\" -> \"%s\";\n", func, citer->c_str () );
- }
- }
- if(f) {
- fprintf (f, "}\n");
- fclose (f);
- f = NULL;
- }
- return;
- }
- int
- plugin_init (struct plugin_name_args *plugin_info,
- struct plugin_gcc_version *version)
- {
- /* Check the building plugin compiler and the executing compiler are the
- same. */
- if (!plugin_default_version_check (version, &gcc_version))
- return 1;
- /* Dump the callgraph before IPA passes. */
- register_callback (plugin_info -> base_name,
- PLUGIN_ALL_IPA_PASSES_START,
- dump_callgraph,
- NULL);
- return 0;
- }
- /* end. */
|