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