Re: Broken dwarf unwinding - wrong stack pointer register value?

From: Milian Wolff
Date: Mon Oct 22 2018 - 15:26:25 EST


On Montag, 22. Oktober 2018 15:58:17 CEST Andi Kleen wrote:
> Milian Wolff <milian.wolff@xxxxxxxx> writes:
> > After more digging, it turns out that I've apparently chased a red
> > herring.
> > I'm running archlinux which isn't shipping debug symbols for libm.
>
> 64bit executables normally have unwind information even when stripped.
> Unless someone forcefully stripped those too.
>
> You can checkout with objdump --sections.

Right, we do have .eh_frame and .eh_frame_hdr according to readelf:

```
$ readelf --sections /usr/lib/libm.so.6
There are 26 section headers, starting at offset 0x183120:

Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.build-i NOTE 0000000000000270 00000270
0000000000000024 0000000000000000 A 0 0 4
[ 2] .note.ABI-tag NOTE 0000000000000294 00000294
0000000000000020 0000000000000000 A 0 0 4
[ 3] .note.gnu.propert NOTE 00000000000002b8 000002b8
0000000000000020 0000000000000000 A 0 0 8
[ 4] .gnu.hash GNU_HASH 00000000000002d8 000002d8
00000000000024d0 0000000000000000 A 5 0 8
[ 5] .dynsym DYNSYM 00000000000027a8 000027a8
00000000000066c0 0000000000000018 A 6 1 8
[ 6] .dynstr STRTAB 0000000000008e68 00008e68
0000000000002352 0000000000000000 A 0 0 1
[ 7] .gnu.version VERSYM 000000000000b1ba 0000b1ba
0000000000000890 0000000000000002 A 5 0 2
[ 8] .gnu.version_d VERDEF 000000000000ba50 0000ba50
000000000000017c 0000000000000000 A 6 11 8
[ 9] .gnu.version_r VERNEED 000000000000bbd0 0000bbd0
0000000000000060 0000000000000000 A 6 2 8
[10] .rela.dyn RELA 000000000000bc30 0000bc30
0000000000000480 0000000000000018 A 5 0 8
[11] .init PROGBITS 000000000000d000 0000d000
000000000000001b 0000000000000000 AX 0 0 4
[12] .text PROGBITS 000000000000d020 0000d020
00000000000a063b 0000000000000000 AX 0 0 16
[13] .fini PROGBITS 00000000000ad65c 000ad65c
000000000000000d 0000000000000000 AX 0 0 4
[14] .rodata PROGBITS 00000000000ae000 000ae000
00000000000c76a4 0000000000000000 A 0 0 32
[15] .eh_frame_hdr PROGBITS 00000000001756a4 001756a4
0000000000001c34 0000000000000000 A 0 0 4
[16] .eh_frame PROGBITS 00000000001772d8 001772d8
00000000000093f0 0000000000000000 A 0 0 8
[17] .hash HASH 00000000001806c8 001806c8
000000000000210c 0000000000000004 A 5 0 8
[18] .init_array INIT_ARRAY 0000000000183c80 00182c80
0000000000000008 0000000000000008 WA 0 0 8
[19] .fini_array FINI_ARRAY 0000000000183c88 00182c88
0000000000000008 0000000000000008 WA 0 0 8
[20] .dynamic DYNAMIC 0000000000183c90 00182c90
00000000000001f0 0000000000000010 WA 6 0 8
[21] .got PROGBITS 0000000000183e80 00182e80
0000000000000180 0000000000000008 WA 0 0 8
[22] .data PROGBITS 0000000000184000 00183000
000000000000000c 0000000000000000 WA 0 0 8
[23] .bss NOBITS 000000000018400c 0018300c
000000000000000c 0000000000000000 WA 0 0 4
[24] .comment PROGBITS 0000000000000000 0018300c
000000000000001a 0000000000000001 MS 0 0 1
[25] .shstrtab STRTAB 0000000000000000 00183026
00000000000000fa 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
l (large), p (processor specific)
```

But should that be enough information to be able to unwind from a function
prologue? I mean, it obviously seems to work when we unwind from the function
body. But how would I know whether it should work from the prologue too?

Reading e.g. https://www.airs.com/blog/archives/460, I can find:

> There should be exactly one FDE covering each instruction which may be being
executed when an exception occurs. By default an exception can only occur
during a function call or a throw. When using the -fnon-call-exceptions gcc
option, an exception can also occur on most memory references and floating
point operations. When using -fasynchronous-unwind-tables, the FDE will cover
every instruction, to permit unwinding from a signal handler.

So what if my libm wasn't compiled with -fasynchronous-unwind-tables? We
probably cannot throw an exception in the function prologue, so potentially
that range is simply not mapped? But this is just a shot in the dark, I have
no clue how to get more information about what contents are actually stored in
the .eh_frame section. I would love to find out though! Does anyone know a
tool to sched some light into this section?

I found http://www.bitlackeys.org/#eh_frame which at least shows me that
__hypot_finite is mentioned in the .eh_frame section:

$ nm -aD /usr/lib/libm.so.6 |& grep hypot_finite
0000000000029660 T __hypot_finite
$ ./eh_frame /usr/lib/libm.so.6 |& grep 29660
Function size: 878 Function Addr: 29660

Thanks

--
Milian Wolff | milian.wolff@xxxxxxxx | Senior Software Engineer
KDAB (Deutschland) GmbH, a KDAB Group company
Tel: +49-30-521325470
KDAB - The Qt, C++ and OpenGL Experts

Attachment: smime.p7s
Description: S/MIME cryptographic signature