https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105389
Bug ID: 105389 Summary: variable displayed as available at -O1 and -O3 but as optimized out at -Og and with an incorrect value at -O2 Product: gcc Version: 12.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: debug Assignee: unassigned at gcc dot gnu.org Reporter: assaiante at diag dot uniroma1.it Target Milestone: --- In this minimized C example, variable l_43, defined within the scope of function c, has wrong debug information definition that lead to optimized out or incorrect value being shown at -Og and -O2 while it has always the correct value with optimization levels -O1 and -O3. At -Og the variable is marked as optimized out at line 6 when its value should be 5 and it becomes available with its correct value only starting from line 9, where it is assigned to 0 via pointer arithmetics. At -O2 the variable has a wrong value at line 10 (the only one actually stepped), it should be 0 but the value available during debugging is 5. We provide a detailed analysis on x64 with a quick assessment of older gcc versions. $ cat a.c int a ; char b ; void c() { int l_43 = 5; int *d = &l_43; e: b++; for (; a != -8; --a) *d = 0; if (b) goto e; } int main() { c(); } GCC and GDB version (GCC commit id: 500d3f0a302): gcc (GCC) 12.0.0 20211227 (experimental) GNU gdb (GDB) 11.2 GDB trace at -Og: $ gcc -Og -g a.c -o opt-g $ gdb -q opt-g Reading symbols from opt-g... (gdb) b c Breakpoint 1 at 0x400486: file a.c, line 3. (gdb) r Starting program: /tmp/opt-g Breakpoint 1, c () at a.c:3 3 void c() { (gdb) info loc l_43 = <optimized out> d = <optimized out> (gdb) n 6 e: b++; (gdb) info loc l_43 = <optimized out> d = <optimized out> (gdb) n 7 for (; (gdb) info loc l_43 = <optimized out> d = <optimized out> (gdb) n 8 a != -8; (gdb) info loc l_43 = <optimized out> d = <optimized out> (gdb) n 9 --a) *d = 0; (gdb) info loc l_43 = 0 d = <optimized out> (gdb) n 8 a != -8; (gdb) info loc l_43 = <optimized out> d = <optimized out> (gdb) n 9 --a) *d = 0; (gdb) info loc l_43 = 0 d = <optimized out> GDB trace at -O2: $ gcc -O2 -g a.c -o opt-2 $ gdb -q opt-2 Reading symbols from opt-2... (gdb) b c Breakpoint 1 at 0x4004a0: file a.c, line 10. (gdb) r Starting program: /tmp/opt-2 Breakpoint 1, c () at a.c:10 10 if (b) goto e; (gdb) info loc l_43 = 5 d = <synthetic pointer> e = <optimized out> ASM at -Og: 0000000000400486 <c>: 400486: eb 18 jmp 4004a0 <c+0x1a> 400488: 83 e8 01 sub $0x1,%eax 40048b: 89 05 9f 0b 20 00 mov %eax,0x200b9f(%rip) # 601030 <a> 400491: 8b 05 99 0b 20 00 mov 0x200b99(%rip),%eax # 601030 <a> 400497: 83 f8 f8 cmp $0xfffffff8,%eax 40049a: 75 ec jne 400488 <c+0x2> 40049c: 84 d2 test %dl,%dl 40049e: 74 12 je 4004b2 <c+0x2c> 4004a0: 0f b6 05 85 0b 20 00 movzbl 0x200b85(%rip),%eax # 60102c <b> 4004a7: 8d 50 01 lea 0x1(%rax),%edx 4004aa: 88 15 7c 0b 20 00 mov %dl,0x200b7c(%rip) # 60102c <b> 4004b0: eb df jmp 400491 <c+0xb> 4004b2: c3 retq DWARF at -Og: 0x000000ae: DW_TAG_variable DW_AT_name ("l_43") DW_AT_decl_file ("/tmp/a.c") DW_AT_decl_line (4) DW_AT_decl_column (0x08) DW_AT_type (0x00000041 "int") DW_AT_location (0x0000000e: [0x0000000000400488, 0x0000000000400491): DW_OP_lit0, DW_OP_stack_value) DW_AT_GNU_locviews (0x0000000c) ASM and DWARF analysis at -Og: >From DWARF information we can see how there is only a location range defined for variable l_43 and it has value 0 associated with it. The range includes the instructions associated with line 9 making the variable available at line 9, but there is no location defined for the instructions associated with line 6, thus making the variable marked as optimized out when its value is 5. For instance, at -O1 this information is correctly computed: ASM at -O1: 0000000000400486 <c>: 400486: 0f b6 15 9f 0b 20 00 movzbl 0x200b9f(%rip),%edx # 60102c <b> 40048d: 8b 05 9d 0b 20 00 mov 0x200b9d(%rip),%eax # 601030 <a> 400493: b9 00 00 00 00 mov $0x0,%ecx 400498: be 01 00 00 00 mov $0x1,%esi 40049d: 83 c2 01 add $0x1,%edx 4004a0: 83 f8 f8 cmp $0xfffffff8,%eax 4004a3: 74 0a je 4004af <c+0x29> 4004a5: 83 e8 01 sub $0x1,%eax 4004a8: 83 f8 f8 cmp $0xfffffff8,%eax 4004ab: 75 f8 jne 4004a5 <c+0x1f> 4004ad: 89 f1 mov %esi,%ecx 4004af: b8 f8 ff ff ff mov $0xfffffff8,%eax 4004b4: 84 d2 test %dl,%dl 4004b6: 75 e5 jne 40049d <c+0x17> 4004b8: c6 05 6d 0b 20 00 00 movb $0x0,0x200b6d(%rip) # 60102c <b> 4004bf: 84 c9 test %cl,%cl 4004c1: 74 0a je 4004cd <c+0x47> 4004c3: c7 05 63 0b 20 00 f8 movl $0xfffffff8,0x200b63(%rip) # 601030 <a> 4004ca: ff ff ff 4004cd: c3 retq DWARF at -O1: 0x000000ae: DW_TAG_variable DW_AT_name ("l_43") DW_AT_decl_file ("/tmp/a.c") DW_AT_decl_line (4) DW_AT_decl_column (0x08) DW_AT_type (0x00000041 "int") DW_AT_location (0x00000010: [0x0000000000400486, 0x000000000040049d): DW_OP_lit5, DW_OP_stack_value [0x00000000004004a5, 0x00000000004004af): DW_OP_lit0, DW_OP_stack_value) DW_AT_GNU_locviews (0x0000000c) ASM at -O2: 00000000004004a0 <c>: 4004a0: 83 3d 89 0b 20 00 f8 cmpl $0xfffffff8,0x200b89(%rip) # 601030 <a> 4004a7: c6 05 7e 0b 20 00 00 movb $0x0,0x200b7e(%rip) # 60102c <b> 4004ae: 74 0a je 4004ba <c+0x1a> 4004b0: c7 05 76 0b 20 00 f8 movl $0xfffffff8,0x200b76(%rip) # 601030 <a> 4004b7: ff ff ff 4004ba: c3 retq DWARF at -O2: 0x000000aa: DW_TAG_variable DW_AT_name ("l_43") DW_AT_decl_file ("/tmp/a.c") DW_AT_decl_line (4) DW_AT_decl_column (0x08) DW_AT_type (0x0000003d "int") DW_AT_location (0x0000000e: [0x00000000004004a0, 0x00000000004004ba): DW_OP_lit5, DW_OP_stack_value) DW_AT_GNU_locviews (0x0000000c) ASM and DWARF analysis at -O2: >From DWARF information we can see how there is only a location range defined for variable l_43 and it has value 5 associated with it. The range includes the instructions associated with line 10, thus making the variable to have a wrong value when stepping on line 10. We tested older gcc versions (6.4, 7.5, 8.4, 9.3, 10.3, 11.1) and the results are identical to the git version starting with gcc-8 for what happens at -O2 and the results are always identical to the git version for what happens at -Og. For previous versions at –O2, the debug information was not generated at all.