|
From: | AJ D |
Subject: | Fwd: GCC DWARF Issue - Frame Pointer Dependency |
Date: | Mon, 12 Oct 2020 20:14:16 -0700 |
Hi,
I have a function for which GCC is generating the following code (just showing the relevant snippet here).
0000000000005a70 <some_func>:
5a70: 4c 8d 54 24 08 lea 0x8(%rsp),%r10
5a75: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
5a79: 41 ff 72 f8 pushq -0x8(%r10)
5a7d: 55 push %rbp
5a7e: 48 89 e5 mov %rsp,%rbp
5a81: 41 57 push %r15
5a83: 41 56 push %r14
5a85: 41 55 push %r13
5a87: 41 54 push %r12
:
5b08: 5b pop %rbx
5b09: 41 5a pop %r10
5b0b: 41 5c pop %r12
5b0d: 41 5d pop %r13
5b0f: 41 5e pop %r14
5b11: 41 5f pop %r15
5b13: 5d pop %rbp
=> 5b14: 49 8d 62 f8 lea -0x8(%r10),%rsp
5b18: c3 retq
I am using a SIGPROF based CPU profiler (Google CPU Profiler) to profile my code. The SIGPROF handler (of the Google CPU Profiler) tries to unwind the stack (using libunwind) every time it gets a SIGPROF. And libunwind (used for unwinding the stack) uses DWARF unwind table (dumped by gcc -O3 -mstackrealign -fomit-frame-pointer).
And I noticed that I get a crash every time my code gets interrupted by SIGPROF while my program is in the middle of setting / resetting frame pointer and the frame pointer %rbp happens to point to the parent/previous frame at that point, for example, in instruction 5b14 (shown above with => and red).
=> 5b14: 49 8d 62 f8 lea -0x8(%r10),%rsp
DWARF dumped by GCC for the snippet shown above is the following:
000002f4 0000000000000044 000002f8 FDE cie=00000000 pc=0000000000005a70..0000000000005d7c
DW_CFA_advance_loc: 5 to 0000000000005a75
DW_CFA_def_cfa: r10 (r10) ofs 0
DW_CFA_advance_loc: 9 to 0000000000005a7e
DW_CFA_expression: r6 (rbp) (DW_OP_breg6 (rbp): 0)
DW_CFA_advance_loc: 11 to 0000000000005a89
DW_CFA_expression: r15 (r15) (DW_OP_breg6 (rbp): -8)
DW_CFA_expression: r14 (r14) (DW_OP_breg6 (rbp): -16)
DW_CFA_expression: r13 (r13) (DW_OP_breg6 (rbp): -24)
DW_CFA_expression: r12 (r12) (DW_OP_breg6 (rbp): -32)
DW_CFA_advance_loc: 5 to 0000000000005a8e
DW_CFA_def_cfa_expression (DW_OP_breg6 (rbp): -40; DW_OP_deref)
DW_CFA_advance_loc: 4 to 0000000000005a92
>> DW_CFA_expression: r3 (rbx) (DW_OP_breg6 (rbp): -48)
DW_CFA_advance_loc1: 121 to 0000000000005b0b
DW_CFA_remember_state
>> DW_CFA_def_cfa: r10 (r10) ofs 0
DW_CFA_advance_loc: 13 to 0000000000005b18
DW_CFA_def_cfa: r7 (rsp) ofs 8
DW_CFA_advance_loc: 8 to 0000000000005b20
DW_CFA_restore_state
000002f4 0000000000000044 000002f8 FDE cie=00000000 pc=0000000000005a70..0000000000005d7c
LOC CFA rbx rbp r12 r13 r14 r15 ra
0000000000005a70 rsp+8 u u u u u u c-8
0000000000005a75 r10+0 u u u u u u c-8
0000000000005a7e r10+0 u exp u u u u c-8
0000000000005a89 r10+0 u exp exp exp exp exp c-8
0000000000005a8e exp u exp exp exp exp exp c-8
0000000000005a92 exp exp exp exp exp exp exp c-8
0000000000005b0b r10+0 exp exp exp exp exp exp c-8
0000000000005b18 rsp+8 exp exp exp exp exp exp c-8
0000000000005b20 exp exp exp exp exp exp exp c-8
And if you see here, the DWARF _expression_ for fetching the CFA is correct, but what about the DWARF _expression_ for fetching the value of %rbx?
>> DW_CFA_expression: r3 (rbx) (DW_OP_breg6 (rbp): -48)
Value of %rbx is (in DWARF) is “%rbp relative” and since %rbp is pointing to the wrong (parent/previous) frame, we will obviously get garbage for the value of %rbx.
If you look at the generated DWARF carefully, pretty much everything is ‘%rbp relative’, so values for each of these registers cannot be restored in this scenario.
DW_CFA_expression: r15 (r15) (DW_OP_breg6 (rbp): -8)
DW_CFA_expression: r14 (r14) (DW_OP_breg6 (rbp): -16)
DW_CFA_expression: r13 (r13) (DW_OP_breg6 (rbp): -24)
DW_CFA_expression: r12 (r12) (DW_OP_breg6 (rbp): -32)
I was just wondering, instead of making these %rbp-relative, could we have made this CFA-relative? That would have taken care of this particular issue, since CFA is correctly maintained/restored in this example.
Another question, is there a known work around for this issue?
Regards
AJ
[Prev in Thread] | Current Thread | [Next in Thread] |