未验证 提交 d4b7def9 编写于 作者: O openharmony_ci 提交者: Gitee

!14179 [翻译完成】#I6864H

Merge pull request !14179 from Annie_wang/PR12944
......@@ -135,7 +135,7 @@
- [Magic Key](kernel-small-debug-shell-magickey.md)
- [User-Space Exception Information](kernel-small-debug-shell-error.md)
- [Trace](kernel-small-debug-trace.md)
- [Perf](kernel-mini-memory-perf.md)
- [Perf](kernel-small-debug-perf.md)
- [LMS](kernel-small-memory-lms.md)
- [Process Debugging](kernel-small-debug-process-cpu.md)
- Kernel-Mode Memory Debugging
......
# Memory Corruption Check
## Basic Concepts<a name="section17368154517335"></a>
## Basic Concepts
As an optional function of the kernel, memory corruption check is used to check the integrity of a dynamic memory pool. This mechanism can detect memory corruption errors in the memory pool in a timely manner and provide alerts. It helps reduce problem locating costs and increase troubleshooting efficiency.
## Function Configuration<a name="section4696190123420"></a>
**LOSCFG\_BASE\_MEM\_NODE\_INTEGRITY\_CHECK**: specifies the setting of the memory corruption check. This function is disabled by default. To enable this function, configure it in **Debug-\> Enable integrity check or not**.
## Function Configuration
**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** specifies the setting of the memory corruption check. This function is disabled by default. You can enable it in **Debug -> Enable integrity check or not**.
If this macro is enabled, the memory pool integrity will be checked in real time upon each memory allocation.
If this macro is not enabled, you can call **LOS\_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS\_MemIntegrityCheck** does not affect the system performance. In addition, the check accuracy decreases because the node header does not contain the magic number \(which is available only when **LOSCFG\_BASE\_MEM\_NODE\_INTEGRITY\_CHECK** is enabled\).
If this macro is not enabled, you can call **LOS_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS_MemIntegrityCheck** does not affect the system performance. However, the check accuracy decreases because the node header does not contain the magic number (which is available only when **LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** is enabled).
This check only detects the corrupted memory node and provides information about the previous node (because memory is contiguous, a node is most likely corrupted by the previous node). To further determine the location where the previous node is requested, you need to enable the memory leak check and use LRs to locate the fault.
> **CAUTION**<br/>
> If memory corruption check is enabled, a magic number is added to the node header, which increases the size of the node header. The real-time integrity check has a great impact on the performance. In performance-sensitive scenarios, you are advised to disable this function and use **LOS_MemIntegrityCheck** to check the memory pool integrity.
This check only detects the corrupted memory node and provides information about the previous node \(because memory is contiguous, a node is most likely corrupted by the previous node\). To further determine the location where the previous node is requested, you need to enable the memory leak check and use LRs to locate the fault.
## Development Guidelines
>![](../public_sys-resources/icon-caution.gif) **CAUTION:**
>If memory corruption check is enabled, a magic number is added to the node header, which increases the size of the node header. The real-time integrity check has a great impact on the performance. In performance-sensitive scenarios, you are advised to disable this function and use **LOS\_MemIntegrityCheck** to check the memory pool integrity.
## Development Guidelines<a name="section672362973417"></a>
### How to Develop
### How to Develop<a name="section026014863416"></a>
Use **LOS_MemIntegrityCheck** to check for memory corruption. If no memory corruption occurs, **0** is returned and no log is output. If memory corruption occurs, the related log is output. For details, see the output of the following example.
Check for memory corruption by calling **LOS\_MemIntegrityCheck**. If no memory corruption occurs, **0** is returned and no log is output. If memory corruption occurs, the related log is output. For details, see the output of the following example.
### Development Example<a name="section186311302356"></a>
### Development Example
This example implements the following:
1. Requests two physically adjacent memory blocks.
2. Calls **memset** to construct an out-of-bounds access and overwrites the first four bytes of the next node.
3. Calls **LOS\_MemIntegrityCheck** to check whether memory corruption occurs.
1. Request two physically adjacent memory blocks.
2. Use **memset** to construct an out-of-bounds access and overwrites the first four bytes of the next node.
3. Call **LOS_MemIntegrityCheck** to check for memory corruption.
**Sample Code**
You can add the test function of the sample code to **TestTaskEntry** in **kernel/liteos_a/testsuites/kernel/src/osTest.c** for testing.
The sample code is as follows:
```
```c
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
......@@ -44,7 +54,7 @@ The sample code is as follows:
void MemIntegrityTest(void)
{
/* Request two physically adjacent memory blocks.*/
/* Request two physically adjacent memory blocks. */
void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
/* Construct an out-of-bounds access to cause memory corruption. The memory block of the first node is 8 bytes. Clearing 12 bytes overwrites the header of the second memory node. */
......@@ -55,24 +65,26 @@ void MemIntegrityTest(void)
**Verification**
The log is as follows:
```
[ERR][OsMemMagicCheckPrint], 2028, memory check error!
memory used but magic num wrong, magic num = 0x00000000 /* Error information, indicating that the first four bytes, that is, the magic number, of the next node are corrupted.*/
memory used but magic num wrong, magic num = 0x00000000 /* Error information, indicating that the first four bytes, that is, the magic number, of the next node are corrupted. */
broken node head: 0x20003af0 0x00000000 0x80000020, prev node head: 0x20002ad4 0xabcddcba 0x80000020
/* Key information about the corrupted node and its previous node, including the address of the previous node, magic number of the node, and sizeAndFlag of the node. In this example, the magic number of the corrupted node is cleared. */
broken node head LR info: /* The node LR information can be output only after the memory leak check is enabled.*/
broken node head LR info: /* The node LR information can be output only after the memory leak check is enabled. */
LR[0]:0x0800414e
LR[1]:0x08000cc2
LR[2]:0x00000000
pre node head LR info: /* Based on the LR information, you can find where the previous node is requested in the assembly file and then perform further analysis.*/
pre node head LR info: /* Based on the LR information, you can find where the previous node is requested in the assembly file and then perform further analysis. */
LR[0]:0x08004144
LR[1]:0x08000cc2
LR[2]:0x00000000
[ERR]Memory interity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* Addresses of the corrupted node and its previous node*/
[ERR]Memory integrity check error, cur node: 0x20003b10, pre node: 0x20003af0 /* Addresses of the corrupted node and its previous node */
```
# Memory Information Statistics
## Basic Concepts<a name="section52691565235"></a>
## Basic Concepts
Memory information includes the memory pool size, memory usage, remaining memory size, maximum free memory, memory waterline, number of memory nodes, and fragmentation rate.
- Memory waterline: indicates the maximum memory used in a memory pool. The waterline value is updated upon each memory allocation and release. The memory pool size can be optimized based on this value.
- The memory waterline indicates the maximum memory used in a memory pool. The waterline value is updated each time the memory is allocated or released. The memory pool size can be optimized based on this value.
- The fragmentation rate indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
- Fragmentation rate: indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:
- You can use **LOS_MemInfoGet()** to scan the node information in the memory pool and collect the related statistics.
Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
## Function Configuration
- Other statistics: When **LOS\_MemInfoGet** is called, the node information in the memory pool is scanned and related statistics are collected.
**LOSCFG_MEM_WATERLINE** specifies the setting of the memory information statistics function. This function is disabled by default. If you want to obtain the memory waterline, enable it in **Debug-&gt; Enable MEM Debug-&gt; Enable memory pool waterline or not**.
## Function Configuration<a name="section470611682411"></a>
**LOSCFG\_MEM\_WATERLINE**: specifies the setting of the memory information statistics function. This function is disabled by default. To enable this function, configure it in **Debug-\> Enable memory pool waterline or not in the configuration item**. If you want to obtain the memory waterline, you must enable this macro.
## Development Guidelines
## Development Guidelines<a name="section9368374243"></a>
### How to Develop<a name="section679912407257"></a>
### How to Develop
Key structure:
```
```c
typedef struct {
UINT32 totalUsedSize; // Memory usage of the memory pool
UINT32 totalFreeSize; // Remaining memory in the memory pool
UINT32 maxFreeNodeSize; // Maximum size of the free memory block in the memory pool
UINT32 usedNodeNum; // Number of non-free memory blocks in the memory pool
UINT32 freeNodeNum; // Number of free memory blocks in the memory pool
#if (LOSCFG_MEM_WATERLINE == 1) // This function is disabled by default and can be enabled using the menuconfig tool.
UINT32 usageWaterLine; // Waterline of the memory pool
UINT32 totalUsedSize; // Memory usage of the memory pool.
UINT32 totalFreeSize; // Remaining size of the memory pool.
UINT32 maxFreeNodeSize; // Maximum size of the free memory block in the memory pool.
UINT32 usedNodeNum; // Number of non-free memory blocks in the memory pool.
UINT32 freeNodeNum; // Number of free memory blocks in the memory pool.
#if (LOSCFG_MEM_WATERLINE == 1) // This function is disabled by default and can be enabled using the **menuconfig** tool.
UINT32 usageWaterLine; // Waterline of the memory pool.
#endif
} LOS_MEM_POOL_STATUS;
```
- To obtain the memory waterline, call **LOS\_MemInfoGet**. The first parameter in the API is the start address of the memory pool, and the second parameter is the handle of the **LOS\_MEM\_POOL\_STATUS** type. The **usageWaterLine** field indicates the waterline.
To obtain the memory waterline, call **LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *poolStatus)**. The first parameter specifies the start address of the memory pool, and the second parameter specifies the handle of the **LOS_MEM_POOL_STATUS** type. The **usageWaterLine** field indicates the waterline.
- To calculate the memory fragmentation rate, call **LOS\_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:
To calculate the memory fragmentation rate, call **LOS_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:
Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size
### Development Example<a name="section1025453412611"></a>
### Development Example
This example implements the following:
1. Creates a monitoring task to obtain information about the memory pool.
2. Calls **LOS\_MemInfoGet** to obtain the basic information about the memory pool.
3. Calculates the memory usage and fragmentation rate.
1. Create a monitoring task to obtain information about the memory pool.
2. Call **LOS_MemInfoGet** to obtain the basic information about the memory pool.
3. Calculate the memory usage and fragmentation rate.
**Sample Code**
You can compile and verify the sample code in **kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **MemTest()** function is called in **TestTaskEntry**.
The sample code is as follows:
```
```c
#include <stdio.h>
#include <string.h>
#include "los_task.h"
......@@ -66,15 +72,14 @@ void MemInfoTaskFunc(void)
{
LOS_MEM_POOL_STATUS poolStatus = {0};
/* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example.*/
/* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example. */
void *pool = OS_SYS_MEM_ADDR;
LOS_MemInfoGet(pool, &poolStatus);
/* Calculate the fragmentation rate of the memory pool. */
unsigned char fragment = 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize;
/* Calculate the memory usage of the memory pool. */
unsigned char usage = LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool);
printf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize,
poolStatus.totalFreeSize, poolStatus.usageWaterLine);
dprintf("usage = %d, fragment = %d, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
}
int MemTest(void)
......@@ -88,18 +93,20 @@ int MemTest(void)
taskStatus.usTaskPrio = 10;
ret = LOS_TaskCreate(&taskID, &taskStatus);
if (ret != LOS_OK) {
printf("task create failed\n");
return -1;
dprintf("task create failed\n");
return LOS_NOK;
}
return 0;
return LOS_OK;
}
```
**Verification**
The result is as follows:
The data may vary depending on the running environment.
```
usage = 22, fragment = 3, maxFreeSize = 49056, totalFreeSize = 50132, waterLine = 1414
```
# Memory Leak Check
## Basic Concepts<a name="section1026719436293"></a>
## Basic Concepts
As an optional function of the kernel, memory leak check is used to locate dynamic memory leak problems. After this function is enabled, the dynamic memory mechanism automatically records the link registers \(LRs\) used when memory is allocated. If a memory leak occurs, the recorded information helps locate the memory allocated for further analysis.
As an optional function of the kernel, memory leak check is used to locate dynamic memory leak problems. After this function is enabled, the dynamic memory mechanism automatically records the link registers (LRs) used when memory is allocated. If a memory leak occurs, the recorded information helps locate the memory allocated for further analysis.
## Function Configuration<a name="section13991354162914"></a>
1. **LOSCFG\_MEM\_LEAKCHECK**: specifies the setting of the memory leak check. This function is disabled by default. To enable this function, configure it in **Debug-\> Enable Function call stack of Mem operation recorded**.
2. **LOS\_RECORD\_LR\_CNT**: number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof\(void \*\)** bytes.
3. **LOS\_OMIT\_LR\_CNT**: number of ignored LRs. The default value is **2**, which indicates that LRs are recorded from the time when **LOS\_MemAlloc** is called. You can change the value based on actual requirements. This macro is configured because:
- **LOS\_MemAlloc** is also called internally.
- **LOS\_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOS\_RECORD\_LR\_CNT** is limited.
## Function Configuration
**LOSCFG_MEM_LEAKCHECK** specifies the setting of the memory leak check. This function is disabled by default. You can enable it in **Debug-&gt; Enable MEM Debug-&gt; Enable Function call stack of Mem operation recorded**.
**LOS_RECORD_LR_CNT** specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void *)** bytes.
**LOS_OMIT_LR_CNT** specifies the number of ignored LRs. The default value is **2**, which indicates that LRs are recorded from the time when **LOS_MemAlloc** is called. You can change the value based on actual requirements. The reasons for this configuration are as follows:
- **LOS_MemAlloc** is also called internally.
- **LOS_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOS_RECORD_LR_CNT** is limited.
Correctly setting this macro can ignore invalid LRs and reduce memory consumption.
## Development Guidelines<a name="section95828159308"></a>
### How to Develop<a name="section369844416304"></a>
## Development Guidelines
Memory leak check provides a method to check for memory leak in key code logic. If this function is enabled, LR information is recorded each time when memory is allocated. When **LOS\_MemUsedNodeShow** is called before and after the code snippet is checked, information about all nodes that have been used in the specified memory pool is printed. You can compare the node information. The newly added node information indicates the node where the memory leak may occur. You can locate the code based on the LR and further check whether a memory leak occurs.
### How to Develop
The node information output by calling **LOS\_MemUsedNodeShow** is in the following format:
Memory leak check provides a method to check for memory leak in key code logic. If this function is enabled, LR information is recorded each time when memory is allocated. When **LOS_MemUsedNodeShow** is called before and after the code snippet is checked, information about all nodes that have been used in the specified memory pool is printed. You can compare the node information. The newly added node information indicates the node where the memory leak may occur. You can locate the code based on the LR and further check whether a memory leak occurs.
- Each line contains information about a node.
- The first column indicates the node address, based on which you can obtain complete node information using a tool such as a GNU Debugger \(GDB\).
- The second column indicates the node size, which is equal to the node header size plus the data field size.
- Columns 3 to 5 list the LR addresses.
The node information output by calling **LOS_MemUsedNodeShow** is in the following format: <br>Each line contains information about a node. The first column indicates the node address, based on which you can obtain complete node information using a tool such as a GNU Debugger (GDB). The second column indicates the node size, which is equal to the node header size plus the data field size. Columns 3 to 5 list the LR addresses. You can determine the specific memory location of the node based on the LR addresses and the assembly file.
You can determine the specific memory location of the node based on the LR addresses and the assembly file.
```
node size LR[0] LR[1] LR[2]
......@@ -42,86 +41,111 @@ node size LR[0] LR[1] LR[2]
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
```
>![](../public_sys-resources/icon-caution.gif) **CAUTION:**
>Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
> **CAUTION**
> Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
### Development Example<a name="section460801313313"></a>
### Development Example
This example implements the following:
1. Call **OsMemUsedNodeShow** to print information about all nodes.
2. Simulate a memory leak by requesting memory without releasing it.
3. Call **OsMemUsedNodeShow** to print information about all nodes.
4. Compare the logs to obtain information about the node where a memory leak occurred.
5. Locate the code based on the LR address.
**Sample Code**
You can compile and verify the sample code in **kernel/liteos_a/testsuites/kernel/src/osTest.c**. The **MemLeakTest()** function is called in **TestTaskEntry**.
In this example, a memory pool is created. To achieve this purpose, you need to define **LOSCFG_MEM_MUL_POOL** in **target_config.h**.
The sample code is as follows:
```
```c
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"
#define TEST_NEW_POOL_SIZE 2000
#define TEST_MALLOC_SIZE 8
void MemLeakTest(void)
{
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
OsMemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
VOID *pool = NULL;
/* Create a memory pool. */
pool = LOS_MemAlloc(OS_SYS_MEM_ADDR, TEST_NEW_POOL_SIZE);
(VOID)LOS_MemInit(pool, TEST_NEW_POOL_SIZE);
OsMemUsedNodeShow(pool);
void *ptr1 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
void *ptr2 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
OsMemUsedNodeShow(pool);
/* Release the memory pool. */
(VOID)LOS_MemDeInit(pool);
}
```
**Verification**
The log is as follows:
```
node size LR[0] LR[1] LR[2]
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc
0x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc
0x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
/* Log for the first OsMemUsedNodeShow. Because the memory pool is not allocated, there is no memory node. */
node LR[0] LR[1] LR[2]
/* Log for the second OsMemUsedNodeShow. There are two memory nodes. */
node LR[0] LR[1] LR[2]
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
node size LR[0] LR[1] LR[2]
0x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc
0x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc
0x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e
0x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a
0x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
```
The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak.
```
0x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6
0x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
```
The following is part of the assembly file:
```
MemLeakTest:
0x80041d4: 0xb510 PUSH {R4, LR}
0x80041d6: 0x4ca8 LDR.N R4, [PC, #0x2a0] ; g_memStart
0x80041d8: 0x0020 MOVS R0, R4
0x80041da: 0xf7fd 0xf93e BL LOS_MemUsedNodeShow ; 0x800145a
0x80041de: 0x2108 MOVS R1, #8
0x80041e0: 0x0020 MOVS R0, R4
0x80041e2: 0xf7fd 0xfbd9 BL LOS_MemAlloc ; 0x8001998
0x80041e6: 0x2108 MOVS R1, #8
0x80041e8: 0x0020 MOVS R0, R4
0x80041ea: 0xf7fd 0xfbd5 BL LOS_MemAlloc ; 0x8001998
0x80041ee: 0x0020 MOVS R0, R4
0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a
0x80041f4: 0xbd10 POP {R4, PC}
0x80041f6: 0x0000 MOVS R0, R0
4009f014: 7d 1e a0 e3 mov r1, #2000
4009f018: 00 00 90 e5 ldr r0, [r0]
4009f01c: 67 7a fe eb bl #-398948 <LOS_MemAlloc>
4009f020: 7d 1e a0 e3 mov r1, #2000
4009f024: 00 40 a0 e1 mov r4, r0
4009f028: c7 79 fe eb bl #-399588 <LOS_MemInit>
4009f02c: 04 00 a0 e1 mov r0, r4
4009f030: 43 78 fe eb bl #-401140 <OsMemUsedNodeShow>
4009f034: 04 00 a0 e1 mov r0, r4
4009f038: 08 10 a0 e3 mov r1, #8
4009f03c: 5f 7a fe eb bl #-398980 <LOS_MemAlloc>
4009f040: 04 00 a0 e1 mov r0, r4
4009f044: 08 10 a0 e3 mov r1, #8
4009f048: 5c 7a fe eb bl #-398992 <LOS_MemAlloc>
4009f04c: 04 00 a0 e1 mov r0, r4
4009f050: 3b 78 fe eb bl #-401172 <OsMemUsedNodeShow>
4009f054: 3c 00 9f e5 ldr r0, [pc, #60]
4009f058: 40 b8 fe eb bl #-335616 <dprintf>
4009f05c: 04 00 a0 e1 mov r0, r4
4009f060: 2c 7a fe eb bl #-399184 <LOS_MemDeInit>
```
The memory node addressed by **0x080041ee** is not released after being requested in **MemLeakTest**.
The memory node addressed by **0x4009f040** is not released after being allocated in **MemLeakTest**.
# perf
## Basic Concepts
perf is a performance analysis tool. It uses the performance monitoring unit (PMU) to count sampling events and collect context information and provides hot spot distribution and hot paths.
## Working Principles
When a performance event occurs, the corresponding event counter overflows and triggers an interrupt. The interrupt handler records the event information, including the current PC, task ID, and call stack.
perf provides two working modes: counting mode and sampling mode.
In counting mode, perf collects only the number of event occurrences and duration. In sampling mode, perf also collects context data and stores the data in a circular buffer. The IDE then analyzes the data and provides information about hotspot functions and paths.
## Available APIs
The Perf module of the OpenHarmony LiteOS-A kernel provides the following APIs. For details, see the [API reference](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h).
**Table 1** APIs of the perf module
| Category| Description|
| -------- | -------- |
| Starting or stopping sampling| **LOS_PerfInit**: initializes perf.<br>**LOS_PerfStart**: starts sampling.<br>**LOS_PerfStop**: stops sampling. |
| Configuring perf sampling events| **LOS_PerfConfig**: sets the event type and sampling period. |
| Reading sampling data| **LOS_PerfDataRead**: reads the sampling data. |
| Registering a hook for the sampling data buffer| **LOS_PerfNotifyHookReg**: registers the hook to be called when the buffer waterline is reached.<br>**LOS_PerfFlushHookReg**: registers the hook for flushing the cache in the buffer. |
**PerfConfigAttr** is the structure of the perf sampling event. For details, see [kernel\include\los_perf.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_perf.h).
The sampling data buffer is a circular buffer, and only the region that has been read in the buffer can be overwritten.
The buffer has limited space. You can register a hook to provide a buffer overflow notification or perform buffer read operation when the buffer waterline is reached. The default buffer waterline is 1/2 of the buffer size. The code snippet is as follows:
```c
VOID Example_PerfNotifyHook(VOID)
{
CHAR buf[LOSCFG_PERF_BUFFER_SIZE] = {0};
UINT32 len;
PRINT_DEBUG("perf buffer reach the waterline!\n");
len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
OsPrintBuff(buf, len); /* print data */
}
LOS_PerfNotifyHookReg(Example_PerfNotifyHook);
```
If the buffer sampled by perf involves caches across CPUs, you can register a hook for flushing the cache to ensure cache consistency. The code snippet is as follows:
```c
VOID Example_PerfFlushHook(VOID *addr, UINT32 size)
{
OsCacheFlush(addr, size); /* platform interface */
}
LOS_PerfNotifyHookReg(Example_PerfFlushHook);
```
The API for flushing the cache is configured based on the platform.
## Development Guidelines
### Kernel-Mode Development Process
The typical process of enabling perf is as follows:
1. Configure the macros related to the perf module.
Configure the perf control macro **LOSCFG_KERNEL_PERF**, which is disabled by default. In the **kernel/liteos_a** directory, run the **make update_config** command, choose **Kernel**, and select **Enable Perf Feature**.
| Configuration Item| menuconfig Option| Description| Value|
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_PERF | Enable&nbsp;Perf&nbsp;Feature | Whether to enable perf.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_TICK | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Tick | Whether to use tick as the perf timing unit.| YES/NO |
| LOSCFG_PERF_CALC_TIME_BY_CYCLE | Time-consuming&nbsp;Calc&nbsp;Methods-&gt;By&nbsp;Cpu&nbsp;Cycle | Whether to use cycle as the perf timing unit.| YES/NO |
| LOSCFG_PERF_BUFFER_SIZE | Perf&nbsp;Sampling&nbsp;Buffer&nbsp;Size | Size of the buffer used for perf sampling.| INT |
| LOSCFG_PERF_HW_PMU | Enable&nbsp;Hardware&nbsp;Pmu&nbsp;Events&nbsp;for&nbsp;Sampling | Whether to enable hardware PMU events. The target platform must support the hardware PMU.| YES/NO |
| LOSCFG_PERF_TIMED_PMU | Enable&nbsp;Hrtimer&nbsp;Period&nbsp;Events&nbsp;for&nbsp;Sampling | Whether to enable high-precision periodical events. The target platform must support the high precision event timer (HPET).| YES/NO |
| LOSCFG_PERF_SW_PMU | Enable&nbsp;Software&nbsp;Events&nbsp;for&nbsp;Sampling | Whether to enable software events. **LOSCFG_KERNEL_HOOK** must also be enabled.| YES/NO |
2. Call **LOS_PerfConfig** to configure the events to be sampled.
perf provides two working modes and three types of events.
- Working modes: counting mode (counts only the number of event occurrences) and sampling mode (collects context information such as task IDs, PC, and backtrace)
- Event types: CPU hardware events (such as cycle, branch, icache, and dcache), high-precision periodical events (such as CPU clock), and OS software events (such as task switch, mux pend, and IRQ)
3. Call **LOS_PerfStart(UINT32 sectionId)** at the start of the code to be sampled. The input parameter **sectionId** specifies different sampling session IDs.
4. Call **LOS_PerfStop** at the end of the code to be sampled.
5. Call **LOS_PerfDataRead** to read the sampling data and use IDE to analyze the collected data.
#### Development Example
This example implements the following:
1. Create a perf task.
2. Configure sampling events.
3. Start perf.
4. Execute algorithms for statistics.
5. Stop perf.
6. Export the result.
#### Sample Code
Prerequisites: **Enable Hook Feature** and **Enable Software Events for Sampling** are selected for the perf module in **menuconfig**.
You can compile and verify the sample code in **kernel/liteos_a/testsuites/kernel/src/osTest.c**.
The code is as follows:
```c
#include "los_perf.h"
#define TEST_MALLOC_SIZE 200
#define TEST_TIME 5
/* Add malloc() and free() in the test() function. */
VOID test(VOID)
{
VOID *p = NULL;
int i;
for (i = 0; i < TEST_TIME; i++) {
p = LOS_MemAlloc(m_aucSysMem1, TEST_MALLOC_SIZE);
if (p == NULL) {
PRINT_ERR("test alloc failed\n");
return;
}
(VOID)LOS_MemFree(m_aucSysMem1, p);
}
}
STATIC VOID OsPrintBuff(const CHAR *buf, UINT32 num)
{
UINT32 i = 0;
PRINTK("num: ");
for (i = 0; i < num; i++) {
PRINTK(" %02d", i);
}
PRINTK("\n");
PRINTK("hex: ");
for (i = 0; i < num; i++) {
PRINTK(" %02x", buf[i]);
}
PRINTK("\n");
}
STATIC VOID perfTestHwEvent(VOID)
{
UINT32 ret;
CHAR *buf = NULL;
UINT32 len;
//LOS_PerfInit(NULL, 0);
PerfConfigAttr attr = {
.eventsCfg = {
.type = PERF_EVENT_TYPE_SW,
.events = {
[0] = {PERF_COUNT_SW_TASK_SWITCH, 0xff}, /* Collect task scheduling information. */
[1] = {PERF_COUNT_SW_MEM_ALLOC, 0xff}, /* Collect memory allocation information. */
PERF_COUNT_SW_TASK_SWITCH
},
.eventsNr = 2,
.predivided = 1, /* cycle counter increase every 64 cycles */
},
.taskIds = {0},
.taskIdsNr = 0,
.needSample = 0,
.sampleType = PERF_RECORD_IP | PERF_RECORD_CALLCHAIN,
};
ret = LOS_PerfConfig(&attr);
if (ret != LOS_OK) {
PRINT_ERR("perf config error %u\n", ret);
return;
}
PRINTK("------count mode------\n");
LOS_PerfStart(0);
test(); /* this is any test function*/
LOS_PerfStop();
PRINTK("--------sample mode------ \n");
attr.needSample = 1;
LOS_PerfConfig(&attr);
LOS_PerfStart(2); // 2: set the section id to 2.
test(); /* this is any test function*/
LOS_PerfStop();
buf = LOS_MemAlloc(m_aucSysMem1, LOSCFG_PERF_BUFFER_SIZE);
if (buf == NULL) {
PRINT_ERR("buffer alloc failed\n");
return;
}
/* get sample data */
len = LOS_PerfDataRead(buf, LOSCFG_PERF_BUFFER_SIZE);
OsPrintBuff(buf, len); /* print data */
(VOID)LOS_MemFree(m_aucSysMem1, buf);
}
UINT32 Example_Perf_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S perfTestTask = {0};
UINT32 taskID;
/* Create a perf task. */
perfTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)perfTestHwEvent;
perfTestTask.pcName = "TestPerfTsk"; /* Test task name. */
perfTestTask.uwStackSize = 0x1000; // 0x8000: perf test task stack size
perfTestTask.usTaskPrio = 5; // 5: perf test task priority
ret = LOS_TaskCreate(&taskID, &perfTestTask);
if (ret != LOS_OK) {
PRINT_ERR("PerfTestTask create failed. 0x%x\n", ret);
return LOS_NOK;
}
return LOS_OK;
}
LOS_MODULE_INIT(perfTestHwEvent, LOS_INIT_LEVEL_KMOD_EXTENDED);
```
#### Verification
The output is as follows:
```
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 0
------count mode------
[task switch] eventType: 0x1 [core 0]: 0
[mem alloc] eventType: 0x3 [core 0]: 5
time used: 0.005000(s)
--------sample mode------
type: 2
events[0]: 1, 0xff
events[1]: 3, 0xff
predivided: 1
sampleType: 0x60
needSample: 1
dump perf data, addr: 0x402c3e6c length: 0x5000
time used: 0.000000(s)
num: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
hex: 00 ffffffef ffffffef ffffffef 02 00 00 00 14 00 00 00 60 00 00 00 02 00 00 00
The print information may vary depending on the running environment.
```
- For the counting mode, the following information is displayed after perf is stopped:
Event name (cycles), event type (0xff), and number of event occurrences (5466989440)
For hardware PMU events, the displayed event type is the hardware event ID, not the abstract type defined in **enum PmuHWId**.
- For the sampling mode, the address and length of the sampled data will be displayed after perf is stopped:
dump section data, addr: (0x8000000) length: (0x5000)
You can export the data using the JTAG interface and then use the IDE offline tool to analyze the data.
You can also call **LOS_PerfDataRead** to read data to a specified address for further analysis. In the example, **OsPrintBuff** is a test API, which prints the sampled data by byte. **num** indicates the sequence number of the byte, and **hex** indicates the value in the byte.
......@@ -3,34 +3,33 @@
## Basic Concepts
The central processing unit percent \(CPUP\) includes the system CPUP, process CPUP, task CPUP, and interrupt CPUP. With the system CPUP, you can determine whether the current system load exceeds the designed specifications. With the CPUP of each task/process/interrupt, you can determine whether their CPU usage meets expectations of the design.
The central processing unit percent (CPUP) includes the system CPUP, process CPUP, task CPUP, and interrupt CPUP. With the system CPUP, you can determine whether the current system load exceeds the designed specifications. With the CPUP of each task/process/interrupt, you can determine whether their CPU usage meets expectations of the design.
- System CPUP
System CPUP is the CPU usage of the system within a period of time. It reflects the CPU load and the system running status \(idle or busy\) in the given period of time. The valid range of the system CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the system runs with full load.
System CPUP is the CPU usage of the system within a period of time. It reflects the CPU load and the system running status (idle or busy) in the given period of time. The valid range of the system CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the system runs with full load.
- Process CPUP
Process CPUP refers to the CPU usage of a single process. It reflects the process status, busy or idle, in a period of time. The valid range of the process CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the process is being executed for a period of time.
- Task CPUP
Task CPUP refers to the CPU usage of a single task. It reflects the task status, busy or idle, in a period of time. The valid range of task CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the task is being executed for the given period of time.
- Interrupt CPUP
Interrupt CPUP refers to the CPU usage of a single interrupt. It reflects the interrupt status, busy or idle, in a period of time. The valid range of the interrupt CPUP is 0 to 100 in percentage. The precision can be adjusted through configuration. The value **100** indicates that the interrupt is being executed for a period of time.
## Working Principles<a name="section593718536227"></a>
## Working Principles
The OpenHarmony LiteOS-A kernel CPUP module records the CPU usage by process, task, and interrupt. When a process or task is switched, the start time of the process or task is recorded. When the process or task is switched out or exits, the system accumulates the CPU time of the entire process or task. When an interrupt is executed, the system accumulates and records the execution time of each interrupt.
OpenHarmony provides the following types of CPUP information:
- System CPUP
- Process CPUP
- Task CPUP
- Interrupt CPUP
The CPUP is calculated as follows:
......@@ -43,134 +42,109 @@ Task CPUP = Total running time of the task/Total running time of the system
Interrupt CPUP = Total running time of the interrupt/Total running time of the system
## Development Guidelines<a name="section11284210152311"></a>
### Available APIs<a name="section3745151592312"></a>
**Table 1** CPUP module APIs
<a name="table147491853163018"></a>
<table><thead align="left"><tr id="row10807205323013"><th class="cellrowborder" valign="top" width="28.3971602839716%" id="mcps1.2.4.1.1"><p id="p980714539304"><a name="p980714539304"></a><a name="p980714539304"></a>Function</p>
</th>
<th class="cellrowborder" valign="top" width="36.47635236476353%" id="mcps1.2.4.1.2"><p id="p1780715533305"><a name="p1780715533305"></a><a name="p1780715533305"></a>API</p>
</th>
<th class="cellrowborder" valign="top" width="35.12648735126487%" id="mcps1.2.4.1.3"><p id="p18807185316301"><a name="p18807185316301"></a><a name="p18807185316301"></a>Description</p>
</th>
</tr>
</thead>
<tbody><tr id="row3807145310300"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p174011140141013"><a name="p174011140141013"></a><a name="p174011140141013"></a>System CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p158071153133013"><a name="p158071153133013"></a><a name="p158071153133013"></a>LOS_HistorySysCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p14808115353010"><a name="p14808115353010"></a><a name="p14808115353010"></a>Obtains the historical CPUP of the system.</p>
</td>
</tr>
<tr id="row147461859201016"><td class="cellrowborder" rowspan="2" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p374720596102"><a name="p374720596102"></a><a name="p374720596102"></a>Process CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p3747859101010"><a name="p3747859101010"></a><a name="p3747859101010"></a>LOS_HistoryProcessCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p1747959131016"><a name="p1747959131016"></a><a name="p1747959131016"></a>Obtains the historical CPUP of a specified process.</p>
</td>
</tr>
<tr id="row2075434812116"><td class="cellrowborder" valign="top" headers="mcps1.2.4.1.1 "><p id="p17541648171114"><a name="p17541648171114"></a><a name="p17541648171114"></a>LOS_GetAllProcessCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" headers="mcps1.2.4.1.2 "><p id="p1575419483116"><a name="p1575419483116"></a><a name="p1575419483116"></a>Obtains the historical CPUP of all processes in the system.</p>
</td>
</tr>
<tr id="row1480855311301"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p1618792981018"><a name="p1618792981018"></a><a name="p1618792981018"></a>Task CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p9808185353016"><a name="p9808185353016"></a><a name="p9808185353016"></a>LOS_HistoryTaskCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p12808653183016"><a name="p12808653183016"></a><a name="p12808653183016"></a>Obtains the historical CPUP of a specified task.</p>
</td>
</tr>
<tr id="row680812535306"><td class="cellrowborder" valign="top" width="28.3971602839716%" headers="mcps1.2.4.1.1 "><p id="p13808125314307"><a name="p13808125314307"></a><a name="p13808125314307"></a>Interrupt CPUP</p>
</td>
<td class="cellrowborder" valign="top" width="36.47635236476353%" headers="mcps1.2.4.1.2 "><p id="p1480835316303"><a name="p1480835316303"></a><a name="p1480835316303"></a>LOS_GetAllIrqCpuUsage</p>
</td>
<td class="cellrowborder" valign="top" width="35.12648735126487%" headers="mcps1.2.4.1.3 "><p id="p33741531163313"><a name="p33741531163313"></a><a name="p33741531163313"></a>Obtains the historical CPUP of all interrupts in the system.</p>
</td>
</tr>
</tbody>
</table>
### How to Develop<a name="section122901429182316"></a>
The typical CPUP development process is as follows.
1. Call **LOS\_HistorySysCpuUsage** to obtain the historical CPUP of the system.
2. Call **LOS\_HistoryProcessCpuUsage** to obtain the historical CPUP of a specified process.
## Development Guidelines
### Available APIs
**Table 1** CPUP module APIs
| Category| API| Description|
| -------- | -------- | -------- |
| System CPUP| LOS_HistorySysCpuUsage | Obtains the historical CPUP of the system.|
| Process CPUP| LOS_HistoryProcessCpuUsage | Obtains the historical CPUP of a specified process.|
| Process CPUP| LOS_GetAllProcessCpuUsage | Obtains the historical CPUP of all processes in the system.|
| Task CPUP| LOS_HistoryTaskCpuUsage | Obtains the historical CPUP of a specified task.|
| Interrupt CPUP| LOS_GetAllIrqCpuUsage | Obtains the historical CPUP of all interrupts in the system.|
| Reset| LOS_CpupReset | Resets CPUP data.|
### How to Develop
The typical CPUP development process is as follows:
1. Call **LOS_HistorySysCpuUsage** to obtain the historical CPUP of the system.
2. Call **LOS_HistoryProcessCpuUsage** to obtain the historical CPUP of a specified process.
- If the process has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the process is not created, return an error code.
3. Call **LOS\_GetAllProcessCpuUsage** to obtain the CPUP of all processes.
- If the CPUP has been initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
3. Call **LOS_GetAllProcessCpuUsage** to obtain the CPUP of all processes.
- If the CPUP is initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP is not initialized or has invalid input parameters, return an error code.
4. Call **LOS\_HistoryTaskCpuUsage** to obtain the historical CPUP of a specified task.
4. Call **LOS_HistoryTaskCpuUsage** to obtain the historical CPUP of a specified task.
- If the task has been created, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If the task is not created, return an error code.
5. Call **LOS\_GetAllIrqCpuUsage** to obtain the CPUP of all interrupts.
5. Call **LOS_GetAllIrqCpuUsage** to obtain the CPUP of all interrupts.
- If the CPUP has been initialized, disable interrupt, obtain the CPUP in different modes, and then enable interrupt.
- If CPUP has not been initialized or has invalid input parameters, return an error code.
- If CPUP is not initialized or has invalid input parameters, return an error code.
### Development Example<a name="section1765785212310"></a>
### Development Example
This example implements the following:
1. Create a task for the CPUP test.
2. Obtain the CPUP of the current system.
3. Obtain the historical system CPUP in different modes.
4. Obtain the CPUP of the created test task.
5. Obtain the CPUP of the created test task in different modes.
Prerequisites
Prerequisites:
The CPUP control is enabled in the **menuconfig** configuration.
**Sample Code**
You can compile and verify the sample code in **kernel/liteos_a/testsuites /kernel/src /osTest.c**. The **CpupTest** function is called in **TestTaskEntry**.
The sample code is as follows:
```
```c
#include "los_task.h"
#include "los_cpup.h"
#define MODE 4
UINT32 g_cpuTestTaskID;
VOID ExampleCpup(VOID)
{
printf("entry cpup test example\n");
while(1) {
usleep(100);
int i = 0;
dprintf("entry cpup test example\n");
for (i = 0; i < 10; i++) {
usleep(100); // 100: delay for 100ms
}
}
UINT32 ItCpupTest(VOID)
UINT32 CpupTest(VOID)
{
UINT32 ret;
UINT32 cpupUse;
TSK_INIT_PARAM_S cpupTestTask = { 0 };
TSK_INIT_PARAM_S cpupTestTask = {0};
memset(&cpupTestTask, 0, sizeof(TSK_INIT_PARAM_S));
cpupTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleCpup;
cpupTestTask.pcName = "TestCpupTsk";
cpupTestTask.uwStackSize = 0x800;
cpupTestTask.usTaskPrio = 5;
cpupTestTask.uwStackSize = 0x800; // 0x800: cpup test task stack size
cpupTestTask.usTaskPrio = 5; // 5: cpup test task priority
ret = LOS_TaskCreate(&g_cpuTestTaskID, &cpupTestTask);
if(ret != LOS_OK) {
if (ret != LOS_OK) {
printf("cpupTestTask create failed .\n");
return LOS_NOK;
}
usleep(100);
usleep(100); // 100: delay for 100ms
/* Obtain the historical CPUP of the system. */
cpupUse = LOS_HistorySysCpuUsage(CPU_LESS_THAN_1S);
printf("the history system cpu usage in all time: %u.%u\n",
cpupUse = LOS_HistorySysCpuUsage(CPUP_LAST_ONE_SECONDS);
dprintf("the history system cpu usage in all time: %u.%u\n",
cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
/* Obtain the CPUP of the specified task (cpupTestTask in this example).*/
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPU_LESS_THAN_1S);
printf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
/* Obtain the CPUP of the specified task (cpupTestTask in this example). */
cpupUse = LOS_HistoryTaskCpuUsage(g_cpuTestTaskID, CPUP_LAST_ONE_SECONDS);
dprintf("cpu usage of the cpupTestTask in all time:\n TaskID: %d\n usage: %u.%u\n",
g_cpuTestTaskID, cpupUse / LOS_CPUP_PRECISION_MULT, cpupUse % LOS_CPUP_PRECISION_MULT);
return LOS_OK;
}
......@@ -180,9 +154,12 @@ UINT32 ItCpupTest(VOID)
The development is successful if the return result is as follows:
```
entry cpup test example
the history system cpu usage in all time: 3.0
cpu usage of the cpupTestTask in all time: TaskID:10 usage: 0.0
The print information may vary depending on the running environment.
```
......@@ -28,20 +28,18 @@ The online mode must be used with the integrated development environment (IDE).
The trace module of the OpenHarmony LiteOS-A kernel provides the following APIs. For more details, see [API reference](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h).
**Table 1** APIs of the trace module
**Table 1** APIs of the trace module
| Category| Description|
| -------- | -------- |
| Starting/Stopping trace| **LOS_TraceStart**: starts trace.<br>**LOS_TraceStop**: stops trace. |
| Managing trace records| **LOS_TraceRecordDump**: dumps data from the trace buffer.<br>**LOS_TraceRecordGet**: obtains the start address of the trace buffer.<br>**LOS_TraceReset**: clears events in the trace buffer. |
| Starting/Stopping trace| **LOS_TraceStart**: starts trace.<br>**LOS_TraceStop**: stops trace.|
| Managing trace records| **LOS_TraceRecordDump**: dumps data from the trace buffer.<br>**LOS_TraceRecordGet**: obtains the start address of the trace buffer.<br>**LOS_TraceReset**: clears events in the trace buffer.|
| Filtering trace records| **LOS_TraceEventMaskSet**: sets the event mask to trace only events of the specified modules.|
| Masking events of specified interrupt IDs| **LOS_TraceHwiFilterHookReg**: registers a hook to filter out events of specified interrupt IDs.|
| Performing function instrumentation| **LOS_TRACE_EASY**: performs simple instrumentation.<br>**LOS_TRACE**: performs standard instrumentation. |
You can perform function instrumentation in the source code to trace specific events. The system provides the following APIs for instrumentation:
- **LOS_TRACE_EASY(TYPE, IDENTITY, params...)** for simple instrumentation
| Performing function instrumentation| **LOS_TRACE_EASY**: performs simple instrumentation.<br>**LOS_TRACE**: performs standard instrumentation.|
- You can perform function instrumentation in the source code to trace specific events. The system provides the following APIs for instrumentation:
- **LOS_TRACE_EASY(TYPE, IDENTITY, params...)** for simple instrumentation
- You only need to insert this API into the source code.
- **TYPE** specifies the event type. The value range is 0 to 0xF. The meaning of each value is user-defined.
- **IDENTITY** specifies the object of the event operation. The value is of the **UIntPtr** type.
......@@ -60,7 +58,7 @@ You can perform function instrumentation in the source code to trace specific ev
Insert the following in the position where the fd2 file is written:
LOS_TRACE_EASY(2, fd2, flag, size);
```
- **LOS_TRACE(TYPE, IDENTITY, params...)** for standard instrumentation.
- **LOS_TRACE(TYPE, IDENTITY, params...)** for standard instrumentation.
- Compared with simple instrumentation, standard instrumentation supports dynamic event filtering and parameter tailoring. However, you need to extend the functions based on rules.
- **TYPE** specifies the event type. You can define the event type in **enum LOS_TRACE_TYPE** in the header file **los_trace.h**. For details about methods and rules for defining events, see other event types.
- The **IDENTITY** and **Params** are the same as those of simple instrumentation.
......@@ -86,34 +84,33 @@ You can perform function instrumentation in the source code to trace specific ev
4. Insert a code stub in a proper position.
Format: LOS_TRACE(#TYPE#, #TYPE#_PARAMS(IDENTITY, parma1...))
LOS_TRACE(FS_READ, fp, fd, flag, size); // Code stub for reading files.
The parameters following #TYPE# are the input parameter of the **FS_READ_PARAMS** function in step 3.
#The parameters following #TYPE# are the input parameter of the **FS_READ_PARAMS** function in step 3.
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> The trace event types and parameters can be modified as required. For details about the parameters, see **kernel\include\los_trace.h**.
For **LOS_TraceEventMaskSet(UINT32 mask)**, only the most significant 28 bits (corresponding to the enable bit of the module in **LOS_TRACE_MASK**) of the mask take effect and are used only for module-based tracing. Currently, fine-grained event-based tracing is not supported. For example, in **LOS_TraceEventMaskSet(0x202)**, the effective mask is **0x200 (TRACE_QUE_FLAG)** and all events of the QUE module are collected. The recommended method is **LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG);**.
> **NOTE**<br>
> The preset trace events and parameters can be tailored in the same way. For details about the parameters, see [kernel\include\los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h).
To enable trace of only simple instrumentation events, set **Trace Mask** to **TRACE_MAX_FLAG**.
- For **LOS_TraceEventMaskSet(UINT32 mask)**, only the most significant 28 bits (corresponding to the enable bit of the module in **LOS_TRACE_MASK**) of the mask take effect and are used only for module-based tracing. Currently, fine-grained event-based tracing is not supported. For example, in **LOS_TraceEventMaskSet(0x202)**, the effective mask is **0x200 (TRACE_QUE_FLAG)** and all events of the QUE module are collected. The recommended method is **LOS_TraceEventMaskSet(TRACE_EVENT_FLAG | TRACE_MUX_FLAG | TRACE_SEM_FLAG | TRACE_QUE_FLAG);**.
The trace buffer has limited capacity. When the trace buffer is full, events will be overwritten. You can use **LOS_TraceRecordDump** to export data from the trace buffer and locate the latest records by **CurEvtIndex**.
- To enable trace of only simple instrumentation events, set **Trace Mask** to **TRACE_MAX_FLAG**.
The typical trace operation process includes **LOS_TraceStart**, **LOS_TraceStop**, and **LOS_TraceRecordDump**.
- The trace buffer has limited capacity. When the trace buffer is full, events will be overwritten. You can use **LOS_TraceRecordDump** to export data from the trace buffer and locate the latest records by **CurEvtIndex**.
You can filter out interrupt events by interrupt ID to prevent other events from being overwritten due to frequent triggering of a specific interrupt in some scenarios. You can customize interrupt filtering rules.
- The typical trace operation process includes **LOS_TraceStart**, **LOS_TraceStop**, and **LOS_TraceRecordDump**.
Example:
- You can filter out interrupt events by interrupt ID to prevent other events from being overwritten due to frequent triggering of a specific interrupt in some scenarios. You can customize interrupt filtering rules.
Example:
```
BOOL Example_HwiNumFilter(UINT32 hwiNum)
{
```c
BOOL Example_HwiNumFilter(UINT32 hwiNum)
{
if ((hwiNum == TIMER_INT) || (hwiNum == DMA_INT)) {
return TRUE;
}
return FALSE;
}
LOS_TraceHwiFilterHookReg(Example_HwiNumFilter);
```
}
LOS_TraceHwiFilterHookReg(Example_HwiNumFilter);
```
The interrupt events with interrupt ID of **TIMER_INT** or **DMA_INT** are not traced.
......@@ -129,7 +126,7 @@ The trace character device is added in **/dev/trace**. You can use **read()**, *
- **ioctl()**: performs user-mode trace operations, including:
```
```c
#define TRACE_IOC_MAGIC 'T'
#define TRACE_START _IO(TRACE_IOC_MAGIC, 1)
#define TRACE_STOP _IO(TRACE_IOC_MAGIC, 2)
......@@ -151,25 +148,24 @@ For details, see [User-Mode Development Example](kernel-small-debug-trace.md#use
The typical trace process is as follows:
1. Configure the macro related to the trace module.
Configure the macro **LOSCFG_KERNEL_TRACE**, which is disabled by default. Run the **make update_config** command in the **kernel/liteos_a** directory, choose **Kernel** > **Enable Hook Feature**, and set **Enable Trace Feature** to **YES**.
| Configuration Item | menuconfig Option| Description| Value|
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_TRACE | Enable&nbsp;Trace&nbsp;Feature | Specifies whether to enable the trace feature.| YES/NO |
| LOSCFG_RECORDER_MODE_OFFLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Offline&nbsp;mode | Specifies whether to enable the online trace mode.| YES/NO |
| LOSCFG_RECORDER_MODE_ONLINE | Trace&nbsp;work&nbsp;mode&nbsp;-&gt;Online&nbsp;mode | Specifies whether to enable the offline trace mode.| YES/NO |
| LOSCFG_TRACE_CLIENT_INTERACT | Enable&nbsp;Trace&nbsp;Client&nbsp;Visualization&nbsp;and&nbsp;Control | Enables interaction with Trace IDE (dev tools), including data visualization and process control.| YES/NO |
| LOSCFG_TRACE_FRAME_CORE_MSG | Enable&nbsp;Record&nbsp;more&nbsp;extended&nbsp;content&nbsp;-<br>&gt;Record&nbsp;cpuid,&nbsp;hardware&nbsp;interrupt<br>&nbsp;status,&nbsp;task&nbsp;lock&nbsp;status | Specifies whether to enable recording of the CPU ID, interruption state, and lock task state.| YES/NO |
| LOSCFG_TRACE_FRAME_EVENT_COUNT | Enable&nbsp;Record&nbsp;more&nbsp;extended&nbsp;content<br>&nbsp;-&gt;Record&nbsp;event&nbsp;count,<br>&nbsp;which&nbsp;indicate&nbsp;the&nbsp;sequence&nbsp;of&nbsp;happend&nbsp;events | Specifies whether to enables recording of the event sequence number.| YES/NO |
| LOSCFG_TRACE_FRAME_MAX_PARAMS | Record&nbsp;max&nbsp;params | Specifies the maximum number of parameters for event recording.| INT |
| LOSCFG_TRACE_BUFFER_SIZE | Trace&nbsp;record&nbsp;buffer&nbsp;size | Specifies the trace buffer size.| INT |
| Item| menuconfig Option| Description| Value|
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_TRACE | Enable Trace Feature | Specifies whether to enable the trace feature.| YES/NO |
| LOSCFG_RECORDER_MODE_OFFLINE | Trace work mode -> Offline mode | Specifies whether to enable the online trace mode.| YES/NO |
| LOSCFG_RECORDER_MODE_ONLINE | Trace work mode -> Online mode | Specifies whether to enable the offline trace mode.| YES/NO |
| LOSCFG_TRACE_CLIENT_INTERACT | Enable Trace Client Visualization and Control | Enables interaction with Trace IDE (dev tools), including data visualization and process control.| YES/NO |
| LOSCFG_TRACE_FRAME_CORE_MSG | Enable Record more extended content -> Record cpuid, hardware interrupt status, task lock status | Specifies whether to enable recording of the CPU ID, interruption state, and lock task state.| YES/NO |
| LOSCFG_TRACE_FRAME_EVENT_COUNT | Enable Record more extended content -> Record event count, which indicate the sequence of happend events | Specifies whether to enables recording of the event sequence number.| YES/NO |
| LOSCFG_TRACE_FRAME_MAX_PARAMS | Record max params | Specifies the maximum number of parameters for event recording.| INT |
| LOSCFG_TRACE_BUFFER_SIZE | Trace record buffer size | Specifies the trace buffer size.| INT |
2. (Optional) Preset event parameters and stubs (or use the default event parameter settings and event stubs).
3. (Optional) Call **LOS_TraceStop** to stop trace and call **LOS_TraceReset** to clear the trace buffer. (Trace is started by default.)
4. (Optional) Call **LOS_TraceEventMaskSet** to set the event mask for trace (only the interrupts and task events are enabled by default). For details about the event mask, see **LOS_TRACE_MASK** in **los_trace.h**.
4. (Optional) Call **LOS_TraceEventMaskSet** to set the mask of the events to be traced. The default event mask enables only trace of interrupts and task events. For details about the event masks, see **LOS_TRACE_MASK** in [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h).
5. Call **LOS_TraceStart** at the start of the code where the event needs to be traced.
......@@ -177,7 +173,7 @@ The typical trace process is as follows:
7. Call **LOS_TraceRecordDump** to output the data in the buffer. (The input parameter of the function is of the Boolean type. The value **FALSE** means to output data in the specified format, and the value **TRUE** means to output data to Trace IDE.)
The methods in steps 3 to 7 are encapsulated with shell commands. You can run these commands on shell. The mappings between the functions and commands are as follows:
The methods in steps 3 to 7 are encapsulated with shell commands. You can run these commands on shell. The mappings between the methods and commands are as follows:
- LOS_TraceReset —— trace_reset
......@@ -207,10 +203,12 @@ This example implements the following:
### Kernel-Mode Sample Code
You can add the test function of the sample code to **TestTaskEntry** in **kernel/liteos_a/testsuites /kernel /src/osTest.c** for testing.
The sample code is as follows:
```
```c
#include "los_trace.h"
UINT32 g_traceTestTaskId;
VOID Example_Trace(VOID)
......@@ -231,18 +229,19 @@ VOID Example_Trace(VOID)
LOS_TraceStop();
LOS_TraceRecordDump(FALSE);
}
UINT32 Example_Trace_test(VOID){
UINT32 Example_Trace_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S traceTestTask;
/* Create a trace task. */
memset(&traceTestTask, 0, sizeof(TSK_INIT_PARAM_S));
traceTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Trace;
traceTestTask.pcName = "TestTraceTsk"; /* Test task name. */
traceTestTask.uwStackSize = 0x800;
traceTestTask.usTaskPrio = 5;
traceTestTask.uwStackSize = 0x800; // 0x800: trace test task stack size
traceTestTask.usTaskPrio = 5; // 5: trace test task priority
traceTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
ret = LOS_TaskCreate(&g_traceTestTaskId, &traceTestTask);
if(ret != LOS_OK){
if (ret != LOS_OK) {
dprintf("TraceTestTask create failed .\n");
return LOS_NOK;
}
......@@ -280,13 +279,13 @@ Index Time(cycles) EventType CurTask Identity params
The output event information includes the occurrence time, event type, task in which the event occurs, object of the event operation, and other parameters of the event.
- **EventType**: event type. For details, see **enum LOS_TRACE_TYPE** in the header file **los_trace.h**.
- **EventType**: type of the event. For details, see **enum LOS_TRACE_TYPE** in [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h).
- **CurrentTask**: ID of the running task.
- **Identity**: object of the event operation. For details, see **#TYPE#_PARAMS** in the header file **los_trace.h**.
- **Identity**: object of the event operation. For details, see **\#TYPE\#_PARAMS** in [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h).
- **params**: event parameters. For details, see **#TYPE#_PARAMS** in the header file **los_trace.h**.
- **params**: event parameters. For details, see **\#TYPE\#_PARAMS** in [los_trace.h](https://gitee.com/openharmony/kernel_liteos_a/blob/master/kernel/include/los_trace.h).
The following uses output No. 0 as an example.
......@@ -302,14 +301,15 @@ Index Time(cycles) EventType CurTask Identity params
- For details about the meanings of **Identity** and **params**, see the **TASK_SWITCH_PARAMS** macro.
```
```c
#define TASK_SWITCH_PARAMS(taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus) \
taskId, oldPriority, oldTaskStatus, newPriority, newTaskStatus
```
Because of **#TYPE#_PARAMS(IDENTITY, parma1...) IDENTITY, ...**, **Identity** is **taskId (0x0)** and the first parameter is **oldPriority (0x1f)**.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**
> **NOTE**
>
> The number of parameters in **params** is specified by **LOSCFG_TRACE_FRAME_MAX_PARAMS**. The default value is **3**. Excess parameters are not recorded. You need to set **LOSCFG_TRACE_FRAME_MAX_PARAMS** based on service requirements.
Task 0x1 is switched to Task 0x0. The priority of task 0x1 is **0x1f**, and the state is **0x4**. The priority of the task 0x0 is **0x0**.
# User-Mode Memory Debugging
## Basic Concepts
The musl libc library of the debug version provides mechanisms, such as memory leak check, heap memory statistics, memory corruption check, and backtrace, to improve the efficiency in locating memory problems in user space.
The musl libc library of the debug version provides maintenance and test methods, such as memory leak check, heap memory statistics, memory corruption check, and backtrace, to improve the efficiency of locating memory problems in user space.
Instrumentation is performed on the **malloc** and **free** APIs to log key node information. When memory is requested and released by a program, the memory node integrity is checked. When the program ends, memory statistics are provided for identifying memory leaks.
Instrumentation is performed in the **malloc** and **free** APIs to log key node information. The memory node integrity is checked when memory is requested and released by an application. When the application ends, memory statistics are provided to help identifying memory leaks.
## Working Principles
......@@ -18,15 +17,15 @@ When memory is requested, key information is saved to the memory node control bl
When memory is released, the system matches the memory node control block based on the memory address to be released and deletes the control block.
**Figure 1** Heap memory node linked list
**Figure 1** Heap memory node linked list
![](figures/heap-memory-node-linked-list.png "heap-memory-node-linked-list")
![](figures/heap-memory-node-linked-list.png "heap-memory-node-linked-list")
When memory is allocated, the returned address is saved in a link register (LR). During the process running, the system adds information, such as the LR corresponding to the suspected leak, to the memory node control block. <xref href="#fig716011269106" idp:producemode_text="auto" class="- topic/xref " id="xref106398301961"></xref> shows the heap memory node information.
When memory is allocated, the returned address is saved in a link register (LR). During the process running, the system adds information, such as the LR corresponding to the suspected leak, to the memory node control block. The following figure shows the heap memory node information.
**Figure 2** Heap memory node information
**Figure 2** Heap memory node information
![](figures/heap-memory-node-information.png "heap-memory-node-information")
![](figures/heap-memory-node-information.png "heap-memory-node-information")
**TID** indicates the thread ID; **PID** indicates the process ID; **ptr** indicates the address of the memory requested; **size** indicates the size of the requested memory; **lr[*n*]** indicates the address of the call stack, and *n* is configurable.
......@@ -34,9 +33,9 @@ When memory is released, the input parameter pointer in the **free** API is used
You can export the memory debugging information of each process through the serial port or file, and use the addr2line tool to convert the exported information into the code lines that cause memory leaks. In this way, the memory leakage problem can be solved.
**Figure 3** Process of locating the code line for a memory leak
**Figure 3** Process of locating the code line for a memory leak
![](figures/process-of-locating-the-code-lines-for-a-memory-leak.png "process-of-locating-the-code-lines-for-a-memory-leak")
![](figures/process-of-locating-the-code-lines-for-a-memory-leak.png "process-of-locating-the-code-lines-for-a-memory-leak")
### Heap Memory Statistics
......@@ -46,21 +45,29 @@ You can collect statistics on the percentage of heap memory requested by each th
### Memory Integrity Check
- If the memory requested by using **malloc** is less than or equal to 0x1c000 bytes, the heap allocation algorithm is used to allocate memory.
- Requested memory less than or equal to 0x1c000 bytes
When the requested memory is less than or equal to 0x1c000 bytes, **malloc** uses the heap allocation algorithm to allocate memory.
When a user program requests heap memory, information such as the check value is added to the heap memory node. If the check value is abnormal, it is probably that the previous heap memory block is overwritten. Currently, the scenario where the check value is damaged by a wild pointer cannot be identified. When memory is allocated or released, the memory node check value is verified. If the memory node is corrupted and the verification fails, the following information is output: TID, PID, and call stack information saved when the previous heap memory block of the corrupted node is allocated. You can use the addr2line tool to obtain the specific code line and rectify the fault.
**Figure 4** Adding a check value to the node header information
![](figures/adding-a-check-value-to-the-node-header-information.png "adding-a-check-value-to-the-node-header-information")
When heap memory is released by using **free**, the memory block is not released immediately. Instead, the magic number 0xFE is written into the memory block, which is then placed in the free queue to prevent the memory block from being allocated by **malloc** within a certain period of time. When a wild pointer or **use-after-free** operation is performed to read the memory, an exception can be detected. However, this mechanism does not apply to write operations.
When heap memory is released by **free**, the memory block is not released immediately. Instead, the magic number 0xFE is written into the memory block, which is then placed in the free queue to prevent the memory block from being allocated by **malloc** within a certain period of time. When a wild pointer or **use-after-free** operation is performed to read the memory, an exception can be detected. However, this mechanism does not apply to write operations.
**Figure 5** Process of releasing memory
![](figures/process-of-releasing-memory.png "process-of-releasing-memory")
- If the memory requested by using **malloc** is greater than 0x1c000 bytes, **mmap** is used to allocate memory.
When **mmap** is used to request a large memory block, one more page is allocated at the start and end of the memory region. The current **PAGE_SIZE** of each page is **0x1000**. The permissions of the two pages are set to **PROT_NONE** (no read or write permission) by using the **mprotect** API to prevent out-of-bounds read and write of memory. If out-of-bounds read and write of memory occurs, the user program becomes abnormal because the user does not have the read or write permission. The code logic can be identified based on the abnormal call stack information.
- Requested memory greater than 0x1c000 bytes
When the requested memory is greater than 0x1c000 bytes, **malloc** uses **mmap** to allocate memory.
When **mmap** is used to allocate a large memory block, one more page is allocated at the start and end of the memory region. The current **PAGE_SIZE** of each page is **0x1000**. The permissions of the two pages are set to **PROT_NONE** (no read or write permission) by using the **mprotect** API to prevent out-of-bounds read and write of memory. If out-of-bounds read and write of memory occurs, the user program becomes abnormal because the user does not have the read or write permission. The code logic can be identified based on the abnormal call stack information.
**Figure 6** Layout of the memory allocated by using the **mmap** mechanism of **malloc**
......@@ -105,7 +112,7 @@ You can perform heap memory debugging by using either of the following:
- CLI: By using the CLI, you do not need to modify user code. However, you cannot accurately check the heap memory information of a specific logic segment.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**<br>
> After memory debugging is enabled, a heap memory leak check and a heap memory integrity check will be performed by default when a process exits. If memory debugging is disabled, the heap memory statistics, heap memory leak check, and heap memory integrity check cannot be enabled, and there is no response to the calling of any debug API.
......@@ -119,7 +126,7 @@ You can perform heap memory debugging by using either of the following:
The sample code explicitly calls the related APIs of the memory debugging module to check the memory.
```
```c
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
......@@ -127,7 +134,8 @@ The sample code explicitly calls the related APIs of the memory debugging module
#define MALLOC_LEAK_SIZE 0x300
void func(void) {
void func(void)
{
char *ptr = malloc(MALLOC_LEAK_SIZE);
memset(ptr, '3', MALLOC_LEAK_SIZE);
}
......@@ -156,7 +164,8 @@ $ clang -o mem_check mem_check.c -funwind-tables -rdynamic -g -mfloat-abi=softfp
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**
>
> - In this example, the compiler path is written into an environment variable in the **.bashrc** file.
>
> - When compiling user programs and required libraries, add the option **-funwind-tables -rdynamic -g** for stack backtracking.
......@@ -293,14 +302,15 @@ kill -37 <pid> # Check whether the head node of the heap memory is complete.
The sample code constructs a memory problem and uses the command line to perform memory debugging.
```
```c
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#define MALLOC_LEAK_SIZE 0x300
void func(void) {
void func(void)
{
char *ptr = malloc(MALLOC_LEAK_SIZE);
memset(ptr, '3', MALLOC_LEAK_SIZE);
}
......@@ -317,7 +327,7 @@ int main()
##### Compilation
For details, see [Compilation](kernel-small-debug-user.md#compilation).
For details, see [Compilation](#compilation).
##### Running the mwatch Command
......@@ -497,25 +507,26 @@ Now using addr2line ...
==PID:4== SUMMARY: 0x640 byte(s) leaked in 2 allocation(s).
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**<br>
> The preceding information recorded gradually is added to the file specified during initialization. Therefore, running the **cat** command can also display the historical information in the file.
## Common Problems
### Use After Free (UAF)
- Requested memory block less than or equal to 0x1c000 bytes:
After the memory is released:
- Requested memory less than or equal to 0x1c000 bytes:
Read operation: If the magic number (0xFEFEFEFE) is read from the memory block released, UAF occurs.
> ![icon-note.gif](public_sys-resources/icon-note.gif) **NOTE**<br>
> **NOTE**
>
> After **free** is called, the heap memory will not be released to the heap memory pool immediately. Instead, the heap memory is placed in a queue with a fixed length and filled with the magic number 0xFE. When the queue is full, the memory block first placed in the queue is released to the heap memory pool first.
Write operation: The memory debugging module cannot detect UAF errors from write operations.
- Requested memory block greater than 0x1c000 bytes:
The heap memory greater than 0x1c000 bytes must be requested by calling the **mmap** API via **malloc**. If the heap memory is accessed after being released, the user program will become abnormal (because the memory region has been unmapped).
......@@ -527,6 +538,7 @@ Double free errors occur when **free()** is called more than once with the same
### Heap Memory Node Corrupted
- Requested memory block less than or equal to 0x1c000 bytes:
When a heap memory node is corrupted, the user program exits unexpectedly, and the call stack that requests the heap memory of the node corrupted is output. The memory debugging module, however, cannot debug the memory corrupted by a wild pointer. For example, if the user program mem_check has heap memory overwriting, you can use the command line to obtain the possible location of the memory corruption.
......
......@@ -59,10 +59,9 @@ The user mode provides only the LMS check library. It does not provide external
The typical process for enabling LMS is as follows:
1. Configure the macros related to the LMS module.
Configure the LMS macro **LOSCFG_KERNEL_LMS**, which is disabled by default. Run the **make update_config** command in the **kernel/liteos_a** directory, choose **Kernel**, and select **Enable Lite Memory Sanitizer**.
| Macro| menuconfig Option| Description| Value:|
| Macro| menuconfig Option| Description| Value |
| -------- | -------- | -------- | -------- |
| LOSCFG_KERNEL_LMS | Enable Lms Feature | Whether to enable LMS.| YES/NO |
| LOSCFG_LMS_MAX_RECORD_POOL_NUM | Lms check pool max num | Maximum number of memory pools that can be checked by LMS.| INT |
......@@ -70,9 +69,7 @@ The typical process for enabling LMS is as follows:
| LOSCFG_LMS_STORE_CHECK | Enable lms write check | Whether to enable LMS write check.| YES/NO |
| LOSCFG_LMS_CHECK_STRICT | Enable lms strict check, byte-by-byte | Whether to enable LMS byte-by-byte check.| YES/NO |
2. Modify the build script of the target module.
Add **-fsanitize=kernel-address** to insert memory access checks, and add the **-O0** option to disable optimization performed by the compiler.
The modifications vary depending on the compiler (GCC or Clang) used. The following is an example:
......@@ -113,9 +110,10 @@ This example implements the following:
#### Kernel-Mode Sample Code
The sample code is as follows:
The functions of the sample code can be added to **TestTaskEntry** in **kernel /liteos_a/testsuites /kernel /src /osTest.c** for testing.
The sample code is as follows:
```
```c
#define PAGE_SIZE (0x1000U)
#define INDEX_MAX 20
UINT32 g_lmsTestTaskId;
......@@ -141,7 +139,7 @@ static VOID LmsTestUseAfterFree(VOID)
PRINTK("\n######%s start ######\n", __FUNCTION__);
UINT32 i;
CHAR *str = (CHAR *)LOS_MemAlloc(g_testLmsPool, INDEX_MAX);
LOS_MemFree(g_testLmsPool, str);
(VOID)LOS_MemFree(g_testLmsPool, str);
PRINTK("str[%2d]=0x%2x ", 0, str[0]); /* trigger use after free at str[0] */
PRINTK("\n######%s stop ######\n", __FUNCTION__);
}
......@@ -151,18 +149,19 @@ VOID LmsTestCaseTask(VOID)
LmsTestOsmallocOverflow();
LmsTestUseAfterFree();
}
UINT32 Example_Lms_test(VOID){
UINT32 Example_Lms_test(VOID)
{
UINT32 ret;
TSK_INIT_PARAM_S lmsTestTask;
/* Create a task for LMS. */
memset(&lmsTestTask, 0, sizeof(TSK_INIT_PARAM_S));
lmsTestTask.pfnTaskEntry = (TSK_ENTRY_FUNC)LmsTestCaseTask;
lmsTestTask.pcName = "TestLmsTsk"; /* Test task name. */
lmsTestTask.uwStackSize = 0x800;
lmsTestTask.usTaskPrio = 5;
lmsTestTask.uwStackSize = 0x800; // 0x800: LMS test task stack size
lmsTestTask.usTaskPrio = 5; // 5: LMS test task priority
lmsTestTask.uwResved = LOS_TASK_STATUS_DETACHED;
ret = LOS_TaskCreate(&g_lmsTestTaskId, &lmsTestTask);
if(ret != LOS_OK){
if (ret != LOS_OK) {
PRINT_ERR("LmsTestTask create failed .\n");
return LOS_NOK;
}
......@@ -260,7 +259,7 @@ The key output information is as follows:
### User-Mode Development Process
Add the following to the build script of the app to be checked. For details about the complete code, see **/kernel/liteos_a/apps/lms/BUILD.gn**.
Add the following to the app build script to be checked. For details about the sample code, see [/kernel/liteos_a/apps/lms/BUILD.gn](https://gitee.com/openharmony/kernel_liteos_a/blob/master/apps/lms/BUILD.gn).
```
......@@ -318,7 +317,7 @@ This example implements the following:
The code is as follows:
```
```c
static void BufWriteTest(void *buf, int start, int end)
{
for (int i = start; i <= end; i++) {
......@@ -335,7 +334,7 @@ static void BufReadTest(void *buf, int start, int end)
static void LmsMallocTest(void)
{
printf("\n-------- LmsMallocTest Start --------\n");
char *buf = (char *)malloc(16);
char *buf = (char *)malloc(16); // 16: buffer size for test
BufReadTest(buf, -1, 16);
free(buf);
printf("\n-------- LmsMallocTest End --------\n");
......@@ -343,7 +342,7 @@ static void LmsMallocTest(void)
static void LmsFreeTest(void)
{
printf("\n-------- LmsFreeTest Start --------\n");
char *buf = (char *)malloc(16);
char *buf = (char *)malloc(16); // 16: buffer size for test
free(buf);
BufReadTest(buf, 1, 1);
free(buf);
......@@ -352,7 +351,7 @@ static void LmsFreeTest(void)
int main(int argc, char * const * argv)
{
printf("\n############### Lms Test start ###############\n");
char *tmp = (char *)malloc(5000);
char *tmp = (char *)malloc(5000); // 5000: temp buffer size
LmsMallocTest();
LmsFreeTest();
printf("\n############### Lms Test End ###############\n");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册