当前位置: 首页 > news >正文

zynq的栈监控与Xil_XXXAbortHandler问题排查

参考

UG585Address Map.csdn

stm32的栈监控与HardFault_Handler问题排查.csdn

崩溃现象

程序崩溃后会跳转到

ps7_cortexa9_0\standalone_domain\bsp\ps7_cortexa9_0\libsrc\standalone_v7_3\src\xil_exception.c

异常总览表

异常类型默认处理函数(Xilinx BSP)CPU进入时机典型触发场景向量表默认绑定关键寄存器/信息默认行为常见根因(重点)架构说明
Reset(复位)启动汇编入口上电 / 硬复位瞬间上电、复位按键、看门狗复位Boot ROM / Reset Vector-从头启动系统硬复位、看门狗复位ARM32/64均有,最高优先级
Undefined InstructionXil_UndefinedExceptionHandler()指令译码阶段(ID)执行非法机器码、跑飞执行数据区默认绑定该函数UndefinedExceptionAddr打印地址 + 死循环PC跑飞、Flash损坏、函数指针错误、代码被破坏ARM32/64均支持(ARM64为同步异常)
SVC / SWI(系统调用)Xil_ExceptionNullHandler()(裸机)执行 SVC 指令瞬间OS系统调用、特权级切换默认空处理-裸机死循环 / OS接管正常系统调用 / 误执行SVCARM32独立 / ARM64同步异常
Prefetch / Instruction AbortXil_PrefetchAbortHandler()取指阶段(IF)PC跳飞、执行非法代码地址默认绑定该函数PrefetchAbortAddr / IFSR打印寄存器 + 死循环栈溢出、函数指针错误、return地址破坏、跳转非法地址、MMU禁止执行ARM32为Prefetch Abort / ARM64为Instruction Abort
Data AbortXil_DataAbortHandler()访存阶段(MEM)读写非法内存或外设地址默认绑定该函数DataAbortAddr / DFSR打印地址 + 死循环野指针、堆损坏、栈溢出、free后使用、访问未映射外设ARM32/64均存在(ARM64为同步异常)
IRQ(普通中断)用户注册 handler(默认NullHandler)GIC中断分发后UART、Timer、GPIO等外设中断未注册则NullHandlerGIC CPU Interface寄存器未注册→死循环中断未清、未注册handlerARM32/64均有
FIQ(快速中断)用户注册 handler(默认NullHandler)GIC高优先级通道高实时控制、电机控制未注册则NullHandlerGIC高优先级路径未注册→死循环高优先级实时任务ARM32/64均有
SError(系统错误)Xil_SErrorAbortHandler()(AArch64)异步触发(与指令无关)ECC错误、AXI总线错误、cache一致性错误AArch64向量表绑定系统错误状态寄存器打印日志 + 死循环DDR ECC损坏、AXI bus fault、硬件一致性错误ARM64常见;ARM32通常归入Abort类

问题1

中断专用栈被破坏了

在中断里调用 AT_println(“ke %d”, code); 崩溃进入 Xil_DataAbortHandler
改成 AT_println(“ke”); 正常
主循环 注释 BspGetMillis 又不崩
把BspGetMillis 代码拷贝到主循环也不崩

解决

修改 链接脚本 lscript.ldx

# 修改_IRQ_STACK_SIZE=DEFINED(_IRQ_STACK_SIZE)? _IRQ_STACK_SIZE:1024;# 为_IRQ_STACK_SIZE=DEFINED(_IRQ_STACK_SIZE)? _IRQ_STACK_SIZE:4000;

lscript.ld

分组功能解释
栈/堆配置_STACK_SIZE0x2000主栈大小System/User 模式栈大小(8KB)
_HEAP_SIZE0x2000堆大小malloc/new 动态内存
_ABORT_STACK_SIZE1024Abort栈Data Abort / Prefetch Abort
_SUPERVISOR_STACK_SIZE2048SVC栈Supervisor模式
_IRQ_STACK_SIZE4000IRQ栈中断模式
_FIQ_STACK_SIZE1024FIQ栈快速中断模式
_UNDEF_STACK_SIZE1024Undefined栈未定义指令异常
MEMORY内存区域ps7_ddr_00x00100000~0x3FFFFFFFDDR区域主程序运行内存
ps7_qspi_linear_00xFC000000~0xFCFFFFFFQSPI线性映射Flash线性访问
ps7_ram_00x00000000~0x0002FFFFOCM低地址On-Chip Memory
ps7_ram_10xFFFF0000~0xFFFFFE00OCM高地址高地址映射OCM
程序入口ENTRY(_vector_table)_vector_table程序入口CPU复位后跳转地址
代码段.text> ps7_ddr_0代码段函数机器码
.vectors异常向量中断入口ARM异常向量表
.bootBoot代码启动代码reset/startup
.init初始化代码CRT初始化main前执行
.fini结束代码程序退出清理main后执行
只读数据.rodataconst数据只读常量字符串/查表
.rodata1扩展rodata编译器扩展次级只读区
.sdata2小只读数据GP优化小常量快速访问
.sbss2小只读BSSGP优化小未初始化数据
数据段.data已初始化变量全局静态变量启动时复制
.data1扩展data编译器扩展次级data
.sdata小数据区GP优化小变量快速访问
.sbss小BSS区GP优化小未初始化变量
.bss未初始化变量零初始化区启动时清零
COMMON公共变量旧式全局变量GCC兼容
TLS线程局部存储.tdataTLS初始化数据线程局部变量Thread Local
.tbssTLS未初始化数据TLS BSSThread Local
C++初始化.ctors构造函数表全局对象构造main前执行
.dtors析构函数表全局对象析构main后执行
.preinit_array预初始化数组libc前初始化极少使用
.init_array初始化数组GCC现代构造机制替代ctors
.fini_array析构数组GCC现代析构机制替代dtors
异常/调试.eh_frame异常展开表C++异常stack unwind
.eh_framehdr异常头unwind索引backtrace辅助
.gcc_except_tableGCC异常表throw/catchC++异常
.ARM.exidxARM异常索引ARM unwindbacktrace
.ARM.extabARM unwind表ARM异常处理unwind数据
MMU相关.mmu_tblMMU页表一级页表Cortex-A9 MMU
ALIGN(16384)16KB对齐页表对齐ARM硬件要求
地址符号__rodata_start地址符号rodata开始边界标记
__rodata_end地址符号rodata结束边界标记
__data_start地址符号data开始数据复制起点
__data_end地址符号data结束数据复制终点
__bss_start地址符号bss开始清零起点
__bss_end地址符号bss结束清零终点
SDA小数据_SDA_BASE_sdata中点SDA基址GP小数据寻址
_SDA2_BASE_sdata2中点SDA2基址小只读寻址
Heap区域.heapheap段动态内存malloc/new
_heap_startheap起点heap开始libc使用
_heap_endheap终点heap结束heap边界
HeapBaseheap基址heap起始调试/库
HeapLimitheap结束heap上限heap边界
Stack区域.stackstack段CPU栈所有模式栈
_stack_end栈底主栈开始向上分配
_stack主栈顶SP初值User/System
__stack主栈符号SP引用BSP使用
__irq_stackIRQ栈顶IRQ SPIRQ模式
__supervisor_stackSVC栈顶SVC SPSupervisor模式
__abort_stackAbort栈顶Abort SPData Abort
__fiq_stackFIQ栈顶FIQ SPFast IRQ
__undef_stackUndefined栈顶Undefined SPUndefined模式
程序结束_end最终地址程序结束heap边界参考
GNU LD语法KEEP()强制保留防止gc删除向量表常用
ALIGN(x)地址对齐cache/MMU要求硬件对齐
NOLOAD不装载不生成binBSS/Stack
SORT()section排序ctor顺序GCC使用
EXCLUDE_FILE()排除文件避免重复ctor/dtor
>section映射指定MEMORY放入内存区

脚本工具

# 设置环境变量>$env:PATH="D:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin;"+$env:PATH# 查源码位置>arm-none-eabi-addr2line-ezynq_wave_app.elf 0x00109264 axi_test/src/main.cpp:44# 查符号表arm-none-eabi-nm zynq_wave_app.elf
# wsl有各种工具更方便>wsl $:arm-none-eabi-nm zynq_wave_app.elf|grepheap 0012d360 B _heap 0012f360 B _heap_end 0012d360 B _heap_start 0012d310 b heap.5721# 查看IRQ栈大小$: arm-none-eabi-nm zynq_wave_app.elf|grep_IRQ_STACK_SIZE 00000fa0 A _IRQ_STACK_SIZE# IRQ 栈地址 0x00131360:0x00132300 向下增长$: arm-none-eabi-nm zynq_wave_app.elf|grepirq 0012ccd8 b _ZL12s_pl_irq_cnt 00107448 t _ZL14pl_irq_handlerPv 00107a20 t _ZL16uart_irq_handlerPvmj 00132300 B __irq_stack 00131360 B _irq_stack_end

栈监控

这里以__irq_stack 栈为例

#defineIRQ_STACK_TOP((uint32_t*)0x00132300)#defineIRQ_STACK_END((uint32_t*)0x00131360)#defineWATERMARK0xA5A5A5A5volatileuint32_tg_irq_stack_max_usage=0;//irq 栈填充水印voidirq_stack_fill_watermark(void){uint32_t*p=IRQ_STACK_END;while(p<IRQ_STACK_TOP){*p++=WATERMARK;}}// irq 栈最大用量写入全局变量g_irq_stack_max_usagevoidirq_stack_update_usage(void){uint32_t*p=IRQ_STACK_END;while(p<IRQ_STACK_TOP){if(*p!=WATERMARK){break;}p++;}g_irq_stack_max_usage=(uint32_t)((uint8_t*)IRQ_STACK_TOP-(uint8_t*)p);}

测试

intmain(){staticuint32_ts_ms_tick=0;staticuint32_ts_pt_tick=0;irq_stack_fill_watermark();BspInit();at_init(Bsp_shell_write);AT_printf("ke");at_app_init();at_show_version();//启动PT协程Protothread::AllStart();while(1){uint32_tms=BspGetTickMs();BspGetMillis();if(ms-s_ms_tick>=10){s_ms_tick=ms;intlen=BspUartRead((uint8_t*)AT_m_buf,-1);at_import((uint8_t*)AT_m_buf,len,ms);}if(g_bt.key_flag){g_bt.key_flag=0;irq_stack_update_usage();AT_println("IRQ stack max usage = %lu bytes\n",g_irq_stack_max_usage);}}return0;}

打印

因为 _IRQ_STACK_SIZE 配置的只有1024 ,irq栈最大用量是1248
所以发生了各种奇怪现象

[18:52:51.763]收←◆ke268435456IRQ stack max usage=1248bytes
http://www.jsqmd.com/news/792760/

相关文章:

  • 从AI编程助手到效能架构师:Cursor深度实践与团队协作心法
  • 开源AI模型评测平台:构建公平、可复现的LLM对比实验框架
  • YoMo边缘实时流处理框架:基于QUIC与无服务器架构的毫秒级响应实践
  • WelsonJS:基于Windows原生WSH的现代JavaScript桌面应用开发框架
  • 印度股票市场实时数据API接口
  • 基于 Simulink 的级联 H 桥(CHB)七电平逆变器载波移相调制实战教程
  • Cursor AI编程助手离线资源库部署与本地模型集成实战
  • 大语言模型自我优化:Self-Refine框架原理与工程实践
  • 3分钟快速找回Navicat数据库连接密码的完整指南
  • 开源营销技能图谱:构建个人与团队的数字化能力体系
  • 基于向量数据库与语义搜索构建个人知识库系统实践指南
  • 什么是悲观锁、乐观锁?
  • AI代码重构工具Refly:从原理到实战的开发者指南
  • 别再复制粘贴了!手把手教你从零搭建STM32F429 MDK5工程模板(附完整源码包)
  • Godot游戏开发快速启动:项目模板化与最佳实践指南
  • Taotoken的用量分析功能让团队资源消耗一目了然
  • Go语言开源工具conforme:配置驱动的数据一致性校验与清洗实战
  • Instrukt框架:构建生产级AI代理的指令操作系统实践指南
  • Obsidian插件Quiz Generator:用AI将笔记自动转化为互动测验
  • 鸿蒙一气总论(五)
  • douyin-downloader:抖音内容获取的技术架构与实践应用
  • 丢掉pip,又一Python实用利器出现了~
  • 手把手教你学Simulink——基于光储微电网虚拟同步发电机(VSG)控制仿真示例
  • PyCharm直连Spark集群:一站式配置与避坑指南
  • 告别明文传输:手把手教你为open62541 OPC UA服务器配置OpenSSL加密(附证书生成避坑指南)
  • 基于Dify Chatflow构建游戏客服多智能体系统:从架构设计到工程实践
  • Go语言轻量级HTTP代理curxy:开发调试与本地环境配置利器
  • 从AI编程助手的“糟糕代码”洞察人机协作:调试、优化与未来
  • 别再手动开账号了!用JupyterHub在Ubuntu上搭建团队数据科学环境(附GitHub登录配置)
  • 智能体工程:从氛围编程到结构化AI辅助开发方法论