From: Nick Alcock Date: Thu, 23 Jan 2014 23:22:21 +0000 (+0000) Subject: ctf: capture all DIEs with structs/enums as their ultimate supertype X-Git-Tag: v4.1.12-92~313^2~46 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=15de1732f33faa494b71c1819d17c39800662b52;p=users%2Fjedix%2Flinux-maple.git ctf: capture all DIEs with structs/enums as their ultimate supertype dwarf2ctf has to scan all the DWARF in the kernel repeatedly while generating its compressed type representation: it even has to scan inside functions, even though it is only interested in file-scope types and variables, because opaque structure, union, or enumeration references at the top level can contain references to a definition inside a function. Repeated scanning of gigabytes of DWARF is slow: dwarf2ctf spends most of its time doing this, not emitting types. To make this less abominably slow, dwarf2ctf contains a filtration mechanism to avoid scanning or emitting DIEs which will never be useful. An iron rule of dwarf2ctf is that *all* DIEs that are emitted as types must first be spotted by this 'duplicate detector' scanning phase, since it not only determines which types are duplicated but also where they should go: whether they are shared between kernel modules (and should go into the shared type repository in ctf.ko) or are shared between translation units in a single module or not duplicated at all, in which case they go into the module's local CTF. So if the filtration mechanism skips types which are later emitted, dwarf2ctf can do little but abort (in general dwarf2ctf aborts if it finds internal consistency problems which may affect the generation of many types, but skips types and warns if it finds problems with single types which are not likely to affect the generation of other types). One of these filtration functions is filter_ctf_file_scope(). This is called to filter out DIEs representing most qualifiers and base types when they appear inside functions, by simply checking if the parent of the DIE is DW_TAG_compile_unit. In GCC 4.4.x, applying this to a variety of DIEs was sufficient to filter out all DIEs inside functions that we weren't going to emit CTF representations of. Unfortunately GCC has since changed its debugging information representation somewhat in a fashion which breaks this. Inside drivers/firmware/dmi-id.c we see the example dwarf2ctf calls out when it fails: static const struct mafield { const char *prefix; int field; } fields[] = { [...] { NULL, DMI_NONE } }; const struct mafield *f; This is a structure inside a function, but even so GCC generates some of its type DIEs at global scope and they are emitted into the CTF. Over time, GCC is moving more of the DIEs into subprogram scope, but not yet all of them: this is what has broken us. The variable 'f' is represented by the following DIEs, where A, B, C and D are DIE offsets: [ A] structure_type name (strp) "mafield" [...] [ B] const_type type (ref4) [ A] [ C] pointer_type byte_size (data1) 8 type (ref4) [ B] In GCC 4.4.x, all of these other than the structure_type itself are at the global scope, not the subprogram scope, so the filter never kicks in for these DIEs and all of them are emitted successfully. Between 4.4.x and 4.8.0, the 'const_type' moved into subprogram scope, but the pointer_type did not, so we have a pointer_type at global scope referring to a const_type at subprogram scope -- which has been filtered out by the filtration function, so emission of the pointer_type fails and dwarf2ctf aborts because its type graph is incomplete, with a type pointing at a type it has no record of. Fix this by having filter_ctf_file_scope() look at the DW_AT_type attribute of its target DIE, chaining to its type-attributeless terminus and note whether that terminus is a structure, union, or enumeration: all DIEs having such types at the terminus of their type chains must not be filtered out. Orabug: 18117464 Signed-off-by: Nick Alcock Reviewed-by: Chuck Anderson --- diff --git a/Documentation/dwarf2ctf b/Documentation/dwarf2ctf index 2e28359afa82..4ebe1fc14e79 100644 --- a/Documentation/dwarf2ctf +++ b/Documentation/dwarf2ctf @@ -359,10 +359,10 @@ tag doesn't appear in the assembly table at all: there's no point doing duplicate detection or anything else for a DWARF DIE we won't be generating CTF from. There are currently two filters defined: filter_ctf_file_scope(), which is called for every DWARF DIE whose tag is one we never expect to see a -reference to if it is inside a function, and filter_ctf_uninteresting(), which -is called for variables to see if they are worthy of recording (top-level named -variables with external linkage not part of the internal workings of macros -only). +reference to if it is inside a function (except if they relate to a structure or +union, as above), and filter_ctf_uninteresting(), which is called for variables +to see if they are worthy of recording (top-level named variables with external +linkage not part of the internal workings of macros only). Type IDs diff --git a/scripts/dwarf2ctf/dwarf2ctf.c b/scripts/dwarf2ctf/dwarf2ctf.c index 445728cd9d45..af3f18e18447 100644 --- a/scripts/dwarf2ctf/dwarf2ctf.c +++ b/scripts/dwarf2ctf/dwarf2ctf.c @@ -499,9 +499,13 @@ typedef int (*ctf_assembly_filter_fun)(Dwarf_Die *die, /* * A CTF assembly filter function which excludes all types not at the global - * scope (i.e. whose immediate parent is not a CU DIE). + * scope (i.e. whose immediate parent is not a CU DIE) and which does not have a + * structure or union as its ultimate dependent type. (All structures and + * unions and everything dependent on them must be recorded, even inside + * functions, because GCC may emit references to the opaque variants of those + * types from file scope.) */ -static int filter_ctf_file_scope(Dwarf_Die *die __unused__, +static int filter_ctf_file_scope(Dwarf_Die *die, Dwarf_Die *parent_die); /* @@ -2581,11 +2585,40 @@ static ctf_id_t lookup_ctf_type(const char *module_name, const char *file_name, /* * A CTF assembly filter function which excludes all types not at the global - * scope (i.e. whose immediate parent is not a CU DIE). + * scope (i.e. whose immediate parent is not a CU DIE) and which does not have a + * structure or union as its ultimate dependent type. (All structures and + * unions and everything dependent on them must be recorded, even inside + * functions, because GCC may emit references to the opaque variants of those + * types from file scope.) */ -static int filter_ctf_file_scope(Dwarf_Die *die __unused__, Dwarf_Die *parent_die) +static int filter_ctf_file_scope(Dwarf_Die *die, Dwarf_Die *parent_die) { - return (dwarf_tag(parent_die) == DW_TAG_compile_unit); + /* + * Find the ultimate parent of this DIE. + */ + + Dwarf_Die dependent_die; + Dwarf_Die *dependent_diep = private_dwarf_type(die, &dependent_die); + + if (dependent_diep != NULL) { + Dwarf_Die *possible_depp = dependent_diep; + do { + Dwarf_Die possible_dep; + possible_depp = private_dwarf_type(possible_depp, + &possible_dep); + + if (possible_depp != NULL) + dependent_die = possible_dep; + } while (possible_depp != NULL); + } + + if (dependent_diep) + return (dwarf_tag(dependent_diep) == DW_TAG_structure_type || + dwarf_tag(dependent_diep) == DW_TAG_union_type || + dwarf_tag(dependent_diep) == DW_TAG_enumeration_type || + dwarf_tag(parent_die) == DW_TAG_compile_unit); + else + return (dwarf_tag(parent_die) == DW_TAG_compile_unit); } /*