One of the jobs of the dwarf2ctf duplicate detector is to trace the members of
structures and unions in every kernel module, one by one, and recursively mark
the types of every such member as used in that module; any such types used in
more than one module are promoted to the shared type repository (and marked as
used in that in the same way). In conjunction with a variety of other rules,
this ensures that types in per-module type repositories can refer to types in
the shared type repository, but that the shared repository is self-contained:
DTrace userspace can then load any module's type repository, set its parent to
be the shared type repository, and be sure that it can fully characterize any
type in that module.
dwarf2ctf was aborting because a type was missed by the duplicate detector but
then emitted by the type generation phase. The type in question is found in
drivers/message/i2o/i2o_proc.c:
typedef struct _i2o_user_table {
[...]
} i2o_user_table;
struct {
[...]
i2o_user_table user[64];
} *result;
The array is represented as the following:
[ beca] structure_type
[ bf2f] member
name (strp) "user"
type (ref4) [ bfa9]
[ bfa9] array_type
type (ref4) [ bebe]
sibling (ref4) [ bfb9]
[ bebe] typedef
name (strp) "i2o_user_table"
decl_file (data1) 1
decl_line (data2) 1114
type (ref4) [ be6f]
[ be6f] structure_type
name (strp) "_i2o_user_table"
byte_size (data1) 8
decl_file (data1) 1
decl_line (data2) 1108
sibling (ref4) [ bebe]
As the indentation makes clear, in GCC 4.4.x the array_type is at the top level,
where it is always spotted by the duplicate detector as a matter of course. In
fact, in GCC 4.4.x *no* types other than aggregates are ever emitted as children
of structure_types: they're all at the top level and thus trivially detected by
the walk through top-level types that the duplicate detector does as a matter of
course: so this part of the scanning phase only needs to look at the types of
structures, unions and enumerations, to handle perverse cases like
struct foo {
struct {
int womble;
} *baz;
};
in which the innermost struct's DIE (but *not* the pointer to it) is represented
as a child of the outer one's, even in GCC 4.4.x.
In GCC 4.8.x this is no longer true: the array_type DIE above is emitted as a
direct child of the structure_type here shown as [ beca], and indeed you can see
all sorts of types as children of structure_types, even basic types like 'int'
if they happen not to be used anywhere else in the translation unit. So we must
mark them all as seen.
-- or almost all. We do not bother marking types we will not later emit CTF
for, and we do not mark structure or union members themselves, because structure
members are not types and cannot be referenced by another member. (Since
members are very numerous and cannot be duplicated across kernel modules unless
their containing structure is also duplicated, not marking them as seen also
saves a great deal of memory.)
Thankfully the emission phase does not care what the parent of DIEs is except if
they are things like structures or unions which have parents in CTF too. So
arrays, basic types, and the like inside structure_type DIEs do not disturb the
actual emission of types: once we have fixed the duplicate detector, all is
well.
Orabug:
18117464
Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
Reviewed-by: Chuck Anderson <chuck.anderson@oracle.com>
of those modules anymore: this should not require rebuilding of any out-of-tree
modules).
-If we mark a type as seen, we must mark aggregate types that appear directly
-within that type's DIE as seen as well. This is done by the recursive function
-mark_seen_contained(). You might wonder what the point of it is: such types
-surely cannot appear anywhere else, and any duplication will precisely match the
-duplication of the containing type. The answer is that they can still be
-referenced as the type of structure members of their containing structure,
-e.g. in
+If we mark a structure or union type as seen, we must mark aggregate types that
+appear directly within that type's DIE as seen as well. This is done by the
+recursive function mark_seen_contained(). You might wonder what the point of it
+is: such types surely cannot appear anywhere else, and any duplication will
+precisely match the duplication of the containing type. The answer is that they
+can still be referenced as the type of structure members of their containing
+structure, e.g. in
struct foo {
struct bar {
} *baz;
+ struct bar wombat[16];
};
Here, a reference to 'struct bar' appears in 'struct foo', and CTF is
-constructed for it, even though it is not a top-level DIE.
+constructed for it, even though it is not a top-level DIE. In GCC 4.8+, a
+reference to the 16-element array-of-struct-bar can also appear in 'struct foo':
+in fact almost anything can appear in there if used nowhere else in the
+translation unit, even base types. So we look for the appearance of anything
+which we can assemble into CTF (anything in the assembly_tab) other than
+members, since members cannot be used as the type of anything else, and mark
+them all as seen in this module. (Nearly everything in a structure or union is
+a member, so this ends up skipping almost but not quite everything.)
If we find that a type has appeared more than once in different kernel modules
}
/*
- * Mark any aggregates contained within a particular type DIE as seen. This is
- * needed since even nameless aggregates contained within other aggregates can
- * be used as the type of members of the outer aggregate (though they cannot
- * possibly be found in a module different from that of their containing
+ * Mark any types contained within a particular type DIE as seen. This is
+ * needed since even nameless types contained within other aggregates can be
+ * used as the type of members in any of their enclosing aggregates (though they
+ * cannot possibly be found in a module different from that of their containing
* aggregate, any more than a structure member can).
*/
static void mark_seen_contained(Dwarf_Die *die, const char *module_name)
}
/*
- * We are only interested in children of type DW_TAG_structure_type,
- * DW_TAG_union_type, or DW_TAG_enumeration_type (and only the former
- * two require further recursion, since only they can have members).
+ * We iterate over all immediate children and recursively call ourselves
+ * for all those of type DW_TAG_structure_type and DW_TAG_union_type.
+ *
+ * Further, everything other than members (which has an entry in
+ * assembly_tab) needs marking, since these may be declared at structure
+ * scope rather than being confined to global scope. Members are
+ * skipped because they cannot be used as the type of another field.
+ * These types cannot be duplicates if their containing type is not a
+ * duplicate, and typedefs cannot occur at this level so they cannot be
+ * aliased; thus we can mark them directly without going back into the
+ * top of detect_duplicates().
*/
int sib_ret;
case DW_TAG_union_type:
mark_seen_contained(&child, module_name);
/* fall through */
- case DW_TAG_enumeration_type: {
- char *id = type_id(&child, NULL, NULL);
+ default:
+ if (dwarf_tag(&child) != DW_TAG_member &&
+ dwarf_tag(&child) <= assembly_len &&
+ assembly_tab[dwarf_tag(&child)] != NULL) {
- dw_ctf_trace("Marking %s as seen in %s\n", id,
- module_name);
- g_hash_table_replace(id_to_module, id,
- xstrdup(module_name));
- }
+ char *id = type_id(&child, NULL, NULL);
+
+ dw_ctf_trace("Marking %s as seen in %s\n", id,
+ module_name);
+ g_hash_table_replace(id_to_module, id,
+ xstrdup(module_name));
+ }
}
while ((sib_ret = dwarf_siblingof(&child, &child)) == 0);