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

debug: support loading elf debug info from external files #15531

Closed
wants to merge 1 commit into from

Conversation

kcbanner
Copy link
Contributor

@kcbanner kcbanner commented May 1, 2023

Some distributions (ie. Ubuntu) have their libc debug info in separate files. This change allows the stack walking code to read that debug info.

  • add support for reading compressed ELF sections
  • support reading the build-id from the elf headers in order to lookup external debug info
  • support reading the .gnu_debuglink section to look up external debug info

Example:

int add_mult3(int x, int y, int* n) {
    puts((const char*)0x1234);
    return (x + y) * (*n);
}

Before:

Segmentation fault at address 0x1234
???:?:?: 0x7f03074ed97d in ??? (???)
src/lib.c:10:12: 0x7f0307581560 in add_mult2 (/home/kcbanner/temp/stack/src/lib.c)
    return add_mult3(x, y, n);
           ^
src/lib.c:14:12: 0x7f0307581590 in add_mult1 (/home/kcbanner/temp/stack/src/lib.c)
    return add_mult2(x, y, n);
           ^
src/lib.c:18:12: 0x7f03075815c0 in add_mult (/home/kcbanner/temp/stack/src/lib.c)
    return add_mult1(x, y, n);
           ^
/home/kcbanner/temp/stack/src/main.zig:6:45: 0x20c417 in main (main)
    std.debug.print("add: {}\n", .{ add_mult(5, 3, null) });

After:

./sysdeps/x86_64/multiarch/strlen-avx2.S:74:0: 0x7fa9c839d97d in ??? (../sysdeps/x86_64/multiarch/strlen-avx2.S)
src/lib.c:10:12: 0x7fa9c8431560 in add_mult2 (/home/kcbanner/temp/stack/src/lib.c)
    return add_mult3(x, y, n);
           ^
src/lib.c:14:12: 0x7fa9c8431590 in add_mult1 (/home/kcbanner/temp/stack/src/lib.c)
    return add_mult2(x, y, n);
           ^
src/lib.c:18:12: 0x7fa9c84315c0 in add_mult (/home/kcbanner/temp/stack/src/lib.c)
    return add_mult1(x, y, n);
           ^
/home/kcbanner/temp/stack/src/main.zig:6:45: 0x211c57 in main (main)
    std.debug.print("add: {}\n", .{ add_mult(5, 3, null) });
                                            ^
/mnt/c/cygwin64/home/kcbanner/kit/zig/lib/std/start.zig:609:37: 0x212246 in main (main)
            const result = root.main() catch |err| {

In this case it's loading the debug info from /usr/lib/debug/.build-id/69/389d485a9793dbe873f0ea2c93e02efaa9aa3d.debug.

Now that the debug info is being loaded, I'm going to see how complex building a DWARF unwinder would be (so that stack frames aren't missed due to -fomit-frame-pointer). In the above example, the puts call is missed because of this.

The same stack in gdb:

#6  0x00007fffff6fd97d in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#7  0x00007fffff5e0ee8 in puts () from /lib/x86_64-linux-gnu/libc.so.6
#8  0x00007fffff7914cc in add_mult3 (x=5, y=3, n=0x0) at /home/kcbanner/temp/stack/src/lib.c:5
#9  0x00007fffff791561 in add_mult2 (x=5, y=3, n=0x0) at /home/kcbanner/temp/stack/src/lib.c:10
#10 0x00007fffff791591 in add_mult1 (x=5, y=3, n=0x0) at /home/kcbanner/temp/stack/src/lib.c:14
#11 0x00007fffff7915c1 in add_mult (x=5, y=3, n=0x0) at /home/kcbanner/temp/stack/src/lib.c:18
#12 0x0000000000211d98 in main.main () at main.zig:6

Some distributions (ie. Ubuntu) have their libc debug
info in separate files. This change allows the stack walking
code to read that debug info.

- add support for reading compressed ELF sections
- support reading the build-id from the elf headers in order to lookup external debug info
- support reading the .gnu_debuglink section to look up external debug info
@kubkon
Copy link
Member

kubkon commented May 1, 2023

Very nice. I had no idea ELF had a debug symbols bundle-like mechanism in place too. Re stack unwinding using DWARF CFI perhaps this can be some inspiration zig-dwarfdump/src/DwarfDump.zig#L928.

.{ .name = ".debug_rnglists", .out = &opt_debug_rnglists },
.{ .name = ".debug_addr", .out = &opt_debug_addr },
.{ .name = ".debug_names", .out = &opt_debug_names },
.{ .name = ".debug_frame", .out = &opt_debug_frame },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For stack unwinding you will most definitely want to include .eh_frame section. In fact, I haven't seen .debug_frame used much or at all in practice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice. I had no idea ELF had a debug symbols bundle-like mechanism in place too. Re stack unwinding using DWARF CFI perhaps this can be some inspiration zig-dwarfdump/src/DwarfDump.zig#L928.

Thanks, this looks like a great reference!

Depending on the amount of work involved (apparently the DWARF unwind stuff is Turing complete: http://kristerw.blogspot.com/2016/01/more-turing-completeness-in-surprising.html) I may move this PR into review before doing that, once I've cleaned things up a bit.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good! Thanks for working on this!

@kcbanner
Copy link
Contributor Author

Superseded by #15823

@kcbanner kcbanner closed this May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants