Gdb 如何从软件中断异常获取调用堆栈

Gdb 如何从软件中断异常获取调用堆栈,gdb,arm,bare-metal,Gdb,Arm,Bare Metal,我正在尝试使用gdb调试一个在裸机ARM平台上运行的程序。在某一点上,会生成SWI(软件中断)异常。但是,正如您所看到的,回溯跟踪没有显示异常的产生原因: (gdb)c 在ARM上运行的程序是用armnonelinuxgnueabigcc-O2-c-ggdb编译的,我还尝试使用-O0获得相同的结果 如何获得有意义的调用堆栈?是否有其他方法可以找到生成此异常的原因?要理解gdb在生成堆栈跟踪时遇到的问题,首先必须了解gdb如何生成堆栈跟踪。编译器在创建C函数时使用标准的序言和尾声,这是函数入口和出

我正在尝试使用
gdb
调试一个在裸机ARM平台上运行的程序。在某一点上,会生成
SWI
(软件中断)异常。但是,正如您所看到的,回溯跟踪没有显示异常的产生原因:

(gdb)c

在ARM上运行的程序是用
armnonelinuxgnueabigcc-O2-c-ggdb
编译的,我还尝试使用
-O0
获得相同的结果


如何获得有意义的调用堆栈?是否有其他方法可以找到生成此异常的原因?

要理解
gdb
在生成堆栈跟踪时遇到的问题,首先必须了解
gdb
如何生成堆栈跟踪。编译器在创建
C
函数时使用标准的序言和尾声,这是函数入口和出口处的汇编代码。其中一部分是在堆栈上保存
lr
,为局部变量保留空间,并链接上一帧指针或
fp
。这些堆栈帧提供一种链表类型,该链表以
fp
为根,通常以零结尾。这取决于ABI(请参阅)。每种手臂类型的细节略有不同,但概念相似

因此,当
SWI
(或发生任何异常)时,它会完全中断
C
编译代码的流,并且帧指针列表可能很难解码,尤其是在堆栈损坏的情况下。而且,
gdb
不会解码程序的上下文。某些系统可能会更改帧指针,并立即从
异常模式
切换到
系统/监控模式
。异常的
sp
甚至可以用作暂存寄存器。当输入
SWI
时,处理程序的部分工作将是保存
用户
寄存器(
r0-r12
)。在多任务O/S的情况下,这可能导致
用户
堆栈从一个任务完全更改为另一个任务

通过在异常模式下检查
lr
,始终可以确定故障/原因指令。这在中指定,并且对于任何ARMCPU都是相同的
0xfff0008
是默认的
SWI
处理程序地址(使用高内存向量表时)。以下是ARM(建筑技术参考手册)
SWI
的例外情况:


A2.6.4软件中断异常

软件中断指令(SWI)进入监控模式以请求特定的监控(操作系统)功能。执行SWI时,将执行以下操作:

要在执行SWI操作后返回,请使用以下指令恢复PC(从R14_svc)和CPSR(从SPSR_svc)并返回到SWI后的指令:


如您所见,
R14_svc
是在监控模式下的
lr
,被设置为
SWI
指令+4。这样,正常返回将重新启动以下指令。通过检查
lr
的位置,可以确定
SWI
发生的位置。如果用户堆栈未损坏,则可以使用编译器通过
fp
使用的ABI将
主管
堆栈链接到
用户
堆栈。如果这样做,那么
gdb
可以给出堆栈跟踪。但是,在讨论的系统中,没有
SWI
支持代码


在这种情况下,您还可以编写
gdb
宏来提供堆栈跟踪。但是,我希望很明显,一般来说,
gdb
将有一个困难的任务。

要理解
gdb
与生成堆栈跟踪有关的问题,首先必须理解
gdb
如何生成堆栈跟踪。编译器在创建
C
函数时使用标准的序言和尾声,这是函数入口和出口处的汇编代码。其中一部分是在堆栈上保存
lr
,为局部变量保留空间,并链接上一帧指针或
fp
。这些堆栈帧提供一种链表类型,该链表以
fp
为根,通常以零结尾。这取决于ABI(请参阅)。每种手臂类型的细节略有不同,但概念相似

因此,当
SWI
(或发生任何异常)时,它会完全中断
C
编译代码的流,并且帧指针列表可能很难解码,尤其是在堆栈损坏的情况下。而且,
gdb
不会解码程序的上下文。某些系统可能会更改帧指针,并立即从
异常模式
切换到
系统/监控模式
。异常的
sp
甚至可以用作暂存寄存器。当输入
SWI
时,处理程序的部分工作将是保存
用户
寄存器(
r0-r12
)。在多任务O/S的情况下,这可能导致
用户
堆栈从一个任务完全更改为另一个任务

通过在异常模式下检查
lr
,始终可以确定故障/原因指令。这在中指定,并且对于任何ARMCPU都是相同的
0xfff0008
是默认的
SWI
处理程序地址(使用高内存向量表时)。以下是ARM(建筑技术参考手册)
SWI
的例外情况:


A2.6.4软件中断异常

软件中断指令(SWI)进入监控模式以请求特定的监控程序(操作系统)
Continuing. 
^C 
Program received signal SIGTRAP, Trace/breakpoint trap. 0xffff0008 in ?? ()
(gdb) bt
#0  0xffff0008 in ?? ()
   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
       MOVS PC,R14