The Gluster Blog

Gluster blog stories provide high-level spotlights on our users all over the world

Compiling GlusterFS with a gcc plug-in – an experiment

Gluster
2016-10-07

Back in February of this year Martin Kletzander gave a talk at devconf.cz on GCC plug-ins. It would seem that gcc plug-ins are a feature that has gone largely overlooked for many years.

I came back from DevConf inspired to try it out. A quick search showed me I was not alone – a colleague here at Red Hat had also seen Martin’s talk, and he wrote about his experiment here source

I had had something similar in mind to what Richard had done. I wanted to check all the struct definitions, i.e. all instances of all the variables of any particular type, and make sure the defined sizes were consistent throughout the GlusterFS sources.

Using Richard’s plug-in I found that while things were generally good, there were a couple structs that appeared to have mismatched sizes. The only thing was, Richard’s plug-in didn’t tell me where those structs were defined. And unfortunately GlusterFS has a lot of cut-and-pasted code, so it wasn’t a matter of a simple grep to find them.

As both Martin and Richard note, the GCC plug-in framework is not well documented. It was not obvious how to do something that seems – on the surface – like it should be trivial. But, with a bit of detective work, I was able to solve it. (And after the fact the change was, in fact, quite simple; finding it however took some time.)

/* structsizes.cc plugin: public domain example code written by
 * Richard W.M. Jones, with modifications by Kaleb S. KEITHLEY
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gcc-plugin.h>
#include <tree.h>
#include <print-tree.h>

int plugin_is_GPL_compatible;

static FILE *log_fp;

static void
plugin_finish_type (void *event_data, void *user_data)
{
  tree type = (tree) event_data;

  if (user_data) {
    char *c = (char *) user_data;
    fprintf (log_fp, "user_data %x %x %x %x\n", c[0], c[1], c[2], c[3]);
  }

  /* We only care about structs, not any other type definition. */
  if (TREE_CODE (type) == RECORD_TYPE) {
    /* This is useful for working out how to navigate the tree below. */
    /* debug_tree (type); */

    /* If the type is not complete, we can't do anything. */
    if (!COMPLETE_TYPE_P (type)) {
      /* fprintf (log_fp, "struct '%s' has incomplete type\n", name); */
      return;
    }

    /* Struct name? */
    tree name_tree = TYPE_NAME (type);

    /* Ignore unnamed structs. */
    if (!name_tree) {
      /* fprintf (log_fp, "ignoring unnamed struct\n"); */
      return;
    }

    const char *name;
    if (TREE_CODE (name_tree) == IDENTIFIER_NODE)
      name = IDENTIFIER_POINTER (name_tree);
    else if (TREE_CODE (name_tree) == TYPE_DECL && DECL_NAME (name_tree))
      name = IDENTIFIER_POINTER (DECL_NAME (name_tree));
    else
      name = "unknown struct name"; /* should never happen? */

    tree decl = type;
    for (; decl; decl = TREE_CHAIN (decl)) {
      if (DECL_P (decl))
        break;
    }

    const char *filename = DECL_SOURCE_FILE (decl);
    int lineno = DECL_SOURCE_LINE (decl);

    /* Get the size of the struct that has been defined. */
    tree size_tree = TYPE_SIZE (type);
    if (TREE_CODE (size_tree) == INTEGER_CST &&
        !TYPE_P (size_tree) && TREE_CONSTANT (size_tree)) {
      size_t size = TREE_INT_CST_LOW (size_tree);
      fprintf (log_fp, "struct '%s' has size %zu [bits] in %s, line %d\n", name, size, filename, lineno);
    }
    else
      fprintf (log_fp, "struct '%s' has non-constant size\n", name);
  }

  fflush (log_fp);
}

int
plugin_init (struct plugin_name_args *plugin_info,
             struct plugin_gcc_version *version)
{
  const char *logfile = NULL;
  size_t i;

  /* Open the log file. */
  for (i = 0; i argc; ++i) {
    if (strcmp (plugin_info->argv[i].key, "log") == 0) {
      logfile = plugin_info->argv[i].value;
    }
  }

  if (!logfile) {
    fprintf (stderr, "structsizes plugin: missing parameter: -fplugin-arg-structsizes-log=\n");
    exit (EXIT_FAILURE);
  }

  log_fp = fopen (logfile, "a");
  if (log_fp == NULL) {
    perror (logfile);
    exit (EXIT_FAILURE);
  }

  fprintf (log_fp, "Loaded structsizes plugin (GCC %s.%s.%s)\n",
           version->basever, version->devphase, version->revision);

  register_callback (plugin_info->base_name, PLUGIN_FINISH_TYPE,
                     plugin_finish_type, NULL);

  return 0;
}

Compile the plug-in using

    gcc -g -I`gcc -print-file-name=plugin`/include \
        -fpic -shared -o structsizes.so structsizes.cc

and when you compile your source, to use the plug-in you must add

    ... -fplugin=./structsizes.so \
        -fplugin-arg-structsizes-log=<logfile> ...

to the compiler command line options.

For the purposes of compiling GlusterFS with this plug-in, I changed GlusterFS’s configure.ac file like this:

    ...
    CFLAGS="${CFLAGS} -g -O2 -fplugin=/path/to/structsizes.so \
        -fplugin-arg-structsizes-log=/tmp/ss2.out"
    ...

and then ran

    autogen.sh && ./configure && make

to build GlusterFS.

Afterwards you can

    sort -u < /tmp/ss2.out > outfile

to reduce the output to something digestible.

And in the end, the seemingly mismatched struct sizes weren’t really a problem. They were two different types – that happened to have the same type name – in two different translators.

BLOG

  • 15 Oct 2019
    Gluster and CentOS Stream

    Progress cannot be made without change. As technologists, we recognize this every day. Most of the time, these changes are iterative: progresssive additions of features to projects like Gluster. Sometimes those changes are small, and sometimes not. And that’s, of course, just talking about our project. But one of the...

    Read more
  • 26 Apr 2019
    Gluster Monthly Newsletter, April 2...

    Upcoming Community Happy Hour at Red Hat Summit! Tue, May 7, 2019, 6:30 PM – 7:30 PM EDT https://cephandglusterhappyhour_rhsummit.eventbrite.com has all the details. Gluster 7 Roadmap Discussion kicked off for our 7 roadmap on the mailing lists, see [Gluster-users] GlusterFS v7.0 (and v8.0) roadmap discussion https://lists.gluster.org/pipermail/gluster-users/2019-March/036139.html for more details. Community...

    Read more
  • 24 Apr 2019
    Community Survey Feedback, 2019

    In this year’s survey, we asked quite a few questions about how people are using Gluster, how much storage they’re managing, their primary use for Gluster, and what they’d like to see added. Here’s some of the highlights from this year!

    Read more