]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ctf: blacklist certain structure members entirely
authorNick Alcock <nick.alcock@oracle.com>
Mon, 25 Mar 2013 16:49:10 +0000 (16:49 +0000)
committerNick Alcock <nick.alcock@oracle.com>
Mon, 29 Jun 2015 21:41:43 +0000 (22:41 +0100)
The problem of structures with identical names but conflicting members has
bitten dwarf2ctf before.  We defined a deduplication blacklist which prevents
specific modules from participating in deduplication, because they define a
structure with the same name as one in the shared type repository but with
different members.  This is, it turns out, not always enough.

Some kernel modules have begun to define structures with conflicting members in
different translation units within the same module.  There is no trick we can
use to help dwarf2ctf deal with this: each module gets one CTF file, covering
all that module's translation units, and if types have conflicting definitions
within that one module, there's nothing we can do: we must skip them entirely.
But we can limit the damage somewhat.

This commit adds a new blacklist, the 'member blacklist', stored in
scripts/dwarf2ctf/member.blacklist, which blacklists structure or union members
by name.  There are some limitations: only members of named structures and
unions can be blacklisted (not members of typedeffed, unnamed structures or
unions); and you can only blacklist types in the kernel tree, not types in
external modules.  Both of these restrictions can be lifted if it ever becomes
necessary, the latter quite easily.

The blacklist is of the form

filename:structure name.member name

The filenames are absolutized and compared with the filenames in the DWARF for
each structure member, both at emission time and when recursing to mark shared
types.

Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
scripts/Makefile.modpost
scripts/dwarf2ctf/dwarf2ctf.c
scripts/dwarf2ctf/member.blacklist [new file with mode: 0644]

index 085d27d6e8b75166dcee002d08cc59517607d521..b7572b234cb85240e76cb8e52fe95ac38513901f 100644 (file)
@@ -147,7 +147,7 @@ ifndef CONFIG_DT_DISABLE_CTF
 ifeq ($(KBUILD_EXTMOD),)
 ctf-dir := .ctf
 quiet_cmd_ctf = CTF
-      cmd_ctf = scripts/dwarf2ctf/dwarf2ctf $(ctf-dir) objects.builtin modules.builtin scripts/dwarf2ctf/dedup.blacklist $^
+      cmd_ctf = scripts/dwarf2ctf/dwarf2ctf $(ctf-dir) objects.builtin modules.builtin scripts/dwarf2ctf/dedup.blacklist scripts/dwarf2ctf/member.blacklist $^
 builtins := $(shell cat objects.builtin 2>/dev/null)
 ctf-stamp := .ctf/ctf.stamp
 
index 205a945ed0ebe17352a0d71570b1ae3b78f85744..dda3b9aa6d3939e508826c4becd7d2b75e738141 100644 (file)
@@ -146,7 +146,27 @@ static GHashTable *dedup_blacklist;
 /*
  * Populate the deduplication blacklist from the dedup_blacklist file.
  */
-static void init_blacklist(const char *dedup_blacklist_file);
+static void init_dedup_blacklist(const char *dedup_blacklist_file);
+
+/*
+ * The member blacklist bans fields with specific names in specifically named
+ * structures, declared in specific source files, from being emitted.  The
+ * mapping is from absolute source file name:structure.member to NULL (this is
+ * safe because type names cannot contain a colon, and structure names cannot
+ * contain a period).
+ */
+static GHashTable *member_blacklist;
+
+/*
+ * Populate the member blacklist from the member_blacklist file.
+ */
+static void init_member_blacklist(const char *member_blacklist_file);
+
+/*
+ * Return 1 if a given DWARF DIE, which must be a DW_TAG_member, appears in the
+ * member blacklist.
+ */
+static int member_blacklisted(Dwarf_Die *die, Dwarf_Die *parent_die);
 
 /*
  * A mapping from translation unit name to the name of the module that
@@ -639,10 +659,11 @@ int main(int argc, char *argv[])
 
        trace = getenv("DWARF2CTF_TRACE");
 
-       if ((argc == 3 && (strcmp(argv[1], "-e") != 0)) || (argc < 4)) {
-               fprintf(stderr, "Syntax: dwarf2ctf outputdir objects.builtin "
-                       "modules.builtin vmlinux.o module.o...,\n");
-               fprintf(stderr, "        or dwarf2ctf outputdir -e module.o ... "
+       if (((argc < 2) && (strcmp(argv[1], "-e") == 0)) ||
+           (argc < 6 && (strcmp(argv[1], "-e") != 0))) {
+               fprintf(stderr, "Syntax: dwarf2ctf outputdir objects.builtin modules.builtin dedup.blacklist\n");
+               fprintf(stderr, "                  member.blacklist vmlinux.o module.o...,\n");
+               fprintf(stderr, "        or dwarf2ctf outputdir -e module.o ... "
                        "for (inefficient)\n");
                fprintf(stderr, "external module use\n");
                exit(1);
@@ -669,13 +690,16 @@ int main(int argc, char *argv[])
                char *builtin_objects_file;
                char *builtin_module_file;
                char *dedup_blacklist_file;
+               char *member_blacklist_file;
 
                builtin_objects_file = argv[2];
                builtin_module_file = argv[3];
                dedup_blacklist_file = argv[4];
-               starting_argv = 5;
+               member_blacklist_file = argv[5];
+               starting_argv = 6;
                init_builtin(builtin_objects_file, builtin_module_file);
-               init_blacklist(dedup_blacklist_file);
+               init_dedup_blacklist(dedup_blacklist_file);
+               init_member_blacklist(member_blacklist_file);
 
                run(starting_argv, argv, output_dir);
        } else {
@@ -896,7 +920,7 @@ static void init_assembly_tab(void)
 /*
  * Populate the deduplication blacklist from the dedup_blacklist file.
  */
-static void init_blacklist(const char *dedup_blacklist_file)
+static void init_dedup_blacklist(const char *dedup_blacklist_file)
 {
        FILE *f;
        char *line = NULL;
@@ -932,6 +956,125 @@ static void init_blacklist(const char *dedup_blacklist_file)
        fclose(f);
 }
 
+/*
+ * Populate the member blacklist from the member_blacklist file.
+ */
+static void init_member_blacklist(const char *member_blacklist_file)
+{
+       FILE *f;
+       char *line = NULL;
+       size_t line_num = 0;
+       size_t line_size = 0;
+
+       /*
+        * Not having a member blacklist is not an error.
+        */
+       if ((f = fopen(member_blacklist_file, "r")) == NULL)
+               return;
+
+       member_blacklist = g_hash_table_new(g_str_hash, g_str_equal);
+
+       while (getline(&line, &line_size, f) >= 0) {
+               size_t len = strlen(line);
+               char *last_colon;
+               const char *last_dot;
+               char *absolutized;
+
+               line_num++;
+
+               if (len == 0)
+                       continue;
+
+               if (line[len-1] == '\n')
+                       line[len-1] = '\0';
+
+               last_colon = strrchr(line, ':');
+               last_dot = strrchr(last_colon + 1, '.');
+               if (!last_colon || !last_dot) {
+                       fprintf(stderr, "Syntax error on line %li of %s.\n"
+                           "Syntax: filename:structure.member.\n",
+                           line_num, member_blacklist_file);
+                       continue;
+               }
+
+               *last_colon = '\0';
+               last_colon++;
+               absolutized = xstrdup(abs_file_name(line));
+               absolutized = str_appendn(absolutized, ":", last_colon, NULL);
+
+               g_hash_table_insert(member_blacklist, absolutized, NULL);
+       }
+
+       if (ferror(f)) {
+               fprintf(stderr, "Error reading from %s: %s\n",
+                       member_blacklist_file, strerror(errno));
+               exit(1);
+       }
+
+       fclose(f);
+}
+
+/*
+ * Return 1 if a given DWARF DIE, which must be a DW_TAG_member, appears in the
+ * member blacklist.
+ */
+static int member_blacklisted(Dwarf_Die *die, Dwarf_Die *parent_die)
+{
+       const char *fname = dwarf_decl_file(die);
+       char *id;
+       int blacklisted = 0;
+
+       /*
+        * If there is no member blacklist, do nothing.
+        */
+       if (!member_blacklist)
+               return 0;
+
+       /*
+        * Unnamed structure and union members cannot be blacklisted, for now.
+        */
+       if ((dwarf_diename(parent_die) == NULL) ||
+           (dwarf_diename(die) == NULL))
+               return 0;
+
+       /*
+        * If the compiler is now emitting members without decl_files, we
+        * want to know.
+        */
+       if (fname == NULL) {
+               static int warned = 0;
+
+               if (!warned)
+                       fprintf(stderr, "Warning: member_blacklisted() called with "
+                           "NULL decl_file, which should never happen.\n");
+
+               warned = 1;
+               return 0;
+       }
+
+       fname = abs_file_name(fname);
+
+       if (dwarf_tag(die) != DW_TAG_member ||
+           (dwarf_tag(parent_die) != DW_TAG_structure_type &&
+               dwarf_tag(parent_die) != DW_TAG_union_type)) {
+               fprintf(stderr, "Warning: member_blacklisted() called on "
+                   "%s:%s.%s at offset %li, which is not a structure member.",
+                   fname, dwarf_diename(parent_die), dwarf_diename(die),
+                   dwarf_dieoffset(die));
+               return 0;
+       }
+
+       id = xstrdup(fname);
+       id = str_appendn(id, ":", dwarf_diename(parent_die), ".",
+           dwarf_diename(die), NULL);
+
+       if (g_hash_table_lookup_extended(member_blacklist, id, NULL, NULL))
+               blacklisted = 1;
+
+       free(id);
+       return blacklisted;
+}
+
 /*
  * Initialize a CTF type table, and possibly fill it with those special types
  * that appear in CTF but not in DWARF (such as 'void').  (This filling happens
@@ -1760,12 +1903,14 @@ static void mark_shared(Dwarf_Die *die, const char *id, void *data)
                }
 
                /*
-                * We are only interested in children of type DW_TAG_member.
+                * We are only interested in non-blacklisted children of type
+                * DW_TAG_member.
                 */
                int sib_ret;
 
                do
-                       free(type_id(&child, mark_shared, state));
+                       if (!member_blacklisted(&child, die))
+                               free(type_id(&child, mark_shared, state));
                while ((sib_ret = dwarf_siblingof(&child, &child)) == 0);
 
                if (sib_ret == -1)
@@ -2841,7 +2986,7 @@ static ctf_id_t assemble_ctf_struct_union(const char *module_name,
  * Assemble a structure or union member.
  *
  * We only assemble a member of a given name if a member by that name does not
- * already exist.
+ * already exist, and if the member is not blacklisted.
  */
 static ctf_id_t assemble_ctf_su_member(const char *module_name,
                                       const char *file_name,
@@ -2863,6 +3008,14 @@ static ctf_id_t assemble_ctf_su_member(const char *module_name,
 
        CTF_DW_ENFORCE(type);
 
+       /*
+        * If this member is blacklisted, just skip it.
+        */
+       if (member_blacklisted(die, parent_die)) {
+               dw_ctf_trace("%s: blacklisted, skipping.\n", locerrstr);
+               return parent_ctf_id;
+       }
+
        /*
         * Find the associated type so we can either add a member with that type
         * (if it is named) or add its members directly (for unnamed types,
diff --git a/scripts/dwarf2ctf/member.blacklist b/scripts/dwarf2ctf/member.blacklist
new file mode 100644 (file)
index 0000000..85122de
--- /dev/null
@@ -0,0 +1 @@
+include/linux/netfilter/ipset/ip_set_ahash.h:ip_set_hash.next