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.

Reply via email to