Red Hat Bugzilla – Bug 1465997
Need a way to exclude sections from eu-strip
Last modified: 2017-07-18 11:34:54 EDT
Rust shared libraries have an unallocated .rustc section containing metadata, which eu-strip greedily removes. I use '%global _find_debuginfo_opts -g' to avoid this, removing only debug sections, but that means we also don't strip stuff like symbol tables.
There's some prior discussion in bug 1380961. At that time I was happy to have .rustc removed but there was a bug doing so. However, now I do need to keep this section in order to support compiler plugins.
This is data that is used by the compiler at build time, not by program execution, which is why the section is not allocated. It has been suggested that it should thus be separated into a devel package. This currently can't be done because rustc only knows how to look for the .rustc section in the *.so itself. But even if we could separate it, that would provide no real benefit, as we would always need to install that as dependency of rustc anyway.
I think the most general solution would be an rpm macro or option to specify sections that need to be preserved. This may need a new elfutils feature too, as I don't see a way for eu-strip to control this. (Just all or -g for debug-only.)
There is eu-strip -g which only strips .debug sections. But that keeps all other non-allocated sections. Most of which aren't needed at runtime. So it looks like we would want to have an eu-strip option --keep-section=SECTION that would not strip a named (unallocated) section, even if it would be stripped otherwise. Only tricky thing about that is how it would interact with symbol sections (would it prevent any symbols to be stripped from that section?)
Do you know how other distributions do this for rust based packages?
What exactly is this .rustc meta-data? And if it isn't needed at runtime, why is it embedded into the main shared library. If it is only needed during compilation can't it go into a separate file in the -devel package, together with the headers, etc.? You say rustc currently doesn't know how to lookup this data except by looking at the runtime shared library object. But how hard would it be to properly separate it out? How is it different from e.g. header files also needed during build time? You see it would always be a dependency of rustc anyway. But what about people who don't install rustc, but only run binaries created by the rust toolchain?
It almost sounds like what you call a shared object library (.so) is in fact really not a shared library at all? But maybe I misunderstand the working of shared libraries in the rust toolchain.
Yes, 'eu-strip -g' is effectively what I'm using now via _find_debuginfo_opts. I don't know how other distros strip debuginfo.
The .rustc metadata contains everything about a library that can't be plain symbols and object code. It's all the Rust-level type information, as well as internal representations of generic code that hasn't been monomorphized (instantiated to particular types) yet. It's similar in concept to C++ template headers, except Rust doesn't use separate source+headers like that. It's not needed by any running program, thus unallocated, but only needed to link a program with that library.
It's perhaps misleading to call these shared libraries a Rust "runtime", because we only ship them for use by the rustc compiler itself. Every other Rust program is required to statically link the standard library, since there's no stable ABI. (Let's not get into the ABI discussion here.) The only time something other than the compiler will link to the shared libraries is for compiler plugins, which we only build and run transitively as part of package builds, never shipped.
So these shared libraries are only shipped for rustc itself, and we only need their .rustc metadata for compiler plugins. If we somehow split that data into a separate -devel package, we would still have to require that as a dependency of rustc, so there would be no benefit to how rust is installed (as I said before).
I find it frustrating to nitpick the way Rust is doing things here. I think that the *generic* request perfectly reasonable, to just give some control to keep unusual sections that the user knows are important, for whatever reason.
(In reply to Josh Stone from comment #2)
> I find it frustrating to nitpick the way Rust is doing things here. I think
> that the *generic* request perfectly reasonable, to just give some control
> to keep unusual sections that the user knows are important, for whatever
Sorry about that. Yes, it is a reasonable request to have a way to not strip a non-allocated section away into a separate .debug file. Please don't see my nitpicking as denying the request.
But it is interesting to know the specific reasons for the request. Because I believe the real issue is debuginfo vs static linking. And that isn't rust(c) specific. If these .so files are really just .a archives then we might want to think about a more generic solution for any toolchain that does help with linking debuginfo correctly into the right binaries.
So forgive me for asking yet another question. But how does the debuginfo from the shared/static (standard) library end up discoverable to a debugger, profiler or tracer that might need to look at it to map an code/address range to specific sources or data types?
So, for more context, maybe related:
Bug 766156 - eu-strip doesn't handle ar archive library
Bug 1395286 - elfutils: Support rewriting source file paths in static libraries
(In reply to Mark Wielaard from comment #3)
> So forgive me for asking yet another question. But how does the debuginfo
> from the shared/static (standard) library end up discoverable to a debugger,
> profiler or tracer that might need to look at it to map an code/address
> range to specific sources or data types?
The shared libraries do contain some real .text code, with corresponding .debug sections, and it works totally fine with debuggers to strip that in that normal way. The generic stuff in .rustc is not really compiled yet, so it doesn't have debuginfo. When you link that and get generics monomorphized into real code, you'll get debuginfo referencing the library's sources in that target too. This is OK for us because again, the only stuff we *ship* this way is all part of the rust srpm, so they share rust-debuginfo.
For the static libraries (*.rlib) it's uglier. Then we have a few normal *.o entries and a few rust specific entries, e.g.
> $ ar t /usr/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-49022a8a9be64aa2.rlib
rpmbuild unconditionally strips static archives, so we lose any debuginfo in those *.o. It also throws warnings about those two unrecognized entries.
Then when we statically link a rust program to this, we get some code from the *.o without debuginfo, and some monomorphized code that does have debuginfo referencing 'std' source files. But those source files don't exist in the program's own debuginfo package.
The workaround I use is to manually install rust-debuginfo and set GDB to search for the program's sources in that path too. Since the distro generally doesn't give *any* debuginfo for statically linked libraries, this manual step is gross but still better than nothing.
Proposed upstream elfutils patch:
strip: Add --keep-section=SECTION and --remove-section=SECTION.
Proposed rpm patch:
find-debuginfo.sh: Add --keep-section and --remove-section for eu-strip.
With that you can:
-%global _find_debuginfo_opts -g
+%global _find_debuginfo_opts --keep-section .rustc
elfutils patch included in elfutils-0.169-4.fc27.
rpm patch submitted, will include in fedora rawhide when accepted upstream.
Added upstream and in rpm-18.104.22.168-32.fc27