In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-03 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
Today, I will talk to you about the principle and analysis of backtrace on STM32, which may not be well understood by many people. in order to make you understand better, the editor has summarized the following contents for you. I hope you can get something according to this article.
1. Description
For the development process of an embedded product, it usually goes through the following stages:
1. Scheme pre-research
two。 Product function design
3. Development and debugging
4. Factory test
5. After the product is sold online
Generally speaking, all the boards are in the hands of developers. Once bug is encountered, as long as it can be reproduced, it can basically be checked out, and then repaired or avoided. But once it has entered the stage 4 and 5, and the product has been formed, it will be more troublesome to check BUG again. For example, in the factory testing phase, it is very complicated to troubleshoot problems that may be run continuously for several days or weeks to reappear. In this case, backtrace is very necessary. We can analyze the key information of the system in the offline state, through the stack backtracking of the function, so as to find the corresponding execution function of the error, and then combined with programming, basically most of the bug can also be found. I have written an article about the analysis and implementation of backtrace on arm. The analysis situation on cortex-an is analyzed. But for cortex-m, the problem is much more complicated, because cortex-m 's size restrictions on firmware and special architecture make backtrack's solution take up too much flash. This is unacceptable to the designer, and what is even more painful is that cortex-m does not have a stack backtracking pointer. This makes the calculation of the depth of the stack very complicated. This paper mainly analyzes the stack layout of cortex-m and some underlying principles and schemes of stack backtracking.
Stack layout on 2.cortex-m
To figure out the layout of the stack on cortex-m, you must understand the mechanism and principle of pushing the stack on cortex-m. Let's talk about the more important details on cortex-m from the architecture.
2.1 registers on cortex-m
When it comes to C language functions, the problem that must be taken into account is the problem of functions entering and leaving the stack, that is, the increase or decrease of SP pointers. Let's review the registers on arm cortex-m.
According to the design of arm cortex-m, there are 32 registers.
13 general registers, r0-r122 SP used in different modes, PSP (SP_process) and MSP (SP_main) 1 link register LR (R14) 1 program counter (PC) 1 program status register (xPSR)
In different modes, there is a copy of R0-R12, SP and LR, so there are a total of 32 registers, but in different modes, the status of these 32 registers can not be fully seen, only some of them can be seen.
General register R0-R12
The picture above divides the general register into low register and high registers according to the instruction set. For thumb instructions, it is 16-bit and can only access low register, that is, R0-R7, while for 32-bit arm instructions, all instructions can be accessed. So there is such a division.
Stack pointer SP
When it comes to stacking and staging of parameters, or when returning from the execution of a function, changes in the stack pointer must be involved. In cortex-m, you should be very careful when using SP because it involves switching between two different sp.
Program link register LR
The program's link register is used when the function returns, such as another function B executed in one function A, as follows
Void fun_A ()
{
Fun_B ()
}
Then when fun_B is executed, the assembly code compiled by the compiler first automatically stores the address of the func_A on the LR stack, and then pushes in other parameters. After the func_B execution is complete, LR will be popped to PC, and it will be returned to the fun_A function for execution.
Program count register
The register automatically points to the address of the program currently pointed to.
2.2 automatic stack pressing on cortex-m
Different from other processor architectures, the positioning of cortex-m is considered for real-time and small capacity design from the very beginning, so in the interrupt processing part, we also do a very interesting design-automatic stack processing.
General CPU will press the stack after entering the interrupt, because the stack is the site of the function, which protects the stack content. When the interrupt exits, you only need to restore the stack data to the state of program execution. In the past, this stage is completed by manual operation, and on cortex-m, part of the stack is automatically pressed into the stack by hardware. The order in which they are pushed into the stack is generally as follows:
XPSR- > PC (return address)-> LR- > R12-> R3-> R2-> R1-> R0
These registers are automatically pressed into the hardware, and the efficiency should be greatly improved. Other registers can be handled manually.
2.3 function execution process on cortex-m
When analyzing the execution of the function, the main purpose is to find out what the underlying hardware registers do, which requires assembly translation. Here we use arm gcc to compile the elf firmware of cortex-m, and look at the execution of any function body through objdump.
For the assembly code of an arm function, it is basically the above execution logic. According to the instruction machine code, the corresponding instruction is obtained.
We know that when the function is executed, the machine code is stored in memory, and it is only through the objdump tool that the machine code is turned into a program. That is, when the program is executing, if you look at the 0x8004794 address at this time, the data you see is something like 80b5 84b0. So how to translate these? How exactly should the sp pointer of this function be calculated?
PUSH instruction analysis
The machine code corresponding to the PUSH instruction is as follows:
1011 010R rrrr rrrr-PUSH reg_list
According to parsing, R represents the LR register, followed by a list of R0-R7 registers. So the machine code b580 is translated into binary b1011 0101 1000 0000. The corresponding actual meaning is to press the LR and R7 registers. When PUSH is executed, the SP pointer will automatically subtract the size of the two registers, that is, 8 bytes.
SUB instruction analysis
The machine code corresponding to the SUB instruction is as follows:
1011 0000 1vvv vvvv-SUB Sp,#immed_7*4
According to the meaning, v means multiplied by 4 respectively. That is, the lowest bit is 4, the second bit is 8, the third bit is 16, the fourth bit is 32, and so on. The current machine code is translated from b084 to binary to b1011 0000 1000 0100, so the number of instants represented is 16. 0.
Combining the two, getting the current function reduces the value of the sp pointer by 16% 8% 24%.
Analysis of 3.cmbacktrace principle
When I was doing backtrace on cortex-m, I looked up some materials and found a CmBacktrace.
Https://github.com/armink/CmBacktrace
Design purpose: for ARM Cortex-M series MCU error code automatic tracking, positioning, error cause automatic analysis of the open source library.
The mechanism of its implementation is determined by using the stack-pressing property of cortex-m. When the stack address is specified, the sp pointer is offset in its own stack space. When the function is pushed into the stack, the parameters are pressed, and the lr register is also pressed. Using the value of the lr register, you can find out who called the function.
For bare metal cases, the stack address points to a
When an exception occurs in the program, you only need to know the current top of the stack and the offset of the current sp, which are easy to get in the program. Then start to facilitate the data in the stack, traversing every four bytes to get the address, the address is not necessarily a function address, may be the address of parameters, manual review of these addresses, as long as a little care can find clues. On CmBacktrace, determine whether the address is a function by determining whether the machine code of the thumb instruction in the first 2 bytes of the address is BL or bLx. This is also possible.
If you use the operating system on cortex-m, the principle is basically similar, because each thread will have its own thread stack, so there will be multiple thread stacks. To get the backtrack of the currently running thread stack, it is in principle the same as bare metal. However, if you want to analyze the backtrace of the stack of other threads, you need to pay attention to the stack pressing problem of the operating system.
For example, in rt-thread, when thread switching is made, pendsv is called to automatically stack once, and then other registers are pressed manually. If you want to do parsing, first remove the previous part of the operating system stack. Stack data in front of the rt-thread operating system
# xPSR- > PC- > LR- > R12-> R3-> R2-> R1-> R0
# R11 R10 R9 R8 R7 R6 R5 R4 FLAG
A total of 16 registers are pressed. If no processing is done, the parsed PC is rt_hw_interrupt_enable and the parsed LR is rt_schedule.
3.1 problem analysis
In the process of parsing the stack, we often involve some dirty data to destroy our analysis. For example, the address passed in the parameter is the address of the function, which may be mistaken for LR, so there is a certain risk in the analysis. Although the resolution of CmBacktrace can be done very well in most cases, it is difficult to do the analysis when the parameter is the address of the function. At this time, it may be analyzed manually. It takes a certain amount of work. So is there a better way to jump to the next LR without convenience?
According to the analysis of the function execution flow on 2.3cortex-m, we can basically calculate the stack data offset of a function, so that this problem can be solved smoothly. Each time it jumps to a fixed function, combining the contents of the current data stack to get the desired result.
4. Practical application
The above analysis is of practical value. In the case of each error, we can save the data of the stack to a specific address of the power-off non-volatile storage medium, because the size of the stack will not be very large, usually 512 bytes or 1k or 2k, etc., after the problem occurs, take out the contents of the stack, and then analyze it through external tools such as python script, combined with the corresponding elf file. You can accurately locate the backtrace of the function. Then the query for the problem will also become traceable, greatly reducing the complexity of post-debugging work.
After reading the above, do you have any further understanding of the principle and analysis of backtrace on STM32? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.