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_process.h"
12 : #include "adiag_utils.h"
13 : #include "trace_system_api.h"
14 : #include "scd_log.h"
15 : #include "scd_layout.h"
16 :
17 : #define SCD_FILE_TXT_SUFFIX ".txt"
18 : #define SCD_FILE_BIN_SUFFIX ".bin"
19 : #define SCD_BUFFER_LENGTH 1024U
20 :
21 : STATIC ScdProcess* g_scdProcessCore = NULL;
22 :
23 289 : static void ScdProcessRecordRegInfo(int32_t fd, const ScdRegs* info)
24 : {
25 289 : char tmpBuf[SCD_BUFFER_LENGTH] = {0};
26 289 : TraStatus ret = ScdRegsGetString(info, tmpBuf, SCD_BUFFER_LENGTH);
27 289 : if (ret != TRACE_SUCCESS) {
28 102 : SCD_DLOG_ERR("get register info string failed, ret=%d.", ret);
29 119 : return;
30 : }
31 :
32 187 : if (ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf)) != strlen(tmpBuf)) {
33 17 : SCD_DLOG_ERR("write regs info to file failed.");
34 17 : return;
35 : }
36 : }
37 :
38 289 : STATIC void ScdProcessRecordKernelVersion(int32_t fd)
39 : {
40 289 : const char* unknownVersion = "kernel version: unknown\n";
41 289 : FILE* fp = popen("uname -a", "r");
42 289 : if (fp == NULL) {
43 17 : SCD_DLOG_ERR("get kernel version failed, errno=%d.", errno);
44 17 : (void)ScdUtilWrite(fd, unknownVersion, strlen(unknownVersion));
45 102 : return;
46 : }
47 :
48 272 : char tmpBuf[SCD_BUFFER_LENGTH] = {0};
49 272 : char kernelVersion[SCD_BUFFER_LENGTH] = {0};
50 272 : if (fgets(kernelVersion, (int32_t)sizeof(kernelVersion), fp) != NULL) {
51 : int32_t err =
52 272 : snprintf_s(tmpBuf, SCD_BUFFER_LENGTH, SCD_BUFFER_LENGTH - 1U, "kernel version: %s", kernelVersion);
53 272 : if (err == -1) {
54 68 : SCD_DLOG_ERR("snprintf_s kernel version failed, errno = %d.", errno);
55 68 : (void)ScdUtilWrite(fd, unknownVersion, strlen(unknownVersion));
56 68 : (void)pclose(fp);
57 68 : return;
58 : }
59 : }
60 204 : (void)pclose(fp);
61 204 : size_t ret = ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf));
62 204 : if (ret != strlen(tmpBuf)) {
63 17 : SCD_DLOG_ERR("write kernel version to file failed.");
64 17 : (void)ScdUtilWrite(fd, unknownVersion, strlen(unknownVersion));
65 17 : return;
66 : }
67 : }
68 :
69 289 : STATIC void ScdProcessRecordSiginfo(int32_t fd, const ScdProcess* info)
70 : {
71 289 : char tmpBuf[SCD_BUFFER_LENGTH] = {0};
72 289 : int32_t err = snprintf_s(
73 : tmpBuf, SCD_BUFFER_LENGTH, SCD_BUFFER_LENGTH - 1U,
74 : "crash task:%s\n"
75 : "crash pid:%d\n"
76 : "crash tid:%d\n"
77 : "crash stack base:0x%016lx\n"
78 : "crash stack top:0x%016lx\n"
79 : "crash reason: signal %d\n",
80 289 : info->pname, info->args.pid, info->args.crashTid, info->args.stackBaseAddr,
81 289 : GET_SPREG_FROM_CONTEXT(&info->args.uc.uc_mcontext), info->args.signo);
82 289 : if (err == -1) {
83 34 : SCD_DLOG_ERR("snprintf_s failed, errno = %d.", errno);
84 51 : return;
85 : }
86 :
87 255 : size_t ret = ScdUtilWrite(fd, tmpBuf, strlen(tmpBuf));
88 255 : if (ret != strlen(tmpBuf)) {
89 17 : SCD_DLOG_ERR("write signal info to file failed.");
90 17 : return;
91 : }
92 : }
93 :
94 289 : STATIC TraStatus ScdProcessRecordInfo(int32_t fd, const ScdProcess* pro)
95 : {
96 : // record [process]
97 289 : ScdUtilWriteTitle(fd, SCD_SECTION_PROCESS);
98 289 : ScdProcessRecordSiginfo(fd, pro);
99 289 : ScdProcessRecordKernelVersion(fd);
100 289 : ScdProcessRecordRegInfo(fd, &pro->thds.ucRegs);
101 289 : ScdUtilWriteNewLine(fd);
102 289 : return TRACE_SUCCESS;
103 : }
104 :
105 51 : STATIC TraStatus ScdProcessRecordStack(int32_t fd, const ScdProcess* pro)
106 : {
107 : // record [stack]
108 51 : ScdUtilWriteTitle(fd, SCD_SECTION_STACK);
109 51 : if (ScdThreadsRecord(fd, &pro->thds) != TRACE_SUCCESS) {
110 17 : SCD_DLOG_ERR("record stack info failed.");
111 17 : return TRACE_FAILURE;
112 : }
113 34 : return TRACE_SUCCESS;
114 : }
115 :
116 221 : STATIC INLINE TraStatus ScdProcessRecordProcInfo(int32_t fd, pid_t pid, const char* name)
117 : {
118 : // 拼接文件:/proc/{pid}/name
119 : // 从文件中逐行读取,逐行写
120 221 : TraStatus ret = TRACE_SUCCESS;
121 221 : if (strcmp(name, SCD_SECTION_MEMORY) == 0) {
122 51 : ScdUtilWriteTitle(fd, name);
123 51 : ret = ScdUtilWriteProcInfo(fd, -1, "meminfo");
124 170 : } else if (strcmp(name, SCD_SECTION_STATUS) == 0) {
125 51 : ScdUtilWriteTitle(fd, name);
126 51 : ret = ScdUtilWriteProcInfo(fd, pid, "status");
127 119 : } else if (strcmp(name, SCD_SECTION_LIMITS) == 0) {
128 51 : ScdUtilWriteTitle(fd, name);
129 51 : ret = ScdUtilWriteProcInfo(fd, pid, "limits");
130 68 : } else if (strcmp(name, SCD_SECTION_MAPS) == 0) {
131 51 : ScdUtilWriteTitle(fd, name);
132 51 : ret = ScdUtilWriteProcInfo(fd, pid, "maps");
133 : } else {
134 17 : SCD_DLOG_WAR("invalid section name [%s].", name);
135 17 : return ret;
136 : }
137 :
138 204 : ScdUtilWriteNewLine(fd);
139 204 : return ret;
140 : }
141 :
142 170 : STATIC TraStatus ScdProcessLoadInfo(ScdProcess* pro)
143 : {
144 : // get pname
145 170 : ScdUtilGetProcessName(pro->args.pid, pro->pname, SCD_PNAME_LEN);
146 :
147 : // get tname and regs
148 170 : return ScdThreadsLoadInfo(&pro->thds);
149 : }
150 :
151 170 : STATIC TraStatus ScdProcessLoad(ScdProcess* pro)
152 : {
153 170 : TraStatus ret = ScdMapsLoad(&pro->maps);
154 170 : if (ret != TRACE_SUCCESS) {
155 0 : SCD_DLOG_ERR("load maps failed, ret=%d.", ret);
156 0 : return ret;
157 : }
158 :
159 170 : ret = ScdProcessLoadInfo(pro);
160 170 : if (ret != TRACE_SUCCESS) {
161 0 : SCD_DLOG_ERR("load process info failed, ret=%d.", ret);
162 0 : return ret;
163 : }
164 :
165 170 : ret = ScdThreadsLoadFrames(&pro->thds, &pro->maps);
166 170 : if (ret != TRACE_SUCCESS) {
167 0 : SCD_DLOG_ERR("load frames failed, ret=%d.", ret);
168 0 : return ret;
169 : }
170 170 : return TRACE_SUCCESS;
171 : }
172 :
173 323 : STATIC TraStatus ScdProcessInit(ScdProcess** process, const ScdProcessArgs* args)
174 : {
175 323 : ScdProcess* pro = (ScdProcess*)AdiagMalloc(sizeof(ScdProcess));
176 323 : if (pro == NULL) {
177 17 : SCD_DLOG_ERR("malloc struct ScdProcess failed.");
178 17 : return TRACE_FAILURE;
179 : }
180 :
181 306 : pro->shdrUsed = false;
182 306 : errno_t err = memcpy_s(&pro->args, sizeof(ScdProcessArgs), args, sizeof(ScdProcessArgs));
183 306 : if (err != EOK) {
184 17 : AdiagFree(pro);
185 17 : SCD_DLOG_ERR("memcpy_s failed, err=%d.", err);
186 17 : return TRACE_FAILURE;
187 : }
188 289 : TraStatus ret = ScdMapsInit(&pro->maps, pro->args.pid);
189 289 : if (ret != TRACE_SUCCESS) {
190 17 : AdiagFree(pro);
191 17 : SCD_DLOG_ERR("init maps failed, ret=%d.", ret);
192 17 : return TRACE_FAILURE;
193 : }
194 272 : ret = ScdThreadsInit(&pro->thds, pro->args.pid, pro->args.crashTid, &pro->args.uc);
195 272 : if (ret != TRACE_SUCCESS) {
196 17 : ScdMapsUninit(&pro->maps);
197 17 : AdiagFree(pro);
198 17 : SCD_DLOG_ERR("init threads failed, ret=%d.", ret);
199 17 : return TRACE_FAILURE;
200 : }
201 255 : *process = pro;
202 255 : return TRACE_SUCCESS;
203 : }
204 :
205 255 : STATIC void ScdProcessUninit(ScdProcess** process)
206 : {
207 255 : if (*process == NULL) {
208 0 : return;
209 : }
210 255 : ScdProcess* pro = *process;
211 255 : ScdMapsUninit(&pro->maps);
212 255 : ScdThreadsUninit(&pro->thds);
213 255 : AdiagFree(pro);
214 255 : pro = NULL;
215 255 : return;
216 : }
217 :
218 204 : STATIC TraStatus ScdProcessCreateFile(const ScdProcessArgs* args, const char* suffix, int32_t* fd)
219 : {
220 204 : if (access(args->filePath, F_OK) != 0) {
221 51 : SCD_DLOG_ERR("file path \"%s\" does not exist.", args->filePath);
222 51 : return TRACE_FAILURE;
223 : }
224 153 : char path[SCD_MAX_FULLPATH_LEN + 1U] = {0};
225 153 : int32_t err = snprintf_s(
226 153 : path, SCD_MAX_FULLPATH_LEN + 1U, SCD_MAX_FULLPATH_LEN, "%s/%s%s", args->filePath, args->fileName, suffix);
227 153 : if (err == -1) {
228 17 : SCD_DLOG_ERR("snprintf_s failed, err=%d.", err);
229 17 : return TRACE_FAILURE;
230 : }
231 :
232 136 : char realPath[TRACE_MAX_PATH] = {0};
233 136 : if ((TraceRealPath(path, realPath, TRACE_MAX_PATH) != EN_OK) && (AdiagGetErrorCode() != ENOENT)) {
234 17 : SCD_DLOG_ERR("can not get realpath, path=%s, strerr=%s.", path, strerror(AdiagGetErrorCode()));
235 17 : return TRACE_FAILURE;
236 : }
237 :
238 119 : int32_t fileFd = open(realPath, O_CREAT | O_RDWR | O_TRUNC, 0640);
239 119 : if (fileFd < 0) {
240 17 : SCD_DLOG_ERR("open \"%s\" failed, fd=%d.", realPath, fileFd);
241 17 : return TRACE_FAILURE;
242 : }
243 102 : *fd = fileFd;
244 102 : SCD_DLOG_INF("create file \"%s\" successfully, fd=%d.", realPath, fileFd);
245 102 : return TRACE_SUCCESS;
246 : }
247 :
248 153 : STATIC TraStatus ScdProcessRecordTxt(const ScdProcess* pro)
249 : {
250 : // open file
251 153 : int32_t fd = -1;
252 153 : TraStatus ret = ScdProcessCreateFile(&pro->args, SCD_FILE_TXT_SUFFIX, &fd);
253 153 : if (ret != TRACE_SUCCESS) {
254 85 : SCD_DLOG_ERR("create txt file failed, ret=%d.", ret);
255 85 : return TRACE_FAILURE;
256 : }
257 :
258 : // write [process] to txt
259 68 : (void)ScdProcessRecordInfo(fd, pro);
260 :
261 68 : if (pro->shdrUsed) {
262 : // write [stack] to txt
263 17 : (void)ScdSectionRecord(fd, pro, SCD_SECTION_STACK);
264 :
265 : // write proc([maps]、[meminfo]、[status]、[limits]...) to txt
266 17 : (void)ScdSectionRecord(fd, pro, SCD_SECTION_MAPS);
267 17 : (void)ScdSectionRecord(fd, pro, SCD_SECTION_MEMORY);
268 17 : (void)ScdSectionRecord(fd, pro, SCD_SECTION_STATUS);
269 17 : (void)ScdSectionRecord(fd, pro, SCD_SECTION_LIMITS);
270 : } else {
271 : // write [stack] to txt
272 51 : (void)ScdProcessRecordStack(fd, pro);
273 :
274 : // write proc([maps]、[meminfo]、[status]、[limits]...) to txt
275 51 : (void)ScdProcessRecordProcInfo(fd, pro->args.pid, SCD_SECTION_MAPS);
276 51 : (void)ScdProcessRecordProcInfo(fd, pro->args.pid, SCD_SECTION_MEMORY);
277 51 : (void)ScdProcessRecordProcInfo(fd, pro->args.pid, SCD_SECTION_STATUS);
278 51 : (void)ScdProcessRecordProcInfo(fd, pro->args.pid, SCD_SECTION_LIMITS);
279 : }
280 :
281 68 : (void)close(fd);
282 68 : return TRACE_SUCCESS;
283 : }
284 :
285 51 : STATIC TraStatus ScdProcessRecordCore(ScdProcess* pro)
286 : {
287 : // create bin file
288 51 : int32_t fd = -1;
289 51 : TraStatus ret = ScdProcessCreateFile(&pro->args, SCD_FILE_BIN_SUFFIX, &fd);
290 51 : if (ret != TRACE_SUCCESS) {
291 17 : SCD_DLOG_ERR("create bin file failed, ret=%d.", ret);
292 17 : return TRACE_FAILURE;
293 : }
294 :
295 34 : ret = ScdLayoutWrite(fd, pro);
296 34 : if (ret != TRACE_SUCCESS) {
297 17 : SCD_DLOG_ERR("write bin file failed, ret=%d.", ret);
298 17 : (void)close(fd);
299 17 : return TRACE_FAILURE;
300 : }
301 17 : (void)close(fd);
302 17 : return TRACE_SUCCESS;
303 : }
304 :
305 51 : STATIC TraStatus ScdProcessReadCore(ScdProcess** pro, const char* filePath) { return ScdLayoutRead(pro, filePath); }
306 :
307 323 : TraStatus ScdProcessDump(const ScdProcessArgs* args)
308 : {
309 : // 1. init process object
310 323 : TraStatus ret = ScdProcessInit(&g_scdProcessCore, args);
311 323 : if (ret != TRACE_SUCCESS) {
312 68 : return TRACE_FAILURE;
313 : }
314 :
315 : // 2. get tid
316 255 : ret = ScdThreadsLoad(&g_scdProcessCore->thds);
317 255 : if (ret != TRACE_SUCCESS) {
318 85 : STACKTRACE_LOG_ERR("load threads failed, ret=%d.", ret);
319 85 : ScdProcessUninit(&g_scdProcessCore);
320 85 : return TRACE_FAILURE;
321 : }
322 :
323 : // 3. suspend all threads
324 170 : ScdThreadsSuspend(&g_scdProcessCore->thds);
325 170 : STACKTRACE_LOG_RUN("suspend process(%d).", g_scdProcessCore->args.pid);
326 :
327 : // 4. load core info to global variable
328 170 : ret = ScdProcessLoad(g_scdProcessCore);
329 170 : if (ret != TRACE_SUCCESS) {
330 0 : STACKTRACE_LOG_ERR("load process failed, ret=%d.", ret);
331 0 : ScdThreadsResume(&g_scdProcessCore->thds);
332 0 : ScdProcessUninit(&g_scdProcessCore);
333 0 : return TRACE_FAILURE;
334 : }
335 :
336 : // 5. record to file (txt or core)
337 170 : if (g_scdProcessCore->args.handleType == SCD_DUMP_THREADS_TXT) {
338 : // write to txt
339 119 : ret = ScdProcessRecordTxt(g_scdProcessCore);
340 : } else {
341 : // write to core
342 51 : ret = ScdProcessRecordCore(g_scdProcessCore);
343 : }
344 :
345 : // 6. resume all threads
346 170 : ScdThreadsResume(&g_scdProcessCore->thds);
347 170 : STACKTRACE_LOG_RUN("resume process(%d).", g_scdProcessCore->args.pid);
348 :
349 : // 7. uninit process object
350 170 : ScdProcessUninit(&g_scdProcessCore);
351 170 : return ret;
352 : }
353 :
354 153 : static TraStatus ScdProcessCheckBinPath(const char* filePath, uint32_t len)
355 : {
356 153 : if (len >= TRACE_MAX_PATH) {
357 17 : SCD_DLOG_ERR("path length [%u] bytes exceeds [%d] bytes", len, TRACE_MAX_PATH);
358 17 : return TRACE_INVALID_PARAM;
359 : }
360 136 : if (len == 0) {
361 17 : SCD_DLOG_ERR("path length is 0 bytes");
362 17 : return TRACE_INVALID_PARAM;
363 : }
364 119 : if (access(filePath, F_OK) != 0) {
365 34 : SCD_DLOG_ERR("input path [%s] does not exist", filePath);
366 34 : return TRACE_INVALID_PARAM;
367 : }
368 85 : const char* suffix = strrchr(filePath, '.');
369 85 : if ((suffix != NULL) && strcmp(suffix, SCD_FILE_BIN_SUFFIX) == 0) {
370 68 : return TRACE_SUCCESS;
371 : } else {
372 17 : SCD_DLOG_ERR("invalid path [%s]", filePath);
373 17 : return TRACE_INVALID_PARAM;
374 : }
375 : }
376 :
377 153 : TraStatus ScdProcessParseCore(const char* filePath, uint32_t len)
378 : {
379 153 : TraStatus ret = ScdProcessCheckBinPath(filePath, len);
380 153 : if (ret != TRACE_SUCCESS) {
381 85 : SCD_DLOG_ERR("check bin path failed, ret=%d.", ret);
382 85 : return TRACE_FAILURE;
383 : }
384 :
385 68 : char realPath[TRACE_MAX_PATH] = {0};
386 68 : if ((TraceRealPath(filePath, realPath, TRACE_MAX_PATH) != EN_OK) && (errno != ENOENT)) {
387 17 : SCD_DLOG_ERR("can not get realpath, path=%s, errno=%d.", filePath, errno);
388 17 : return TRACE_FAILURE;
389 : }
390 :
391 : // read from core
392 51 : SCD_DLOG_INF("parse core file=%s.", realPath);
393 51 : ret = ScdProcessReadCore(&g_scdProcessCore, realPath);
394 51 : if (ret != TRACE_SUCCESS) {
395 17 : SCD_DLOG_ERR("read core file failed, ret=%d.", ret);
396 17 : return TRACE_FAILURE;
397 : }
398 :
399 : // write to txt
400 34 : ret = ScdProcessRecordTxt(g_scdProcessCore);
401 34 : ADIAG_SAFE_FREE(g_scdProcessCore);
402 34 : if (ret != TRACE_SUCCESS) {
403 17 : SCD_DLOG_ERR("record to txt failed, ret=%d.", ret);
404 17 : return TRACE_FAILURE;
405 : }
406 :
407 17 : if (remove(realPath) != 0) {
408 17 : SCD_DLOG_WAR("can not remove file [%s]", realPath);
409 : }
410 17 : return TRACE_SUCCESS;
411 : }
|