Summary: | Dwarf line numbering inadequate when using -fstack-protector-strong | ||
---|---|---|---|
Product: | gcc | Reporter: | alahay01 |
Component: | debug | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | UNCONFIRMED --- | ||
Severity: | normal | Keywords: | wrong-debug |
Priority: | P3 | ||
Version: | unknown | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | ||
Attachments: |
Example breaking program
rtl final dump for the .cc file Final assembly dump for the .cc file with dwarf |
Created attachment 45199 [details]
rtl final dump for the .cc file
Created attachment 45200 [details]
Final assembly dump for the .cc file with dwarf
I considered a number of solutions, but they all had issues: 1) Place the RTL for the stack guard inside the prologue, giving: *function prologue rtl *stack guard code (__stack_chk_guard) *NOTE_INSN_PROLOGUE_END *NOTE_INSN_FUNCTION_BEG *rest of the function rtl Then this would then automatically stop the line number being dumped for the stack guard. The rest of the assembly would be the same. Downside here is that in the future new optimisations could be added that have exactly the same issue. 2) Add line numbers to NOTE_INSN_FUNCTION_BEG and remove line numbers from stack guard code (which currently has the line number for the { line) 3) Ensure the stack guard code has the line number of the first line of the function main body. I'm not sure if 2 and 3 will break instruction reordering. |
Created attachment 45198 [details] Example breaking program Using -fstack-protector-strong will cause GDB to break on the wrong line when placing a breakpoint on a function. [ Note that the GCC provided with Ubuntu will default to -fstack-protector-strong, causing all function breakpoints to break on the wrong line. This breaks roughly 50 GDB tests when run on x86 and AArch64 Ubuntu ] The issue in GDB ================= Consider the following program: 47: int main () 48: { 49: char arg2 = 2; 50: signed char arg3 = 3; (full program attached. Ignore everything in it except for main. Testcase taken from the GDB testsuite.) When compiled with -fstack-protector-strong, then running it in GDB, “breakpoint main” will stop at line 48, the "{". This is wrong, it should instead stop on line 49 – the first line of the function body. GDB figures this out by looking at the dwarf line numbers. It finds the entry for the start of the function (from other dwarf entries), and assumes that it the entry for the function prologue. It then jumps forward one entry. With stack proctector turned off we get the following. Note that the dwarf label for main points at index 2. INDEX LINE ADDRESS 0 45 0x0000000000400680 1 45 0x0000000000400680 2 48 0x0000000000400688 - main: prologue pt1 3 49 0x00000000004006ac - main: first line of function 4 50 0x00000000004006b4 - main: second line of function ...etc With stack protector on (like Ubuntu): INDEX LINE ADDRESS 0 45 0x0000000000400680 1 45 0x0000000000400680 2 48 0x0000000000400688 - main: prologue pt1 3 48 0x0000000000400698 - main: stack protector code 4 49 0x00000000004006ac - main: first line of function 5 50 0x00000000004006b4 - main: second line of function ...etc Ok, we could jump forward two entries. But then breaks with the following (with either stack protector on or off): 47: int main () 48: { char arg2 = 2; 49: signed char arg3 = 3; It will result in the same line table, with just two entries at line 48: INDEX LINE ADDRESS 0 45 0x0000000000400680 1 45 0x0000000000400680 2 48 0x0000000000400688 - main: prologue pt1 3 48 0x0000000000400698 - main: stack protector code 4 49 0x00000000004006ac - main: second line of function ...etc There is no way to tell if a repeated line is the first line of code or the stack protector. The underlying issue in GCC =========================== See the attached rtl final dump from GCC (note: aarch64 code, but that doesn't matter). With the stack protector on, GCC produces RTL for the stack protector at the beginning of the function, after the prologue. You roughly get: *function prologue rtl *NOTE_INSN_PROLOGUE_END *NOTE_INSN_FUNCTION_BEG *stack guard code (__stack_chk_guard) *rest of the function rtl The stack guard rtl is given the line number of the "{" line. When dumping line locations, notice_source_line() decides which RTL expressions should cause a dump. It will force a dump of the first expression following the end of the prologue - expecting this to be the first line of the function. This gives us: .LFB1: .loc 1 48 0. – function prologue. .cfi_startproc sub sp, sp, #176 .cfi_def_cfa_offset 176 stp x29, x30, [sp, 32] .cfi_offset 29, -144 .cfi_offset 30, -136 add x29, sp, 32 .cfi_def_cfa 29, 144 str x19, [sp, 48] .cfi_offset 19, -128 .loc 1 48 0 -- Start of stack guard code adrp x0, __stack_chk_guard add x0, x0, :lo12:__stack_chk_guard ldr x1, [x0] str x1, [x29, 136] mov x1,0 .loc 1 49 0. – first line of function mov w0, 2 strb w0, [x29, 45] .loc 1 50 0 mov w0, 3 strb w0, [x29, 46]