Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FR] create_minidebuginfo should be bundled in the NDK #1949

Open
edechamps-Google opened this issue Oct 17, 2023 · 8 comments
Open

[FR] create_minidebuginfo should be bundled in the NDK #1949

edechamps-Google opened this issue Oct 17, 2023 · 8 comments

Comments

@edechamps-Google
Copy link

edechamps-Google commented Oct 17, 2023

create_minidebuginfo is a tool that makes it possible to compress native .so debug information (in particular, unwind tables) so that they take less space on device disk.

Unfortunately, this tool is only available from within AOSP, despite the fact that it is generally useful to anyone building native code for Android, not just platform code.

Making this tool more widely available would provide more opportunities for developers to reduce the footprint of their binaries. The other approach, stripping the unwind tables entirely, is unpalatable because that means native crash reports do not contain usable stack traces.

As an example, here is the impact of compressed unwind tables on Cronet (a134cecb, arm64):

  • Normal release build: 5902688 bytes (5.7 MiB)
  • Unwind tables stripped: 4813520 bytes (4.6 MiB)
  • Unwind tables compressed: 5029632 bytes (4.8 MiB)

Cronet already uses compressed unwind tables when it's bundled inside Google 1P apps; for more background on this, see this internal doc. In order to be able to do this, we had to jump through hoops and transplant create_minidebuginfo to the internal build system. Having this tool inside the NDK would allow us to clean this up, and would also make it easier for third-party app developers to start using it and reap the benefits.

As far as I know, the only real downside to using compressed unwind tables is that debuggerd only understands them starting from Android P. This caveat should be documented.

Even better would be to get rid of create_minidebuginfo altogether and have the linker do it automatically, but I'm not sure how feasible that would be.

@DanAlbert
Copy link
Member

Generally speaking, we prefer to not add anything to the NDK that doesn't have a good reason for being coupled to Clang's release cycle (that's mostly what "in the NDK" means: it cannot be upgraded independently of Clang). Unnecessary coupling of build dependencies can cause problems for developers, since you may need a new version of create_minidebuginfo to fix a bug but not be ready to update to a new version of Clang (or vice-versa, though Clang updates usually require the most work to adopt).

We have some tools that don't follow that rule: simpleperf and the shader compiler being the most obvious. If we were making those decisions again today, I don't think we'd have included those tools in the NDK.

The alternative that's usually (but not always) the better choice is including it in the SDK. That is, it can be downloaded from the Android SDK manager the same way the NDK is, but it can be updated and released independently of the NDK's release cycle.

That said, if this turns out to be the best place for it, then sure :) This one may be a good candidate because it's not useful to anyone but NDK developers, and it sounds like it is useful to all NDK developers with a minSdkVersion of P or higher (which is probably just about nobody today, but will likely grow substantially over the next decade).

Even better would be to get rid of create_minidebuginfo altogether and have the linker do it automatically, but I'm not sure how feasible that would be.

I agree. If this is possible this is definitely the way this should be done. I'm not at all familiar with mini debuginfo so I can't say, but @cferris1000 and @pirama-arumuga-nainar probably can. It also makes it much more accessible, since it isn't dependent on each build system adding support before it can be used.

@cferris1000
Copy link
Collaborator

I don't know how likely it is to get this support in the linker. It's already supported in gdb, but I don't know if any linker supports it.

@enh-google
Copy link
Collaborator

isn't this the same think @MaskRay talked about? https://maskray.me/blog/2022-09-09-zstd-compressed-debug-sections

@cferris1000
Copy link
Collaborator

I believe this is a tool that processes an elf file and compresses it. That output is then used to create the .gnu_debugdata section in the Android build system. So not -gz=zstd, which does something slightly different. My understanding is that the zstd option compresses the section data, while gnu_debugdata is, basically, compressed elf data stuffed into the section named .gnu_debugdata. gnu_debugdata can include multiple sections, and we usually have the symbol table and a debug_frame in it. For zstd, I would expect that it would compress the debug_frame, but there would still be a debug_frame, but the flags for the section would indicate it's compressed.

@edechamps-Google
Copy link
Author

Just FYI I also found this doc from 2020 that has this to say about minidebuginfo in Android, which might or might not be relevant (not sure if it applies to native code):

ART compiler follows the standard format, but additionally:

  • Ensures that all .symtab entries are sorted. This makes it possible to binary search it.
  • Sorts .debug_frame entries by their content (by the raw opcode data lexicographically). This ensures similar opcode patterns are nearby, which improves 7z compression by 2x.
  • Splits the 7z data into fixed-size independent blocks. This makes it possible to decompress only needed parts of the file. The whole is still a standard valid 7z file.
  • It omits function parameters to save space.

@serhiihuralniksc
Copy link

isn't this the same think @MaskRay talked about? https://maskray.me/blog/2022-09-09-zstd-compressed-debug-sections

They both are aimed to solve similar problems but differently. MaskRay' work is an extending already existing mechanism for compressing featured ELF sections with a new compression method. GNU MiniDebugInfo is basically embedding a filtered and xz-compressed copy of self into an ELF as a .gnu_debugdata section. This allows to pack virtually any part of original ELF that user wants, not only .debug_*. (As it was said above)

This should be an original description of MiniDebugInfo. All prerequisites are already in NDK (except for xz but I guess it is ubiquitous among typical dev machines or CI builders). It should be fairly simple to follow original guide and add a custom build step that embeds MiniDebugInfo into your binary, e.g. via CMake POST_BUILD command.

Also it feels like having MiniDebugInfo is not necessarily as beneficial for NDK users as it is for Android platform:

  • many NDK projects are built with C++ EH enabled which means that there must be an instance of uncompressed unwind tables anyways to let libunwind work properly.
  • app developer can usually afford to collect unstripped versions of their binaries somewhere and access them later when DI is needed, e.g. to decode crash stack, which renders shipping of .symtab/.debug_* with the app useless, whether compressed or not.

Though it still can be desired to some extent, e.g. for assisting platform crash_dump or custom crash reporters with unwinding through non-EH frames by providing compressed .eh_frame for them.

As an alternative to originally proposed tool - NDK could distribute a CMake function that implements objcopy+xz build step that can be attached to user defined SHARED_LIBRARY or EXECUTABLE.

@DanAlbert
Copy link
Member

As an alternative to originally proposed tool - NDK could distribute a CMake function that implements objcopy+xz build step that can be attached to user defined SHARED_LIBRARY or EXECUTABLE.

If we were to go that route, I'd want to see that done in upstream CMake, since it's not Android specific (right?)

Implementation within lld would still be better so it can serve non-CMake users, of course.

@serhiihuralniksc
Copy link

It is not Android-specific, but still makes sense for ELF platforms only and CMake implementation would impose requirements to a toolchain used to supply needed binutils which can be easily broken by user-provided CMAKE_TOOLCHAIN_FILE. Not sure if CMake is clearly the right place for it.

Regarding ld.lld - to me MiniDebugInfo is a post-link modification that needs no special knowledge that only linker possesses. So likely it is better to have it as a separate build step, just like strip --strip-unneeded. Moreover - different users may want to see different sections in their MiniDebugInfo (this actually questions my suggestion for a CMake function as well).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants