LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace - stacktrace_parse.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 74.8 % 163 122
Test Date: 2026-08-31 10:07:06 Functions: 100.0 % 11 11

            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_parse.h"
      12              : #include <stdio.h>
      13              : #include <stdlib.h>
      14              : #include <string.h>
      15              : #include <fcntl.h>
      16              : #include <sys/stat.h>
      17              : #include <sys/utsname.h>
      18              : #include "securec.h"
      19              : #include "adiag_print.h"
      20              : #include "adiag_utils.h"
      21              : #include "trace_system_api.h"
      22              : #include "stacktrace_logger.h"
      23              : #include "stacktrace_file_struct.h"
      24              : 
      25              : #define MAX_BUFFER_LENGTH 1024U
      26              : #define TXT_FILE_MODE 0640U
      27              : #define PROCESS_SECTION "[process]\n"
      28              : #define STACK_SECTION "[stack]\n"
      29              : 
      30              : /**
      31              :  * @brief       safe write data to file
      32              :  * @param [in]  fd:         file descriptor
      33              :  * @param [in]  data:       write data
      34              :  * @param [in]  len:        data buffer length
      35              :  * @return      TraStatus
      36              :  */
      37           90 : static TraStatus TraceWrite(int32_t fd, const char* data, size_t len)
      38              : {
      39           90 :     if ((fd < 0) || (data == NULL) || (len == 0)) {
      40           18 :         return TRACE_INVALID_PARAM;
      41              :     }
      42              : 
      43           72 :     size_t reserved = len;
      44              :     do {
      45           72 :         ssize_t wrLen = write(fd, data + (len - reserved), reserved);
      46           72 :         if (wrLen < 0 && errno == EINTR) {
      47            0 :             wrLen = 0;
      48           72 :         } else if (wrLen < 0) {
      49            0 :             return TRACE_FAILURE;
      50              :         } else {
      51              :             ;
      52              :         }
      53           72 :         reserved -= (size_t)wrLen;
      54           72 :     } while (reserved != 0);
      55           72 :     return TRACE_SUCCESS;
      56              : }
      57              : 
      58          126 : static TraStatus TraceCheckBinPath(const char* filePath, uint32_t len)
      59              : {
      60          126 :     if (len >= TRACE_MAX_PATH) {
      61           18 :         LOGE("path length [%u] bytes exceeds [%d] bytes", len, TRACE_MAX_PATH);
      62           18 :         return TRACE_INVALID_PARAM;
      63              :     }
      64          108 :     if (len == 0) {
      65           18 :         LOGE("path length is 0 bytes");
      66           18 :         return TRACE_INVALID_PARAM;
      67              :     }
      68           90 :     if (access(filePath, F_OK) != 0) {
      69           18 :         LOGE("input path [%s] does not exist", filePath);
      70           18 :         return TRACE_INVALID_PARAM;
      71              :     }
      72           72 :     const char* suffix = strrchr(filePath, '.');
      73           72 :     if ((suffix != NULL) && strcmp(suffix, ".bin") == 0) {
      74           54 :         return TRACE_SUCCESS;
      75              :     } else {
      76           18 :         LOGE("invalid path [%s]", filePath);
      77           18 :         return TRACE_INVALID_PARAM;
      78              :     }
      79              : }
      80              : 
      81           36 : static TraStatus TraceCheckBinHead(const struct ScHead* head)
      82              : {
      83           36 :     if ((head->magic == STACK_HEAD_MAGIC) && (head->version == STACK_HEAD_VERSION)) {
      84           18 :         LOGR("check head successfully, magic=%x, version=%x.", head->magic, head->version);
      85           18 :         return TRACE_SUCCESS;
      86              :     }
      87           18 :     LOGE("check head failed, magic=%x, version=%x.", head->magic, head->version);
      88           18 :     return TRACE_FAILURE;
      89              : }
      90              : 
      91           18 : STATIC int32_t TraceGetTxtFd(const char* filePath, uint32_t len)
      92              : {
      93              :     (void)len;
      94           18 :     char* fullPath = strdup(filePath);
      95           18 :     char* pos = strstr(fullPath, ".bin");
      96           18 :     if (pos == NULL) {
      97            0 :         LOGE("find string failed, path = %s.", filePath);
      98            0 :         ADIAG_SAFE_FREE(fullPath);
      99            0 :         return -1;
     100              :     }
     101           18 :     errno_t err = strncpy_s(pos, strlen(pos) + 1U, ".txt", strlen(".txt"));
     102           18 :     if (err != EOK) {
     103            0 :         LOGE("strncpy_s failed, path = %s.", filePath);
     104            0 :         ADIAG_SAFE_FREE(fullPath);
     105            0 :         return -1;
     106              :     }
     107              : 
     108           18 :     int32_t fd = open(fullPath, (uint32_t)O_CREAT | (uint32_t)O_WRONLY | (uint32_t)O_APPEND, TXT_FILE_MODE);
     109           18 :     if (fd >= 0) {
     110           18 :         (void)fchmod(fd, TXT_FILE_MODE);
     111              :     }
     112           18 :     ADIAG_SAFE_FREE(fullPath);
     113           18 :     return fd;
     114              : }
     115              : 
     116           18 : static void TraceWriteProcessReg(int32_t fd, const ScProcessInfo* info)
     117              : {
     118           18 :     char tmpBuf[MAX_BUFFER_LENGTH] = {0};
     119           18 :     int32_t ret = -1;
     120              : #if defined(__aarch64__)
     121              :     ret = snprintf_s(
     122              :         tmpBuf, MAX_BUFFER_LENGTH, MAX_BUFFER_LENGTH - 1U,
     123              :         "crash registers:\n"
     124              :         "    x0  0x%016lx  x1  0x%016lx  x2  0x%016lx  x3  0x%016lx\n"
     125              :         "    x4  0x%016lx  x5  0x%016lx  x6  0x%016lx  x7  0x%016lx\n"
     126              :         "    x8  0x%016lx  x9  0x%016lx  x10 0x%016lx  x11 0x%016lx\n"
     127              :         "    x12 0x%016lx  x13 0x%016lx  x14 0x%016lx  x15 0x%016lx\n"
     128              :         "    x16 0x%016lx  x17 0x%016lx  x18 0x%016lx  x19 0x%016lx\n"
     129              :         "    x20 0x%016lx  x21 0x%016lx  x22 0x%016lx  x23 0x%016lx\n"
     130              :         "    x24 0x%016lx  x25 0x%016lx  x26 0x%016lx  x27 0x%016lx\n"
     131              :         "    x28 0x%016lx  x29 0x%016lx\n"
     132              :         "    sp  0x%016lx  lr  0x%016lx  pc  0x%016lx\n\n",
     133              :         info->regs[SCD_REGS_X0], info->regs[SCD_REGS_X1], info->regs[SCD_REGS_X2], info->regs[SCD_REGS_X3],
     134              :         info->regs[SCD_REGS_X4], info->regs[SCD_REGS_X5], info->regs[SCD_REGS_X6], info->regs[SCD_REGS_X7],
     135              :         info->regs[SCD_REGS_X8], info->regs[SCD_REGS_X9], info->regs[SCD_REGS_X10], info->regs[SCD_REGS_X11],
     136              :         info->regs[SCD_REGS_X12], info->regs[SCD_REGS_X13], info->regs[SCD_REGS_X14], info->regs[SCD_REGS_X15],
     137              :         info->regs[SCD_REGS_X16], info->regs[SCD_REGS_X17], info->regs[SCD_REGS_X18], info->regs[SCD_REGS_X19],
     138              :         info->regs[SCD_REGS_X20], info->regs[SCD_REGS_X21], info->regs[SCD_REGS_X22], info->regs[SCD_REGS_X23],
     139              :         info->regs[SCD_REGS_X24], info->regs[SCD_REGS_X25], info->regs[SCD_REGS_X26], info->regs[SCD_REGS_X27],
     140              :         info->regs[SCD_REGS_X28], info->regs[SCD_REGS_X29], info->regs[SCD_REGS_SP], info->regs[SCD_REGS_LR],
     141              :         info->regs[SCD_REGS_PC]);
     142              : #elif defined(__x86_64__)
     143           18 :     ret = snprintf_s(
     144              :         tmpBuf, MAX_BUFFER_LENGTH, MAX_BUFFER_LENGTH - 1U,
     145              :         "crash registers:\n"
     146              :         "    rax 0x%016lx  rbx 0x%016lx  rcx 0x%016lx  rdx 0x%016lx\n"
     147              :         "    r8  0x%016lx  r9  0x%016lx  r10 0x%016lx  r11 0x%016lx\n"
     148              :         "    r12 0x%016lx  r13 0x%016lx  r14 0x%016lx  r15 0x%016lx\n"
     149              :         "    rdi 0x%016lx  rsi 0x%016lx\n"
     150              :         "    rbp 0x%016lx  rsp 0x%016lx  rip 0x%016lx\n\n",
     151           18 :         info->regs[SCD_REGS_RAX], info->regs[SCD_REGS_RBX], info->regs[SCD_REGS_RCX], info->regs[SCD_REGS_RDX],
     152           18 :         info->regs[SCD_REGS_R8], info->regs[SCD_REGS_R9], info->regs[SCD_REGS_R10], info->regs[SCD_REGS_R11],
     153           18 :         info->regs[SCD_REGS_R12], info->regs[SCD_REGS_R13], info->regs[SCD_REGS_R14], info->regs[SCD_REGS_R15],
     154           18 :         info->regs[SCD_REGS_RDI], info->regs[SCD_REGS_RSI], info->regs[SCD_REGS_RBP], info->regs[SCD_REGS_RSP],
     155           18 :         info->regs[SCD_REGS_RIP]);
     156              : #else
     157              :     (void)info;
     158              : #endif
     159              : 
     160           18 :     if (ret == -1) {
     161            0 :         LOGE("snprintf_s failed, ret = %d, errno = %d.", ret, errno);
     162            0 :         return;
     163              :     }
     164           18 :     (void)TraceWrite(fd, tmpBuf, strlen(tmpBuf));
     165              : }
     166              : 
     167           18 : STATIC void TraceWriteKernelVersion(int32_t fd)
     168              : {
     169           18 :     char tmpBuf[MAX_BUFFER_LENGTH] = {0};
     170           18 :     int32_t ret = snprintf_s(tmpBuf, MAX_BUFFER_LENGTH, MAX_BUFFER_LENGTH - 1U, "kernel version: unknown\n");
     171           18 :     if (ret == -1) {
     172            0 :         LOGE("snprintf_s failed, ret = %d, errno = %d.", ret, errno);
     173            0 :         return;
     174              :     }
     175              : 
     176           18 :     FILE* fp = popen("uname -a", "r");
     177           18 :     if (fp == NULL) {
     178            0 :         LOGE("get kernel version failed, errno=%d.", errno);
     179            0 :         (void)TraceWrite(fd, tmpBuf, strlen(tmpBuf));
     180            0 :         return;
     181              :     }
     182              : 
     183           18 :     char kernelVersion[MAX_BUFFER_LENGTH] = {0};
     184           18 :     if (fgets(kernelVersion, (int32_t)sizeof(kernelVersion), fp) != NULL) {
     185           18 :         ret = snprintf_s(tmpBuf, MAX_BUFFER_LENGTH, MAX_BUFFER_LENGTH - 1U, "kernel version: %s", kernelVersion);
     186           18 :         if (ret == -1) {
     187            0 :             LOGE("snprintf_s failed, ret = %d, errno = %d.", ret, errno);
     188              :         }
     189              :     }
     190           18 :     (void)pclose(fp);
     191           18 :     (void)TraceWrite(fd, tmpBuf, strlen(tmpBuf));
     192              : }
     193              : 
     194           18 : static void TraceWriteProcess(int32_t fd, const ScProcessInfo* info)
     195              : {
     196           18 :     char tmpBuf[MAX_BUFFER_LENGTH] = {0};
     197           18 :     int32_t ret = snprintf_s(
     198              :         tmpBuf, MAX_BUFFER_LENGTH, MAX_BUFFER_LENGTH - 1U,
     199              :         PROCESS_SECTION "crash task:%s\n"
     200              :                         "crash pid:%d\n"
     201              :                         "crash tid:%d\n"
     202              :                         "crash stack base:0x%016lx\n"
     203              :                         "crash stack top:0x%016lx\n"
     204              :                         "crash reason: signal %d\n",
     205           18 :         info->task, info->pid, info->crashTid, info->baseAddr, info->topAddr, info->signo);
     206           18 :     if (ret == -1) {
     207            0 :         LOGE("snprintf_s failed, ret = %d, errno = %d.", ret, errno);
     208            0 :         return;
     209              :     }
     210           18 :     (void)TraceWrite(fd, tmpBuf, strlen(tmpBuf));
     211           18 :     TraceWriteKernelVersion(fd);
     212           18 :     TraceWriteProcessReg(fd, info);
     213              : }
     214              : 
     215           18 : static void TraceWriteStack(int32_t fd, const struct ScThreadInfo* data)
     216              : {
     217           18 :     (void)TraceWrite(fd, STACK_SECTION, strlen(STACK_SECTION));
     218           18 :     char tmpBuf[MAX_BUFFER_LENGTH] = {0};
     219           18 :     for (uint32_t i = 0; i < MAX_THREAD_NUM; i++) {
     220           18 :         if (data[i].tid == 0) {
     221           18 :             break;
     222              :         }
     223            0 :         int32_t ret = snprintf_s(
     224            0 :             tmpBuf, MAX_BUFFER_LENGTH, MAX_BUFFER_LENGTH - 1U, "Thread %u (%d, %s)\n", i + 1U, data[i].tid,
     225            0 :             data[i].name);
     226            0 :         if (ret == -1) {
     227            0 :             LOGE("snprintf_s failed, ret = %d, errno = %d.", ret, errno);
     228            0 :             return;
     229              :         }
     230            0 :         (void)TraceWrite(fd, tmpBuf, strlen(tmpBuf));
     231            0 :         for (int32_t j = 0; j <= data[i].layer; j++) {
     232            0 :             (void)TraceWrite(fd, data[i].frames[j].frame, strlen(data[i].frames[j].frame));
     233              :         }
     234            0 :         (void)TraceWrite(fd, "\n", strlen("\n"));
     235              :     }
     236              : }
     237              : 
     238           18 : static void TraceWriteTxt(int32_t fd, const struct StackcoreBuffer* data)
     239              : {
     240           18 :     TraceWriteProcess(fd, &data->process);
     241           18 :     TraceWriteStack(fd, data->thread);
     242           18 :     return;
     243              : }
     244              : 
     245           54 : STATIC TraStatus TraceParseBinFile(const char* filePath, uint32_t len)
     246              : {
     247           54 :     int32_t binFile = open(filePath, O_RDONLY);
     248           54 :     if (binFile == -1) {
     249            0 :         LOGE("could not open file [%s]", filePath);
     250            0 :         return TRACE_INVALID_PARAM;
     251              :     }
     252              : 
     253           54 :     struct StackcoreBuffer* data = (struct StackcoreBuffer*)AdiagMalloc(sizeof(struct StackcoreBuffer));
     254           54 :     if (data == NULL) {
     255            0 :         TraceClose(&binFile);
     256            0 :         LOGE("malloc failed.");
     257            0 :         return TRACE_FAILURE;
     258              :     }
     259              : 
     260           54 :     ssize_t readBytes = read(binFile, data, sizeof(struct StackcoreBuffer));
     261           54 :     if ((size_t)readBytes != sizeof(struct StackcoreBuffer)) {
     262           18 :         TraceClose(&binFile);
     263           18 :         ADIAG_SAFE_FREE(data);
     264           18 :         LOGE("can not read data from file [%s]", filePath);
     265           18 :         return TRACE_INVALID_PARAM;
     266              :     }
     267              : 
     268           36 :     TraStatus ret = TraceCheckBinHead(&data->head);
     269           36 :     if (ret != TRACE_SUCCESS) {
     270           18 :         TraceClose(&binFile);
     271           18 :         ADIAG_SAFE_FREE(data);
     272           18 :         return ret;
     273              :     }
     274              : 
     275           18 :     int32_t txtFile = TraceGetTxtFd(filePath, len);
     276           18 :     if (txtFile == -1) {
     277            0 :         LOGE("could not open txt file[%s]", filePath);
     278            0 :         TraceClose(&binFile);
     279            0 :         ADIAG_SAFE_FREE(data);
     280            0 :         return TRACE_FAILURE;
     281              :     }
     282              : 
     283           18 :     TraceWriteTxt(txtFile, data);
     284              : 
     285           18 :     char tmpBuf[MAX_BUFFER_LENGTH] = {0};
     286              :     do {
     287           18 :         readBytes = read(binFile, tmpBuf, MAX_BUFFER_LENGTH);
     288           18 :         (void)TraceWrite(txtFile, tmpBuf, (size_t)readBytes);
     289           18 :     } while (readBytes > 0);
     290              : 
     291           18 :     ADIAG_SAFE_FREE(data);
     292           18 :     TraceClose(&binFile);
     293           18 :     TraceClose(&txtFile);
     294           18 :     return TRACE_SUCCESS;
     295              : }
     296              : 
     297          126 : TraStatus TraceStackParse(const char* filePath, uint32_t len)
     298              : {
     299          126 :     LOGR("start to parse bin file[%s]", filePath);
     300          126 :     TraStatus ret = TraceCheckBinPath(filePath, len);
     301          126 :     if (ret != TRACE_SUCCESS) {
     302           72 :         return ret;
     303              :     }
     304           54 :     char realPath[TRACE_MAX_PATH] = {0};
     305           54 :     if ((TraceRealPath(filePath, realPath, TRACE_MAX_PATH) != EN_OK) && (AdiagGetErrorCode() != ENOENT)) {
     306            0 :         LOGE("can not get realpath, path=%s, strerr=%s.", filePath, strerror(AdiagGetErrorCode()));
     307            0 :         return TRACE_FAILURE;
     308              :     }
     309              : 
     310           54 :     ret = TraceParseBinFile(realPath, (uint32_t)strlen(realPath));
     311           54 :     if (ret != TRACE_SUCCESS) {
     312           36 :         return ret;
     313              :     }
     314              : 
     315           18 :     if (remove(realPath) != 0) {
     316            0 :         LOGW("can not remove file [%s]", realPath);
     317            0 :         return TRACE_SUCCESS;
     318              :     }
     319              : 
     320           18 :     return TRACE_SUCCESS;
     321              : }
        

Generated by: LCOV version 2.0-1