From: Nick Alcock Date: Mon, 25 Mar 2013 16:49:10 +0000 (+0000) Subject: ctf: blacklist certain structure members entirely X-Git-Tag: v4.1.12-92~313^2~84 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=f16c109a73b4f16101035288211e8ad4751a48c8;p=users%2Fjedix%2Flinux-maple.git ctf: blacklist certain structure members entirely 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 --- diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 085d27d6e8b75..b7572b234cb85 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -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 diff --git a/scripts/dwarf2ctf/dwarf2ctf.c b/scripts/dwarf2ctf/dwarf2ctf.c index 205a945ed0ebe..dda3b9aa6d393 100644 --- a/scripts/dwarf2ctf/dwarf2ctf.c +++ b/scripts/dwarf2ctf/dwarf2ctf.c @@ -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 index 0000000000000..85122def7b5f6 --- /dev/null +++ b/scripts/dwarf2ctf/member.blacklist @@ -0,0 +1 @@ +include/linux/netfilter/ipset/ip_set_ahash.h:ip_set_hash.next