- Support ARM Compiler6. Thx @ChenxuanZhao https://github.com/armink-rtt-pkgs/CmBacktrace/pull/4
- Support Chinese UTF-8. Thx @ChenxuanZhao https://github.com/armink-rtt-pkgs/CmBacktrace/pull/5
- Support Cortex-M33 Core. Thx @StackRyan https://github.com/armink-rtt-pkgs/CmBacktrace/pull/10
pull/52/head
armink 5 years ago
parent f1244876cd
commit f4c50b13be

@ -1,219 +1,221 @@
# CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库
# CmBacktrace: ARM Cortex-M series MCU error tracking library
[中文页](README_ZH.md) | English
[![GitHub release](https://img.shields.io/github/release/armink/CmBacktrace.svg)](https://github.com/armink/CmBacktrace/releases/latest) [![GitHub commits](https://img.shields.io/github/commits-since/armink/CmBacktrace/1.4.0.svg)](https://github.com/armink/CmBacktrace/compare/1.0.0...master) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/armink/CmBacktrace/master/LICENSE)
## 0、CmBacktrace 是什么
## 0、What is CmBacktrace
[CmBacktrace](https://github.com/armink/CmBacktrace) Cortex Microcontroller Backtrace是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。主要特性如下:
[CmBacktrace](https://github.com/armink/CmBacktrace) (Cortex Microcontroller Backtrace) is an open source library that automatically tracks and locates error codes for ARM Cortex-M series MCUs, and automatically analyzes the causes of errors. The main features are as follows:
- 支持的错误包括:
- 断言assert
- 故障Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault
- 故障原因 **自动诊断** :可在故障发生时,自动分析出故障的原因,定位发生故障的代码位置,而无需再手动分析繁杂的故障寄存器;
- 输出错误现场的 **函数调用栈**(需配合 addr2line 工具进行精确定位),还原发生错误时的现场信息,定位问题代码位置、逻辑更加快捷、精准。也可以在正常状态下使用该库,获取当前的函数调用栈;
- 支持 裸机 及以下操作系统平台:
- Supported errors include:
- Assert
- Fault (Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault)
- Failure reason **Automatic diagnosis**: When a failure occurs, the cause of the failure can be automatically analyzed, and the code location of the failure can be located, without the need to manually analyze the complicated fault registers;
-Output the **function call stack** of the error site (need to cooperate with the addr2line tool for precise positioning), restore the field information when the error occurred, and locate the problem code location and logic more quickly and accurately. You can also use the library under normal conditions to get the current function call stack;
- Support bare metal and the following operating system platforms:
- [RT-Thread](http://www.rt-thread.org/)
- UCOS
- FreeRTOS(需修改源码)
- 根据错误现场状态,输出对应的 线程栈 或 C 主栈;
- 故障诊断信息支持多国语言(目前:简体中文、英文);
- 适配 Cortex-M0/M3/M4/M7 MCU
- 支持 IAR、KEIL、GCC 编译器;
- FreeRTOS (source code needs to be modified)
- According to the error scene status, output the corresponding thread stack or C main stack;
- The fault diagnosis information supports multiple languages (currently: Simplified Chinese, English);
- Adapt to Cortex-M0/M3/M4/M7 MCU;
- Support IAR, KEIL, GCC compiler;
## 1、为什么选择 CmBacktrace
## 1. Why choose CmBacktrace
**入门新人** :对于从 C51 、MSP430 等简单单片机转而使用更加复杂的 ARM 新人来说,时不时出现的 "hard falut" 死机会让新人瞬间懵掉。定位错误的方法也往往是连接上仿真器,一步步 F10/F11 单步,定位到具体的错误代码,再去猜测、排除、推敲错误原因,这种过程十分痛苦。
**Beginner Newcomer**: For newcomers who switch from simple microcontrollers such as C51 and MSP430 to more complex ARM, the chance of "hard falut" death from time to time makes newcomers instantly stunned. The method of locating errors is often to connect to the emulator, step by step F10/F11, locate the specific error code, and then guess, eliminate, and deliberate on the cause of the error. This process is very painful.
**熟练老手** :慢慢的大家知道可以通过故障寄存器信息来定位故障原因及故障代码地址,虽然这样能解决一小部分问题,但是重复的、繁琐的分析过程也会耽误很多时间。而且对于一些复杂问题,只依靠代码地址是无法解决的,必须得还原错误现场的函数调用逻辑关系。虽然连接仿真器可以查看到的函数调用栈,但故障状态下是无法显示的,所以还是得一步步 F10/F11 单步去定位错误代码的位置。另外,还有两种场景,
**Skilled veteran**: Slowly everyone knows that the fault cause and fault code address can be located through the fault register information. Although this can solve a small part of the problem, the repeated and tedious analysis process will also delay a lot of time. Moreover, for some complex problems, it is impossible to solve only by the code address, and the function call logic relationship of the wrong scene must be restored. Although the function call stack can be viewed by connecting to the emulator, it cannot be displayed in the fault state, so it is necessary to step by step F10/F11 to locate the error code. In addition, there are two scenarios,
- 1、很多产品真机调试时必须断开仿真器
- 2、问题确实存在但是极难被重现
1. The emulator must be disconnected when debugging many products
2. The problem does exist, but it is extremely difficult to reproduce
所以定位这类问题就显得难上加难。
So locating such problems is even more difficult.
**使用本库** :上述所有问题都迎刃而解,可以将错误信息输出到控制台上,还可以将错误信息使用 [EasyFlash](https://github.com/armink/EasyFlash) 的 Log 功能保存至 Flash 中设备死机后重启依然能够读取上次的错误信息。CmBacktrace 输出的信息包括函数调用栈、故障诊断结果、堆栈、故障寄存器及产品固件信息,极大的提升了错误定位的效率及准确性。
**Use this library**: All the above problems can be solved easily. The error message can be output to the console, and the error message can also be saved using the Log function of [EasyFlash](https://github.com/armink/EasyFlash) In Flash, the last error message can still be read after the device crashes and restarts. The information output by CmBacktrace includes function call stack, fault diagnosis result, stack, fault register and product firmware information, which greatly improves the efficiency and accuracy of error location.
俗话说,工欲善其事,必先利其器。所以有时候做事效率低的原因也许是,你会用的工具种类太少。
As the saying goes, a worker must first sharpen his tools if he wants to do his job well. So sometimes the reason for the low efficiency may be that you will use too few types of tools.
**合作、贡献** :开源软件的发展离不开大家的支持,欢迎大家多提建议,也希望更多的人一起参与进来,共同提高 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/CmBacktrace) **([Github](https://github.com/armink/CmBacktrace)|[OSChina](http://git.oschina.net/armink/CmBacktrace)|[Coding](https://coding.net/u/armink/p/CmBacktrace/git))** 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
**Cooperation, Contribution**: The development of open source software is inseparable from everyone's support. You are welcome to make more suggestions and hope that more people will join in and improve together. If you think this open source project is great, you can click [Project Homepage](https://github.com/armink/CmBacktrace) **([Github](https://github.com/armink/CmBacktrace)|[OSChina](http://git.oschina.net/armink/CmBacktrace)|[Coding](https://coding.net/u/armink/p/CmBacktrace/git))** Star** in the upper right corner, At the same time recommend it to more friends in need.
## 2、CmBacktrace 如何使用
## 2. How to use CmBacktrace
### 2.1 演示
### 2.1 Demo
该演示分如下几个步骤:
The demonstration is divided into the following steps:
- 1、制造除零异常[IAR 工程,点击查看源码](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x/app/src)
- 2、查看错误诊断信息
- 3、查看函数调用栈基本信息
- 4、通过命令行工具进入项目工程存放可执行文件的路径
- 5、使用 addr2line 命令,查看函数调用栈详细信息,并定位错误代码
1. Manufacturing division by zero exception ([IAR project, click to view source code](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x/app/src))
2. View error diagnosis information
3. View the basic information of the function call stack
4. Enter the path where the executable file is stored in the project project through the command line tool
5. Use the addr2line command to view the function call stack details and locate the error code
[![cm_backtrace_demo](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/cm_backtrace_demo.gif)](https://github.com/armink/CmBacktrace)
### 2.2 Demo
|目录|平台|链接|
|Catalog|Platform|Link|
|:--|:--:|:--:|
| `\demos\non_os\stm32f10x` |裸机 STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x)|
| `\demos\os\rtthread\stm32f4xx`|RT-Thread STM32 Cortex-M4|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/rtthread/stm32f4xx)|
| `\demos\os\ucosii\stm32f10x` |UCOSII STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/ucosii/stm32f10x)|
| `\demos\os\freertos\stm32f10x` |FreeRTOS STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/freertos/stm32f10x)|
| `\demos\non_os\stm32f10x` |bare metal STM32 Cortex-M3|[click to view](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x)|
| `\demos\os\rtthread\stm32f4xx`|RT-Thread STM32 Cortex-M4|[Click to view](https://github.com/armink/CmBacktrace/tree/master/demos/os/rtthread/stm32f4xx)|
| `\demos\os\ucosii\stm32f10x` |UCOSII STM32 Cortex-M3|[Click to view](https://github.com/armink/CmBacktrace/tree/master/demos/os/ucosii/stm32f10x)|
| `\demos\os\freertos\stm32f10x` |FreeRTOS STM32 Cortex-M3|[Click to view](https://github.com/armink/CmBacktrace/tree/master/demos/os/freertos/stm32f10x)|
### 2.3 移植说明
### 2.3 Porting instructions
#### 2.3.1 准备工作
#### 2.3.1 Preparation
- 1、查看 `\demos` 目录下有没有合适自己的 Demo ,如有类似,则建议在其基础上修改
- 2、明确操作系统/裸机平台及 CPU 平台
- 3、将 `\src` 下的全部源文件添加至产品工程中,并保证源码目录被添加至头文件路径
- 4、cmb_fault.s 汇编文件([点击查看](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler))可以选择性添加至工程,添加后需要把项目原有的 `HardFault_Handler` 注释掉
- 5、把 `cm_backtrace_init` 函数放在项目初始化地方执行
- 6、将 `cm_backtrace_assert` 放在项目的断言函数中执行,具体使用方法参照下面的 API 说明
- 7、如果第 4 步骤没有将 cmb_fault.s 汇编文件启用,则需要将 `cm_backtrace_fault` 放到故障处理函数(例如: `HardFault_Handler` )中执行,具体使用方法参照下面的 API 说明
1. Check whether there is a suitable Demo in the `\demos` directory, if there is a similar, it is recommended to modify it on the basis of it
2. Identify the operating system/bare metal platform and CPU platform
3. Add all source files under `\src` to the product project, and ensure that the source code directory is added to the header file path
4. The cmb_fault.s assembly file ([click to view](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler)) can be optionally added to the project. After adding, you need to add the original project `HardFault_Handler` comment out
5. Put the `cm_backtrace_init` function in the project initialization place for execution
6. Put `cm_backtrace_assert` in the assertion function of the project for execution. For specific usage, please refer to the API description below
7. If the cmb_fault.s assembly file is not enabled in step 4, you need to put `cm_backtrace_fault` in the fault handling function (for example: `HardFault_Handler`) for execution. For details, refer to the API description below
#### 2.3.2 配置说明
#### 2.3.2 Configuration Instructions
配置文件名: `cmb_cfg.h` ,针对不同的平台和场景,用户需要自自行手动配置,常用配置如下:
Configuration file name: `cmb_cfg.h`, users need to manually configure themselves for different platforms and scenarios. Common configurations are as follows:
| 配置名称 |功能|备注|
| Configuration name | Function | Remarks |
|:--|:--|:--|
|cmb_println(...)|错误及诊断信息输出|必须配置|
|CMB_USING_BARE_METAL_PLATFORM|是否使用在裸机平台|使用则定义该宏|
|CMB_USING_OS_PLATFORM|是否使用在操作系统平台|操作系统与裸机必须二选一|
|CMB_OS_PLATFORM_TYPE|操作系统平台|RTT/UCOSII/UCOSIII/FREERTOS|
|CMB_CPU_PLATFORM_TYPE|CPU平台|M0/M3/M4/M7|
|CMB_USING_DUMP_STACK_INFO|是否使用 Dump 堆栈的功能|使用则定义该宏|
|CMB_PRINT_LANGUAGE|输出信息时的语言|CHINESE/ENGLISH|
|cmb_println(...)|Error and diagnostic information output|Must be configured|
|CMB_USING_BARE_METAL_PLATFORM|Whether it is used on a bare metal platform|Define this macro if it is used|
|CMB_USING_OS_PLATFORM|Whether it is used on the operating system platform|Operating system and bare metal must choose one of two|
|CMB_OS_PLATFORM_TYPE|Operating System Platform|RTT/UCOSII/UCOSIII/FREERTOS|
|CMB_CPU_PLATFORM_TYPE|CPU platform|M0/M3/M4/M7|
|CMB_USING_DUMP_STACK_INFO|Whether to use Dump stack function|Use to define this macro|
|CMB_PRINT_LANGUAGE|Language when outputting information|CHINESE/ENGLISH|
> 注意:以上部分配置的内容可以在 `cmb_def.h` 中选择,更多灵活的配置请阅读源码
> Note: The content of the above configuration can be selected in `cmb_def.h`, please read the source code for more flexible configuration
### 2.4 API 说明
### 2.4 API description
#### 2.4.1 库初始化
#### 2.4.1 Library initialization
```C
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver)
```
|参数 |描述|
|:----- |:----|
|firmware_name |固件名称,需与编译器生成的固件名称对应|
|hardware_ver |固件对应的硬件版本号|
|software_ver |固件的软件版本号|
|Parameter |Description|
|:----- |:----|
|firmware_name |firmware name, which must correspond to the firmware name generated by the compiler|
|hardware_ver |The hardware version number corresponding to the firmware|
|software_ver |Software version number of the firmware|
> **注意** :以上入参将会在断言或故障时输出,主要起了追溯的作用
> **Note**: The above input parameters will be output in case of assertion or failure, mainly for retrospective purposes
#### 2.4.2 获取函数调用栈
#### 2.4.2 Get function call stack
```C
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp)
```
|参数 |描述|
|:----- |:----|
|buffer |存储函数调用栈的缓冲区|
|size |缓冲区大小|
|sp |待获取的堆栈指针|
|Parameter |Description|
|:----- |:----|
|buffer |Buffer for storing function call stack|
|size |Buffer size|
|sp |Stack pointer to be obtained|
示例:
Example:
```C
/* 建立深度为 16 的函数调用栈缓冲区,深度大小不应该超过 CMB_CALL_STACK_MAX_DEPTH默认16 */
/* Create a function call stack buffer with a depth of 16, and the depth should not exceed CMB_CALL_STACK_MAX_DEPTH (default 16) */
uint32_t call_stack[16] = {0};
size_t i, depth = 0;
/* 获取当前环境下的函数调用栈,每个元素将会以 32 位地址形式存储, depth 为函数调用栈实际深度 */
/* Get the function call stack in the current environment, each element will be stored as a 32-bit address, and depth is the actual depth of the function call stack */
depth = cm_backtrace_call_stack(call_stack, sizeof(call_stack), cmb_get_sp());
/* 输出当前函数调用栈信息
* 注意:查看函数名称及具体行号时,需要使用 addr2line 工具转换
/* Output current function call stack information
* Note: When viewing the function name and specific line number, you need to use the addr2line tool to convert
*/
for (i = 0; i < depth; i++) {
for (i = 0; i <depth; i++) {
printf("%08x ", call_stack[i]);
}
```
#### 2.4.3 追踪断言错误信息
#### 2.4.3 Tracking assertion error messages
```C
void cm_backtrace_assert(uint32_t sp)
```
|参数 |描述|
|:----- |:----|
|sp |断言环境时的堆栈指针|
|Parameter |Description|
|:----- |:----|
|sp |Stack pointer when asserting environment|
> **注意** :入参 SP 尽量在断言函数内部获取,而且尽可能靠近断言函数开始的位置。当在断言函数的子函数中(例如:在 RT-Thread 的断言钩子方法中)使用时,由于函数嵌套会存在寄存器入栈的操作,此时再获取 SP 将发生变化,就需要人为调整(加减固定的偏差值)入参值,所以作为新手 **不建议在断言的子函数** 中使用该函数。
> **Note**: The input parameter SP should be obtained inside the assertion function as much as possible, and as close as possible to the beginning of the assertion function. When used in the sub-function of the assertion function (for example: in the assertion hook method of RT-Thread), due to the nesting of the function, there will be the operation of registering the stack, and the SP will be changed at this time, and manual adjustment is required ( Add and subtract a fixed deviation value) into the parameter value, so as a novice, it is not recommended to use this function in the sub-function of the assertion.
#### 2.4.4 追踪故障错误信息
#### 2.4.4 Tracking fault information
```C
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp)
```
|参数 |描述|
|:----- |:----|
|fault_handler_lr |故障处理函数环境下的 LR 寄存器值|
|fault_handler_sp |故障处理函数环境下的 SP 寄存器值|
|Parameter |Description|
|:----- |:----|
|fault_handler_lr |LR register value under fault handling function environment|
|fault_handler_sp |SP register value under fault handling function environment|
该函数可以在故障处理函数(例如: `HardFault_Handler`)中调用。另外,库本身提供了 `HardFault` 处理的汇编文件([点击查看](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler),需根据自己编译器进行选择),会在故障时自动调用 `cm_backtrace_fault` 方法。所以移植时,最简单的方式就是直接使用该汇编文件。
This function can be called in the fault handling function (for example: `HardFault_Handler`). In addition, the library itself provides assembly files processed by `HardFault` ([click to view](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler), you need to choose according to your own compiler), The `cm_backtrace_fault` method is automatically called in the event of a fault. So when transplanting, the easiest way is to use the assembly file directly.
### 2.5 常见问题
### 2.5 FAQ
#### 2.5.1 编译出错,提示需要 C99 支持
#### 2.5.1 Compilation error, suggesting that C99 support is required
[点击查看教程:一步开启 Keil/IAR/GCC 的 C99 支持](https://github.com/armink/CmBacktrace/blob/master/docs/zh/enable_c99_for_keil_iar_gcc.md)
[Click to view the tutorial: Open Keil/IAR/GCC C99 support in one step](https://github.com/armink/CmBacktrace/blob/master/docs/zh/enable_c99_for_keil_iar_gcc.md)
#### 2.5.2 如何查看到函数调用栈中函数的具体名称及代码行号
#### 2.5.2 How to view the specific name and code line number of the function in the function call stack
[点击查看教程:如何使用 addr2line 工具获取函数调用栈详细信息](https://github.com/armink/CmBacktrace/blob/master/docs/zh/how_to_use_addr2line_for_call_stack.md)
[Click to view the tutorial: How to use the addr2line tool to get the function call stack details](https://github.com/armink/CmBacktrace/blob/master/docs/zh/how_to_use_addr2line_for_call_stack.md)
#### 2.5.3 故障处理函数HardFault_Handler 重复定义
#### 2.5.3 Fault handling function: HardFault_Handler repeated definition
在使用了本库提供的 cmb_fault.s 汇编文件时,因为该汇编文件内部已经定义了 HardFault_Handler ,所以如果项目中还有其他地方定义了该函数,则会提示 HardFault_Handler 被重复定义的错误。此时有两种解决方法:
When the cmb_fault.s assembly file provided by this library is used, because HardFault_Handler is already defined in the assembly file, if this function is defined elsewhere in the project, an error that HardFault_Handler is repeatedly defined will be prompted. There are two solutions at this time:
- 1、注释/删除其他文件中定义的 `HardFault_Handler` 函数,仅保留 cmb_fault.s 中的;
- 2、将 cmb_fault.s 移除工程,手动添加 `cm_backtrace_fault` 函数至现有的故障处理函数,但需要注意的是,务必 **保证该函数数入参的准备性** ,否则可能会导致故障诊断功能及堆栈打印功能无法正常运行。所以如果是新手,不推荐第二种解决方法。
1. Comment/delete the `HardFault_Handler` function defined in other files, and only keep the cmb_fault.s;
2. Remove cmb_fault.s from the project, and manually add the `cm_backtrace_fault` function to the existing fault handling function, but it should be noted that you must ** ensure the readiness of the function to enter the parameters**, otherwise it may cause The fault diagnosis function and stack printing function cannot operate normally. So if you are a novice, the second solution is not recommended.
#### 2.5.4 初始化时提示无法获取主栈main stack信息
#### 2.5.4 Prompt that the main stack information cannot be obtained during initialization
`cmd_def.h` 中有定义默认的主栈配置,大致如下:
The default main stack configuration is defined in `cmd_def.h`, roughly as follows:
```c
#if defined(__CC_ARM)
/* C stack block name, default is STACK */
/* C stack block name,default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
#define CMB_CSTACK_BLOCK_NAME STACK
#endif
...
#elif defined(__ICCARM__)
/* C stack block name, default is 'CSTACK' */
/* C stack block name, default is'CSTACK' */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#endif
...
#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is _sstack */
#ifndef CMB_CSTACK_BLOCK_START
#define CMB_CSTACK_BLOCK_START _sstack
#define CMB_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack */
#ifndef CMB_CSTACK_BLOCK_END
#define CMB_CSTACK_BLOCK_END _estack
#define CMB_CSTACK_BLOCK_END _estack
#endif
...
#else
```
比如在 Keil-MDK 编译器下会默认选择 `STACK` 作为主栈 block 的名称,但在一些特殊平台下,项目的主栈 block 名称可能不叫 `STACK`,导致 CmBacktrace 无法获取到正确的主栈信息,所以在初始化时会有如上的错误提示信息。
For example, under the Keil-MDK compiler, `STACK` will be selected as the name of the main stack block by default, but under some special platforms, the name of the main stack block of the project may not be called `STACK`, causing CmBacktrace to fail to obtain the correct main stack Information, so there will be the above error message during initialization.
解决这个问题一般有两个思路
There are generally two ways to solve this problem
- 1、在 `cmb_cfg.h` 中重新定义主栈的信息,此时 CmBacktrace 会优先使用 `cmb_cfg.h` 中的配置信息;
- 2、修改项目配置如果是 Keil-MDK ,则在启动文件的开头位置,将主栈的名称修改为默认的 `STACK` ,其他编译器一般很少出现该问题。
1. Redefine the main stack information in `cmb_cfg.h`. At this time, CmBacktrace will give priority to using the configuration information in `cmb_cfg.h`;
2. Modify the project configuration. If it is Keil-MDK, change the name of the main stack to the default `STACK` at the beginning of the startup file. This problem rarely occurs with other compilers.
### 2.6 许可
### 2.6 License
采用 MIT 开源协议,细节请阅读项目中的 LICENSE 文件内容。
The MIT open source agreement is adopted. For details, please read the contents of the LICENSE file in the project.

@ -0,0 +1,221 @@
# CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库
中文页 | [English](README.md)
[![GitHub release](https://img.shields.io/github/release/armink/CmBacktrace.svg)](https://github.com/armink/CmBacktrace/releases/latest) [![GitHub commits](https://img.shields.io/github/commits-since/armink/CmBacktrace/1.4.0.svg)](https://github.com/armink/CmBacktrace/compare/1.0.0...master) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/armink/CmBacktrace/master/LICENSE)
## 0、CmBacktrace 是什么
[CmBacktrace](https://github.com/armink/CmBacktrace) Cortex Microcontroller Backtrace是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位,错误原因自动分析的开源库。主要特性如下:
- 支持的错误包括:
- 断言assert
- 故障Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault
- 故障原因 **自动诊断** :可在故障发生时,自动分析出故障的原因,定位发生故障的代码位置,而无需再手动分析繁杂的故障寄存器;
- 输出错误现场的 **函数调用栈**(需配合 addr2line 工具进行精确定位),还原发生错误时的现场信息,定位问题代码位置、逻辑更加快捷、精准。也可以在正常状态下使用该库,获取当前的函数调用栈;
- 支持 裸机 及以下操作系统平台:
- [RT-Thread](http://www.rt-thread.org/)
- UCOS
- FreeRTOS需修改源码
- 根据错误现场状态,输出对应的 线程栈 或 C 主栈;
- 故障诊断信息支持多国语言(目前:简体中文、英文);
- 适配 Cortex-M0/M3/M4/M7 MCU
- 支持 IAR、KEIL、GCC 编译器;
## 1、为什么选择 CmBacktrace
**入门新人** :对于从 C51 、MSP430 等简单单片机转而使用更加复杂的 ARM 新人来说,时不时出现的 "hard falut" 死机会让新人瞬间懵掉。定位错误的方法也往往是连接上仿真器,一步步 F10/F11 单步,定位到具体的错误代码,再去猜测、排除、推敲错误原因,这种过程十分痛苦。
**熟练老手** :慢慢的大家知道可以通过故障寄存器信息来定位故障原因及故障代码地址,虽然这样能解决一小部分问题,但是重复的、繁琐的分析过程也会耽误很多时间。而且对于一些复杂问题,只依靠代码地址是无法解决的,必须得还原错误现场的函数调用逻辑关系。虽然连接仿真器可以查看到的函数调用栈,但故障状态下是无法显示的,所以还是得一步步 F10/F11 单步去定位错误代码的位置。另外,还有两种场景,
- 1、很多产品真机调试时必须断开仿真器
- 2、问题确实存在但是极难被重现
所以定位这类问题就显得难上加难。
**使用本库** :上述所有问题都迎刃而解,可以将错误信息输出到控制台上,还可以将错误信息使用 [EasyFlash](https://github.com/armink/EasyFlash) 的 Log 功能保存至 Flash 中设备死机后重启依然能够读取上次的错误信息。CmBacktrace 输出的信息包括函数调用栈、故障诊断结果、堆栈、故障寄存器及产品固件信息,极大的提升了错误定位的效率及准确性。
俗话说,工欲善其事,必先利其器。所以有时候做事效率低的原因也许是,你会用的工具种类太少。
**合作、贡献** :开源软件的发展离不开大家的支持,欢迎大家多提建议,也希望更多的人一起参与进来,共同提高 。如果觉得这个开源项目很赞,可以点击 [项目主页](https://github.com/armink/CmBacktrace) **([Github](https://github.com/armink/CmBacktrace)|[OSChina](http://git.oschina.net/armink/CmBacktrace)|[Coding](https://coding.net/u/armink/p/CmBacktrace/git))** 右上角的 **Star** ,同时把它推荐给更多有需要的朋友。
## 2、CmBacktrace 如何使用
### 2.1 演示
该演示分如下几个步骤:
- 1、制造除零异常[IAR 工程,点击查看源码](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x/app/src)
- 2、查看错误诊断信息
- 3、查看函数调用栈基本信息
- 4、通过命令行工具进入项目工程存放可执行文件的路径
- 5、使用 addr2line 命令,查看函数调用栈详细信息,并定位错误代码
[![cm_backtrace_demo](https://raw.githubusercontent.com/armink/CmBacktrace/master/docs/zh/images/cm_backtrace_demo.gif)](https://github.com/armink/CmBacktrace)
### 2.2 Demo
|目录|平台|链接|
|:--|:--:|:--:|
| `\demos\non_os\stm32f10x` |裸机 STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/non_os/stm32f10x)|
| `\demos\os\rtthread\stm32f4xx`|RT-Thread STM32 Cortex-M4|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/rtthread/stm32f4xx)|
| `\demos\os\ucosii\stm32f10x` |UCOSII STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/ucosii/stm32f10x)|
| `\demos\os\freertos\stm32f10x` |FreeRTOS STM32 Cortex-M3|[点击查看](https://github.com/armink/CmBacktrace/tree/master/demos/os/freertos/stm32f10x)|
### 2.3 移植说明
#### 2.3.1 准备工作
- 1、查看 `\demos` 目录下有没有合适自己的 Demo ,如有类似,则建议在其基础上修改
- 2、明确操作系统/裸机平台及 CPU 平台
- 3、将 `\src` 下的全部源文件添加至产品工程中,并保证源码目录被添加至头文件路径
- 4、cmb_fault.s 汇编文件([点击查看](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler))可以选择性添加至工程,添加后需要把项目原有的 `HardFault_Handler` 注释掉
- 5、把 `cm_backtrace_init` 函数放在项目初始化地方执行
- 6、将 `cm_backtrace_assert` 放在项目的断言函数中执行,具体使用方法参照下面的 API 说明
- 7、如果第 4 步骤没有将 cmb_fault.s 汇编文件启用,则需要将 `cm_backtrace_fault` 放到故障处理函数(例如: `HardFault_Handler` )中执行,具体使用方法参照下面的 API 说明
#### 2.3.2 配置说明
配置文件名: `cmb_cfg.h` ,针对不同的平台和场景,用户需要自自行手动配置,常用配置如下:
| 配置名称 |功能|备注|
|:--|:--|:--|
|cmb_println(...)|错误及诊断信息输出|必须配置|
|CMB_USING_BARE_METAL_PLATFORM|是否使用在裸机平台|使用则定义该宏|
|CMB_USING_OS_PLATFORM|是否使用在操作系统平台|操作系统与裸机必须二选一|
|CMB_OS_PLATFORM_TYPE|操作系统平台|RTT/UCOSII/UCOSIII/FREERTOS|
|CMB_CPU_PLATFORM_TYPE|CPU平台|M0/M3/M4/M7|
|CMB_USING_DUMP_STACK_INFO|是否使用 Dump 堆栈的功能|使用则定义该宏|
|CMB_PRINT_LANGUAGE|输出信息时的语言|CHINESE/ENGLISH|
> 注意:以上部分配置的内容可以在 `cmb_def.h` 中选择,更多灵活的配置请阅读源码
### 2.4 API 说明
#### 2.4.1 库初始化
```C
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver)
```
|参数 |描述|
|:----- |:----|
|firmware_name |固件名称,需与编译器生成的固件名称对应|
|hardware_ver |固件对应的硬件版本号|
|software_ver |固件的软件版本号|
> **注意** :以上入参将会在断言或故障时输出,主要起了追溯的作用
#### 2.4.2 获取函数调用栈
```C
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp)
```
|参数 |描述|
|:----- |:----|
|buffer |存储函数调用栈的缓冲区|
|size |缓冲区大小|
|sp |待获取的堆栈指针|
示例:
```C
/* 建立深度为 16 的函数调用栈缓冲区,深度大小不应该超过 CMB_CALL_STACK_MAX_DEPTH默认16 */
uint32_t call_stack[16] = {0};
size_t i, depth = 0;
/* 获取当前环境下的函数调用栈,每个元素将会以 32 位地址形式存储, depth 为函数调用栈实际深度 */
depth = cm_backtrace_call_stack(call_stack, sizeof(call_stack), cmb_get_sp());
/* 输出当前函数调用栈信息
* 注意:查看函数名称及具体行号时,需要使用 addr2line 工具转换
*/
for (i = 0; i < depth; i++) {
printf("%08x ", call_stack[i]);
}
```
#### 2.4.3 追踪断言错误信息
```C
void cm_backtrace_assert(uint32_t sp)
```
|参数 |描述|
|:----- |:----|
|sp |断言环境时的堆栈指针|
> **注意** :入参 SP 尽量在断言函数内部获取,而且尽可能靠近断言函数开始的位置。当在断言函数的子函数中(例如:在 RT-Thread 的断言钩子方法中)使用时,由于函数嵌套会存在寄存器入栈的操作,此时再获取 SP 将发生变化,就需要人为调整(加减固定的偏差值)入参值,所以作为新手 **不建议在断言的子函数** 中使用该函数。
#### 2.4.4 追踪故障错误信息
```C
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp)
```
|参数 |描述|
|:----- |:----|
|fault_handler_lr |故障处理函数环境下的 LR 寄存器值|
|fault_handler_sp |故障处理函数环境下的 SP 寄存器值|
该函数可以在故障处理函数(例如: `HardFault_Handler`)中调用。另外,库本身提供了 `HardFault` 处理的汇编文件([点击查看](https://github.com/armink/CmBacktrace/tree/master/cm_backtrace/fault_handler),需根据自己编译器进行选择),会在故障时自动调用 `cm_backtrace_fault` 方法。所以移植时,最简单的方式就是直接使用该汇编文件。
### 2.5 常见问题
#### 2.5.1 编译出错,提示需要 C99 支持
[点击查看教程:一步开启 Keil/IAR/GCC 的 C99 支持](https://github.com/armink/CmBacktrace/blob/master/docs/zh/enable_c99_for_keil_iar_gcc.md)
#### 2.5.2 如何查看到函数调用栈中函数的具体名称及代码行号
[点击查看教程:如何使用 addr2line 工具获取函数调用栈详细信息](https://github.com/armink/CmBacktrace/blob/master/docs/zh/how_to_use_addr2line_for_call_stack.md)
#### 2.5.3 故障处理函数HardFault_Handler 重复定义
在使用了本库提供的 cmb_fault.s 汇编文件时,因为该汇编文件内部已经定义了 HardFault_Handler ,所以如果项目中还有其他地方定义了该函数,则会提示 HardFault_Handler 被重复定义的错误。此时有两种解决方法:
- 1、注释/删除其他文件中定义的 `HardFault_Handler` 函数,仅保留 cmb_fault.s 中的;
- 2、将 cmb_fault.s 移除工程,手动添加 `cm_backtrace_fault` 函数至现有的故障处理函数,但需要注意的是,务必 **保证该函数数入参的准备性** ,否则可能会导致故障诊断功能及堆栈打印功能无法正常运行。所以如果是新手,不推荐第二种解决方法。
#### 2.5.4 初始化时提示无法获取主栈main stack信息
`cmd_def.h` 中有定义默认的主栈配置,大致如下:
```c
#if defined(__CC_ARM)
/* C stack block name, default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
#endif
...
#elif defined(__ICCARM__)
/* C stack block name, default is 'CSTACK' */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME "CSTACK"
#endif
...
#elif defined(__GNUC__)
/* C stack block start address, defined on linker script file, default is _sstack */
#ifndef CMB_CSTACK_BLOCK_START
#define CMB_CSTACK_BLOCK_START _sstack
#endif
/* C stack block end address, defined on linker script file, default is _estack */
#ifndef CMB_CSTACK_BLOCK_END
#define CMB_CSTACK_BLOCK_END _estack
#endif
...
#else
```
比如在 Keil-MDK 编译器下会默认选择 `STACK` 作为主栈 block 的名称,但在一些特殊平台下,项目的主栈 block 名称可能不叫 `STACK`,导致 CmBacktrace 无法获取到正确的主栈信息,所以在初始化时会有如上的错误提示信息。
解决这个问题一般有两个思路
- 1、在 `cmb_cfg.h` 中重新定义主栈的信息,此时 CmBacktrace 会优先使用 `cmb_cfg.h` 中的配置信息;
- 2、修改项目配置如果是 Keil-MDK ,则在启动文件的开头位置,将主栈的名称修改为默认的 `STACK` ,其他编译器一般很少出现该问题。
### 2.6 许可
采用 MIT 开源协议,细节请阅读项目中的 LICENSE 文件内容。

@ -0,0 +1,8 @@
# CmBacktrace: ARM Cortex-M 系列 MCU 错误追踪库
## 多语言支持
| Language | Location (or type) | Language tag |
|----------------------|----------------------------|--------------|
| English | United States | en-US |
| Chinese (Simplified) | People's Republic of China | zh-CN |

@ -0,0 +1,71 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Chenxuan, <chenxuan.zhao@icloud.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NOTE: DO NOT include this file on the header file.
* Encoding: UTF-8
* Created on: 2020-09-06
*/
[PRINT_MAIN_STACK_CFG_ERROR] = "ERROR: Unable to get the main stack information, please check the configuration of the main stack",
[PRINT_FIRMWARE_INFO] = "Firmware name: %s, hardware version: %s, software version: %s",
[PRINT_ASSERT_ON_THREAD] = "Assert on thread %s",
[PRINT_ASSERT_ON_HANDLER] = "Assert on interrupt or bare metal(no OS) environment",
[PRINT_THREAD_STACK_INFO] = "===== Thread stack information =====",
[PRINT_MAIN_STACK_INFO] = "====== Main stack information ======",
[PRINT_THREAD_STACK_OVERFLOW] = "Error: Thread stack(%08x) was overflow",
[PRINT_MAIN_STACK_OVERFLOW] = "Error: Main stack(%08x) was overflow",
[PRINT_CALL_STACK_INFO] = "Show more call stack info by run: addr2line -e %s%s -a -f %.*s",
[PRINT_CALL_STACK_ERR] = "Dump call stack has an error",
[PRINT_FAULT_ON_THREAD] = "Fault on thread %s",
[PRINT_FAULT_ON_HANDLER] = "Fault on interrupt or bare metal(no OS) environment",
[PRINT_REGS_TITLE] = "=================== Registers information ====================",
[PRINT_HFSR_VECTBL] = "Hard fault is caused by failed vector fetch",
[PRINT_MFSR_IACCVIOL] = "Memory management fault is caused by instruction access violation",
[PRINT_MFSR_DACCVIOL] = "Memory management fault is caused by data access violation",
[PRINT_MFSR_MUNSTKERR] = "Memory management fault is caused by unstacking error",
[PRINT_MFSR_MSTKERR] = "Memory management fault is caused by stacking error",
[PRINT_MFSR_MLSPERR] = "Memory management fault is caused by floating-point lazy state preservation",
[PRINT_BFSR_IBUSERR] = "Bus fault is caused by instruction access violation",
[PRINT_BFSR_PRECISERR] = "Bus fault is caused by precise data access violation",
[PRINT_BFSR_IMPREISERR] = "Bus fault is caused by imprecise data access violation",
[PRINT_BFSR_UNSTKERR] = "Bus fault is caused by unstacking error",
[PRINT_BFSR_STKERR] = "Bus fault is caused by stacking error",
[PRINT_BFSR_LSPERR] = "Bus fault is caused by floating-point lazy state preservation",
[PRINT_UFSR_UNDEFINSTR] = "Usage fault is caused by attempts to execute an undefined instruction",
[PRINT_UFSR_INVSTATE] = "Usage fault is caused by attempts to switch to an invalid state (e.g., ARM)",
[PRINT_UFSR_INVPC] = "Usage fault is caused by attempts to do an exception with a bad value in the EXC_RETURN number",
[PRINT_UFSR_NOCP] = "Usage fault is caused by attempts to execute a coprocessor instruction",
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
[PRINT_UFSR_STKOF] = "Usage fault is caused by indicates that a stack overflow (hardware check) has taken place",
#endif
[PRINT_UFSR_UNALIGNED] = "Usage fault is caused by indicates that an unaligned access fault has taken place",
[PRINT_UFSR_DIVBYZERO0] = "Usage fault is caused by Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)",
[PRINT_DFSR_HALTED] = "Debug fault is caused by halt requested in NVIC",
[PRINT_DFSR_BKPT] = "Debug fault is caused by BKPT instruction executed",
[PRINT_DFSR_DWTTRAP] = "Debug fault is caused by DWT match occurred",
[PRINT_DFSR_VCATCH] = "Debug fault is caused by Vector fetch occurred",
[PRINT_DFSR_EXTERNAL] = "Debug fault is caused by EDBGRQ signal asserted",
[PRINT_MMAR] = "The memory management fault occurred address is %08x",
[PRINT_BFAR] = "The bus fault occurred address is %08x",

@ -0,0 +1,71 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Chenxuan, <chenxuan.zhao@icloud.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NOTE: DO NOT include this file on the header file.
* Encoding: GB18030
* Created on: 2020-09-06
*/
[PRINT_MAIN_STACK_CFG_ERROR] = "错误:无法获取主栈信息,请检查主栈的相关配置",
[PRINT_FIRMWARE_INFO] = "固件名称:%s硬件版本号%s软件版本号%s",
[PRINT_ASSERT_ON_THREAD] = "在线程(%s)中发生断言",
[PRINT_ASSERT_ON_HANDLER] = "在中断或裸机环境下发生断言",
[PRINT_THREAD_STACK_INFO] = "=========== 线程堆栈信息 ===========",
[PRINT_MAIN_STACK_INFO] = "============ 主堆栈信息 ============",
[PRINT_THREAD_STACK_OVERFLOW] = "错误:线程栈(%08x)发生溢出",
[PRINT_MAIN_STACK_OVERFLOW] = "错误:主栈(%08x)发生溢出",
[PRINT_CALL_STACK_INFO] = "查看更多函数调用栈信息请运行addr2line -e %s%s -a -f %.*s",
[PRINT_CALL_STACK_ERR] = "获取函数调用栈失败",
[PRINT_FAULT_ON_THREAD] = "在线程(%s)中发生错误异常",
[PRINT_FAULT_ON_HANDLER] = "在中断或裸机环境下发生错误异常",
[PRINT_REGS_TITLE] = "========================= 寄存器信息 =========================",
[PRINT_HFSR_VECTBL] = "发生硬错误,原因:取中断向量时出错",
[PRINT_MFSR_IACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域取指令",
[PRINT_MFSR_DACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域读、写数据",
[PRINT_MFSR_MUNSTKERR] = "发生存储器管理错误,原因:出栈时企图访问不被允许的区域",
[PRINT_MFSR_MSTKERR] = "发生存储器管理错误,原因:入栈时企图访问不被允许的区域",
[PRINT_MFSR_MLSPERR] = "发生存储器管理错误,原因:惰性保存浮点状态时发生错误",
[PRINT_BFSR_IBUSERR] = "发生总线错误,原因:指令总线错误",
[PRINT_BFSR_PRECISERR] = "发生总线错误,原因:精确的数据总线错误",
[PRINT_BFSR_IMPREISERR] = "发生总线错误,原因:不精确的数据总线错误",
[PRINT_BFSR_UNSTKERR] = "发生总线错误,原因:出栈时发生错误",
[PRINT_BFSR_STKERR] = "发生总线错误,原因:入栈时发生错误",
[PRINT_BFSR_LSPERR] = "发生总线错误,原因:惰性保存浮点状态时发生错误",
[PRINT_UFSR_UNDEFINSTR] = "发生用法错误,原因:企图执行未定义指令",
[PRINT_UFSR_INVSTATE] = "发生用法错误,原因:试图切换到 ARM 状态",
[PRINT_UFSR_INVPC] = "发生用法错误,原因:无效的异常返回码",
[PRINT_UFSR_NOCP] = "发生用法错误,原因:企图执行协处理器指令",
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
[PRINT_UFSR_STKOF] = "发生用法错误,原因:硬件检测到栈溢出",
#endif
[PRINT_UFSR_UNALIGNED] = "发生用法错误,原因:企图执行非对齐访问",
[PRINT_UFSR_DIVBYZERO0] = "发生用法错误,原因:企图执行除 0 操作",
[PRINT_DFSR_HALTED] = "发生调试错误原因NVIC 停机请求",
[PRINT_DFSR_BKPT] = "发生调试错误,原因:执行 BKPT 指令",
[PRINT_DFSR_DWTTRAP] = "发生调试错误,原因:数据监测点匹配",
[PRINT_DFSR_VCATCH] = "发生调试错误,原因:发生向量捕获",
[PRINT_DFSR_EXTERNAL] = "发生调试错误,原因:外部调试请求",
[PRINT_MMAR] = "发生存储器管理错误的地址:%08x",
[PRINT_BFAR] = "发生总线错误的地址:%08x",

@ -0,0 +1,71 @@
/*
* This file is part of the CmBacktrace Library.
*
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
* Chenxuan, <chenxuan.zhao@icloud.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* 'Software'), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* NOTE: DO NOT include this file on the header file.
* Encoding: UTF-8
* Created on: 2020-09-06
*/
[PRINT_MAIN_STACK_CFG_ERROR] = "错误:无法获取主栈信息,请检查主栈的相关配置",
[PRINT_FIRMWARE_INFO] = "固件名称:%s硬件版本号%s软件版本号%s",
[PRINT_ASSERT_ON_THREAD] = "在线程(%s)中发生断言",
[PRINT_ASSERT_ON_HANDLER] = "在中断或裸机环境下发生断言",
[PRINT_THREAD_STACK_INFO] = "=========== 线程堆栈信息 ===========",
[PRINT_MAIN_STACK_INFO] = "============ 主堆栈信息 ============",
[PRINT_THREAD_STACK_OVERFLOW] = "错误:线程栈(%08x)发生溢出",
[PRINT_MAIN_STACK_OVERFLOW] = "错误:主栈(%08x)发生溢出",
[PRINT_CALL_STACK_INFO] = "查看更多函数调用栈信息请运行addr2line -e %s%s -a -f %.*s",
[PRINT_CALL_STACK_ERR] = "获取函数调用栈失败",
[PRINT_FAULT_ON_THREAD] = "在线程(%s)中发生错误异常",
[PRINT_FAULT_ON_HANDLER] = "在中断或裸机环境下发生错误异常",
[PRINT_REGS_TITLE] = "========================= 寄存器信息 =========================",
[PRINT_HFSR_VECTBL] = "发生硬错误,原因:取中断向量时出错",
[PRINT_MFSR_IACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域取指令",
[PRINT_MFSR_DACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域读、写数据",
[PRINT_MFSR_MUNSTKERR] = "发生存储器管理错误,原因:出栈时企图访问不被允许的区域",
[PRINT_MFSR_MSTKERR] = "发生存储器管理错误,原因:入栈时企图访问不被允许的区域",
[PRINT_MFSR_MLSPERR] = "发生存储器管理错误,原因:惰性保存浮点状态时发生错误",
[PRINT_BFSR_IBUSERR] = "发生总线错误,原因:指令总线错误",
[PRINT_BFSR_PRECISERR] = "发生总线错误,原因:精确的数据总线错误",
[PRINT_BFSR_IMPREISERR] = "发生总线错误,原因:不精确的数据总线错误",
[PRINT_BFSR_UNSTKERR] = "发生总线错误,原因:出栈时发生错误",
[PRINT_BFSR_STKERR] = "发生总线错误,原因:入栈时发生错误",
[PRINT_BFSR_LSPERR] = "发生总线错误,原因:惰性保存浮点状态时发生错误",
[PRINT_UFSR_UNDEFINSTR] = "发生用法错误,原因:企图执行未定义指令",
[PRINT_UFSR_INVSTATE] = "发生用法错误,原因:试图切换到 ARM 状态",
[PRINT_UFSR_INVPC] = "发生用法错误,原因:无效的异常返回码",
[PRINT_UFSR_NOCP] = "发生用法错误,原因:企图执行协处理器指令",
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
[PRINT_UFSR_STKOF] = "发生用法错误,原因:硬件检测到栈溢出",
#endif
[PRINT_UFSR_UNALIGNED] = "发生用法错误,原因:企图执行非对齐访问",
[PRINT_UFSR_DIVBYZERO0] = "发生用法错误,原因:企图执行除 0 操作",
[PRINT_DFSR_HALTED] = "发生调试错误原因NVIC 停机请求",
[PRINT_DFSR_BKPT] = "发生调试错误,原因:执行 BKPT 指令",
[PRINT_DFSR_DWTTRAP] = "发生调试错误,原因:数据监测点匹配",
[PRINT_DFSR_VCATCH] = "发生调试错误,原因:发生向量捕获",
[PRINT_DFSR_EXTERNAL] = "发生调试错误,原因:外部调试请求",
[PRINT_MMAR] = "发生存储器管理错误的地址:%08x",
[PRINT_BFAR] = "发生总线错误的地址:%08x",

@ -35,7 +35,7 @@
#error "must be C99 or higher. try to add '-std=c99' to compile parameters"
#endif
#if defined(__CC_ARM)
#if defined(__CC_ARM) || defined(__CLANG_ARM)
#define SECTION_START(_name_) _name_##$$Base
#define SECTION_END(_name_) _name_##$$Limit
#define IMAGE_SECTION_START(_name_) Image$$##_name_##$$Base
@ -91,6 +91,9 @@ enum {
PRINT_UFSR_INVSTATE,
PRINT_UFSR_INVPC,
PRINT_UFSR_NOCP,
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
PRINT_UFSR_STKOF,
#endif
PRINT_UFSR_UNALIGNED,
PRINT_UFSR_DIVBYZERO0,
PRINT_DFSR_HALTED,
@ -104,83 +107,11 @@ enum {
static const char * const print_info[] = {
#if (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_ENGLISH)
[PRINT_MAIN_STACK_CFG_ERROR] = "ERROR: Unable to get the main stack information, please check the configuration of the main stack",
[PRINT_FIRMWARE_INFO] = "Firmware name: %s, hardware version: %s, software version: %s",
[PRINT_ASSERT_ON_THREAD] = "Assert on thread %s",
[PRINT_ASSERT_ON_HANDLER] = "Assert on interrupt or bare metal(no OS) environment",
[PRINT_THREAD_STACK_INFO] = "===== Thread stack information =====",
[PRINT_MAIN_STACK_INFO] = "====== Main stack information ======",
[PRINT_THREAD_STACK_OVERFLOW] = "Error: Thread stack(%08x) was overflow",
[PRINT_MAIN_STACK_OVERFLOW] = "Error: Main stack(%08x) was overflow",
[PRINT_CALL_STACK_INFO] = "Show more call stack info by run: addr2line -e %s%s -a -f %.*s",
[PRINT_CALL_STACK_ERR] = "Dump call stack has an error",
[PRINT_FAULT_ON_THREAD] = "Fault on thread %s",
[PRINT_FAULT_ON_HANDLER] = "Fault on interrupt or bare metal(no OS) environment",
[PRINT_REGS_TITLE] = "=================== Registers information ====================",
[PRINT_HFSR_VECTBL] = "Hard fault is caused by failed vector fetch",
[PRINT_MFSR_IACCVIOL] = "Memory management fault is caused by instruction access violation",
[PRINT_MFSR_DACCVIOL] = "Memory management fault is caused by data access violation",
[PRINT_MFSR_MUNSTKERR] = "Memory management fault is caused by unstacking error",
[PRINT_MFSR_MSTKERR] = "Memory management fault is caused by stacking error",
[PRINT_MFSR_MLSPERR] = "Memory management fault is caused by floating-point lazy state preservation",
[PRINT_BFSR_IBUSERR] = "Bus fault is caused by instruction access violation",
[PRINT_BFSR_PRECISERR] = "Bus fault is caused by precise data access violation",
[PRINT_BFSR_IMPREISERR] = "Bus fault is caused by imprecise data access violation",
[PRINT_BFSR_UNSTKERR] = "Bus fault is caused by unstacking error",
[PRINT_BFSR_STKERR] = "Bus fault is caused by stacking error",
[PRINT_BFSR_LSPERR] = "Bus fault is caused by floating-point lazy state preservation",
[PRINT_UFSR_UNDEFINSTR] = "Usage fault is caused by attempts to execute an undefined instruction",
[PRINT_UFSR_INVSTATE] = "Usage fault is caused by attempts to switch to an invalid state (e.g., ARM)",
[PRINT_UFSR_INVPC] = "Usage fault is caused by attempts to do an exception with a bad value in the EXC_RETURN number",
[PRINT_UFSR_NOCP] = "Usage fault is caused by attempts to execute a coprocessor instruction",
[PRINT_UFSR_UNALIGNED] = "Usage fault is caused by indicates that an unaligned access fault has taken place",
[PRINT_UFSR_DIVBYZERO0] = "Usage fault is caused by Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)",
[PRINT_DFSR_HALTED] = "Debug fault is caused by halt requested in NVIC",
[PRINT_DFSR_BKPT] = "Debug fault is caused by BKPT instruction executed",
[PRINT_DFSR_DWTTRAP] = "Debug fault is caused by DWT match occurred",
[PRINT_DFSR_VCATCH] = "Debug fault is caused by Vector fetch occurred",
[PRINT_DFSR_EXTERNAL] = "Debug fault is caused by EDBGRQ signal asserted",
[PRINT_MMAR] = "The memory management fault occurred address is %08x",
[PRINT_BFAR] = "The bus fault occurred address is %08x",
#include "Languages/en-US/cmb_en_US.h"
#elif (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_CHINESE)
[PRINT_MAIN_STACK_CFG_ERROR] = "错误:无法获取主栈信息,请检查主栈的相关配置",
[PRINT_FIRMWARE_INFO] = "固件名称:%s硬件版本号%s软件版本号%s",
[PRINT_ASSERT_ON_THREAD] = "在线程(%s)中发生断言",
[PRINT_ASSERT_ON_HANDLER] = "在中断或裸机环境下发生断言",
[PRINT_THREAD_STACK_INFO] = "=========== 线程堆栈信息 ===========",
[PRINT_MAIN_STACK_INFO] = "============ 主堆栈信息 ============",
[PRINT_THREAD_STACK_OVERFLOW] = "错误:线程栈(%08x)发生溢出",
[PRINT_MAIN_STACK_OVERFLOW] = "错误:主栈(%08x)发生溢出",
[PRINT_CALL_STACK_INFO] = "查看更多函数调用栈信息请运行addr2line -e %s%s -a -f %.*s",
[PRINT_CALL_STACK_ERR] = "获取函数调用栈失败",
[PRINT_FAULT_ON_THREAD] = "在线程(%s)中发生错误异常",
[PRINT_FAULT_ON_HANDLER] = "在中断或裸机环境下发生错误异常",
[PRINT_REGS_TITLE] = "========================= 寄存器信息 =========================",
[PRINT_HFSR_VECTBL] = "发生硬错误,原因:取中断向量时出错",
[PRINT_MFSR_IACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域取指令",
[PRINT_MFSR_DACCVIOL] = "发生存储器管理错误,原因:企图从不允许访问的区域读、写数据",
[PRINT_MFSR_MUNSTKERR] = "发生存储器管理错误,原因:出栈时企图访问不被允许的区域",
[PRINT_MFSR_MSTKERR] = "发生存储器管理错误,原因:入栈时企图访问不被允许的区域",
[PRINT_MFSR_MLSPERR] = "发生存储器管理错误,原因:惰性保存浮点状态时发生错误",
[PRINT_BFSR_IBUSERR] = "发生总线错误,原因:指令总线错误",
[PRINT_BFSR_PRECISERR] = "发生总线错误,原因:精确的数据总线错误",
[PRINT_BFSR_IMPREISERR] = "发生总线错误,原因:不精确的数据总线错误",
[PRINT_BFSR_UNSTKERR] = "发生总线错误,原因:出栈时发生错误",
[PRINT_BFSR_STKERR] = "发生总线错误,原因:入栈时发生错误",
[PRINT_BFSR_LSPERR] = "发生总线错误,原因:惰性保存浮点状态时发生错误",
[PRINT_UFSR_UNDEFINSTR] = "发生用法错误,原因:企图执行未定义指令",
[PRINT_UFSR_INVSTATE] = "发生用法错误,原因:试图切换到 ARM 状态",
[PRINT_UFSR_INVPC] = "发生用法错误,原因:无效的异常返回码",
[PRINT_UFSR_NOCP] = "发生用法错误,原因:企图执行协处理器指令",
[PRINT_UFSR_UNALIGNED] = "发生用法错误,原因:企图执行非对齐访问",
[PRINT_UFSR_DIVBYZERO0] = "发生用法错误,原因:企图执行除 0 操作",
[PRINT_DFSR_HALTED] = "发生调试错误原因NVIC 停机请求",
[PRINT_DFSR_BKPT] = "发生调试错误,原因:执行 BKPT 指令",
[PRINT_DFSR_DWTTRAP] = "发生调试错误,原因:数据监测点匹配",
[PRINT_DFSR_VCATCH] = "发生调试错误,原因:发生向量捕获",
[PRINT_DFSR_EXTERNAL] = "发生调试错误,原因:外部调试请求",
[PRINT_MMAR] = "发生存储器管理错误的地址:%08x",
[PRINT_BFAR] = "发生总线错误的地址:%08x",
#include "Languages/zh-CN/cmb_zh_CN.h"
#elif (CMB_PRINT_LANGUAGE == CMB_PRINT_LANGUAGE_CHINESE_UTF8)
#include "Languages/zh-CN/cmb_zh_CN_UTF8.h"
#else
#error "CMB_PRINT_LANGUAGE defined error in 'cmb_cfg.h'"
#endif
@ -199,7 +130,8 @@ static bool on_fault = false;
static bool stack_is_overflow = false;
static struct cmb_hard_fault_regs regs;
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
static bool statck_has_fpu_regs = false;
#endif
@ -213,7 +145,7 @@ void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, cons
strncpy(hw_ver, hardware_ver, CMB_NAME_MAX);
strncpy(sw_ver, software_ver, CMB_NAME_MAX);
#if defined(__CC_ARM)
#if defined(__CC_ARM) || defined(__CLANG_ARM)
main_stack_start_addr = (uint32_t)&CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
main_stack_size = (uint32_t)&CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME) - main_stack_start_addr;
code_start_addr = (uint32_t)&CODE_SECTION_START(CMB_CODE_SECTION_NAME);
@ -408,7 +340,7 @@ size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp) {
}
/* fix the PC address in thumb mode */
pc = *((uint32_t *) sp) - 1;
if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
if ((pc >= code_start_addr + sizeof(size_t)) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
/* check the the instruction before PC address is 'BL' or 'BLX' */
&& disassembly_ins_is_bl_blx(pc - sizeof(size_t)) && (depth < size)) {
/* the second depth function may be already saved, so need ignore repeat */
@ -434,7 +366,7 @@ static void print_call_stack(uint32_t sp) {
cur_depth = cm_backtrace_call_stack(call_stack_buf, CMB_CALL_STACK_MAX_DEPTH, sp);
for (i = 0; i < cur_depth; i++) {
sprintf(call_stack_info + i * (8 + 1), "%08lx", call_stack_buf[i]);
sprintf(call_stack_info + i * (8 + 1), "%08lx", (unsigned long)call_stack_buf[i]);
call_stack_info[i * (8 + 1) + 8] = ' ';
}
@ -518,7 +450,8 @@ static void fault_diagnosis(void) {
cmb_println(print_info[PRINT_MFSR_MSTKERR]);
}
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
if (regs.mfsr.bits.MLSPERR) {
cmb_println(print_info[PRINT_MFSR_MLSPERR]);
}
@ -548,7 +481,8 @@ static void fault_diagnosis(void) {
cmb_println(print_info[PRINT_BFSR_STKERR]);
}
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
if (regs.bfsr.bits.LSPERR) {
cmb_println(print_info[PRINT_BFSR_LSPERR]);
}
@ -575,6 +509,11 @@ static void fault_diagnosis(void) {
if (regs.ufsr.bits.NOCP) {
cmb_println(print_info[PRINT_UFSR_NOCP]);
}
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
if (regs.ufsr.bits.STKOF) {
cmb_println(print_info[PRINT_UFSR_STKOF]);
}
#endif
if (regs.ufsr.bits.UNALIGNED) {
cmb_println(print_info[PRINT_UFSR_UNALIGNED]);
}
@ -606,7 +545,8 @@ static void fault_diagnosis(void) {
}
#endif /* (CMB_CPU_PLATFORM_TYPE != CMB_CPU_ARM_CORTEX_M0) */
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
static uint32_t statck_del_fpu_regs(uint32_t fault_handler_lr, uint32_t sp) {
statck_has_fpu_regs = (fault_handler_lr & (1UL << 4)) == 0 ? true : false;
@ -662,7 +602,8 @@ void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp) {
/* delete saved R0~R3, R12, LR,PC,xPSR registers space */
stack_pointer += sizeof(size_t) * 8;
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) || \
(CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
stack_pointer = statck_del_fpu_regs(fault_handler_lr, stack_pointer);
#endif /* (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) */

@ -31,10 +31,18 @@
#include "cmb_def.h"
#ifdef __cplusplus
extern "C" {
#endif
void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver);
void cm_backtrace_firmware_info(void);
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp);
void cm_backtrace_assert(uint32_t sp);
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp);
#ifdef __cplusplus
}
#endif
#endif /* _CORTEXM_BACKTRACE_H_ */

@ -36,31 +36,33 @@
/* library software version number */
#define CMB_SW_VERSION "1.4.0"
#define CMB_CPU_ARM_CORTEX_M0 0
#define CMB_CPU_ARM_CORTEX_M3 1
#define CMB_CPU_ARM_CORTEX_M4 2
#define CMB_CPU_ARM_CORTEX_M7 3
#define CMB_CPU_ARM_CORTEX_M0 0
#define CMB_CPU_ARM_CORTEX_M3 1
#define CMB_CPU_ARM_CORTEX_M4 2
#define CMB_CPU_ARM_CORTEX_M7 3
#define CMB_CPU_ARM_CORTEX_M33 4
#define CMB_OS_PLATFORM_RTT 0
#define CMB_OS_PLATFORM_UCOSII 1
#define CMB_OS_PLATFORM_UCOSIII 2
#define CMB_OS_PLATFORM_FREERTOS 3
#define CMB_OS_PLATFORM_RTT 0
#define CMB_OS_PLATFORM_UCOSII 1
#define CMB_OS_PLATFORM_UCOSIII 2
#define CMB_OS_PLATFORM_FREERTOS 3
#define CMB_PRINT_LANGUAGE_ENGLISH 0
#define CMB_PRINT_LANGUAGE_CHINESE 1
#define CMB_PRINT_LANGUAGE_ENGLISH 0
#define CMB_PRINT_LANGUAGE_CHINESE 1
#define CMB_PRINT_LANGUAGE_CHINESE_UTF8 2
/* name max length, default size: 32 */
#ifndef CMB_NAME_MAX
#define CMB_NAME_MAX 32
#define CMB_NAME_MAX 32
#endif
/* print information language, default is English */
#ifndef CMB_PRINT_LANGUAGE
#define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH
#define CMB_PRINT_LANGUAGE CMB_PRINT_LANGUAGE_ENGLISH
#endif
#if defined(__CC_ARM)
#if defined(__CC_ARM) || defined(__CLANG_ARM)
/* C stack block name, default is STACK */
#ifndef CMB_CSTACK_BLOCK_NAME
#define CMB_CSTACK_BLOCK_NAME STACK
@ -164,9 +166,15 @@ struct cmb_hard_fault_regs{
union {
unsigned int value;
struct {
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int IPSR : 9; // Interrupt Program Status register (IPSR)
unsigned int EPSR : 18; // Execution Program Status register (EPSR)
unsigned int APSR : 5; // Application Program Status register (APSR)
#else
unsigned int IPSR : 8; // Interrupt Program Status register (IPSR)
unsigned int EPSR : 19; // Execution Program Status register (EPSR)
unsigned int APSR : 5; // Application Program Status register (APSR)
#endif
} bits;
} psr; // Program status register.
} saved;
@ -176,9 +184,19 @@ struct cmb_hard_fault_regs{
struct {
unsigned int MEMFAULTACT : 1; // Read as 1 if memory management fault is active
unsigned int BUSFAULTACT : 1; // Read as 1 if bus fault exception is active
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int HARDFAULTACT : 1; // Read as 1 if hardfault is active
#else
unsigned int UnusedBits1 : 1;
#endif
unsigned int USGFAULTACT : 1; // Read as 1 if usage fault exception is active
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int SECUREFAULTACT : 1; // Read as 1 if secure fault exception is active
unsigned int NMIACT : 1; // Read as 1 if NMI exception is active
unsigned int UnusedBits2 : 1;
#else
unsigned int UnusedBits2 : 3;
#endif
unsigned int SVCALLACT : 1; // Read as 1 if SVC exception is active
unsigned int MONITORACT : 1; // Read as 1 if debug monitor exception is active
unsigned int UnusedBits3 : 1;
@ -191,6 +209,13 @@ struct cmb_hard_fault_regs{
unsigned int MEMFAULTENA : 1; // Memory management fault handler enable
unsigned int BUSFAULTENA : 1; // Bus fault handler enable
unsigned int USGFAULTENA : 1; // Usage fault handler enable
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned int SECUREFAULTENA : 1; // Secure fault handler enable
unsigned int SECUREFAULTPENDED : 1; // Secure fault pended; Secure fault handler was started but was replaced by a higher-priority exception
unsigned int HARDFAULTPENDED : 1; // Hard fault pended; Hard fault handler was started but was replaced by a higher-priority exception
#else
// None
#endif
} bits;
} syshndctrl; // System Handler Control and State Register (0xE000ED24)
@ -231,7 +256,12 @@ struct cmb_hard_fault_regs{
unsigned short INVSTATE : 1; // Attempts to switch to an invalid state (e.g., ARM)
unsigned short INVPC : 1; // Attempts to do an exception with a bad value in the EXC_RETURN number
unsigned short NOCP : 1; // Attempts to execute a coprocessor instruction
#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M33)
unsigned short STKOF : 1; // Indicates a stack overflow error has occured
unsigned short UnusedBits : 3;
#else
unsigned short UnusedBits : 4;
#endif
unsigned short UNALIGNED : 1; // Indicates that an unaligned access fault has taken place
unsigned short DIVBYZERO0 : 1; // Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set)
} bits;
@ -271,7 +301,7 @@ if (!(EXPR)) \
}
/* ELF(Executable and Linking Format) file extension name for each compiler */
#if defined(__CC_ARM)
#if defined(__CC_ARM) || defined(__CLANG_ARM)
#define CMB_ELF_FILE_EXTENSION_NAME ".axf"
#elif defined(__ICCARM__)
#define CMB_ELF_FILE_EXTENSION_NAME ".out"
@ -325,6 +355,22 @@ if (!(EXPR)) \
mov r0, sp
bx lr
}
#elif defined(__CLANG_ARM)
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_msp(void) {
uint32_t result;
__asm volatile ("mrs %0, msp" : "=r" (result) );
return (result);
}
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_psp(void) {
uint32_t result;
__asm volatile ("mrs %0, psp" : "=r" (result) );
return (result);
}
__attribute__( (always_inline) ) static __inline uint32_t cmb_get_sp(void) {
uint32_t result;
__asm volatile ("mov %0, sp" : "=r" (result) );
return (result);
}
#elif defined(__ICCARM__)
/* IAR iccarm specific functions */
/* Close Raw Asm Code Warning */

Loading…
Cancel
Save