Brussels / 1 & 2 February 2020

schedule

Support for mini-debuginfo in LLDB

How to read the .gnu_debugdata section.


The "official" mini-debuginfo man-page describes the topic best:

Some systems ship pre-built executables and libraries that have a special .gnu_debugdata section. This feature is called MiniDebugInfo. This section holds an LZMA-compressed object and is used to supply extra symbols for backtraces.

The intent of this section is to provide extra minimal debugging information for use in simple backtraces. It is not intended to be a replacement for full separate debugging information (see Separate Debug Files).

In this talk I'll explain what it took to interpret support for mini-debuginfo in LLDB, how we've tested it, and what to think about when implementing this support (e.g. merging .symtab and .gnu_debugdata sections).

If the .symtab section is stripped from the binary it might be that there's a .gnu_debugdata section which contains a smaller .symtab in order to provide enough information to create a backtrace with function names or to set and hit a breakpoint on a function name.

My change looks for a .gnu_debugdata section in the ELF object file. The .gnu_debugdata section contains a xz-compressed ELF file with a .symtab section inside. Symbols from that compressed .symtab section are merged with the main object file's .dynsym symbols (if any). In addition we always load the .dynsym even if there's a .symtab section.

For example, the Fedora and RHEL operating systems strip their binaries but keep a .gnu_debugdata section. While gdb already can read this section, LLDB until my patch couldn't. To test this patch on a Fedora or RHEL operating system, try to set a breakpoint on the "help" symbol in the "zip" binary. Before this patch, only GDB can set this breakpoint; now LLDB also can do so without installing extra debug symbols:

lldb /usr/bin/zip -b -o "b help" -o "r" -o "bt" -- -h

The above line runs LLDB in batch mode and on the "/usr/bin/zip -h" target:

(lldb) target create "/usr/bin/zip"
Current executable set to '/usr/bin/zip' (x86_64).
(lldb) settings set -- target.run-args  "-h"

Before the program starts, we set a breakpoint on the "help" symbol:

(lldb) b help
Breakpoint 1: where = zip`help, address = 0x00000000004093b0

Once the program is run and has hit the breakpoint we ask for a backtrace:

(lldb) r
Process 10073 stopped
* thread #1, name = 'zip', stop reason = breakpoint 1.1
    frame #0: 0x00000000004093b0 zip`help
zip`help:
->  0x4093b0 <+0>:  pushq  %r12
    0x4093b2 <+2>:  movq   0x2af5f(%rip), %rsi       ;  + 4056
    0x4093b9 <+9>:  movl   $0x1, %edi
    0x4093be <+14>: xorl   %eax, %eax

Process 10073 launched: '/usr/bin/zip' (x86_64)
(lldb) bt
* thread #1, name = 'zip', stop reason = breakpoint 1.1
  * frame #0: 0x00000000004093b0 zip`help
    frame #1: 0x0000000000403970 zip`main + 3248
    frame #2: 0x00007ffff7d8bf33 libc.so.6`__libc_start_main + 243
    frame #3: 0x0000000000408cee zip`_start + 46

In order to support the .gnu_debugdata section, one has to have LZMA development headers installed. The CMake section, that controls this part looks for the LZMA headers and enables .gnu_debugdata support by default if they are found; otherwise or if explicitly requested, the minidebuginfo support is disabled.

GDB supports the "mini debuginfo" section .gnu_debugdata since v7.6 (2013).

Speakers

Konrad Kleine

Links