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
October 7, 2016

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

  • 12 Dec 2018
    Gluster Container Storage milestone...

    Today, we are announcing the availability of GCS (Gluster Container Storage) 0.4. The release was bit delayed to address some of the critical issues identified. This release brings in a good amount of bug fixes along with some key feature enhancements in GlusterD2. We’d request all of you to try...

    Read more
  • 05 Dec 2018
    Gluster Monthly Newsletter, Novembe...

    Gluster 6 – We’re in planning for our Gluster 6 release, currently scheduled for Feb 2019. More details on the mailing lists at https://lists.gluster.org/pipermail/gluster-devel/2018-November/055672.html Upcoming Community Meeting – December 19 – 15:00 UTC in #gluster-meeting on freenode. https://bit.ly/gluster-community-meetings has the agenda. Want swag for your meetup? https://www.gluster.org/events/ has a contact...

    Read more
  • 06 Nov 2018
    Gluster Monthly Newsletter, October...

    Gluster Monthly Newsletter, October 2018 Gluster 5 is out and our retrospective is currently open! This feedback is anonymous and goes to our release team. https://lists.gluster.org/pipermail/gluster-users/2018-October/035171.html https://www.gluster.org/gluster-5-0-retrospective/ Upcoming Community Meeting  – November 7, November 21 – 15:00 UTC in #gluster-meeting on freenode. https://bit.ly/gluster-community-meetings has the agenda. We’re participating in Outreachy...

    Read more