Wrong breakpoint location, -Og, dwarf & gdb

Bug #1395077 reported by Liviu Ionescu
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
Fix Released
Undecided
Terry Guo

Bug Description

I received a report from one of the GNU ARM Eclipse users that, for some instructions inside loops, the breakpoints are not placed properly.

I checked and the problem is real, probably due to common subexpression optimisations, for statements that have some parts moved outside the loop, when breakpoints are set, they use the address of the part outside the loop, not the address of the part inside the loop.

For tests, I used -mcpu=cortex-m4 -mthumb -Og, -g3, -gdwarf-4, and a code like this:

for (int i=0, i < 5; ++i)
  printf("%d\n", i);

printf("done\n");

Set two breakpoints, one on the inner printf(), and one on the final printf().

For the first run, execution will stop as expected on the first printf(), but after a continue execution will stop at the final printf(), although the loop is performed correctly and the first breakpoint is still active.

As I already mentioned, the printf() statement has a common part (setting the address of the string in a register) that is moved outside the loop, and a part with the actual call, inside the loop.

When the breakpoint is set, the location used by GDB is the address of the code outside the loop. This makes execution stop for the firs time, but a 'continue' at this point will make execution never reach the first breakpoint, and the program will run up to the final printf() without any problems.

Since switching from dwarf to stubs+ seems ok, I expect the problem to be either in the way the dwarf sections are generated by GCC, or in the way these sections are used by GDB.

I don't know details about dwarf internals, and how would it be possible for gdb to set breakpoints to both outer and inner addresses, but the current behaviour is not ok.

Since on -O0 the problem is not present, one possible way to avoid the problem would be to configure -Og so that moving code outside the loop be disabled.

Regards,

Liviu

Revision history for this message
Terry Guo (terry.guo) wrote :

Thanks for reporting. We are trying to improve the overall debugging experience of Og option. Welcome to report more Og related issues/concerns/comments.

Changed in gcc-arm-embedded:
assignee: nobody → Terry Guo (terry.guo)
Revision history for this message
Terry Guo (terry.guo) wrote :

However I can' t reproduce this issue. I am using OpenOCD and STM32F407VG board. The breakpoint to printf works fine for me:

(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, 0x0800069c in printf ()
(gdb) c
Continuing.

Breakpoint 1, 0x0800069c in printf ()
(gdb) c
Continuing.

Breakpoint 1, 0x0800069c in printf ()
(gdb) c
Continuing.

Breakpoint 1, 0x0800069c in printf ()
(gdb) c
Continuing.

Breakpoint 1, 0x0800069c in printf ()
(gdb) c
Continuing.

(gdb) !cat h.c
#include<stdio.h>

int
main ()
{
  for (int i = 0; i < 5; i++)
    printf ("%d\n", i);

  printf ("done\n");

  return 0;
}

Changed in gcc-arm-embedded:
status: New → Incomplete
Revision history for this message
Terry Guo (terry.guo) wrote :

Or do you mean setting breakpoint like below?

(gdb) !cat -n h.c
     1 #include<stdio.h>
     2
     3 int
     4 main ()
     5 {
     6 for (int i = 0; i < 5; i++)
     7 printf ("%d\n", i);
     8
     9 printf ("done\n");
    10
    11 return 0;
    12 }
(gdb) b h.c:7
Breakpoint 2 at 0x80002bc: file h.c, line 7.

Revision history for this message
Terry Guo (terry.guo) wrote :

Your investigation:
"As I already mentioned, the printf() statement has a common part (setting the address of the string in a register) that is moved outside the loop, and a part with the actual call, inside the loop."
is the cause of such issue. Please use option -fno-move-loop-invariants to disable the move and you will get expected behavior. Meanwhile I will try to get upstream gcc to disable such move for -Og option.

Changed in gcc-arm-embedded:
status: Incomplete → In Progress
Revision history for this message
Liviu Ionescu (ilg) wrote :

Thank you Terry for providing the workaround, I tested it and placing the breakpoint inside the loop was functional.

I'll add -fno-move-loop-invariants automatically to the debug configuration for the projects generated by the GNU ARM Eclipse templates.

Revision history for this message
Terry Guo (terry.guo) wrote :

I believe this one is fixed in latest 4.9 major release. The gcc code shows the option -fmove-loop-invariants is disabled by default for Og in 4.9 and 5.0. So you needn't to add -fno-move-loop-invariants for Og option. Would you please help to confirm? Thanks.

Revision history for this message
Liviu Ionescu (ilg) wrote :

I checked 4_9-2014q4 without an explicit -fmove-loop-invariants and is seems ok.

Thank you,

Liviu

Terry Guo (terry.guo)
Changed in gcc-arm-embedded:
status: In Progress → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.