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-08-31 10:07:06 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          276 : STATIC TraStatus TraceGetSelfMap(uintptr_t pc, char* data, uint32_t len)
      37              : {
      38          276 :     if (data == NULL || len == 0) {
      39            0 :         return TRACE_FAILURE;
      40              :     }
      41              : 
      42          276 :     int32_t fd = open(SELF_MAP_PATH, O_RDONLY);
      43          276 :     if (fd < 0) {
      44            0 :         LOGW("self map fopen null");
      45            0 :         return TRACE_FAILURE;
      46              :     }
      47              : 
      48          276 :     char* vmPath = NULL;
      49          276 :     uintptr_t vmStart = 0;
      50          276 :     uintptr_t vmEnd = 0;
      51          276 :     char currentPath[CORE_BUFFER_LEN] = {0};
      52          276 :     uintptr_t baseAddr = 0; // the minimum addr of load segment
      53        12574 :     while (TraceSafeReadLine(fd, data, len) > 0) {
      54        12517 :         vmPath = strchr(data, OS_SPLIT);
      55        12517 :         if (vmPath == NULL) {
      56         3446 :             continue;
      57              :         }
      58         9071 :         if (sscanf_s(data, "%lx-%lx", &vmStart, &vmEnd) <= 0) {
      59            0 :             continue;
      60              :         }
      61              : 
      62         9071 :         if (strcmp(currentPath, vmPath) != 0) {
      63         1177 :             errno_t err = strncpy_s(currentPath, CORE_BUFFER_LEN, vmPath, CORE_BUFFER_LEN - 1U);
      64         1177 :             if (err != 0) {
      65            0 :                 LOGE("copy vmPath to currentPath failed.");
      66            0 :                 break;
      67              :             }
      68         1177 :             baseAddr = vmStart; // update baseAddr when path change
      69              :         }
      70              :         // pcAddr is in code-segment(r-xp)
      71         9071 :         if ((pc < vmStart) || (pc > vmEnd) || (strstr(data, EXEC_MAP_ATTR) == NULL)) {
      72         8852 :             continue;
      73              :         }
      74              : 
      75          219 :         int32_t ret = snprintf_s(data, len, (size_t)len - 1U, "0x%016lx %s", baseAddr, currentPath);
      76          219 :         if (ret == -1) {
      77            0 :             LOGE("snprintf_s map info failed");
      78            0 :             break;
      79              :         }
      80          219 :         TraceClose(&fd);
      81          219 :         return TRACE_SUCCESS;
      82              :     }
      83           57 :     TraceClose(&fd);
      84           57 :     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          364 : STATIC uintptr_t TraceStackFrame(int32_t layer, uintptr_t fp, char* data, size_t len)
      96              : {
      97          364 :     uintptr_t nfp = 0;
      98          364 :     uintptr_t pc = 0;
      99          364 :     char info[CORE_BUFFER_LEN] = {0};
     100          364 :     if (fp == 0 || layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
     101           88 :         return 0;
     102              :     }
     103              : 
     104          276 :     if (layer == 0) { // current pc frame
     105           83 :         pc = fp;
     106           83 :         nfp = pc;
     107              :     } else { // fp inference pc frame
     108          193 :         uintptr_t lr = fp + LR_OFFSET;
     109          193 :         if (lr < fp) {
     110            0 :             return 0;
     111              :         }
     112          193 :         pc = *(uintptr_t*)lr;
     113          193 :         nfp = *(uintptr_t*)fp;
     114              :     }
     115              :     int32_t ret;
     116          276 :     if (TraceGetSelfMap(pc, info, (uint32_t)sizeof(info)) != TRACE_SUCCESS) {
     117           57 :         ret = snprintf_s(data, len, len - 1U, "invalid pc address 0x%016lx, can not reason stack.\n", pc);
     118           57 :         if (ret == -1) {
     119            0 :             LOGE("snprintf_s core info failed");
     120              :         }
     121           57 :         return 0;
     122              :     }
     123          219 :     ret = snprintf_s(data, len, len - 1U, "#%02d 0x%016lx %s", layer, pc, info);
     124          219 :     if (ret == -1) {
     125            0 :         LOGE("snprintf_s core info failed");
     126            0 :         return 0;
     127              :     }
     128          219 :     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          171 : STATIC void TraceStackPcFrame(int32_t layer, uintptr_t pc, char* data, size_t len)
     139              : {
     140          171 :     if (layer >= MAX_STACK_LAYER || data == NULL || len == 0) {
     141            0 :         return;
     142              :     }
     143              : 
     144          171 :     if (pc == 0) { // current pc frame
     145              :         int32_t ret =
     146           88 :             snprintf_s(data, len, len - 1U, "#%d 0x%016lx 0x%016lx %s\n", layer, pc, pc, program_invocation_name);
     147           88 :         if (ret == -1) {
     148            0 :             LOGE("snprintf_s core info failed");
     149              :         }
     150              :     }
     151          171 :     (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          193 : STATIC bool TraceCheckRegister(uintptr_t rbp, uintptr_t rsp, uintptr_t stackBaseAddr)
     161              : {
     162          193 :     if ((rbp >= rsp) && (rbp < stackBaseAddr)) {
     163          171 :         return true;
     164              :     }
     165              : 
     166           22 :     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          281 : TraStatus TraceStackFp(const ThreadArgument* arg, uintptr_t* regs, uint32_t regNum, TraceStackInfo* stackInfo)
     178              : {
     179          281 :     if (regs == NULL || arg == NULL || stackInfo == NULL || regNum < MAX_USE_REG_NUM) {
     180           66 :         return TRACE_INVALID_PARAM;
     181              :     }
     182              : 
     183          215 :     uintptr_t fp = GET_FPREG(regs);
     184          215 :     uintptr_t sp = GET_SPREG(regs);
     185          215 :     uintptr_t pc = GET_PCREG(regs);
     186              : 
     187          215 :     int32_t layer = 0;
     188          215 :     stackInfo->layer = -1;
     189          215 :     char info[CORE_BUFFER_LEN] = {0};
     190          215 :     if (!TraceCheckRegister(fp, sp, arg->stackBaseAddr)) {
     191           44 :         int32_t ret = snprintf_s(
     192              :             info, CORE_BUFFER_LEN, CORE_BUFFER_LEN - 1U,
     193           44 :             "invalid register value, stack_start_addr=0x%016lx rbp=0x%016lx rsp=0x%016lx \n\n", arg->stackBaseAddr, fp,
     194              :             sp);
     195           44 :         if (ret != -1) {
     196           44 :             (void)memcpy_s(&stackInfo->errLog, CORE_BUFFER_LEN, info, strlen(info));
     197              :         }
     198           44 :         return TRACE_FAILURE;
     199              :     }
     200              : 
     201              :     // save pc frame info
     202          171 :     TraceStackPcFrame(layer, pc, info, sizeof(info));
     203          171 :     errno_t err = memcpy_s(&stackInfo->frame[0].info, CORE_BUFFER_LEN, info, strlen(info));
     204          171 :     if (err != EOK) {
     205           22 :         LOGE("memcpy pc frame failed, ret=%d", err);
     206           22 :         return TRACE_FAILURE;
     207              :     }
     208          149 :     stackInfo->layer = 0;
     209              : 
     210              :     // save stack frame info
     211          149 :     uintptr_t nfp = fp;
     212          342 :     while ((fp != 0) && (fp >= nfp) && (layer < MAX_STACK_LAYER - 1)) {
     213          193 :         layer++;
     214          193 :         fp = TraceStackFrame(layer, fp, info, sizeof(info));
     215          193 :         err = memcpy_s(&stackInfo->frame[layer].info, CORE_BUFFER_LEN, info, strlen(info));
     216          193 :         if (err != EOK) {
     217            0 :             LOGE("memcpy stack frame failed, ret=%d", err);
     218            0 :             stackInfo->layer = layer - 1;
     219            0 :             return TRACE_FAILURE;
     220              :         }
     221              :     }
     222              : 
     223          149 :     stackInfo->layer = layer;
     224          149 :     return TRACE_SUCCESS;
     225              : }
     226              : 
     227              : /**
     228              :  * @brief       write "process" info
     229              :  * @param [in]  fd:     handle of stack_core file
     230              :  * @param [in]  arg:    argument
     231              :  * @return      TraStatus
     232              :  */
     233          171 : STATIC TraStatus TraceWriteProcessInfo(int32_t fd, const ThreadArgument* arg)
     234              : {
     235          171 :     uintptr_t sp = 0;
     236          171 :     const mcontext_t* mcontext = &(arg->ucontext.uc_mcontext);
     237          171 :     if (mcontext != NULL) {
     238          171 :         sp = GET_SPREG_FROM_CONTEXT(mcontext);
     239              :     }
     240              : 
     241          171 :     TraceStackProcessInfo info = {arg->signo, arg->pid, arg->tid, arg->crashTime, arg->stackBaseAddr, sp};
     242          171 :     return TraceSafeWriteProcessInfo(fd, &info);
     243              : }
     244              : 
     245              : /**
     246              :  * @brief       process the exception signal, write info to stack_core file
     247              :  * @param [in]  arg:        argument
     248              :  * @return      TraStatus
     249              :  */
     250          215 : TraStatus TraceStackSigHandler(const ThreadArgument* arg)
     251              : {
     252          215 :     if (arg == NULL) {
     253            0 :         return TRACE_FAILURE;
     254              :     }
     255              : 
     256          215 :     LOGI("get signal number:%d, start to analysis stack info.", arg->signo);
     257          215 :     TraceStackInfo* stackInfo = TraceSafeGetStackBuffer();
     258          215 :     stackInfo->threadIdx = 0;
     259          215 :     stackInfo->threadTid = arg->tid;
     260          215 :     const ucontext_t* utext = &arg->ucontext;
     261          215 :     const mcontext_t* mcontext = (const mcontext_t*)&(utext->uc_mcontext);
     262          215 :     uintptr_t regs[TRACE_CORE_REG_NUM] = {0};
     263          215 :     GET_REGISTER_FROM_CONTEXT(regs, mcontext);
     264          215 :     TraStatus ret = TraceStackFp(arg, regs, TRACE_CORE_REG_NUM, stackInfo);
     265          215 :     if (ret != TRACE_SUCCESS) {
     266           66 :         LOGW("can not derivation stack by fp, ret=%d.", ret);
     267              :     }
     268              : 
     269          215 :     int32_t fd = -1;
     270          215 :     TraceStackRecorderInfo info = {arg->crashTime, arg->signo, arg->pid, arg->tid};
     271          215 :     ret = TraceSafeGetFd(&info, TRACE_FILE_TXT_SUFFIX, &fd);
     272          215 :     if (ret != TRACE_SUCCESS) {
     273           44 :         LOGE("get fd failed.");
     274           44 :         return TRACE_FAILURE;
     275              :     }
     276              : 
     277          171 :     ret = TraceWriteProcessInfo(fd, arg);
     278          171 :     if (ret != TRACE_SUCCESS) {
     279            0 :         LOGE("write process info to file failed, ret=%d.", ret);
     280              :     }
     281              : 
     282          171 :     ret = TraceSafeWriteStackInfo(fd, stackInfo);
     283          171 :     if (ret != TRACE_SUCCESS) {
     284           44 :         LOGE("write stack info to file failed, ret=%d.", ret);
     285              :     }
     286              : 
     287          171 :     ret = TraceSafeWriteSystemInfo(fd, arg->pid);
     288          171 :     if (ret != TRACE_SUCCESS) {
     289            0 :         LOGE("write process info to file failed, ret=%d.", ret);
     290              :     }
     291              : 
     292          171 :     TraceClose(&fd);
     293          171 :     LOGI("write stackcore file end.");
     294          171 :     return TRACE_SUCCESS;
     295              : }
        

Generated by: LCOV version 2.0-1