Created
October 12, 2021 10:14
-
-
Save mayeths/69098833a4c15e664acf271c86e564a2 to your computer and use it in GitHub Desktop.
Creating custom gcc attribute to instrument specific functions: whitelisting, not blacklisting /* https://stackoverflow.com/a/57242241/11702338 */
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* https://stackoverflow.com/a/57242241/11702338 */ | |
#include <stdio.h> | |
#ifdef PLUGIN_DEBUG | |
#define DEBUG(...) printf(__VA_ARGS__) | |
#else | |
#define DEBUG(...) ((void)0) | |
#endif | |
/* clang-format off */ | |
#pragma GCC diagnostic push | |
#pragma GCC diagnostic ignored "-Wunused-variable" | |
#include "gcc-plugin.h" | |
#include "plugin-version.h" | |
#include "tree.h" | |
#include "stringpool.h" | |
#include "attribs.h" | |
#pragma GCC diagnostic pop | |
/* clang-format on */ | |
int plugin_is_GPL_compatible; | |
static struct plugin_info info = { | |
"1.0.0", | |
"This plugin provides the do_instrument_function attribute.", | |
}; | |
static struct attribute_spec instrumentx_attr = { | |
"do_instrument_function", 0, -1, false, false, false, NULL, /* No need for a handling function */ | |
}; | |
static void register_attributes(void* event_data, void* data) { register_attribute(&instrumentx_attr); } | |
void handle_function(void* event_data, void* data) { | |
tree fndecl = (tree)event_data; | |
/* Make sure it's a function */ | |
if (TREE_CODE(fndecl) == FUNCTION_DECL) { | |
/* If the function has our attribute, enable instrumentation, */ | |
/* otherwise explicitly disable it */ | |
if (lookup_attribute("do_instrument_function", DECL_ATTRIBUTES(fndecl)) != NULL_TREE) { | |
DEBUG("do_instrument_function: <%s:%d> %s()\n", DECL_SOURCE_FILE(fndecl), DECL_SOURCE_LINE(fndecl), | |
get_name(fndecl)); | |
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(fndecl) = 0; | |
} else { | |
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT(fndecl) = 1; | |
} | |
} | |
} | |
int plugin_init(struct plugin_name_args* plugin_info, struct plugin_gcc_version* version) { | |
for (int i = 0; i < plugin_info->argc; i++) { | |
DEBUG("plugin in argv[%d] k=%s, v=%s\n", i, plugin_info->argv->key, plugin_info->argv->value); | |
} | |
register_callback(plugin_info->base_name, PLUGIN_INFO, NULL, &info); | |
register_callback(plugin_info->base_name, PLUGIN_FINISH_PARSE_FUNCTION, handle_function, NULL); | |
register_callback(plugin_info->base_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PLUGIN=instrumentx | |
TEST=test | |
PLUGIN_CXX=g++ | |
PLUGIN_CXXFLAGS= -std=c++11 -Wall -fno-rtti -fPIC -I`$(PLUGIN_CXX) -print-file-name=plugin`/include | |
PLUGIN_LDFLAGS= -std=c++11 -Wall -shared | |
TEST_CC=gcc | |
TEST_CFLAGS= -Wall -finstrument-functions -fplugin=$(PLUGIN).so -fplugin-arg-$(PLUGIN)-config=./instrument-function-list.txt | |
all: plugin test | |
plugin: | |
$(PLUGIN_CXX) $(PLUGIN_CXXFLAGS) -o $(PLUGIN).o -c $(PLUGIN).c | |
$(PLUGIN_CXX) $(PLUGIN_LDFLAGS) -o $(PLUGIN).so $(PLUGIN).o | |
test: | |
$(TEST_CC) $(TEST_CFLAGS) -o $(TEST).exe $(TEST).c | |
./$(TEST).exe | |
clean: | |
rm *.exe *.so *.o | |
.PHONY: all plugin test clean |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#define NO_INSTRUMENT __attribute__((no_instrument_function)) | |
#define INSTRUMENT __attribute__((do_instrument_function)) | |
NO_INSTRUMENT void __cyg_profile_func_enter(void *this_fn, void *call_site) { | |
printf("Enter %p from %p\n", this_fn, call_site); | |
} | |
NO_INSTRUMENT void __cyg_profile_func_exit(void *this_fn, void *call_site) { | |
printf("Exit %p to %p\n", this_fn, call_site); | |
} | |
void normal() { | |
printf("This function normal() used nothing\n"); | |
} | |
NO_INSTRUMENT void no_profile() { | |
printf("This function no_profile() used __attribute__((no_instrument_function))\n"); | |
} | |
INSTRUMENT void do_profile() { | |
printf("This function do_profile() used __attribute__((do_instrument_function))\n"); | |
} | |
NO_INSTRUMENT int main() { | |
printf("Hello world!\n"); | |
normal(); | |
no_profile(); | |
do_profile(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment