All of lore.kernel.org
 help / color / mirror / Atom feed
From: Emese Revfy <re.emese@gmail.com>
To: linux-kbuild@vger.kernel.org
Cc: pageexec@freemail.hu, spender@grsecurity.net,
	kernel-hardening@lists.openwall.com, mmarek@suse.com,
	keescook@chromium.org, linux@rasmusvillemoes.dk
Subject: [PATCH v2 2/3] Add Cyclomatic complexity GCC plugin
Date: Thu, 11 Feb 2016 23:41:35 +0100	[thread overview]
Message-ID: <20160211234135.4478fabfc780825379936963@gmail.com> (raw)
In-Reply-To: <20160211233646.97c2af3675dc5b0f525f0489@gmail.com>

Add a very simple plugin to demonstrate the GCC plugin infrastructure. This GCC
plugin computes the cyclomatic complexity of each function.

The complexity M of a function's control flow graph is defined as:
 M = E - N + 2P
where
 E = the number of edges
 N = the number of nodes
 P = the number of connected components (exit nodes).
---
 arch/Kconfig                      |  12 ++++
 scripts/Makefile.gcc-plugins      |   6 +-
 tools/gcc/Makefile                |   4 ++
 tools/gcc/cyc_complexity_plugin.c | 120 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 1 deletion(-)
 create mode 100644 tools/gcc/cyc_complexity_plugin.c

diff --git a/arch/Kconfig b/arch/Kconfig
index a95e5b1..a558ecb 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -365,6 +365,18 @@ config HAVE_GCC_PLUGINS
 	  An arch should select this symbol if it supports building with
 	  gcc plugins.
 
+config GCC_PLUGIN_CYC_COMPLEXITY
+	bool "Compute the cyclomatic complexity of a function"
+	depends on HAVE_GCC_PLUGINS
+	help
+	  The complexity M of a function's control flow graph is defined as:
+	   M = E - N + 2P
+	  where
+
+	  E = the number of edges
+	  N = the number of nodes
+	  P = the number of connected components (exit nodes).
+
 endmenu # "GCC plugins"
 
 config HAVE_CC_STACKPROTECTOR
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index a60a88e..c49abcd 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -4,7 +4,11 @@ else
 PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
 endif
 ifneq ($(PLUGINCC),)
-export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
+ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
+GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so
+endif
+GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
 ifeq ($(KBUILD_EXTMOD),)
 gcc-plugins:
 	$(Q)$(MAKE) $(build)=tools/gcc
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
index b2d64af..31c72bf 100644
--- a/tools/gcc/Makefile
+++ b/tools/gcc/Makefile
@@ -12,4 +12,8 @@ endif
 
 export GCCPLUGINS_DIR HOSTLIBS
 
+$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) := cyc_complexity_plugin.so
+
 always := $($(HOSTLIBS)-y)
+
+cyc_complexity_plugin-objs := cyc_complexity_plugin.o
diff --git a/tools/gcc/cyc_complexity_plugin.c b/tools/gcc/cyc_complexity_plugin.c
new file mode 100644
index 0000000..c6f0d58
--- /dev/null
+++ b/tools/gcc/cyc_complexity_plugin.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
+ *
+ * http://en.wikipedia.org/wiki/Cyclomatic_complexity
+ * The complexity M is then defined as:
+ * M = E - N + 2P
+ * where
+ *
+ *  E = the number of edges of the graph
+ *  N = the number of nodes of the graph
+ *  P = the number of connected components (exit nodes).
+ *
+ * Usage (4.5 - 5):
+ * $ make clean; make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+static struct plugin_info cyc_complexity_plugin_info = {
+	.version	= "20150523",
+	.help		= "Cyclomatic Complexity\n",
+};
+
+static unsigned int handle_function(void)
+{
+	int complexity;
+	expanded_location xloc;
+
+	// M = E - N + 2P
+	complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
+
+	xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+	fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity, xloc.file, DECL_NAME_POINTER(current_function_decl));
+
+	return 0;
+}
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const struct pass_data cyc_complexity_pass_data = {
+#else
+static struct gimple_opt_pass cyc_complexity_pass = {
+	.pass = {
+#endif
+		.type			= GIMPLE_PASS,
+		.name			= "cyc_complexity",
+#if BUILDING_GCC_VERSION >= 4008
+		.optinfo_flags		= OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION >= 4009
+		.has_gate		= false,
+		.has_execute		= true,
+#else
+		.gate			= NULL,
+		.execute		= handle_function,
+		.sub			= NULL,
+		.next			= NULL,
+		.static_pass_number	= 0,
+#endif
+		.tv_id			= TV_NONE,
+		.properties_required	= 0,
+		.properties_provided	= 0,
+		.properties_destroyed	= 0,
+		.todo_flags_start	= 0,
+		.todo_flags_finish	= TODO_dump_func
+#if BUILDING_GCC_VERSION < 4009
+	}
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class cyc_complexity_pass : public gimple_opt_pass {
+public:
+	cyc_complexity_pass() : gimple_opt_pass(cyc_complexity_pass_data, g) {}
+#if BUILDING_GCC_VERSION >= 5000
+	virtual unsigned int execute(function *) { return handle_function(); }
+#else
+	unsigned int execute() { return handle_function(); }
+#endif
+};
+}
+
+static struct opt_pass *make_cyc_complexity_pass(void)
+{
+	return new cyc_complexity_pass();
+}
+#else
+static struct opt_pass *make_cyc_complexity_pass(void)
+{
+	return &cyc_complexity_pass.pass;
+}
+#endif
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+	const char * const plugin_name = plugin_info->base_name;
+	struct register_pass_info cyc_complexity_pass_info;
+
+	cyc_complexity_pass_info.pass				= make_cyc_complexity_pass();
+	cyc_complexity_pass_info.reference_pass_name		= "ssa";
+	cyc_complexity_pass_info.ref_pass_instance_number	= 1;
+	cyc_complexity_pass_info.pos_op				= PASS_POS_INSERT_AFTER;
+
+	if (!plugin_default_version_check(version, &gcc_version)) {
+		error(G_("incompatible gcc/plugin versions"));
+		return 1;
+	}
+
+	register_callback(plugin_name, PLUGIN_INFO, NULL, &cyc_complexity_plugin_info);
+	register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &cyc_complexity_pass_info);
+
+	return 0;
+}
-- 
2.4.1


WARNING: multiple messages have this Message-ID (diff)
From: Emese Revfy <re.emese@gmail.com>
To: linux-kbuild@vger.kernel.org
Cc: pageexec@freemail.hu, spender@grsecurity.net,
	kernel-hardening@lists.openwall.com, mmarek@suse.com,
	keescook@chromium.org, linux@rasmusvillemoes.dk
Subject: [kernel-hardening] [PATCH v2 2/3] Add Cyclomatic complexity GCC plugin
Date: Thu, 11 Feb 2016 23:41:35 +0100	[thread overview]
Message-ID: <20160211234135.4478fabfc780825379936963@gmail.com> (raw)
In-Reply-To: <20160211233646.97c2af3675dc5b0f525f0489@gmail.com>

Add a very simple plugin to demonstrate the GCC plugin infrastructure. This GCC
plugin computes the cyclomatic complexity of each function.

The complexity M of a function's control flow graph is defined as:
 M = E - N + 2P
where
 E = the number of edges
 N = the number of nodes
 P = the number of connected components (exit nodes).
---
 arch/Kconfig                      |  12 ++++
 scripts/Makefile.gcc-plugins      |   6 +-
 tools/gcc/Makefile                |   4 ++
 tools/gcc/cyc_complexity_plugin.c | 120 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 141 insertions(+), 1 deletion(-)
 create mode 100644 tools/gcc/cyc_complexity_plugin.c

diff --git a/arch/Kconfig b/arch/Kconfig
index a95e5b1..a558ecb 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -365,6 +365,18 @@ config HAVE_GCC_PLUGINS
 	  An arch should select this symbol if it supports building with
 	  gcc plugins.
 
+config GCC_PLUGIN_CYC_COMPLEXITY
+	bool "Compute the cyclomatic complexity of a function"
+	depends on HAVE_GCC_PLUGINS
+	help
+	  The complexity M of a function's control flow graph is defined as:
+	   M = E - N + 2P
+	  where
+
+	  E = the number of edges
+	  N = the number of nodes
+	  P = the number of connected components (exit nodes).
+
 endmenu # "GCC plugins"
 
 config HAVE_CC_STACKPROTECTOR
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins
index a60a88e..c49abcd 100644
--- a/scripts/Makefile.gcc-plugins
+++ b/scripts/Makefile.gcc-plugins
@@ -4,7 +4,11 @@ else
 PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(HOSTCC)" "$(HOSTCXX)" "$(CC)")
 endif
 ifneq ($(PLUGINCC),)
-export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS
+ifdef CONFIG_GCC_PLUGIN_CYC_COMPLEXITY
+GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS := -fplugin=$(objtree)/tools/gcc/cyc_complexity_plugin.so
+endif
+GCC_PLUGINS_CFLAGS := $(GCC_PLUGIN_CYC_COMPLEXITY_CFLAGS)
+export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGINS_AFLAGS GCC_PLUGIN_CYC_COMPLEXITY
 ifeq ($(KBUILD_EXTMOD),)
 gcc-plugins:
 	$(Q)$(MAKE) $(build)=tools/gcc
diff --git a/tools/gcc/Makefile b/tools/gcc/Makefile
index b2d64af..31c72bf 100644
--- a/tools/gcc/Makefile
+++ b/tools/gcc/Makefile
@@ -12,4 +12,8 @@ endif
 
 export GCCPLUGINS_DIR HOSTLIBS
 
+$(HOSTLIBS)-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) := cyc_complexity_plugin.so
+
 always := $($(HOSTLIBS)-y)
+
+cyc_complexity_plugin-objs := cyc_complexity_plugin.o
diff --git a/tools/gcc/cyc_complexity_plugin.c b/tools/gcc/cyc_complexity_plugin.c
new file mode 100644
index 0000000..c6f0d58
--- /dev/null
+++ b/tools/gcc/cyc_complexity_plugin.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011-2016 by Emese Revfy <re.emese@gmail.com>
+ * Licensed under the GPL v2, or (at your option) v3
+ *
+ * Homepage:
+ * https://github.com/ephox-gcc-plugins/cyclomatic_complexity
+ *
+ * http://en.wikipedia.org/wiki/Cyclomatic_complexity
+ * The complexity M is then defined as:
+ * M = E - N + 2P
+ * where
+ *
+ *  E = the number of edges of the graph
+ *  N = the number of nodes of the graph
+ *  P = the number of connected components (exit nodes).
+ *
+ * Usage (4.5 - 5):
+ * $ make clean; make run
+ */
+
+#include "gcc-common.h"
+
+int plugin_is_GPL_compatible;
+
+static struct plugin_info cyc_complexity_plugin_info = {
+	.version	= "20150523",
+	.help		= "Cyclomatic Complexity\n",
+};
+
+static unsigned int handle_function(void)
+{
+	int complexity;
+	expanded_location xloc;
+
+	// M = E - N + 2P
+	complexity = n_edges_for_fn(cfun) - n_basic_blocks_for_fn(cfun) + 2;
+
+	xloc = expand_location(DECL_SOURCE_LOCATION(current_function_decl));
+	fprintf(stderr, "Cyclomatic Complexity %d %s:%s\n", complexity, xloc.file, DECL_NAME_POINTER(current_function_decl));
+
+	return 0;
+}
+
+#if BUILDING_GCC_VERSION >= 4009
+namespace {
+static const struct pass_data cyc_complexity_pass_data = {
+#else
+static struct gimple_opt_pass cyc_complexity_pass = {
+	.pass = {
+#endif
+		.type			= GIMPLE_PASS,
+		.name			= "cyc_complexity",
+#if BUILDING_GCC_VERSION >= 4008
+		.optinfo_flags		= OPTGROUP_NONE,
+#endif
+#if BUILDING_GCC_VERSION >= 5000
+#elif BUILDING_GCC_VERSION >= 4009
+		.has_gate		= false,
+		.has_execute		= true,
+#else
+		.gate			= NULL,
+		.execute		= handle_function,
+		.sub			= NULL,
+		.next			= NULL,
+		.static_pass_number	= 0,
+#endif
+		.tv_id			= TV_NONE,
+		.properties_required	= 0,
+		.properties_provided	= 0,
+		.properties_destroyed	= 0,
+		.todo_flags_start	= 0,
+		.todo_flags_finish	= TODO_dump_func
+#if BUILDING_GCC_VERSION < 4009
+	}
+#endif
+};
+
+#if BUILDING_GCC_VERSION >= 4009
+class cyc_complexity_pass : public gimple_opt_pass {
+public:
+	cyc_complexity_pass() : gimple_opt_pass(cyc_complexity_pass_data, g) {}
+#if BUILDING_GCC_VERSION >= 5000
+	virtual unsigned int execute(function *) { return handle_function(); }
+#else
+	unsigned int execute() { return handle_function(); }
+#endif
+};
+}
+
+static struct opt_pass *make_cyc_complexity_pass(void)
+{
+	return new cyc_complexity_pass();
+}
+#else
+static struct opt_pass *make_cyc_complexity_pass(void)
+{
+	return &cyc_complexity_pass.pass;
+}
+#endif
+
+int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version)
+{
+	const char * const plugin_name = plugin_info->base_name;
+	struct register_pass_info cyc_complexity_pass_info;
+
+	cyc_complexity_pass_info.pass				= make_cyc_complexity_pass();
+	cyc_complexity_pass_info.reference_pass_name		= "ssa";
+	cyc_complexity_pass_info.ref_pass_instance_number	= 1;
+	cyc_complexity_pass_info.pos_op				= PASS_POS_INSERT_AFTER;
+
+	if (!plugin_default_version_check(version, &gcc_version)) {
+		error(G_("incompatible gcc/plugin versions"));
+		return 1;
+	}
+
+	register_callback(plugin_name, PLUGIN_INFO, NULL, &cyc_complexity_plugin_info);
+	register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, &cyc_complexity_pass_info);
+
+	return 0;
+}
-- 
2.4.1

  parent reply	other threads:[~2016-02-11 22:43 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-11 22:36 [PATCH v2 0/3] Introduce GCC plugin infrastructure Emese Revfy
2016-02-11 22:36 ` [kernel-hardening] " Emese Revfy
2016-02-11 22:39 ` [PATCH v2 1/3] " Emese Revfy
2016-02-11 22:39   ` [kernel-hardening] " Emese Revfy
2016-02-18  0:18   ` Kees Cook
2016-02-18  0:18     ` [kernel-hardening] " Kees Cook
2016-02-18 21:21     ` Emese Revfy
2016-02-18 21:21       ` [kernel-hardening] " Emese Revfy
2016-02-11 22:41 ` Emese Revfy [this message]
2016-02-11 22:41   ` [kernel-hardening] [PATCH v2 2/3] Add Cyclomatic complexity GCC plugin Emese Revfy
2016-02-18  0:27   ` Kees Cook
2016-02-18  0:27     ` [kernel-hardening] " Kees Cook
2016-02-18 21:32     ` Emese Revfy
2016-02-18 21:32       ` [kernel-hardening] " Emese Revfy
2016-02-11 22:43 ` [PATCH v2 3/3] Documentation for the GCC plugin infrastructure Emese Revfy
2016-02-11 22:43   ` [kernel-hardening] " Emese Revfy
2016-02-18  0:35   ` Kees Cook
2016-02-18  0:35     ` [kernel-hardening] " Kees Cook
2016-02-18 22:13     ` Emese Revfy
2016-02-18 22:13       ` [kernel-hardening] " Emese Revfy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160211234135.4478fabfc780825379936963@gmail.com \
    --to=re.emese@gmail.com \
    --cc=keescook@chromium.org \
    --cc=kernel-hardening@lists.openwall.com \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=mmarek@suse.com \
    --cc=pageexec@freemail.hu \
    --cc=spender@grsecurity.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.