Skip to content

Instantly share code, notes, and snippets.

@mayeths
Created October 12, 2021 10:14
Show Gist options
  • Save mayeths/69098833a4c15e664acf271c86e564a2 to your computer and use it in GitHub Desktop.
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 */
/* 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;
}
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
#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