view src/cospy.c @ 8:5502f175d348

Show functions being called
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 08 Sep 2010 22:16:25 +0800
parents 7fec19e27411
children 958c2366e682
line wrap: on
line source

#include "gcc-plugin.h"
#include "plugin-version.h"
#include "system.h"
#include "coretypes.h"
#include "tree-pass.h"
#include "tree.h"
#include "gimple.h"
#include "cgraph.h"
#include <stdio.h>

int plugin_is_GPL_compatible;

/*! \brief Parse a tree of type and return respective string.
 *
 * \return a string for the type.  It must be free through ggc_free().
 */
static char *
parse_type(tree type_node) {
    tree type_v;
    tree *pointers;
    tree type_decl, type_name;
    int lvl = 0;
    int const_cnt = 0;
    char *type_str;
    const char *base_type_name;
    int type_str_len;
    int i, ptr_i;
    
    /* Collect pointers */
    type_v = type_node;
    while(TREE_CODE(type_v) == POINTER_TYPE) {
	if(TREE_READONLY(type_v))
	    const_cnt++;
	type_v = TREE_TYPE(type_v);
	lvl++;
    }

    pointers = (tree *)ggc_alloc(sizeof(tree) * lvl);
    type_v = type_node;
    for(ptr_i = 0; ptr_i < lvl; ptr_i++) {
	pointers[ptr_i] = type_v;
	type_v = TREE_TYPE(type_v);
    }

    /* Get name of base type */
    type_decl = TYPE_NAME(type_v);
    type_name = DECL_NAME(type_decl);
    base_type_name = IDENTIFIER_POINTER(type_name);
    
    /* Compute total length of string of full type */
    type_str_len = lvl + strlen(base_type_name) + const_cnt * 5; /* "const" */
    if(TREE_READONLY(type_v))
	type_str_len += 6;	/* "const " */
    type_str = (char *)ggc_alloc(type_str_len + 1);
    
    /* modify const for base type */
    type_str[0] = 0;
    if(TREE_READONLY(type_v))
	strcpy(type_str, "const ");
    strcat(type_str, base_type_name);
    
    /* Add pointers and const modifications after base type */
    i = strlen(type_str);
    for(ptr_i = lvl - 1; ptr_i >= 0; ptr_i--) {
	type_v = pointers[ptr_i];
	type_str[i++] = '*';
	if(TREE_READONLY(type_v)) {
	    type_str[i] = 0;
	    strcat(type_str, "const");
	    i += 5;
	}
    }
    type_str[i] = 0;
    
    ggc_free(pointers);

    return type_str;
}

/*! \brief Show functions that called by a specified function.
 *
 * \param cgn is cgraph_node of a function.
 */
static void
show_callees(struct cgraph_node *cgn) {
    struct cgraph_edge *edge;
    struct cgraph_node *callee_cgn;
    tree callee, callee_name;

    /* Follow edges to called functions */
    edge = cgn->callees;
    while(edge) {
	callee_cgn = edge->callee;
	callee = callee_cgn->decl;
	callee_name = DECL_NAME(callee);
	
	printf("    call %s\n", IDENTIFIER_POINTER(callee_name));
	
	edge = edge->next_callee;
    }
}

static void
handle_all_passes(void *gcc_data, void *user_data) {
    tree decl;
    tree fntype;
    tree arg, arg_name;
    tree arg_type;
    struct cgraph_node *cgn;
    char *arg_type_str;
    function_args_iterator itr;
    
    decl = cfun->decl;
    cgn = cgraph_node(decl);
     
    printf("%s:%d:%s\n", current_function_name(),
	   DECL_SOURCE_LINE(decl),
	   DECL_SOURCE_FILE(decl));
    show_callees(cgn);
    
    arg = DECL_ARGUMENTS(decl);
    while(arg) {
	arg_name = DECL_NAME(arg);
	arg_type = TREE_TYPE(arg);
	arg_type_str = parse_type(arg_type);
	printf("    %s:%s\n",
	       IDENTIFIER_POINTER(arg_name),
	       arg_type_str);
	ggc_free(arg_type_str);
	arg = TREE_CHAIN(arg);
    }
}

int
plugin_init(struct plugin_name_args *plugin_info,
	    struct plugin_gcc_version *version) {
    struct cgraph_node_hook_list *hook;
    
    if (!plugin_default_version_check (version, &gcc_version))
	return 1;
    printf("Initialize plugin %s\n", plugin_info->base_name);

    register_callback(plugin_info->base_name, PLUGIN_ALL_PASSES_START,
		      handle_all_passes, NULL);
    return 0;
}