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 15 : TraStatus ScdThreadsRecord(int32_t fd, const ScdThreads *thds)
18 : {
19 15 : SCD_CHK_PTR_ACTION(thds, return TRACE_INVALID_PARAM);
20 15 : char tmpBuf[SCD_FRAME_LENGTH] = {0};
21 15 : int32_t threadIdx = 0;
22 15 : struct ListHead *pos = NULL;
23 15 : struct AdiagListNode *node = NULL;
24 15 : LIST_FOR_EACH(pos, &thds->thdList.list) {
25 0 : node = LIST_ENTRY(pos, struct AdiagListNode, list);
26 0 : threadIdx++;
27 0 : ScdThread *threadInfo = (ScdThread *)node->data;
28 0 : int32_t err = snprintf_s(tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U,
29 0 : "Thread %d (%d, %s)\n", threadIdx, threadInfo->tid, threadInfo->tname);
30 0 : if (err == -1) {
31 0 : SCD_DLOG_ERR("snprintf_s thread header failed, tid=%d.", threadInfo->tid);
32 0 : return TRACE_FAILURE;
33 : }
34 0 : (void)ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf));
35 :
36 : // record frame info
37 0 : struct ListHead *posFrame = NULL;
38 0 : struct AdiagListNode *nodeFrame = NULL;
39 0 : int32_t frameIdx = -1;
40 0 : LIST_FOR_EACH(posFrame, &threadInfo->frames.frameList.list) {
41 0 : nodeFrame = LIST_ENTRY(posFrame, struct AdiagListNode, list);
42 0 : frameIdx++;
43 0 : ScdFrame *frame = (ScdFrame *)nodeFrame->data;
44 0 : if (strlen(frame->funcName) == 0) {
45 0 : err = snprintf_s(tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U,
46 0 : "#%02u 0x%016lx 0x%016lx %s\n", frame->num, frame->pc, frame->base, frame->soName);
47 : } else {
48 0 : err = snprintf_s(tmpBuf, SCD_FRAME_LENGTH, SCD_FRAME_LENGTH - 1U,
49 0 : "#%02u 0x%016lx 0x%016lx %s (%s)\n", frame->num, frame->pc, frame->base, frame->soName, frame->funcName);
50 : }
51 0 : if (err == -1) {
52 0 : SCD_DLOG_ERR("snprintf_s frame failed, tid=%d, frame index=%d.", threadInfo->tid, frameIdx);
53 0 : return TRACE_FAILURE;
54 : }
55 0 : (void)ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf));
56 : }
57 0 : ScdUtilWriteNewLine(fd);
58 : }
59 15 : return TRACE_SUCCESS;
60 : }
61 :
62 15 : STATIC TraStatus ScdThreadsTraverseLoadFrames(void *node, void *data)
63 : {
64 15 : ScdThread *thd = (ScdThread *)node;
65 15 : ScdMaps *maps = (ScdMaps *)data;
66 15 : if (ScdThreadLoadFrames(thd, maps) != TRACE_SUCCESS) {
67 0 : SCD_DLOG_WAR("can not load thread frames, pid=%d, tid=%d.", thd->pid, thd->tid);
68 0 : return TRACE_FAILURE;
69 : }
70 15 : return TRACE_SUCCESS;
71 : }
72 :
73 150 : TraStatus ScdThreadsLoadFrames(ScdThreads *thds, ScdMaps *maps)
74 : {
75 : // 遍历tid
76 150 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseLoadFrames, maps);
77 150 : return TRACE_SUCCESS;
78 : }
79 :
80 0 : STATIC TraStatus ScdThreadsTraverseLoadInfo(void *node, void *data)
81 : {
82 0 : ScdThread *thd = (ScdThread *)node;
83 0 : ScdThreads *thds = (ScdThreads *)data;
84 :
85 : //load thread regs
86 0 : if(thd->tid != thds->crashTid) {
87 0 : return ScdThreadLoadInfo(thd);
88 : } else {
89 0 : return ScdThreadLoadInfoForCrash(thd, &thds->ucRegs);
90 : }
91 : }
92 :
93 135 : TraStatus ScdThreadsLoadInfo(ScdThreads *thds)
94 : {
95 : // 遍历tid
96 135 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseLoadInfo, thds);
97 135 : return TRACE_SUCCESS;
98 : }
99 :
100 75 : TraStatus ScdThreadsLoad(ScdThreads *thds)
101 : {
102 75 : SCD_CHK_PTR_ACTION(thds, return TRACE_FAILURE);
103 :
104 75 : char buf[SCD_UTIL_TMP_BUF_LEN] = {0};
105 75 : int32_t ret = snprintf_s(buf, SCD_UTIL_TMP_BUF_LEN, SCD_UTIL_TMP_BUF_LEN - 1U, "/proc/%d/task", thds->pid);
106 75 : if (ret == -1) {
107 0 : SCD_DLOG_ERR("snprintf_s task path failed, pid=%d, errno=%d.", thds->pid, errno);
108 0 : return TRACE_FAILURE;
109 : }
110 :
111 75 : DIR *dir = opendir(buf);
112 75 : if (dir == NULL) {
113 60 : SCD_DLOG_ERR("open dir %s failed, errno=%d", buf, errno);
114 60 : return TRACE_FAILURE;
115 : }
116 :
117 15 : struct dirent *ent = NULL;
118 60 : while ((ent = readdir(dir)) != NULL) {
119 45 : if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0)) {
120 30 : continue;
121 : }
122 :
123 15 : int32_t tid = -1;
124 15 : if (AdiagStrToInt(ent->d_name, &tid) != ADIAG_SUCCESS) {
125 0 : continue;
126 : }
127 :
128 15 : ScdThread *thd = ScdThreadCreate(thds->pid, tid);
129 15 : if (thd == NULL) {
130 0 : SCD_DLOG_ERR("create thread failed, pid=%d, tid=%d.", thds->pid, tid);
131 0 : (void)closedir(dir);
132 0 : return TRACE_FAILURE;
133 : }
134 :
135 15 : ret = AdiagListInsert(&thds->thdList, (void *)thd);
136 15 : if (ret != ADIAG_SUCCESS) {
137 0 : ScdThreadDestroy(&thd);
138 0 : (void)closedir(dir);
139 0 : SCD_DLOG_ERR("insert thread failed, pid=%d, tid=%d.", thds->pid, tid);
140 0 : return TRACE_FAILURE;
141 : }
142 15 : SCD_DLOG_INF("load thread successfully, pid=%d, tid=%d.", thds->pid, tid);
143 : }
144 15 : (void)closedir(dir);
145 15 : return TRACE_SUCCESS;
146 : }
147 :
148 0 : STATIC TraStatus ScdThreadsTraverseSuspend(void *node, void *data)
149 : {
150 : (void)data;
151 0 : return ScdThreadSuspend((ScdThread *)node);
152 : }
153 :
154 135 : void ScdThreadsSuspend(ScdThreads *thds)
155 : {
156 : // 遍历tid
157 135 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseSuspend, NULL);
158 135 : }
159 :
160 0 : STATIC TraStatus ScdThreadsTraverseResume(void *node, void *data)
161 : {
162 : (void)data;
163 0 : ScdThreadResume((ScdThread *)node);
164 0 : return TRACE_SUCCESS;
165 : }
166 :
167 135 : void ScdThreadsResume(ScdThreads *thds)
168 : {
169 : // 遍历tid
170 135 : AdiagListForEachTraverse(&thds->thdList, ScdThreadsTraverseResume, NULL);
171 135 : }
172 :
173 225 : TraStatus ScdThreadsInit(ScdThreads *thds, int32_t pid, int32_t crashTid, ucontext_t *uc)
174 : {
175 225 : SCD_CHK_PTR_ACTION(thds, return TRACE_FAILURE);
176 225 : SCD_CHK_PTR_ACTION(uc, return TRACE_FAILURE);
177 225 : thds->pid = pid;
178 225 : thds->crashTid = crashTid;
179 225 : ScdRegsLoadFromUcontext(&thds->ucRegs, uc);
180 225 : AdiagStatus ret = AdiagListInit(&thds->thdList);
181 225 : if (ret != ADIAG_SUCCESS) {
182 0 : SCD_DLOG_ERR("init thread list failed, ret = %d.", ret);
183 0 : return TRACE_FAILURE;
184 : }
185 225 : SCD_DLOG_DBG("init all threads successfully, pid=%d, crash tid=%d, pc=0x%lx, sp=0x%lx, fp=0x%lx.",
186 : pid, crashTid, GET_PCREG(thds->ucRegs.r), GET_SPREG(thds->ucRegs.r), GET_FPREG(thds->ucRegs.r));
187 225 : return TRACE_SUCCESS;
188 : }
189 :
190 225 : void ScdThreadsUninit(ScdThreads *thds)
191 : {
192 225 : if (thds == NULL) {
193 0 : return;
194 : }
195 225 : ScdThread *node = (ScdThread *)AdiagListTakeOut(&thds->thdList);
196 240 : while (node != NULL) {
197 15 : ScdThreadDestroy(&node);
198 15 : node = (ScdThread *)AdiagListTakeOut(&thds->thdList);
199 : }
200 : }
|