一.需求
1.造成主栈(MSP)溢出的原因有很多,如过多的定义局部变量,递归调用,中断嵌套等都有可能会导致主栈溢出。
2.主栈溢出后会对其他内存空间做恶意修改,导致不可预料的后果
3.stm32不具备MPU,没有对内存进行保护的硬件机制
4.软件检测栈溢出有其局限性
二.实现原理
1.将主栈的栈底定位在0x20000000处,当主栈溢出时将导致数据被push到低于0x20000000的非法区域,从而触发HardFault异常
2.由于进入HardFault_Handler后栈有可能已经溢出了,C语言的运行环境可能已不存在,故HardFault_Handler需要改用汇编来实现,在HardFault_Handler
中先根据LR的值判断当前使用的栈是主MSP还是PSP,然后检查BFSR==0x00000092 SP<0x20000000
这三个条件是否同时满足,如果同时满足则可判断主栈确实溢出了,否则可判断出不是因为栈溢出而触发的HardFault异常可以调用C语言实现的
HardFaultShow函数,打印出相关的寄存器的值以及其每个含义位的值帮助我们分析产生HardFault的其他原因
三.添加步骤
1.将STM32F10x.s中的
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
改为
AREA |.ARM.__AT_0x20000000|, DATA, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
2.在STM32F10x.s中增加一个RO段
AREA STKV, DATA, READONLY
STK_OV_MSG DCB "MAIN STACK OVERFLOW!",0
3.将STM32F10x.s中的
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
改为
BFSR EQU 0xE000ED29
STKVBFSR EQU 0x00000092
ERRSP EQU 0x20000000
UART0_FLAG EQU 0x40013800
UART0_DATA EQU 0x40013804
HardFault_Handler PROC
IMPORT HardFaultShow
;Get info
TST LR, #4
ITE EQ
MRSEQ R0, MSP
MRSNE R0, PSP
;Check stack memory overflow
;if(BFSR==0x00000092 && MMAR==0x1FFFFFFC && SP<0x20000000),is stack overflow,output deubg msg to uart.
;else goto HardFaultShow
LDR R1,=ERRSP
CMP R0, R1
BGE HardFaultShow ;
LDR R1,=BFSR
LDR R1,[R1]
LDR R2,=STKVBFSR
CMP R1,R2
BNE HardFaultShow
;Yes,Stack is overflow,we must output the msg for programmer.
LDR R1,=STK_OV_MSG
LDR R2,=UART0_FLAG
LDR R3,=UART0_DATA
PutsLoop2
LDRB R0, [R1], #1
CBZ R0, Loop
PutcWaitLoop2
LDR R4, [R2]
TST R4, #0x80
BEQ PutcWaitLoop2
STRB R0, [R3]
B PutsLoop2
Loop
B .
ENDP
4.将stm32f10x_it.c中的
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
改为
void HardFaultShow(unsigned int * hardfault_args,unsigned int *sp)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
unsigned int CFSR;
unsigned int HFSR;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
printf ("################Hard fault handler]################\r\n");
printf ("R0 = 0x%08x\r\n", stacked_r0);
printf ("R1 = 0x%08x\r\n", stacked_r1);
printf ("R2 = 0x%08x\r\n", stacked_r2);
printf ("R3 = 0x%08x\r\n", stacked_r3);
printf ("R12 = 0x%08x\r\n", stacked_r12);
printf ("SP = 0x%08x\r\n",(unsigned int)sp);
printf ("LR = 0x%08x\r\n", stacked_lr);
printf ("PC = 0x%08x\r\n", stacked_pc);
printf ("PSR = 0x%08x\r\n", stacked_psr);
CFSR = *((volatile unsigned long *)(0xE000ED28));
printf ("CFSR = 0x%08x\r\n", CFSR);
printf (" BFARVALID :%d\r\n",CFSR&(1<<15)?1:0);
printf (" STKERR :%d\r\n",CFSR&(1<<12)?1:0);
printf (" UNSTKERR :%d\r\n",CFSR&(1<<11)?1:0);
printf (" IMPRECISERR :%d\r\n",CFSR&(1<<10)?1:0);
printf (" PRECISERR :%d\r\n",CFSR&(1<<9)?1:0);
printf (" IBUSERR :%d\r\n",CFSR&(1<<8)?1:0);
printf (" MMARVALID :%d\r\n",CFSR&(1<<7)?1:0);
printf (" MSTKERR :%d\r\n",CFSR&(1<<4)?1:0);
printf (" MUNSTKERR :%d\r\n",CFSR&(1<<3)?1:0);
printf (" DACCVIOL :%d\r\n",CFSR&(1<<1)?1:0);
printf (" IACCVIOL :%d\r\n",CFSR&(1<<0)?1:0);
printf (" DIVBYZERO :%d\r\n",CFSR&(1<<25)?1:0);
printf (" UNALIGNED :%d\r\n",CFSR&(1<<24)?1:0);
printf (" NOCP :%d\r\n",CFSR&(1<<19)?1:0);
printf (" INVPC :%d\r\n",CFSR&(1<<18)?1:0);
printf (" INVSTATE :%d\r\n",CFSR&(1<<17)?1:0);
printf (" UNDEFINSTR :%d\r\n",CFSR&(1<<16)?1:0);
HFSR = *((volatile unsigned long *)(0xE000ED2C));
printf ("HFSR = 0x%08x\r\n", HFSR);
printf (" DEBUGEVT :%d\r\n",HFSR&((u32)1<<31)?1:0);
printf (" FORCED :%d\r\n",HFSR&(1<<30)?1:0);
printf (" VECTBL :%d\r\n",HFSR&(1<<1)?1:0);
printf ("DFSR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED30))));
printf ("AFSR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
printf ("BFAR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED38))));
printf ("MMAR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED34))));
while(1);
}
一.需求
1.造成主栈(MSP)溢出的原因有很多,如过多的定义局部变量,递归调用,中断嵌套等都有可能会导致主栈溢出。
2.主栈溢出后会对其他内存空间做恶意修改,导致不可预料的后果
3.stm32不具备MPU,没有对内存进行保护的硬件机制
4.软件检测栈溢出有其局限性
二.实现原理
1.将主栈的栈底定位在0x20000000处,当主栈溢出时将导致数据被push到低于0x20000000的非法区域,从而触发HardFault异常
2.由于进入HardFault_Handler后栈有可能已经溢出了,C语言的运行环境可能已不存在,故HardFault_Handler需要改用汇编来实现,在HardFault_Handler
中先根据LR的值判断当前使用的栈是主MSP还是PSP,然后检查BFSR==0x00000092 SP<0x20000000
这三个条件是否同时满足,如果同时满足则可判断主栈确实溢出了,否则可判断出不是因为栈溢出而触发的HardFault异常可以调用C语言实现的
HardFaultShow函数,打印出相关的寄存器的值以及其每个含义位的值帮助我们分析产生HardFault的其他原因
三.添加步骤
1.将STM32F10x.s中的
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
改为
AREA |.ARM.__AT_0x20000000|, DATA, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
2.在STM32F10x.s中增加一个RO段
AREA STKV, DATA, READONLY
STK_OV_MSG DCB "MAIN STACK OVERFLOW!",0
3.将STM32F10x.s中的
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
改为
BFSR EQU 0xE000ED29
STKVBFSR EQU 0x00000092
ERRSP EQU 0x20000000
UART0_FLAG EQU 0x40013800
UART0_DATA EQU 0x40013804
HardFault_Handler PROC
IMPORT HardFaultShow
;Get info
TST LR, #4
ITE EQ
MRSEQ R0, MSP
MRSNE R0, PSP
;Check stack memory overflow
;if(BFSR==0x00000092 && MMAR==0x1FFFFFFC && SP<0x20000000),is stack overflow,output deubg msg to uart.
;else goto HardFaultShow
LDR R1,=ERRSP
CMP R0, R1
BGE HardFaultShow ;
LDR R1,=BFSR
LDR R1,[R1]
LDR R2,=STKVBFSR
CMP R1,R2
BNE HardFaultShow
;Yes,Stack is overflow,we must output the msg for programmer.
LDR R1,=STK_OV_MSG
LDR R2,=UART0_FLAG
LDR R3,=UART0_DATA
PutsLoop2
LDRB R0, [R1], #1
CBZ R0, Loop
PutcWaitLoop2
LDR R4, [R2]
TST R4, #0x80
BEQ PutcWaitLoop2
STRB R0, [R3]
B PutsLoop2
Loop
B .
ENDP
4.将stm32f10x_it.c中的
void HardFault_Handler(void)
{
/* Go to infinite loop when Hard Fault exception occurs */
while (1)
{
}
}
改为
void HardFaultShow(unsigned int * hardfault_args,unsigned int *sp)
{
unsigned int stacked_r0;
unsigned int stacked_r1;
unsigned int stacked_r2;
unsigned int stacked_r3;
unsigned int stacked_r12;
unsigned int stacked_lr;
unsigned int stacked_pc;
unsigned int stacked_psr;
unsigned int CFSR;
unsigned int HFSR;
stacked_r0 = ((unsigned long) hardfault_args[0]);
stacked_r1 = ((unsigned long) hardfault_args[1]);
stacked_r2 = ((unsigned long) hardfault_args[2]);
stacked_r3 = ((unsigned long) hardfault_args[3]);
stacked_r12 = ((unsigned long) hardfault_args[4]);
stacked_lr = ((unsigned long) hardfault_args[5]);
stacked_pc = ((unsigned long) hardfault_args[6]);
stacked_psr = ((unsigned long) hardfault_args[7]);
printf ("################Hard fault handler]################\r\n");
printf ("R0 = 0x%08x\r\n", stacked_r0);
printf ("R1 = 0x%08x\r\n", stacked_r1);
printf ("R2 = 0x%08x\r\n", stacked_r2);
printf ("R3 = 0x%08x\r\n", stacked_r3);
printf ("R12 = 0x%08x\r\n", stacked_r12);
printf ("SP = 0x%08x\r\n",(unsigned int)sp);
printf ("LR = 0x%08x\r\n", stacked_lr);
printf ("PC = 0x%08x\r\n", stacked_pc);
printf ("PSR = 0x%08x\r\n", stacked_psr);
CFSR = *((volatile unsigned long *)(0xE000ED28));
printf ("CFSR = 0x%08x\r\n", CFSR);
printf (" BFARVALID :%d\r\n",CFSR&(1<<15)?1:0);
printf (" STKERR :%d\r\n",CFSR&(1<<12)?1:0);
printf (" UNSTKERR :%d\r\n",CFSR&(1<<11)?1:0);
printf (" IMPRECISERR :%d\r\n",CFSR&(1<<10)?1:0);
printf (" PRECISERR :%d\r\n",CFSR&(1<<9)?1:0);
printf (" IBUSERR :%d\r\n",CFSR&(1<<8)?1:0);
printf (" MMARVALID :%d\r\n",CFSR&(1<<7)?1:0);
printf (" MSTKERR :%d\r\n",CFSR&(1<<4)?1:0);
printf (" MUNSTKERR :%d\r\n",CFSR&(1<<3)?1:0);
printf (" DACCVIOL :%d\r\n",CFSR&(1<<1)?1:0);
printf (" IACCVIOL :%d\r\n",CFSR&(1<<0)?1:0);
printf (" DIVBYZERO :%d\r\n",CFSR&(1<<25)?1:0);
printf (" UNALIGNED :%d\r\n",CFSR&(1<<24)?1:0);
printf (" NOCP :%d\r\n",CFSR&(1<<19)?1:0);
printf (" INVPC :%d\r\n",CFSR&(1<<18)?1:0);
printf (" INVSTATE :%d\r\n",CFSR&(1<<17)?1:0);
printf (" UNDEFINSTR :%d\r\n",CFSR&(1<<16)?1:0);
HFSR = *((volatile unsigned long *)(0xE000ED2C));
printf ("HFSR = 0x%08x\r\n", HFSR);
printf (" DEBUGEVT :%d\r\n",HFSR&((u32)1<<31)?1:0);
printf (" FORCED :%d\r\n",HFSR&(1<<30)?1:0);
printf (" VECTBL :%d\r\n",HFSR&(1<<1)?1:0);
printf ("DFSR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED30))));
printf ("AFSR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED3C))));
printf ("BFAR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED38))));
printf ("MMAR = 0x%08x\r\n", (*((volatile unsigned long *)(0xE000ED34))));
while(1);
}
修改原因:去掉了 MMAR==0x1FFFFFFC 这个非必要的条件
专营STM8/32
QQ 940436962
http://y-ec.taobao.com/ |