Search code examples
elfdisassemblydebug-symbolsobjdumpdwarf

What to do with "DWARF error: section .debug_info is larger than its filesize!"?


Looking for ways to see generated assembler of a specific function in my binary (an .so to be exact), just as I can see similar on Compiler Explorer, I found How to disassemble one single function using objdump? and based on answers there (and also my further search) I ended up using the following command:

objdump --wide --no-address --no-show-raw-insn [--demangle] --disassemble="<symbol>" -- "<binary>"

where the <symbol> I have found using:

objdump --syms [--demangle] -- "<binary>" | grep <function>

where again the <function> is the C++ function name I was interested in. Of course, the <symbol> is a mangled name. (For completeness, I got two results - the one expected and another one with .cold suffix, which is used by the "main one".)


The result is already pretty solid. However, browsing through objdump options I see promising ones:

  • -C / --demangle,
  • -l / --line-numbers,
  • -S / --source.

However, I cannot get them to work...

INITIAL: The first one (-C / --demangle) results in no disassembly printed at all. Without it, after the Disassembly of section .text: line I have a line with the symbol followed by disassembly. With this option the symbol and disassembly are not shown, instead Disassembly of section .fini: follows immediately.

EDIT: After some more attempts I noticed that the -C / --demangle seems to be working fine if I'm providing just --disassemble, without naming the symbol. And this helped me identify the problem with this option: if used it expects also the <symbol> argument to be demangled! With C++ it is may not be easy to write down the proper symbol name but the same trick as described above will help - just add the -C / --demangle along the --syms call as well to have demangled name printed. However, below described issues are still present.

The second one (-l / --line-numbers) and third one (-S / --source) result in error print

objdump: DWARF error: section .debug_info is larger than its filesize! (0x7b5000e1 vs 0x3e503e10)

immediately after the symbol line and then the disassembly follows. There are no apparent changes in the output except for the -l / --line-numbers option where before the disassembly there is another line with the symbol name printed as if function name (with () suffix).

Where this error comes from? What can I do? The binary was built with GCC 10.2.0. The objdump is 2.36.


Another doubt is the use of --no-address. It does help with comparing disassembly results between various builds. Otherwise, changes of the addresses clutter the diff.

However, without the addresses, how can I see targets of jumps? Now, I know there is --visualize-jumps but with longer functions this is too messy output. And again, it doesn't go well with diffs.

Is there perhaps an option to "recalculate" addresses so that they always start from a specified index (0 I guess...)? Or adding "labels" as the Compiler Explorer does in one of its output modes


Solution

  • I made some more "research" and it seems I got hit by the problem reported to GNU binutils as bug 28834. The diff of the fix even shows how the is larger than its filesize! print changed.

    However, this fix isn't yet released, the current version 2.38 was released on 2022-01-22, while the fix was done on 2022-02-02. Based on the dates of two previous releases, we could expect 2.39 (with the fix) somewhere around 2022-07.

    EDIT: It seems there is more mess in how binutils release their versions and the 2.38 does contain the fix after all. I got it installed on my machine and no longer observe the errors reported in question. It takes absurdly long time to get anything with --line-numbers and --source out of an optimized build (in fact, I didn't manage to wait till the end...) but it does not report the error anymore. Hence, it seems the problem in question was kind of a bug in binutils that got fixed in 2.38.