• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Exception Debugging
2
3
4## Basic Concepts
5
6The OpenHarmony LiteOS-M provides exception handling and debugging measures to help locate and analyze problems. Exception handling involves a series of actions taken by the OS to respond to exceptions occurred during the OS running, for example, printing the exception type, system status, call stack information of the current function, CPU information, and call stack information of tasks.
7
8
9## Working Principles
10
11A stack frame contains information such as function parameters, variables, and return value in a function call process. When a function is called, a stack frame of the subfunction is created, and the input parameters, local variables, and registers of the function are stored into the stack. Stack frames grow towards lower addresses. The ARM32 CPU architecture is used as an example. Each stack frame stores the historical values of the program counter (PC), link register (LR), stack pointer (SP), and frame pointer (FP) registers. The LR points to the return address of a function, and the FP points to the start address of the stack frame of the function's parent function. The FP helps locate the parent function's stack frame, which further helps locate the parent function's FP. The parent function's FP helps locate the grandparent function's stack frame and FP... In this way, the call stack of the program can be traced to obtain the relationship between the functions called.
12
13When an exception occurs in the system, the system prints the register information in the stack frame of the abnormal function as well as the LRs and FPs in the stack frames of its parent function and grandfather function. The relationships between the functions help you locate the cause of the exception.
14
15The following figure illustrates the stack analysis mechanism for your reference. The actual stack information varies depending on the CPU architecture.
16
17**Figure 1** Stack analysis mechanism
18
19![](figures/stack-analysis-mechanism.png "stack-analysis-mechanism")
20
21In the figure, the registers in different colors indicate different functions. The registers save related data when functions are called. The FP register helps track the stack to the parent function of the abnormal function and further presents the relationships between the functions called.
22
23
24## Available APIs
25
26The following table describes APIs available for the OpenHarmony LiteOS-M stack trace module. For more details about the APIs, see the API reference.
27
28  **Table 1** APIs of the stack trace module
29
30| Category| API|
31| -------- | -------- |
32| Stack tracing| **LOS_BackTrace**: prints the call stack relationship at the calling point.<br>**LOS_RecordLR**: obtains the call stack relationship at the calling point when print is unavailable.|
33
34
35## Development Guidelines
36
37
38### How to Develop
39
40The typical process for enabling exception debugging is as follows:
41
421. Configure the macros related to exception handling
43     in the **target_config.h** file.
44     | Configuration Item| Description| Value|
45   | -------- | -------- | -------- |
46   | LOSCFG_BACKTRACE_DEPTH | Depth of the function call stack. The default value is **15**.| 15 |
47   | LOSCFG_BACKTRACE_TYPE | Type of the stack tracing.<br>**0**: The stack tracing is disabled.<br>**1**: supports call stack analysis of the Cortex-M series hardware.<br>**2**: supports call stack analysis of the RISC-V series hardware.| Set this parameter to **1** or **2** based on the toolchain type.|
48
491. Use the error code in the example to build and run a project, and check the error information displayed on the serial port terminal. The sample code simulates error code. During actual product development, use the exception debugging mechanism to locate exceptions.
50     The following example demonstrates the exception output through a task. The task entry function simulates calling of multiple functions and finally calls a function that simulates an exception. The sample code is as follows:
51
52   The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **ExampleExcEntry** function is called in **TestTaskEntry**.
53
54   ```
55   #include <stdio.h>
56   #include "los_config.h"
57   #include "los_interrupt.h"
58   #include "los_task.h"
59
60   UINT32 g_taskExcId;
61   #define TSK_PRIOR 4
62
63   /* Simulate an exception. */
64   UINT32 GetResultException0(UINT16 dividend){
65       UINT32 result = *(UINT32 *)(0xffffffff);
66       printf("Enter GetResultException0. %u\r\n", result);
67       return result;
68   }
69
70   UINT32 GetResultException1(UINT16 dividend){
71       printf("Enter GetResultException1.\r\n");
72       return GetResultException0(dividend);
73   }
74
75   UINT32 GetResultException2(UINT16 dividend){
76       printf("Enter GetResultException2.\r\n");
77       return GetResultException1(dividend);
78   }
79
80   UINT32 ExampleExc(VOID)
81   {
82       UINT32 ret;
83
84       printf("Enter Example_Exc Handler.\r\n");
85
86       /* Simulate the triggering of the exception. */
87       ret = GetResultException2(TSK_PRIOR);
88       printf("Divided result =%u.\r\n", ret);
89
90       printf("Exit Example_Exc Handler.\r\n");
91       return ret;
92   }
93
94
95   /* Create a task with an exception in the task entry function. */
96   UINT32 ExampleExcEntry(VOID)
97   {
98       UINT32 ret;
99       TSK_INIT_PARAM_S initParam = { 0 };
100
101       /* Lock task scheduling to prevent newly created tasks from being scheduled prior to this task due to higher priority. */
102       LOS_TaskLock();
103
104       printf("LOS_TaskLock() Success!\r\n");
105
106       initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleExc;
107       initParam.usTaskPrio = TSK_PRIOR;
108       initParam.pcName = "Example_Exc";
109       initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
110       /* Create a task with a higher priority. The task will not be executed because task scheduling is locked. */
111       ret = LOS_TaskCreate(&g_taskExcId, &initParam);
112       if (ret != LOS_OK) {
113           LOS_TaskUnlock();
114
115           printf("Example_Exc create Failed!\r\n");
116           return LOS_NOK;
117       }
118
119       printf("Example_Exc create Success!\r\n");
120
121         /* Unlock task scheduling. The task with the highest priority in the Ready queue will be executed. */
122         LOS_TaskUnlock();
123
124         return LOS_OK;
125     }
126   ```
127
128   The error information output by the serial port terminal is as follows:
129
130   ```
131   LOS_TaskLock() Success!
132   Example_Exc create Success!
133   Enter Example_Exc Handler.
134   Enter GetResultException2.
135   Enter GetResultException1.
136   *************Exception Information**************
137   Type      = 4
138   ThrdPid   = 5
139   Phase     = exc in task
140   FaultAddr = 0xfffffffc
141   Current task info:
142   Task name = Example_Exc
143   Task ID   = 5
144   Task SP   = 0x210549bc
145   Task ST   = 0x21053a00
146   Task SS   = 0x1000
147   Exception reg dump:
148   PC        = 0x2101c61a
149   LR        = 0x2101c64d
150   SP        = 0x210549a8
151   R0        = 0x4
152   R1        = 0xa
153   R2        = 0x0
154   R3        = 0xffffffff
155   R4        = 0x2103fb20
156   R5        = 0x5050505
157   R6        = 0x6060606
158   R7        = 0x210549a8
159   R8        = 0x8080808
160   R9        = 0x9090909
161   R10       = 0x10101010
162   R11       = 0x11111111
163   R12       = 0x0
164   PriMask   = 0x0
165   xPSR      = 0x41000000
166   ----- backtrace start -----
167   backtrace 0 -- lr = 0x2101c64c
168   backtrace 1 -- lr = 0x2101c674
169   backtrace 2 -- lr = 0x2101c696
170   backtrace 3 -- lr = 0x2101b1ec
171   ----- backtrace end -----
172
173    TID  Priority   Status StackSize WaterLine StackPoint TopOfStack EventMask  SemID  CPUUSE CPUUSE10s CPUUSE1s   TaskEntry name
174    ---  -------- -------- --------- --------- ---------- ---------- --------- ------ ------- --------- --------  ---------- ----
175      0        0      Pend    0x1000      0xdc 0x2104730c 0x210463e8         0 0xffff     0.0       0.0      0.0  0x2101a199 Swt_Task
176      1       31     Ready     0x500      0x44 0x210478e4 0x21047428         0 0xffff     0.0       0.0      0.0  0x2101a9c9 IdleCore000
177      2        5  PendTime    0x6000      0xd4 0x2104e8f4 0x210489c8         0 0xffff     5.7       5.7      0.0  0x21016149 tcpip_thread
178      3        3      Pend    0x1000     0x488 0x2104f90c 0x2104e9e8       0x1 0xffff     8.6       8.6      0.0  0x21016db5 ShellTaskEntry
179      4       25     Ready    0x4000     0x460 0x21053964 0x2104f9f0         0 0xffff     9.0       8.9      0.0  0x2101c765 IT_TST_INI
180      5        4   Running    0x1000     0x458 0x210549bc 0x21053a00         0 0xffff    76.5      76.6      0.0  0x2101c685 Example_Exc
181
182   OS exception NVIC dump:
183   interrupt enable register, base address: 0xe000e100, size: 0x20
184   0x2001 0x0 0x0 0x0 0x0 0x0 0x0 0x0
185   interrupt pending register, base address: 0xe000e200, size: 0x20
186   0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
187   interrupt active register, base address: 0xe000e300, size: 0x20
188   0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
189   interrupt priority register, base address: 0xe000e400, size: 0xf0
190   0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
191   0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
192   0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
193   0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
194   interrupt exception register, base address: 0xe000ed18, size: 0xc
195   0x0 0x0 0xf0f00000
196   interrupt shcsr register, base address: 0xe000ed24, size: 0x4
197   0x70002
198   interrupt control register, base address: 0xe000ed04, size: 0x4
199   0x1000e805
200
201   memory pools check:
202   system heap memcheck over, all passed!
203   memory pool check end!
204
205   The preceding data may vary depending on the running environment.
206   ```
207
208
209### How to Locate Exceptions
210
211The procedure for locating the exception is as follows:
212
2131. Ensure that the compiler optimization is disabled. Otherwise, the following problems may be optimized during the compilation process.
214
2152. Open the image disassembly file (.asm) generated. If the file is not generated, use the objdump tool to generate it. The command is as follows:
216
217   ```
218   arm-none-eabi-objdump -S -l XXX.elf
219   ```
220
2213. Search for the PC (pointing to the instruction being executed) in the .asm file to locate the abnormal function.
222
223   The PC address directs to the instruction being executed when the exception occurs. In the .asm file corresponding to the currently executed binary file, search for the PC value **0x2101c61a** and locate the instruction being executed by the CPU. Disassemble the code as follows:
224
225   ```
226   2101c60c <GetResultException0>:
227   2101c60c:	b580      	push	{r7, lr}
228   2101c60e:	b084      	sub	sp, #16
229   2101c610:	af00      	add	r7, sp, #0
230   2101c612:	4603      	mov	r3, r0
231   2101c614:	80fb      	strh	r3, [r7, #6]
232   2101c616:	f04f 33ff 	mov.w	r3, #4294967295	; 0xffffffff
233   2101c61a:	681b      	ldr	r3, [r3, #0]
234   2101c61c:	60fb      	str	r3, [r7, #12]
235   2101c61e:	68f9      	ldr	r1, [r7, #12]
236   2101c620:	4803      	ldr	r0, [pc, #12]	; (2101c630 <GetResultException0+0x24>)
237   2101c622:	f001 f92b 	bl	2101d87c <printf>
238   2101c626:	68fb      	ldr	r3, [r7, #12]
239   2101c628:	4618      	mov	r0, r3
240   2101c62a:	3710      	adds	r7, #16
241   2101c62c:	46bd      	mov	sp, r7
242   2101c62e:	bd80      	pop	{r7, pc}
243   2101c630:	21025f90 	.word	0x21025f90
244   ```
245
246   As indicated by the information displayed:
247
248   - The CPU is executing **ldr r3, [r3, #0]** when an exception occurs. The value of **r3** is **0xffffffff**, which causes an invalid address.
249   - The exception occurs in the **GetResultException0** function.
250
2514. Search for the parent function of the abnormal function based on the LR value.
252   The code disassembly of the LR value **0x2101c64d** is as follows:
253
254   ```
255   2101c634 <GetResultException1>:
256   2101c634:	b580      	push	{r7, lr}
257   2101c636:	b082      	sub	sp, #8
258   2101c638:	af00      	add	r7, sp, #0
259   2101c63a:	4603      	mov	r3, r0
260   2101c63c:	80fb      	strh	r3, [r7, #6]
261   2101c63e:	4806      	ldr	r0, [pc, #24]	; (2101c658 <GetResultException1+0x24>)
262   2101c640:	f001 f91c 	bl	2101d87c <printf>
263   2101c644:	88fb      	ldrh	r3, [r7, #6]
264   2101c646:	4618      	mov	r0, r3
265   2101c648:	f7ff ffe0 	bl	2101c60c <GetResultException0>
266   2101c64c:	4603      	mov	r3, r0
267   2101c64e:	4618      	mov	r0, r3
268   2101c650:	3708      	adds	r7, #8
269   2101c652:	46bd      	mov	sp, r7
270   2101c654:	bd80      	pop	{r7, pc}
271   2101c656:	bf00      	nop
272   2101c658:	21025fb0 	.word	0x21025fb0
273   ```
274
275   The previous line of LR **2101c648** is **bl2101c60c <GetResultException0>**, which calls the abnormal function. The parent function is **GetResultException1**.
276
2775. Parse the LR value between **backtrace start** and **backtrace end** in the exception information to obtain the call stack relationship where the exception occurs and find the cause of the exception.