LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace - stacktrace_fp.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.8 % 141 121
Test Date: 2026-07-28 10:53:44 Functions: 100.0 % 7 7

            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_fp.h"
      12              : #include <errno.h>
      13              : #include <string.h>
      14              : #include <ucontext.h>
      15              : #include <fcntl.h>
      16              : #include <pthread.h>
      17              : #include "securec.h"
      18              : #include "stacktrace_unwind_reg.h"
      19              : #include "adiag_print.h"
      20              : #include "adiag_utils.h"
      21              : #include "trace_types.h"
      22              : #include "trace_system_api.h"
      23              : 
      24              : #define EXEC_READ_MAP                       "r"
      25              : #define EXEC_MAP_ATTR                       "r-xp"
      26              : #define OS_SPLIT                            '/'
      27              : #define LR_OFFSET           8U
      28              : 
      29              : /**
      30              :  * @brief       get current pc self map
      31              :  * @param [in]  pc:         exception PC register
      32              :  * @param [out] data:       exception map info
      33              :  * @param [in]  len:        data buffer length
      34              :  * @return      TRACE_SUCCESS  success; TRACE_FAILURE  failure
      35              :  */
      36          250 : STATIC TraStatus TraceGetSelfMap(uintptr_t pc, char *data, uint32_t len)
      37              : {
      38          250 :     if (data == NULL || len == 0) {
      39            0 :         return TRACE_FAILURE;
      40              :     }
      41              : 
      42          250 :     int32_t fd = open(SELF_MAP_PATH, O_RDONLY);
      43          250 :     if (fd < 0) {
      44            0 :         LOGW("self map fopen null");
      45            0 :         return TRACE_FAILURE;
      46              :     }
      47              : 
      48          250 :     char *vmPath = NULL;
      49          250 :     uintptr_t vmStart = 0;
      50          250 :     uintptr_t vmEnd = 0;
      51          250 :     char currentPath[CORE_BUFFER_LEN] = { 0 };
      52          250 :     uintptr_t baseAddr = 0; // the minimum addr of load segment
      53        12337 :     while (TraceSafeReadLine(fd, data, len) > 0) {
      54        12286 :         vmPath = strchr(data, OS_SPLIT);
      55        12286 :         if (vmPath == NULL) {
      56         3098 :             continue;
      57              :         }
      58         9188 :         if (sscanf_s(data, "%lx-%lx", &vmStart, &vmEnd) <= 0) {
      59            0 :             continue;
      60              :         }
      61              : 
      62         9188 :         if (strcmp(currentPath, vmPath) != 0) {
      63         1255 :             errno_t err = strncpy_s(currentPath, CORE_BUFFER_LEN, vmPath, CORE_BUFFER_LEN - 1U);
      64         1255 :             if (err != 0) {
      65            0 :                 LOGE("copy vmPath to currentPath failed.");
      66            0 :                 break;
      67              :             }
      68         1255 :             baseAddr = vmStart; // update baseAddr when path change
      69              :         }
      70              :         // pcAddr is in code-segment(r-xp)
      71         9188 :         if ((pc < vmStart) || (pc > vmEnd) || (strstr(data, EXEC_MAP_ATTR) == NULL)) {
      72         8989 :             continue;
      73              :         }
      74              : 
      75          199 :         int32_t ret = snprintf_s(data, len, (size_t)len - 1U, "0x%016lx %s", baseAddr, currentPath);
      76          199 :         if (ret == -1) {
      77            0 :             LOGE("snprintf_s map info failed");
      78            0 :             break;
      79              :         }
      80          199 :         TraceClose(&fd);
      81          199 :         return TRACE_SUCCESS;
      82              :     }
      83           51 :     TraceClose(&fd);
      84           51 :     return TRACE_FAILURE;
      85              : }
      86              : 
      87              : /**
      88              :  * @brief       reason the stack frame by FP
      89              :  * @param [in]  layer:      exception layer
      90              :  * @param [in]  fp:         exception FP register
      91              :  * @param [out] data:       exception info
      92              :  * @param [in]  len:        data buffer length
      93              :  * @return      0  reason end; other  continue to reason
      94              :  */
      95          330 : STATIC uintptr_t TraceStackFrame(int32_t layer, uintptr_t fp, char *data, size_t len)
      96              : {
      97          330 :     uintptr_t nfp = 0;
      98          330 :     uintptr_t pc = 0;
      99          330 :     char info[CORE_BUFFER_LEN] = { 0 };
     100          330 :     if (fp == 0 || layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
     101           80 :         return 0;
     102              :     }
     103              : 
     104          250 :     if (layer == 0) { // current pc frame
     105           75 :         pc = fp;
     106           75 :         nfp = pc;
     107              :     } else { // fp inference pc frame
     108          175 :         uintptr_t lr = fp + LR_OFFSET;
     109          175 :         if (lr < fp) {
     110            0 :             return 0;
     111              :         }
     112          175 :         pc = *(uintptr_t *)lr;
     113          175 :         nfp = *(uintptr_t *)fp;
     114              :     }
     115              :     int32_t ret;
     116          250 :     if (TraceGetSelfMap(pc, info, (uint32_t)sizeof(info)) != TRACE_SUCCESS) {
     117           51 :         ret = snprintf_s(data, len, len - 1U, "invalid pc address 0x%016lx, can not reason stack.\n", pc);
     118           51 :         if (ret == -1) {
     119            0 :             LOGE("snprintf_s core info failed");
     120              :         }
     121           51 :         return 0;
     122              :     }
     123          199 :     ret = snprintf_s(data, len, len - 1U, "#%02d 0x%016lx %s", layer, pc, info);
     124          199 :     if (ret == -1) {
     125            0 :         LOGE("snprintf_s core info failed");
     126            0 :         return 0;
     127              :     }
     128          199 :     return nfp;
     129              : }
     130              : 
     131              : /**
     132              :  * @brief       reason the stack frame by PC
     133              :  * @param [in]  layer:      exception layer
     134              :  * @param [in]  pc:         current pc
     135              :  * @param [out] data:       exception info
     136              :  * @param [in]  len:        data buffer length
     137              :  */
     138          155 : STATIC void TraceStackPcFrame(int32_t layer, uintptr_t pc, char *data, size_t len)
     139              : {
     140          155 :     if (layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
     141            0 :         return;
     142              :     }
     143              : 
     144          155 :     if (pc == 0) { // current pc frame
     145           80 :         int32_t ret = snprintf_s(data, len, len - 1U, "#%d 0x%016lx 0x%016lx %s\n",
     146              :             layer, pc, pc, program_invocation_name);
     147           80 :         if (ret == -1) {
     148            0 :             LOGE("snprintf_s core info failed");
     149              :         }
     150              :     }
     151          155 :     (void)TraceStackFrame(layer, pc, data, len);
     152              : }
     153              : 
     154              : /**
     155              :  * @brief       check rbp register value is valid or not
     156              :  * @param [in]  rbp:        exception BP register
     157              :  * @param [in]  rsp:        exception SP register
     158              :  * @return      true  valid; false  invalid
     159              :  */
     160          175 : STATIC bool TraceCheckRegister(uintptr_t rbp, uintptr_t rsp, uintptr_t stackBaseAddr)
     161              : {
     162          175 :     if ((rbp >= rsp) && (rbp < stackBaseAddr)) {
     163          155 :         return true;
     164              :     }
     165              : 
     166           20 :     return false;
     167              : }
     168              : 
     169              : /**
     170              :  * @brief       derivation stack by fp
     171              :  * @param [in]  arg:        argument
     172              :  * @param [in]  regs:       register info
     173              :  * @param [in]  regNum:     number of register
     174              :  * @param [out] stackInfo:  buffer to save stack info
     175              :  * @return      TraStatus
     176              :  */
     177          255 : TraStatus TraceStackFp(const ThreadArgument *arg, uintptr_t *regs, uint32_t regNum, TraceStackInfo *stackInfo)
     178              : {
     179          255 :     if (regs == NULL || arg == NULL || stackInfo == NULL || regNum < MAX_USE_REG_NUM) {
     180           60 :         return TRACE_INVALID_PARAM;
     181              :     }
     182              : 
     183          195 :     uintptr_t fp = GET_FPREG(regs);
     184          195 :     uintptr_t sp = GET_SPREG(regs);
     185          195 :     uintptr_t pc = GET_PCREG(regs);
     186              : 
     187          195 :     int32_t layer = 0;
     188          195 :     stackInfo->layer = -1;
     189          195 :     char info[CORE_BUFFER_LEN] = { 0 };
     190          195 :     if (!TraceCheckRegister(fp, sp, arg->stackBaseAddr)) {
     191           40 :         int32_t ret = snprintf_s(info, CORE_BUFFER_LEN, CORE_BUFFER_LEN - 1U,
     192           40 :             "invalid register value, stack_start_addr=0x%016lx rbp=0x%016lx rsp=0x%016lx \n\n", arg->stackBaseAddr, fp, sp);
     193           40 :         if (ret != -1) {
     194           40 :             (void)memcpy_s(&stackInfo->errLog, CORE_BUFFER_LEN, info, strlen(info));
     195              :         }
     196           40 :         return TRACE_FAILURE;
     197              :     }
     198              : 
     199              :     // save pc frame info
     200          155 :     TraceStackPcFrame(layer, pc, info, sizeof(info));
     201          155 :     errno_t err = memcpy_s(&stackInfo->frame[0].info, CORE_BUFFER_LEN, info, strlen(info));
     202          155 :     if (err != EOK) {
     203           20 :         LOGE("memcpy pc frame failed, ret=%d", err);
     204           20 :         return TRACE_FAILURE;
     205              :     }
     206          135 :     stackInfo->layer = 0;
     207              : 
     208              :     // save stack frame info
     209          135 :     uintptr_t nfp = fp;
     210          310 :     while ((fp != 0) && (fp >= nfp) && (layer < MAX_STACK_LAYER - 1)) {
     211          175 :         layer++;
     212          175 :         fp = TraceStackFrame(layer, fp, info, sizeof(info));
     213          175 :         err = memcpy_s(&stackInfo->frame[layer].info, CORE_BUFFER_LEN, info, strlen(info));
     214          175 :         if (err != EOK) {
     215            0 :             LOGE("memcpy stack frame failed, ret=%d", err);
     216            0 :             stackInfo->layer = layer - 1;
     217            0 :             return TRACE_FAILURE;
     218              :         }
     219              :     }
     220              : 
     221          135 :     stackInfo->layer = layer;
     222          135 :     return TRACE_SUCCESS;
     223              : }
     224              : 
     225              : /**
     226              :  * @brief       write "process" info
     227              :  * @param [in]  fd:     handle of stack_core file
     228              :  * @param [in]  arg:    argument
     229              :  * @return      TraStatus
     230              :  */
     231          155 : STATIC TraStatus TraceWriteProcessInfo(int32_t fd, const ThreadArgument *arg)
     232              : {
     233          155 :     uintptr_t sp = 0;
     234          155 :     const mcontext_t *mcontext = &(arg->ucontext.uc_mcontext);
     235          155 :     if (mcontext != NULL) {
     236          155 :         sp = GET_SPREG_FROM_CONTEXT(mcontext);
     237              :     }
     238              : 
     239          155 :     TraceStackProcessInfo info = { arg->signo, arg->pid, arg->tid, arg->crashTime, arg->stackBaseAddr, sp };
     240          155 :     return TraceSafeWriteProcessInfo(fd, &info);
     241              : }
     242              : 
     243              : /**
     244              :  * @brief       process the exception signal, write info to stack_core file
     245              :  * @param [in]  arg:        argument
     246              :  * @return      TraStatus
     247              :  */
     248          195 : TraStatus TraceStackSigHandler(const ThreadArgument *arg)
     249              : {
     250          195 :     if (arg == NULL) {
     251            0 :         return TRACE_FAILURE;
     252              :     }
     253              : 
     254          195 :     LOGI("get signal number:%d, start to analysis stack info.", arg->signo);
     255          195 :     TraceStackInfo *stackInfo = TraceSafeGetStackBuffer();
     256          195 :     stackInfo->threadIdx = 0;
     257          195 :     stackInfo->threadTid = arg->tid;
     258          195 :     const ucontext_t *utext = &arg->ucontext;
     259          195 :     const mcontext_t *mcontext = (const mcontext_t *)&(utext->uc_mcontext);
     260          195 :     uintptr_t regs[TRACE_CORE_REG_NUM] = { 0 };
     261          195 :     GET_REGISTER_FROM_CONTEXT(regs, mcontext);
     262          195 :     TraStatus ret = TraceStackFp(arg, regs, TRACE_CORE_REG_NUM, stackInfo);
     263          195 :     if (ret != TRACE_SUCCESS) {
     264           60 :         LOGW("can not derivation stack by fp, ret=%d.", ret);
     265              :     }
     266              : 
     267          195 :     int32_t fd = -1;
     268          195 :     TraceStackRecorderInfo info = {arg->crashTime, arg->signo, arg->pid, arg->tid};
     269          195 :     ret = TraceSafeGetFd(&info, TRACE_FILE_TXT_SUFFIX, &fd);
     270          195 :     if (ret != TRACE_SUCCESS) {
     271           40 :         LOGE("get fd failed.");
     272           40 :         return TRACE_FAILURE;
     273              :     }
     274              : 
     275          155 :     ret = TraceWriteProcessInfo(fd, arg);
     276          155 :     if (ret != TRACE_SUCCESS) {
     277            0 :         LOGE("write process info to file failed, ret=%d.", ret);
     278              :     }
     279              : 
     280          155 :     ret = TraceSafeWriteStackInfo(fd, stackInfo);
     281          155 :     if (ret != TRACE_SUCCESS) {
     282           40 :         LOGE("write stack info to file failed, ret=%d.", ret);
     283              :     }
     284              : 
     285          155 :     ret = TraceSafeWriteSystemInfo(fd, arg->pid);
     286          155 :     if (ret != TRACE_SUCCESS) {
     287            0 :         LOGE("write process info to file failed, ret=%d.", ret);
     288              :     }
     289              : 
     290          155 :     TraceClose(&fd);
     291          155 :     LOGI("write stackcore file end.");
     292          155 :     return TRACE_SUCCESS;
     293              : }
        

Generated by: LCOV version 2.0-1