You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ctf: do not emit types in functions, or types that point into them
Even though dwarf2ctf's users are only interested in top-level
types and variables, we have always recursed through functions and
emitted all structure and union types found there. This is because some
versions of GCC translate 'struct foo * bar' into a subroutine DIE
'struct foo' and a *global* pointer DIE, and since we emit all global
type DIEs we would fail horribly if we didn't also find the things they
might point to.
But this is very wasteful: READ_ONCE() defines an anonymous union, and
over a thousand of these, used inside static and inline functions
defined in header files, are found in the generated CTFA, in addition to
a number of other useless structures.
GCC 8 has perturbed things enough that we are getting assertion failures
when emitting some of these useless types: enough. Rather than spending
time and disk space emitting types nobody will ever access, let's just
remove them.
But this wasn't being done already because it's rather tricky. We can
avoid the obvious cases by just not recursing into subroutine DIEs, but
if we are also to avoid the top-level DIEs with type DIEs inside
subroutines that caused this problem in the first place, we have to
detect and avoid to remove all DIEs which have a type DIE which is
inside a subroutine, recursively. And *that* requires being able to
determine, for an arbitrary DIE which we reached by following a type DIE
pointer from some other type (rather than via recursion) whether it is
inside a subroutine or not. And elfutils does not make that easy: we go
through contortions in several places to avoid having to figure this
out, but here we cannot get away from it.
You can get from a DIE to its children easily, via dwarf_child() -- but
there is no dwarf_parent(): elfutils does not expose child->parent
pointers at all. So we need to build a map linking children to their
parents. Since type DIEs can point forward in files as well as
backward, we need the entire child->parent graph of any given file
before calling any process_file() filter functions: so we must traverse
the entire file redundantly before that, which is not cheap.
We can amortize the cost of this by building the map once on first
opening any given file and keeping it across the lifetime of dwarf2ctf,
in a hash of hashes, absolute file name -> DIE offset -> DIE offset: DIE
offsets are unique within files in the kernel build process so this is
sufficient. This uses a few dozen megabytes of RAM (fairly
insignificant): since it both saves time (through emitting less) and
spends it, we end up almost a wash: a 20s slowdown in total.
The CTF file shrinks substantially: in my testing, 6398074 -> 6252458
bytes, regaining most of the space we lost in the libdtrace-ctf range
expansion that accompanied libdtrace-ctf 1.0.0. The shared type repo
loses about 220 useless types: vmlinux.ctf loses about 2500 (!): other
CTF repos lose some too, but obviously not quite as many. Of course the
shared type repo is the *full* one, and even after this it's nearly
blowing the 0x8000 types limit of libdtrace-ctf < 1.0.0, so the range
expansion was still necessary.
Orabug: 29054887
Signed-off-by: Nick Alcock <[email protected]>
Reported-and-tested-by: Victor Erminpour <[email protected]>
Reviewed-by: Kris Van Hees <[email protected]>
0 commit comments