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

Generated by: LCOV version 2.0-1