To understand the issue gdb
has with producing a stack trace, you first have to understand how gdb
produces a stack trace. A compiler use a standard prologue and epilogue when it creates a C
function, this is assembler code at function entry and exit. Part of this is to save the lr
on the stack, reserve space for local variables and link the previous frame pointer or fp
. These stack frames provide a type of linked list that is root-ed with the fp
and normally terminated with zero. This depends on the ABI (see -mabi). The specifics are slightly different for each ARM ABI type, but the concepts are similar.
So, when the SWI
(or any exception happens), it completely interrupts the flow of the C
compiled code and the frame pointer list can be difficult to decode, especially in the case of a stack corruption. Also, gdb
does not decode the context of the program. Some systems may change the frame pointer and immediately switch from an exception mode
to system/supervisor mode
. The sp
of the exception may even be used as a scratch register. When the SWI
is entered, part of the job of the handler will be to save the user
registers (r0-r12
). In the case of a multi-tasking O/S, this may result in a complete change of the user
stack, from one task to another.
You can always determine the faulting/causing instruction by examining the lr
in the exception mode. This specified in the ARM Architechure, and is the same for any ARM CPU. 0xfff0008
is the default SWI
handler address (when using a high memory vector table). Excepts from the SWI
in the ARM ARM (architechure reference manual) follows,
A2.6.4 Software Interrupt exception
The Software Interrupt instruction (SWI) enters Supervisor mode to request a particular supervisor (operating system) function. When a SWI is executed, the following actions are performed:
R14_svc = address of next instruction after the SWI instruction
SPSR_svc = CPSR
CPSR[4:0] = 0b10011 /* Enter Supervisor mode */
CPSR[5] = 0 /* Execute in ARM state */
/* CPSR[6] is unchanged */
CPSR[7] = 1 /* Disable normal interrupts */
/* CPSR[8] is unchanged */
CPSR[9] = CP15_reg1_EEbit /* Endianness on exception entry */
if high vectors configured then
PC = 0xFFFF0008
else
PC = 0x00000008
To return after performing the SWI operation, use the following instruction to restore the PC (from R14_svc) and CPSR (from SPSR_svc) and return to the instruction following the SWI:
MOVS PC,R14
As you can see, R14_svc
which is the lr
when in supervisor mode, is set to the SWI
instruction+4. This is so that the normal return will restart the following instruction. By examining where the lr
is, you can determine where the SWI
occurred. If the user stack is not corrupted, you can link your supervisor
stack to the user
stack using the ABI the compiler is using via the fp
. If you do this, then gdb
can give a stack trace. However, in the system under discussion, there is no SWI
support code.
You could also write gdb
macros to give a stack trace in this situation. However, I hope it is clear that gdb
would have a difficult task to do this generically.