LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace/stacktrace_dumper - scd_process.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 95.4 % 240 229
Test Date: 2026-08-31 10:07:06 Functions: 100.0 % 17 17

            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              : }
        

Generated by: LCOV version 2.0-1