https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88432
Bug ID: 88432
Summary: Dwarf line numbering inadequate when using
-fstack-protector-strong
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: debug
Assignee: unassigned at gcc dot gnu.org
Reporter: alahay01 at gcc dot gnu.org
Target Milestone: ---
Created attachment 45198
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=45198&action=edit
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]