RAP-optimizations/src/kallocstat_plugin.c

132 lines
3.1 KiB
C

/*
* Copyright 2011-2017 by the PaX Team <pageexec@freemail.hu>
* Licensed under the GPL v2
*
* Note: the choice of the license means that the compilation process is
* NOT 'eligible' as defined by gcc's library exception to the GPL v3,
* but for the kernel it doesn't matter since it doesn't link against
* any of the gcc libraries
*
* gcc plugin to find the distribution of k*alloc sizes
*
* TODO:
*
* BUGS:
* - none known
*/
#include "gcc-common.h"
__visible int plugin_is_GPL_compatible;
static struct plugin_info kallocstat_plugin_info = {
.version = "201602181345",
.help = NULL
};
static const char * const kalloc_functions[] = {
"__kmalloc",
"kmalloc",
"kmalloc_large",
"kmalloc_node",
"kmalloc_order",
"kmalloc_order_trace",
"kmalloc_slab",
"kzalloc",
"kzalloc_node",
};
static bool is_kalloc(const char *fnname)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(kalloc_functions); i++)
if (!strcmp(fnname, kalloc_functions[i]))
return true;
return false;
}
static unsigned int kallocstat_execute(void)
{
basic_block bb;
// 1. loop through BBs and GIMPLE statements
FOR_EACH_BB_FN(bb, cfun) {
gimple_stmt_iterator gsi;
for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) {
// gimple match:
tree fndecl, size;
gimple stmt;
const char *fnname;
// is it a call
stmt = gsi_stmt(gsi);
if (!is_gimple_call(stmt))
continue;
fndecl = gimple_call_fndecl(stmt);
if (fndecl == NULL_TREE)
continue;
if (TREE_CODE(fndecl) != FUNCTION_DECL)
continue;
// is it a call to k*alloc
fnname = DECL_NAME_POINTER(fndecl);
if (!is_kalloc(fnname))
continue;
// is the size arg const or the result of a simple const assignment
size = gimple_call_arg(stmt, 0);
while (true) {
expanded_location xloc;
size_t size_val;
if (TREE_CONSTANT(size)) {
xloc = expand_location(gimple_location(stmt));
if (!xloc.file)
xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
size_val = TREE_INT_CST_LOW(size);
fprintf(stderr, "kallocsize: %8zu %8zx %s %s:%u\n", size_val, size_val, fnname, xloc.file, xloc.line);
break;
}
if (TREE_CODE(size) != SSA_NAME)
break;
stmt = SSA_NAME_DEF_STMT(size);
//debug_gimple_stmt(stmt);
//debug_tree(size);
if (!stmt || !is_gimple_assign(stmt))
break;
if (gimple_num_ops(stmt) != 2)
break;
size = gimple_assign_rhs1(stmt);
}
//print_gimple_stmt(stderr, call_stmt, 0, TDF_LINENO);
//debug_tree(gimple_call_fn(call_stmt));
//print_node(stderr, "pax", fndecl, 4);
}
}
return 0;
}
#define PASS_NAME kallocstat
#define NO_GATE
#include "gcc-generate-gimple-pass.h"
__visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
{
const char * const plugin_name = plugin_info->base_name;
PASS_INFO(kallocstat, "ssa", 1, PASS_POS_INSERT_AFTER);
if (!plugin_default_version_check(version, &gcc_version)) {
error_gcc_version(version);
return 1;
}
register_callback(plugin_name, PLUGIN_INFO, NULL, &kallocstat_plugin_info);
register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &kallocstat_pass_info);
return 0;
}