1 /*
2  * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  *    conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *    of conditions and the following disclaimer in the documentation and/or other materials
12  *    provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15  *    to endorse or promote products derived from this software without specific prior written
16  *    permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "los_debugtools.h"
32 #include "securec.h"
33 #include "los_debug.h"
34 #include "los_memory.h"
35 #include "los_arch.h"
36 
37 #if (LOSCFG_DEBUG_TOOLS == 1)
38 typedef struct {
39     UINT32 waterLine;
40     UINT32 taskSPTop;
41     UINT32 taskSPLimit;
42     UINTPTR taskSP;
43 } DumpInfo;
44 
ShowFormat(UINTPTR *buf, DumpInfo *info)45 STATIC VOID ShowFormat(UINTPTR *buf, DumpInfo *info)
46 {
47     INT32 i;
48 
49     UINT32 len = info->waterLine / sizeof(UINTPTR);
50     UINTPTR addr = (info->taskSPLimit - info->waterLine);
51 
52     for (i = 0; i < len; i++) {
53         if ((i % PRINT_PER_ROW) == 0) {
54             PRINTK("\r\n 0x%08x: ", addr);
55         }
56         if (addr == info->taskSP) {
57             PRINTK(" *%08x", buf[i]);
58         } else {
59             PRINTK("  %08x", buf[i]);
60         }
61         addr += sizeof(UINTPTR);
62     }
63 
64     PRINTK("\r\n");
65 }
66 
DumpTaskInfo(UINT32 taskID, UINTPTR *buf, DumpInfo *info)67 STATIC INT32 DumpTaskInfo(UINT32 taskID, UINTPTR *buf, DumpInfo *info)
68 {
69     errno_t ret;
70     LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
71 
72     if (taskID == LOS_CurTaskIDGet()) {
73         info->taskSP = ArchSpGet();
74     } else {
75         info->taskSP = (UINTPTR)taskCB->stackPointer;
76     }
77 
78     info->taskSPTop = taskCB->topOfStack;
79     info->taskSPLimit = taskCB->topOfStack + taskCB->stackSize;
80     if ((info->taskSP > info->taskSPLimit) || (info->taskSP < info->taskSPTop)) {
81         return LOS_NOK;
82     }
83 
84     ret = memcpy_s(buf, info->waterLine, (const VOID *)(info->taskSPLimit - info->waterLine), info->waterLine);
85     if (ret != EOK) {
86         return LOS_NOK;
87     }
88 
89     return LOS_OK;
90 }
91 
LOS_TaskStackDump(UINT32 taskID)92 VOID LOS_TaskStackDump(UINT32 taskID)
93 {
94     UINTPTR *buf = NULL;
95     DumpInfo info;
96     UINT32 intSave;
97     INT32 ret;
98 
99     if (taskID > g_taskMaxNum) {
100         PRINT_ERR("error taskID %u\r\n", taskID);
101         return;
102     }
103 
104     if (OS_INT_ACTIVE) {
105         PRINT_ERR("called during an interrupt.\r\n");
106         return;
107     }
108 
109     intSave = LOS_IntLock();
110     info.waterLine = OsGetTaskWaterLine(taskID);
111     if (info.waterLine == OS_NULL_INT) {
112         LOS_IntRestore(intSave);
113         return;
114     }
115 
116     buf = (UINTPTR *)LOS_MemAlloc(OS_SYS_MEM_ADDR, info.waterLine);
117     if (buf == NULL) {
118         LOS_IntRestore(intSave);
119         PRINT_ERR("alloc failed for dump\n");
120         return;
121     }
122     (VOID)memset_s(buf, info.waterLine, 0, info.waterLine);
123 
124     ret = DumpTaskInfo(taskID, buf, &info);
125     if (ret != LOS_OK) {
126         LOS_IntRestore(intSave);
127         (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, buf);
128         PRINT_ERR("SP 0x%x may error or memcpy_s failed, stack space from 0x%x to 0x%x\r\n", \
129                   info.taskSP, info.taskSPTop, info.taskSPLimit);
130         return;
131     }
132 
133     LOS_IntRestore(intSave);
134     PRINTK("Task %u, SP 0x%x, WaterLine 0x%x", taskID, info.taskSP, info.waterLine);
135     ShowFormat(buf, &info);
136     (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, buf);
137 
138     return;
139 }
140 
OsShellCmdStackDump(INT32 argc, const CHAR **argv)141 UINT32 OsShellCmdStackDump(INT32 argc, const CHAR **argv)
142 {
143     UINT32 taskID;
144 
145     if (argc != 1) {
146         PRINT_ERR("\nUsage: stack taskID\n");
147         return LOS_NOK;
148     }
149 
150     taskID = (UINT32)atoi(argv[0]);
151 
152     LOS_TaskStackDump(taskID);
153     return LOS_OK;
154 }
155 #endif /* LOSCFG_STACK_DUMP == 1 */
156