LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace - stacktrace_exec.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.2 % 141 137
Test Date: 2026-08-31 10:07:06 Functions: 100.0 % 6 6

            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 "stacktrace_exec.h"
      12              : #include <signal.h>
      13              : #include "adiag_print.h"
      14              : #include "stacktrace_safe_recorder.h"
      15              : #include "stacktrace_err_code.h"
      16              : #include "scd_process.h"
      17              : 
      18              : #define STACKTRACE_DUMP_EXE "asc_dumper"
      19              : #define TRACE_UTIL_TEMP_FAILURE_RETRY(exp)    \
      20              :     ({                                        \
      21              :         __typeof__(exp) rc;                   \
      22              :         do {                                  \
      23              :             errno = 0;                        \
      24              :             rc = (exp);                       \
      25              :         } while (rc == -1 && errno == EINTR); \
      26              :         rc;                                   \
      27              :     })
      28              : 
      29          239 : STATIC TraStatus ScExecUnblockDumpSignals(void)
      30              : {
      31          239 :     const int32_t dumpSignals[] = {SIGINT, SIGTERM, SIGQUIT, SIGILL,  SIGTRAP, SIGABRT,   SIGBUS,
      32              :                                    SIGFPE, SIGSEGV, SIGXCPU, SIGXFSZ, SIGSYS,  SIG_ATRACE};
      33              :     sigset_t set;
      34          239 :     if (sigemptyset(&set) != 0) {
      35           18 :         STACKTRACE_LOG_ERR("empty signal mask failed, errno=%d.", errno);
      36           18 :         return TRACE_FAILURE;
      37              :     }
      38         2860 :     for (size_t i = 0; i < sizeof(dumpSignals) / sizeof(dumpSignals[0]); i++) {
      39         2657 :         if (sigaddset(&set, dumpSignals[i]) != 0) {
      40           18 :             STACKTRACE_LOG_ERR("add signal %d to mask failed, errno=%d.", dumpSignals[i], errno);
      41           18 :             return TRACE_FAILURE;
      42              :         }
      43              :     }
      44          203 :     if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
      45           18 :         STACKTRACE_LOG_ERR("unblock stacktrace signals failed, errno=%d.", errno);
      46           18 :         return TRACE_FAILURE;
      47              :     }
      48          185 :     return TRACE_SUCCESS;
      49              : }
      50              : 
      51          311 : STATIC TraStatus ScExecSetArgs(ScdProcessArgs* args, const ThreadArgument* info)
      52              : {
      53          311 :     errno_t ret = memcpy_s(&args->si, sizeof(siginfo_t), &info->siginfo, sizeof(siginfo_t));
      54          311 :     if (ret != EOK) {
      55           18 :         LOGE("copy siginfo failed, err=%d.", ret);
      56           18 :         return TRACE_FAILURE;
      57              :     }
      58          293 :     ret = memcpy_s(&args->uc, sizeof(ucontext_t), &info->ucontext, sizeof(ucontext_t));
      59          293 :     if (ret != EOK) {
      60           18 :         LOGE("copy context failed, err=%d.", ret);
      61           18 :         return TRACE_FAILURE;
      62              :     }
      63          275 :     ret = strcpy_s(args->filePath, SCD_MAX_FILEPATH_LEN + 1U, info->filePath);
      64          275 :     if (ret != EOK) {
      65           18 :         LOGE("copy file path failed, err=%d.", ret);
      66           18 :         return TRACE_FAILURE;
      67              :     }
      68          257 :     ret = strcpy_s(args->fileName, SCD_MAX_FILENAME_LEN + 1U, info->fileName);
      69          257 :     if (ret != EOK) {
      70           18 :         LOGE("copy file name failed, err=%d.", ret);
      71           18 :         return TRACE_FAILURE;
      72              :     }
      73          239 :     args->pid = info->pid;
      74          239 :     args->crashTid = info->tid;
      75          239 :     args->signo = info->signo;
      76          239 :     args->crashTime = info->crashTime;
      77          239 :     args->stackBaseAddr = info->stackBaseAddr;
      78              : 
      79              :     // set mode
      80          239 :     uint32_t mode = (uint32_t)info->siginfo.si_value.sival_int;
      81          239 :     if ((info->signo == SIG_ATRACE) && (mode == STACKTRACE_DUMP_BIN_MODE)) {
      82           19 :         args->handleType = SCD_DUMP_THREADS_BIN;
      83           19 :         LOGR("core path=%s/%s.bin", args->filePath, args->fileName);
      84              :     } else {
      85          220 :         args->handleType = SCD_DUMP_THREADS_TXT;
      86          220 :         LOGR("core path=%s/%s.txt", args->filePath, args->fileName);
      87              :     }
      88              : 
      89          239 :     return TRACE_SUCCESS;
      90              : }
      91              : 
      92          329 : STATIC int32_t ScExecEntry(void* args)
      93              : {
      94          329 :     if (args == NULL) {
      95           18 :         LOGE("args is null.");
      96           18 :         return 1;
      97              :     }
      98          311 :     const ThreadArgument* info = (const ThreadArgument*)args;
      99              :     ScdProcessArgs scdArgs;
     100          311 :     if (ScExecSetArgs(&scdArgs, info) != TRACE_SUCCESS) {
     101           72 :         LOGE("set args failed.");
     102           72 :         return SCD_ERR_CODE_SET_ARG;
     103              :     }
     104          239 :     if (ScExecUnblockDumpSignals() != TRACE_SUCCESS) {
     105           54 :         return SCD_ERR_CODE_SIGMASK;
     106              :     }
     107              : 
     108              :     // create args pipe
     109              :     int32_t pipeFd[2];
     110          185 :     errno = 0;
     111          185 :     if (pipe2(pipeFd, O_CLOEXEC) != 0) {
     112           54 :         STACKTRACE_LOG_ERR("create args pipe failed, errno=%d.", errno);
     113           54 :         return SCD_ERR_CODE_PIPE2;
     114              :     }
     115          131 :     int32_t writeLen = (int32_t)sizeof(ScdProcessArgs);
     116          131 :     if (fcntl(pipeFd[1], F_SETPIPE_SZ, writeLen) < writeLen) {
     117           36 :         STACKTRACE_LOG_ERR("set args pipe size failed, errno=%d", errno);
     118           36 :         return SCD_ERR_CODE_FCNTL;
     119              :     }
     120              : 
     121              :     // write args to pipe
     122           95 :     struct iovec iovs[1] = {{.iov_base = &scdArgs, .iov_len = sizeof(ScdProcessArgs)}};
     123           95 :     int32_t iovsCnt = 1;
     124           95 :     ssize_t ret = TRACE_UTIL_TEMP_FAILURE_RETRY(writev(pipeFd[1], iovs, iovsCnt));
     125           95 :     if (ret != writeLen) {
     126           54 :         STACKTRACE_LOG_ERR("write args to pipe failed, ret=%ld, errno=%d.", ret, errno);
     127           54 :         return SCD_ERR_CODE_WRITEV;
     128              :     }
     129           41 :     if (TRACE_UTIL_TEMP_FAILURE_RETRY(dup2(pipeFd[0], STDIN_FILENO)) == -1) {
     130           36 :         STACKTRACE_LOG_ERR("dup2 stdin failed, errno=%d.", errno);
     131           36 :         return SCD_ERR_CODE_DUP2;
     132              :     }
     133            5 :     (void)syscall(SYS_close, pipeFd[0]);
     134            5 :     (void)syscall(SYS_close, pipeFd[1]);
     135              : 
     136            0 :     if (execlp(info->exePath, STACKTRACE_DUMP_EXE, NULL) < 0) {
     137            0 :         STACKTRACE_LOG_ERR("execlp stacktrace dumper process failed, path=%s, errno=%d.", info->exePath, errno);
     138            0 :         _exit(SCD_ERR_CODE_EXECLP);
     139              :     }
     140            0 :     return SCD_ERR_CODE_SUCCESS;
     141              : }
     142              : 
     143          209 : STATIC void ScExecLogExitError(int32_t pid, int32_t exitStatus)
     144              : {
     145          209 :     switch (exitStatus) {
     146           18 :         case SCD_ERR_CODE_PIPE2:
     147           18 :             STACKTRACE_LOG_ERR("create args pipe failed.");
     148           18 :             break;
     149           18 :         case SCD_ERR_CODE_FCNTL:
     150           18 :             STACKTRACE_LOG_ERR("set args pipe size failed.");
     151           18 :             break;
     152           18 :         case SCD_ERR_CODE_WRITEV:
     153           18 :             STACKTRACE_LOG_ERR("write args to pipe failed.");
     154           18 :             break;
     155           18 :         case SCD_ERR_CODE_DUP2:
     156           18 :             STACKTRACE_LOG_ERR("dup2 stdin failed.");
     157           18 :             break;
     158          101 :         case SCD_ERR_CODE_EXECLP:
     159          101 :             STACKTRACE_LOG_ERR("execlp stacktrace dumper process failed.");
     160          101 :             break;
     161           18 :         case SCD_ERR_CODE_SIGMASK:
     162           18 :             STACKTRACE_LOG_ERR("unblock stacktrace signals failed.");
     163           18 :             break;
     164           18 :         default:
     165           18 :             STACKTRACE_LOG_ERR("child %d exited normally with non-zero exit status(%d)", pid, exitStatus);
     166           18 :             break;
     167              :     }
     168          209 : }
     169              : 
     170          250 : TraStatus ScExecStart(void* stack, ThreadArgument* args, int32_t* pid)
     171              : {
     172          250 :     if (stack == NULL) {
     173           18 :         LOGE("stack for clone is null");
     174           18 :         return TRACE_FAILURE;
     175              :     }
     176          232 :     int32_t err = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
     177          232 :     if (err != 0) {
     178           36 :         STACKTRACE_LOG_ERR("set dumpable failed, errno=%d", errno);
     179           36 :         return TRACE_FAILURE;
     180              :     }
     181          196 :     const int32_t child = clone(ScExecEntry, stack, CLONE_VFORK | CLONE_FS | CLONE_UNTRACED, args, NULL, NULL, NULL);
     182          191 :     if (child == -1) {
     183           36 :         STACKTRACE_LOG_ERR("clone failed, errno=%d", errno);
     184           36 :         return TRACE_FAILURE;
     185              :     }
     186          155 :     *pid = child;
     187          155 :     STACKTRACE_LOG_RUN("create sub process, pid=%d", child);
     188          155 :     err = prctl(PR_SET_PTRACER, child, 0, 0, 0);
     189          155 :     if (err != 0) {
     190           36 :         STACKTRACE_LOG_ERR("set ptracer failed, child=%d, errno=%d", child, errno);
     191              :     } else {
     192          119 :         LOGI("set ptracer successfully, child=%d", child);
     193              :     }
     194          155 :     if ((err == 0) || (args->signo == SIG_ATRACE)) {
     195          137 :         TraceStackRecorderInfo recordInfo = {args->crashTime, args->signo, args->pid, args->tid};
     196          137 :         TraStatus ret = TraceSafeMkdirPath(&recordInfo);
     197          137 :         if (ret != TRACE_SUCCESS) {
     198           36 :             STACKTRACE_LOG_ERR("mkdir path failed, ret=%d.", ret);
     199              :         }
     200              :     }
     201          155 :     return TRACE_SUCCESS;
     202              : }
     203              : 
     204          281 : TraStatus ScExecEnd(int32_t pid)
     205              : {
     206          281 :     int32_t status = 0;
     207          281 :     int32_t ret = TRACE_UTIL_TEMP_FAILURE_RETRY(waitpid(pid, &status, __WALL));
     208          281 :     if (ret == -1) {
     209           18 :         STACKTRACE_LOG_ERR("waitpid failed, child=%d, errno=%d", pid, errno);
     210           18 :         return TRACE_FAILURE;
     211              :     }
     212              : 
     213              :     // check child process state
     214          263 :     if (WIFEXITED(status)) {
     215          227 :         int32_t exitStatus = WEXITSTATUS(status);
     216          227 :         STACKTRACE_LOG_RUN("get sub process result(%d).", exitStatus);
     217          227 :         if (exitStatus == 0) {
     218           18 :             LOGR("child %d exited normally with zero", pid);
     219           18 :             return TRACE_SUCCESS;
     220              :         } else {
     221          209 :             ScExecLogExitError(pid, exitStatus);
     222              :         }
     223           36 :     } else if (WIFSIGNALED(status)) {
     224           18 :         int32_t signalNum = WTERMSIG(status);
     225           18 :         STACKTRACE_LOG_ERR("sub process exited by signal, signal(%d), child=%d.", signalNum, pid);
     226              :     } else {
     227           18 :         STACKTRACE_LOG_ERR("child %d did not exit normally", pid);
     228              :     }
     229              : 
     230          245 :     return TRACE_FAILURE;
     231              : }
        

Generated by: LCOV version 2.0-1