Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "scd_threads.h"
12 : #include "adiag_utils.h"
13 : #include "scd_thread.h"
14 : #include "scd_log.h"
15 : #include "scd_frame.h"
16 :
17 21 : TraStatus ScdThreadsRecord(int32_t fd, const ScdThreads* thds)
18 : {
19 21 : SCD_CHK_PTR_ACTION(thds, return TRACE_INVALID_PARAM);
20 20 : char tmpBuf[SCD_FRAME_LENGTH] = {0};
21 20 : int32_t threadIdx = 0;
22 20 : struct ListHead* pos = NULL;
23 20 : struct AdiagListNode* node = NULL;
24 24 : LIST_FOR_EACH(pos, &thds->thdList.list)
25 : {
26 5 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
27 5 : threadIdx++;
28 5 : ScdThread* threadInfo = (ScdThread*)node->data;
29 5 : int32_t err = snprintf_s(
30 : tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U, "Thread %d (%d, %s)\n", threadIdx, threadInfo->tid,
31 5 : threadInfo->tname);
32 5 : if (err == -1) {
33 1 : SCD_DLOG_ERR("snprintf_s thread header failed, tid=%d.", threadInfo->tid);
34 1 : return TRACE_FAILURE;
35 : }
36 4 : (void)ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf));
37 :
38 : // record frame info
39 4 : struct ListHead* posFrame = NULL;
40 4 : struct AdiagListNode* nodeFrame = NULL;
41 4 : int32_t frameIdx = -1;
42 6 : LIST_FOR_EACH(posFrame, &threadInfo->frames.frameList.list)
43 : {
44 2 : nodeFrame = LIST_ENTRY(posFrame, struct AdiagListNode, list);
45 2 : frameIdx++;
46 2 : ScdFrame* frame = (ScdFrame*)nodeFrame->data;
47 2 : if (strlen(frame->funcName) == 0) {
48 1 : err = snprintf_s(
49 : tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U, "#%02u 0x%016lx 0x%016lx %s\n", frame->num,
50 1 : frame->pc, frame->base, frame->soName);
51 : } else {
52 1 : err = snprintf_s(
53 : tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U, "#%02u 0x%016lx 0x%016lx %s (%s)\n", frame->num,
54 1 : frame->pc, frame->base, frame->soName, frame->funcName);
55 : }
56 2 : if (err == -1) {
57 0 : SCD_DLOG_ERR("snprintf_s frame failed, tid=%d, frame index=%d.", threadInfo->tid, frameIdx);
58 0 : return TRACE_FAILURE;
59 : }
60 2 : (void)ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf));
61 : }
62 4 : ScdUtilWriteNewLine(fd);
63 : }
64 19 : return TRACE_SUCCESS;
65 : }
66 :
67 23 : STATIC TraStatus ScdThreadsTraverseLoadFrames(void* node, void* data)
68 : {
69 23 : ScdThread* thd = (ScdThread*)node;
70 23 : ScdMaps* maps = (ScdMaps*)data;
71 23 : if (ScdThreadLoadFrames(thd, maps) != TRACE_SUCCESS) {
72 6 : SCD_DLOG_WAR("can not load thread frames, pid=%d, tid=%d.", thd->pid, thd->tid);
73 6 : return TRACE_FAILURE;
74 : }
75 17 : return TRACE_SUCCESS;
76 : }
77 :
78 189 : TraStatus ScdThreadsLoadFrames(ScdThreads* thds, ScdMaps* maps)
79 : {
80 : // 遍历tid
81 189 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseLoadFrames, maps);
82 189 : return TRACE_SUCCESS;
83 : }
84 :
85 6 : STATIC TraStatus ScdThreadsTraverseLoadInfo(void* node, void* data)
86 : {
87 6 : ScdThread* thd = (ScdThread*)node;
88 6 : ScdThreads* thds = (ScdThreads*)data;
89 :
90 : // load thread regs
91 6 : if (thd->tid != thds->crashTid) {
92 4 : return ScdThreadLoadInfo(thd);
93 : } else {
94 2 : return ScdThreadLoadInfoForCrash(thd, &thds->ucRegs);
95 : }
96 : }
97 :
98 172 : TraStatus ScdThreadsLoadInfo(ScdThreads* thds)
99 : {
100 : // 遍历tid
101 172 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseLoadInfo, thds);
102 172 : return TRACE_SUCCESS;
103 : }
104 :
105 92 : TraStatus ScdThreadsLoad(ScdThreads* thds)
106 : {
107 92 : SCD_CHK_PTR_ACTION(thds, return TRACE_FAILURE);
108 :
109 92 : char buf[SCD_UTIL_TMP_BUF_LEN] = {0};
110 92 : int32_t ret = snprintf_s(buf, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%d/task", thds->pid);
111 92 : if (ret == -1) {
112 1 : SCD_DLOG_ERR("snprintf_s task path failed, pid=%d, errno=%d.", thds->pid, errno);
113 1 : return TRACE_FAILURE;
114 : }
115 :
116 91 : DIR* dir = opendir(buf);
117 91 : if (dir == NULL) {
118 68 : SCD_DLOG_ERR("open dir %s failed, errno=%d", buf, errno);
119 68 : return TRACE_FAILURE;
120 : }
121 :
122 23 : struct dirent* ent = NULL;
123 94 : while ((ent = readdir(dir)) != NULL) {
124 73 : if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
125 47 : continue;
126 : }
127 :
128 27 : int32_t tid = -1;
129 27 : if (AdiagStrToInt(ent->d_name, &tid) != ADIAG_SUCCESS) {
130 1 : continue;
131 : }
132 :
133 26 : ScdThread* thd = ScdThreadCreate(thds->pid, tid);
134 26 : if (thd == NULL) {
135 1 : SCD_DLOG_ERR("create thread failed, pid=%d, tid=%d.", thds->pid, tid);
136 1 : (void)closedir(dir);
137 2 : return TRACE_FAILURE;
138 : }
139 :
140 25 : ret = AdiagListInsert(&thds->thdList, (void*)thd);
141 25 : if (ret != ADIAG_SUCCESS) {
142 1 : ScdThreadDestroy(&thd);
143 1 : (void)closedir(dir);
144 1 : SCD_DLOG_ERR("insert thread failed, pid=%d, tid=%d.", thds->pid, tid);
145 1 : return TRACE_FAILURE;
146 : }
147 24 : SCD_DLOG_INF("load thread successfully, pid=%d, tid=%d.", thds->pid, tid);
148 : }
149 21 : (void)closedir(dir);
150 21 : return TRACE_SUCCESS;
151 : }
152 :
153 6 : STATIC TraStatus ScdThreadsTraverseSuspend(void* node, void* data)
154 : {
155 : (void)data;
156 6 : return ScdThreadSuspend((ScdThread*)node);
157 : }
158 :
159 172 : void ScdThreadsSuspend(ScdThreads* thds)
160 : {
161 : // 遍历tid
162 172 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseSuspend, NULL);
163 172 : }
164 :
165 6 : STATIC TraStatus ScdThreadsTraverseResume(void* node, void* data)
166 : {
167 : (void)data;
168 6 : ScdThreadResume((ScdThread*)node);
169 6 : return TRACE_SUCCESS;
170 : }
171 :
172 172 : void ScdThreadsResume(ScdThreads* thds)
173 : {
174 : // 遍历tid
175 172 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseResume, NULL);
176 172 : }
177 :
178 277 : TraStatus ScdThreadsInit(ScdThreads* thds, int32_t pid, int32_t crashTid, ucontext_t* uc)
179 : {
180 277 : SCD_CHK_PTR_ACTION(thds, return TRACE_FAILURE);
181 277 : SCD_CHK_PTR_ACTION(uc, return TRACE_FAILURE);
182 277 : thds->pid = pid;
183 277 : thds->crashTid = crashTid;
184 277 : ScdRegsLoadFromUcontext(&thds->ucRegs, uc);
185 277 : AdiagStatus ret = AdiagListInit(&thds->thdList);
186 277 : if (ret != ADIAG_SUCCESS) {
187 1 : SCD_DLOG_ERR("init thread list failed, ret = %d.", ret);
188 1 : return TRACE_FAILURE;
189 : }
190 276 : SCD_DLOG_DBG(
191 : "init all threads successfully, pid=%d, crash tid=%d, pc=0x%lx, sp=0x%lx, fp=0x%lx.", pid, crashTid,
192 : GET_PCREG(thds->ucRegs.r), GET_SPREG(thds->ucRegs.r), GET_FPREG(thds->ucRegs.r));
193 276 : return TRACE_SUCCESS;
194 : }
195 :
196 278 : void ScdThreadsUninit(ScdThreads* thds)
197 : {
198 278 : if (thds == NULL) {
199 2 : return;
200 : }
201 276 : ScdThread* node = (ScdThread*)AdiagListTakeOut(&thds->thdList);
202 301 : while (node != NULL) {
203 25 : ScdThreadDestroy(&node);
204 25 : node = (ScdThread*)AdiagListTakeOut(&thds->thdList);
205 : }
206 : }
|