I am currently trying to debug a simple instruction sequence in ARM assembly. However, trying to single-step debug (with arm-none-eabi-gdb) causes the debugger to freeze always at one specific instruction and forces me to kill the debugging session. The debugger does not allow me to suspend the session to check if I entered a Fault Handler, so only terminating is possible.
Some environment information
- IDE: Eclipse
- arm-none-eabi-gcc compiler
- compiler flags: -mcpu=cortex-m4 -mthumb -O0 -g3 -ffunction-sections -c
- running on a stm32f4 discovery board with a M4
The Problem
From my main function I call foo
, which is a function I wrote in assembly. After pushing the non-scratch registers and LR onto the stack and making space for local variables etc. I call inside this assembly function another assembly function bar
and save the scratch register on the stack.
My simplified assembly file looks like this:
.syntax unified
.thumb
.text
.global foo
.global bar
bar:
push {r4,r5,r6,r7,r14} //the debugger "freezes" before executing this instruction
add r4,r5
pop {r4,r5,r6,r7,r15}
foo:
push {r4,r5,r6,r7,r14}
subs r13, r13, #124
.foo_bb1:
push {r0}
push {r1}
push {r2}
push {r3}
bl bar
pop {r4,r5,r6,r7,r15}
My header file looks like this
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_
#include "stdint.h"
void foo();
void bar();
#endif
and my main.c file looks like the following
int main()
{
foo();
return 0;
}
When I attach the debugger and go into foo
everything works fine right after I single step the bl bar
instruction. After this instruction the debugger correctly jumps to bar
but now the debugger freezes (i.e. before executing the push instruction in bar
) and I can not do anything else except terminating the session. This also means I can not look at the content of the registers anymore or inspect the memory layout.
What I tried
The first thing that came into my mind is checking if the stack pointer is correctly aligned. The stack pointer is always 8-byte aligned. This is the case at the beginning of foo
, after subs r13, r13, #124
and before taking the jump instruction. Surprisingly for me, if I remove all the push {rX}
instructions the debugger proceeds without a problem. If I add even one push instruction, the problem comes up again. I can not get rid of storing r0-r3 completely so just removing the push instructions is not really a viable option. I can switch the function call to other functions than bar
, but that also does not change the behavior.
Edit: While creating this minimal example I discovered that there is a label before those push {rX}
instructions in foo
. Removing the label .foo_bb1:
and keeping the push
leads to no crash as well. Unfortunately, I also need the label and can not completely get rid of it.
I tried to see if I run into a Fault Handler but it does not seem to be the case. I also tried to disable interrupts with cpsid i
, but it did not change the behavior. I looked at the stack layout before jumping to see if anything is corrupted, but I could not find any strange looking data. I tried to reduce the local stack region to see if the stack is full by subtracting a smaller number from r13 but without any success.
There is a somewhat related problem regarding single step debugging asked in the st community forum. This tackles the ARM M7 and STMf7 bord, so also not really suitable for my problem. Nevertheless, I also checked the workaround there but it did not work either.
At this point I do not know what kind of error this is anymore. Is this a STM problem, is this a debugger problem, is this an implementation error? If anyone had a similar issue or knows how to tackle this problem I would very much appreciate it :)