LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace - stacktrace_parse.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 179 0
Test Date: 2026-07-28 10:53:44 Functions: 0.0 % 11 0

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

Generated by: LCOV version 2.0-1