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.5 % 245 234
Test Date: 2026-07-28 10:53:44 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          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              : }
        

Generated by: LCOV version 2.0-1