Bug 88432 - Dwarf line numbering inadequate when using -fstack-protector-strong
Summary: Dwarf line numbering inadequate when using -fstack-protector-strong
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-debug
Depends on:
Blocks:
 
Reported: 2018-12-10 15:13 UTC by alahay01
Modified: 2021-12-24 14:04 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
Example breaking program (988 bytes, text/x-csrc)
2018-12-10 15:13 UTC, alahay01
Details
rtl final dump for the .cc file (13.56 KB, text/plain)
2018-12-10 15:14 UTC, alahay01
Details
Final assembly dump for the .cc file with dwarf (5.99 KB, text/plain)
2018-12-10 15:14 UTC, alahay01
Details

Note You need to log in before you can comment on or make changes to this bug.
Description alahay01 2018-12-10 15:13:31 UTC
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]
Comment 1 alahay01 2018-12-10 15:14:13 UTC
Created attachment 45199 [details]
rtl final dump for the .cc file
Comment 2 alahay01 2018-12-10 15:14:50 UTC
Created attachment 45200 [details]
Final assembly dump for the .cc file with dwarf
Comment 3 alahay01 2018-12-10 15:21:23 UTC
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.