当前位置:网站首页>Skillfully use stack backtracking to help you quickly locate problems
Skillfully use stack backtracking to help you quickly locate problems
2022-07-28 03:49:00 【China Mobile oneos】
During system operation or debugging , There are always some unexpected phenomena in the program ( For example, the program is abnormal or a task is not running as expected ). To help users quickly locate problems , Reduce problems that are difficult to locate , Operating system Of Stack backtracking function It's very important .
What is stack backtracking ? How to use it ? Now let's have a detailed look !( Learned the trick , What are you afraid of when you encounter problems that are difficult to locate in the future ?)
One 、 Stack and stack backtracking
1.1 Function of stack
1) Transfer function parameters : For speed , Use CPU Register transfer parameters . This will encounter a problem ,CPU The number of registers is limited , When the function parameters exceed the agreed CPU When the number of registers , Then use the stack to store the remaining parameters , To transfer function parameters .
2) Save local variable : Local variables must be used in functions , Instead of always using global variables .
3) Context of function call : To ensure that the function can return correctly after calling , You need to save the register and return address when the function is called .
4) Context of task switching : When task switching occurs , You need to save the task context , Ensure the normal operation of the program when switching back to the task .
5) Context when interrupt occurs : In the event of an interruption , To ensure correct return , You need to save the current context .
1.2 The basic function of stack backtracking
From the function of the stack, we can see that the return address of the function is stored in the stack , We can recognize these return addresses by the firm rules of the compiler or the special instructions of the program . From these return addresses, we can determine the calling relationship of the function 、 Call to order . We can check the current context through stack backtracking . Stack backtracking is mainly applicable to the following scenarios :
1) In exception 、 Interrupt and task context view task stack backtracking ;
2) If the exception occurs in the interrupt context, you can also backtrace the interrupt stack ;
3) For running tasks, stack backtracking is not only supported for other tasks, but also for itself ;
4) View the interrupt stack backtrace in the interrupt context .
1.3 Support architecture
OneOS At present, we support ARM v6m,v7m,v8m All boards and RISC-V Some boards .
Two 、 Usage method
2.1 Usage method 1- Function call
OneOS The following interfaces are mainly provided for applications :
Interface | explain |
task_stack_show | Display task stack backtracking information |
interrupt_stack_show | Display interrupt stack backtracking information |
os_err_t task_stack_show(os_task_t *task, os_uint32_t context);Parameters | explain |
task | Task control block |
context | 1: Exception context 0: Other contexts (1 Reserved for system use 0: Applications use in interrupt and task contexts ) |
return | explain |
OS_ERROR | Task name is empty , Failure is returned when there is no such task in the system |
OS_EOK | success |
interrupt_stack_show
This function is used to display interrupt stack backtracking information , The prototype is as follows :
os_err_t interrupt_stack_show(void);Parameters | explain |
nothing | nothing |
return | explain |
OS_ERROR | Task name is empty , Failure is returned when there is no such task in the system |
OS_EOK | success |
2.2 Usage method 2-shell command
command | explain |
show_task_stack | Display task stack backtracking information |
show_task_stack
This command supports the display of task stack backtracking information through task name or task handle , The corresponding function prototype is as follows :
static os_err_t sh_task_stack_show(os_int32_t argc, char **argv);Parameters | explain |
argc | Number of parameters |
argv | Parameter values , Command format :show_task_stack task_name/show_task_stack tcb |
return | explain |
OS_ERROR | Task name is empty , The task corresponding to the task name is a system task or the task handle is not found in the system |
OS_EOK | success |
2.3 configuration option
OneOS When using stack backtracking, it provides the configuration of functions and tailoring , The specific configuration is shown in the figure below :
(Top) → Components→ Diagnose OneOS Configuration[*] Stack back trace enable[ ] back trace dump stack(256) The stack overflow back trace size(10) The stack back trace max depth[ ] Monitor CPU usage[ ] Enable wireshark dump eCoreDump ---> Memory Monitor --->Configuration item | explain |
Stack back trace enable | Enable stack backtracking |
back trace dump stack | Stack backtracking displays all the contents of the corresponding stack |
The stack overflow back trace size | Space for additional stack backtracking in case of stack overflow |
The stack back trace max depth | Maximum stack backtrace depth |
3、 ... and 、 Examples of actual usage scenarios
3.1 stay shell Use in
We can shell Use in show_task_stack Get the stack backtrace of a task .show_task_stack The command takes an argument , It can be task name , It can also be a task handle .
STARTUP: OneOS start, version:OneOS-V2.3.0sh>show_taskTask Task ID Priority State Stack top Stack addr Stack size Max used Left tick--------------- ------------ -------- -------------------- ---------- ---------- ---------- -------- ---------timer 0x20001700 0 Suspend 0x20001684 0x20001500 512 24% 10 recycle 0x20001488 0 Suspend 0x20001434 0x20001288 512 16% 10 idle 0x200010e8 31 Ready 0x200010a4 0x20000ce8 1024 6% 8 main 0x20003d04 0 Sleep 0x20003c84 0x200034f8 2048 22% 5 sys_work 0x20002114 8 Block 0x200020a4 0x20001908 2048 4% 10 tshell 0x200029c0 20 Running 0x200028c8 0x200021c0 2048 26% 3 user 0x20004bac 3 Sleep 0x20004b4c 0x200049a0 512 16% 10 sh>sh>show_task_stack user=================Task user stack trace======================R0 : 0x00000000R1 : 0x20000234R2 : 0x20000cb0R3 : 0x00000000R4 : 0x20004bacR5 : 0x00000064R6 : 0x00000000R7 : 0xdeadbeefR8 : 0xdeadbeefR9 : 0xdeadbeefR10: 0xdeadbeefR11: 0xdeadbeefR12: 0x00000000LR : 0x08011505PC : 0x08011504PSR: 0x61000000You can use follow command for backtrace:addr2line -e *.axf/*.elf -a -f 0x08011504 0x080184a8 sh>3.2 Use... In an application
From above API It can be seen from the interface description , We can directly call the function to check the task stack backtracking , See the above directly for details API describe .
3.3 Automatically trigger after program exception
The data in front of the following code represents the code line number ,fun_b() Deliberately call an empty function , An exception occurred in the program while executing an empty function .
#include <board.h> #include <os_task.h> static void user_task(void *parameter) { while (1) { os_task_tsleep(100); } } void fun_b(void) { ((void (*)())0)(); } void fun_a(void) { fun_b(); } int main(void) { os_task_t *task; task = os_task_create("user", user_task, NULL, 512, 3); OS_ASSERT(task); os_task_startup(task); os_task_tsleep(1000); fun_a(); return 0; }When the program is executed to fun_b() after , In the case of enabling stack backtracking, the program will automatically print stack backtracking information :
STARTUP: OneOS start, version:OneOS-V2.3.0sh>Hard fault in task: mainR0 : 0x00000000R1 : 0x20000234R2 : 0x20000cd0R3 : 0x08006f65R4 : 0x20004bacR5 : 0x00000000R6 : 0xdeadbeefR7 : 0xdeadbeefR8 : 0xdeadbeefR9 : 0xdeadbeefR10: 0xdeadbeefR11: 0xdeadbeefR12: 0x00000000LR : 0x0800a8d3PC : 0x00000000PSR: 0x60000000usage fault:SCB_CFSR_UFSR: 0x02INVSTATEYou can user follow command for backtrace:addr2line -e *.axf/*.elf -a -f 0x00000000 0x0800a8d2 0x0800a8ca 0x0800b2dc 0x0800699c Four 、 Parsing stack backtracking information
First of all, I need to explain , What is saved in the stack is the return address of the function , The address printed by stack backtracking and the execution code are shifted backward by an instruction . After the operating system prints out the stack backtracking information , We can combine compiler related tools to parse , Next, stack backtracking triggered by exceptions (addr2line -e .axf/.elf -a -f 0x00000000 0x0800a8d2 0x0800a8ca 0x0800b2dc 0x0800699c) Give an example to illustrate how to parse stack backtracking information .
4.1 adopt addr2line Parsing stack backtracking information
Use cmd Switch to OneOS-Cube Of addr2line Under the path of tools , At the same time, the project generated axf File or elf Copy the file to this path ( Here to axf File as an example ), perform arm-none-eabi-addr2line -e *.axf -a -f 0x00000000 0x0800a8d2 0x0800a8ca 0x0800b2dc 0x0800699c
D:\Program Files\OneOS-Cube-V1.3.7\components\mingw\bin>arm-none-eabi-addr2line -e oneos.axf -a -f 0x00000000 0x0800a8d2 0x0800a8ca 0x0800b2dc 0x0800699c0x00000000????:00x0800a8d2fun_bC:\OneOS\templates\stm32f411-ret6-nucleo/application\main.c:380x0800a8cafun_aC:\OneOS\templates\stm32f411-ret6-nucleo/application\main.c:430x0800b2dcmainC:\OneOS\templates\stm32f411-ret6-nucleo/application\main.c:550x0800699c_k_main_task_entryC:\OneOS\templates\stm32f411-ret6-nucleo/..\..\kernel\source\/os_startup.c:190D:\Program Files\OneOS-Cube-V1.3.7\components\mingw\bin>The result of parsing is os_startup.c:190->main.c:55->main.c:43->main.c:38, This doesn't seem to be our actual code logic . This uses the return address stored in the stack described above. We need to look forward , In this way, I get os_startup.c:189->main.c:54(main)->main.c:42(fun_a)->main.c:37(fun_b)
4.2 MDK Development tools use formelf Parsing stack backtracking information
Use cmd Switch to MDK Of formelf Under the path of tools , At the same time, the project generated axf File or elf Copy the file to this path ( Here to axf File as an example ), perform fromelf --text -a -c --output=oneos.txt oneos.axf Generate oneos.txt( Disassembly file ), from oneos.txt View the function address in (0x0800a8d2 0x0800a8ca 0x0800b2dc 0x0800699c) The previous assembly instruction , So as to get our abnormal scene (0x08006998_k_main_task_entry()->0x0800b2d8($Super$$main)->0x0800a8c6(fun_a)->0x0800a8d0(fun_b)).
i.fun_a fun_a 0x0800a8c4: b510 .. PUSH {r4,lr} 0x0800a8c6: f000f801 .... BL fun_b ; 0x800a8cc 0x0800a8ca: bd10 .. POP {r4,pc} i.fun_b fun_b 0x0800a8cc: b510 .. PUSH {r4,lr} 0x0800a8ce: 2000 . MOVS r0,#0 0x0800a8d0: 4780 .G BLX r0 0x0800a8d2: bd10 .. POP {r4,pc} $Super$$main 0x0800b298: b538 8. PUSH {r3-r5,lr} 0x0800b29a: 2003 . MOVS r0,#3 0x0800b29c: f44f7300 O..s MOV r3,#0x200 0x0800b2a0: 2200 ." MOVS r2,#0 0x0800b2a2: 490f .I LDR r1,[pc,#60] ; [0x800b2e0] = 0x80184a1 0x0800b2a4: 9000 .. STR r0,[sp,#0] 0x0800b2a6: a00f .. ADR r0,{pc}+0x3e ; 0x800b2e4 0x0800b2a8: f005fb42 ..B. BL os_task_create ; 0x8010930 0x0800b2ac: 4604 .F MOV r4,r0 0x0800b2ae: bf00 .. NOP 0x0800b2b0: b954 T. CBNZ r4,0x800b2c8 ; $Super$$main + 48 0x0800b2b2: 2332 2# MOVS r3,#0x32 0x0800b2b4: 4a0d .J LDR r2,[pc,#52] ; [0x800b2ec] = 0x80184e2 0x0800b2b6: a10e .. ADR r1,{pc}+0x3a ; 0x800b2f0 0x0800b2b8: a00f .. ADR r0,{pc}+0x40 ; 0x800b2f8 0x0800b2ba: f002fddd .... BL os_kprintf ; 0x800de78 0x0800b2be: bf00 .. NOP 0x0800b2c0: f7f5f92b ..+. BL os_irq_disable ; 0x800051a 0x0800b2c4: bf00 .. NOP 0x0800b2c6: e7fe .. B 0x800b2c6 ; $Super$$main + 46 0x0800b2c8: bf00 .. NOP 0x0800b2ca: 4620 F MOV r0,r4 0x0800b2cc: f005ffa6 .... BL os_task_startup ; 0x801121c 0x0800b2d0: f44f707a O.zp MOV r0,#0x3e8 0x0800b2d4: f006f874 ..t. BL os_task_tsleep ; 0x80113c0 0x0800b2d8: f7fffaf4 .... BL fun_a ; 0x800a8c4 0x0800b2dc: 2000 . MOVS r0,#0 0x0800b2de: bd38 8. POP {r3-r5,pc} _k_main_task_entry 0x0800696c: b570 p. PUSH {r4-r6,lr} 0x0800696e: 4605 .F MOV r5,r0 0x08006970: f000f8e4 .... BL _k_other_auto_init ; 0x8006b3c 0x08006974: 4604 .F MOV r4,r0 0x08006976: b154 T. CBZ r4,0x800698e ; _k_main_task_entry + 34 0x08006978: bf00 .. NOP 0x0800697a: 22ad ." MOVS r2,#0xad 0x0800697c: 4908 .I LDR r1,[pc,#32] ; [0x80069a0] = 0x8019adf 0x0800697e: 4809 .H LDR r0,[pc,#36] ; [0x80069a4] = 0x801b150 0x08006980: f007fa7a ..z. BL os_kprintf ; 0x800de78 0x08006984: bf00 .. NOP 0x08006986: f7f9fdc8 .... BL os_irq_disable ; 0x800051a 0x0800698a: bf00 .. NOP 0x0800698c: e7fe .. B 0x800698c ; _k_main_task_entry + 32 0x0800698e: a206 .. ADR r2,{pc}+0x1a ; 0x80069a8 0x08006990: a109 .. ADR r1,{pc}+0x28 ; 0x80069b8 0x08006992: a00b .. ADR r0,{pc}+0x2e ; 0x80069c0 0x08006994: f007fa70 ..p. BL os_kprintf ; 0x800de78 0x08006998: f004fc7e ..~. BL $Super$$main ; 0x800b298 0x0800699c: bd70 p. POP {r4-r6,pc}4.3 Use the compiler's corresponding objdump Parsing stack backtracking information
Use cmd Switch to OneOS-Cube Of objdump Under the path of tools , At the same time, the project generated axf File or elf Copy the file to this path ( Here to axf File as an example ), perform arm-none-eabi-objdump -C -x -S oneos.axf > oneos.txt Generate oneos.txt( Disassembly file ), from oneos.txt View the function address in (0x0800a8d2 0x0800a8ca 0x0800b2dc 0x0800699c) The previous assembly instruction , So as to get our abnormal scene (0x08006998_k_main_task_entry()->0x0800b2d8(libc_system_init(gcc analysis mdk The difference caused ))->0x0800a8c6(fun_a)->0x0800a8d0(fun_b)).
void fun_a(void){ 800a8c4: b510 push {r4, lr} fun_b(); 800a8c6: f000 f801 bl 800a8cc <fun_b>} 800a8ca: bd10 pop {r4, pc}0800a8cc <fun_b>: os_task_tsleep(100); }}void fun_b(void){ 800a8cc: b510 push {r4, lr} ((void (*)())0)(); 800a8ce: 2000 movs r0, #0 800a8d0: 4780 blx r0} 800a8d2: bd10 pop {r4, pc}int main(void){ 800b298: b538 push {r3, r4, r5, lr} os_task_t *task; task = os_task_create("user", user_task, NULL, 512, 3); 800b29a: 2003 movs r0, #3 800b29c: f44f 7300 mov.w r3, #512 ; 0x200 800b2a0: 2200 movs r2, #0 800b2a2: 490f ldr r1, [pc, #60] ; (800b2e0 <libc_system_init+0x4e>) 800b2a4: 9000 str r0, [sp, #0] 800b2a6: a00f add r0, pc, #60 ; (adr r0, 800b2e4 <libc_system_init+0x52>) 800b2a8: f005 fb42 bl 8010930 <os_task_create> 800b2ac: 4604 mov r4, r0 OS_ASSERT(task); 800b2ae: bf00 nop 800b2b0: b954 cbnz r4, 800b2c8 <libc_system_init+0x36> 800b2b2: 2332 movs r3, #50 ; 0x32 800b2b4: 4a0d ldr r2, [pc, #52] ; (800b2ec <libc_system_init+0x5a>) 800b2b6: a10e add r1, pc, #56 ; (adr r1, 800b2f0 <libc_system_init+0x5e>) 800b2b8: a00f add r0, pc, #60 ; (adr r0, 800b2f8 <libc_system_init+0x66>) 800b2ba: f002 fddd bl 800de78 <os_kprintf> 800b2be: bf00 nop 800b2c0: f7f5 f92b bl 800051a <os_irq_disable> 800b2c4: bf00 nop 800b2c6: e7fe b.n 800b2c6 <libc_system_init+0x34> 800b2c8: bf00 nop os_task_startup(task); 800b2ca: 4620 mov r0, r4 800b2cc: f005 ffa6 bl 801121c <os_task_startup> os_task_tsleep(1000); 800b2d0: f44f 707a mov.w r0, #1000 ; 0x3e8 800b2d4: f006 f874 bl 80113c0 <os_task_tsleep> fun_a(); 800b2d8: f7ff faf4 bl 800a8c4 <fun_a> return 0; 800b2dc: 2000 movs r0, #0}static void _k_main_task_entry(void *arg){ 800696c: b570 push {r4, r5, r6, lr} 800696e: 4605 mov r5, r0 os_err_t ret; OS_UNREFERENCE(arg); /* Auto initialization for pre/device/component/env/app */ ret = _k_other_auto_init(); 8006970: f000 f8e4 bl 8006b3c <_k_other_auto_init> 8006974: 4604 mov r4, r0 if (OS_EOK != ret) 8006976: b154 cbz r4, 800698e <_k_main_task_entry+0x22> { OS_ASSERT_EX(0, "Automatic initialization after kernel startup failed"); 8006978: bf00 nop 800697a: 22ad movs r2, #173 ; 0xad 800697c: 4908 ldr r1, [pc, #32] ; (80069a0 <_k_main_task_entry+0x34>) 800697e: 4809 ldr r0, [pc, #36] ; (80069a4 <_k_main_task_entry+0x38>) 8006980: f007 fa7a bl 800de78 <os_kprintf> 8006984: bf00 nop 8006986: f7f9 fdc8 bl 800051a <os_irq_disable> 800698a: bf00 nop 800698c: e7fe b.n 800698c <_k_main_task_entry+0x20> }#ifdef OS_USING_KERNEL_DEBUG os_kprintf("%s: OneOS start, version:%s", STARTUP_TAG, ONEOS_VERSION); 800698e: a206 add r2, pc, #24 ; (adr r2, 80069a8 <_k_main_task_entry+0x3c>) 8006990: a109 add r1, pc, #36 ; (adr r1, 80069b8 <_k_main_task_entry+0x4c>) 8006992: a00b add r0, pc, #44 ; (adr r0, 80069c0 <_k_main_task_entry+0x54>) 8006994: f007 fa70 bl 800de78 <os_kprintf>#endif/* Invoke system main function */#if defined(__CC_ARM) || defined(__CLANG_ARM) extern int $Super$$main(void); $Super$$main(); 8006998: f004 fc7e bl 800b298 <libc_system_init+0x6> extern int main(void); main();#endif return;} 800699c: bd70 pop {r4, r5, r6, pc}The above is the sharing about stack backtracking ~ If you have any questions, welcome to exchange and discuss in the comment area
边栏推荐
- Protocols in swift
- How to solve MySQL deep paging problem
- Move notice!
- 高等数学(第七版)同济大学 习题3-4 个人解答(前8题)
- AI chief architect 12 AICA Baidu OCR vertical large-scale landing practice
- C language: find the number of 1 in binary stored in memory as an integer
- 接口自动化测试,完整入门篇
- 95后阿里P7晒出工资单:真的是狠狠扎心了...
- 高等数学(第七版)同济大学 习题3-5 个人解答
- ES6 from getting started to mastering 08: extended object functions
猜你喜欢

4-day excel practical training camp, 0.01 yuan special offer for only three days, 200 sets of learning kits

How to solve MySQL deep paging problem

Leetcode skimming: dynamic programming 08 (segmentation and subsets)

Build an "industrial brain" and improve the park's operation, management and service capabilities with "digitalization"!

Simple and easy-to-use performance testing tools recommended

LeetCode 0141. 环形链表 - 三种方法解决

An article grasps the calculation and processing of date data in PostgreSQL

Xctf attack and defense world web master advanced area php2

TypeError: ufunc ‘bitwise_ and‘ not supported for the input types, and the inputs could not be safely

Leetcode58. Length of the last word
随机推荐
【LeetCode】34、在排序数组中查找元素的第一个和最后一个位置
Data mining-01
Mouse operation and response
Unity backpack system
Greed 122. The best time to buy and sell stocks II
[openvx] VX for basic use of objects_ image
input 上传文件并回显 FileReader并限制选择文件时的类型
超好用的 PC 端长截图工具
WordPress简约mkBlog博客主题模板v2.1
Common weak network testing tools
Dynamic programming - 509. Fibonacci number
Dynamic planning - 1049. Weight of the last stone II
[openvx] VX for basic use of objects_ convolution
Monotonic stack - 739. Daily temperature
ES6 from getting started to mastering 08: extended object functions
我的创作纪念日
基于SSM实现在线租房系统
[openvx] VX for basic use of objects_ lut
Common interface testing tools
LeetCode_ 409_ Longest palindrome string