LCOV - code coverage report
Current view: top level - src/regfwk - stub_backtrace.cpp (source / functions) Coverage Total Hit
Test: coverage.info_filtered Lines: 0.0 % 145 0
Test Date: 2026-07-27 14:41:20 Functions: 0.0 % 14 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              : /* !
      12              :  * \file stub_backtrace.cpp
      13              :  * \brief
      14              :  */
      15              : #include <csignal>
      16              : #include <sstream>
      17              : #include <string>
      18              : #include <cstring>
      19              : #include <map>
      20              : #include <unistd.h>
      21              : #include <sys/mman.h>
      22              : #include <dlfcn.h>
      23              : #include <link.h>
      24              : #include <unwind.h>
      25              : #include "securec.h"
      26              : #include "stub_def.h"
      27              : 
      28              : namespace {
      29            0 : std::map<std::string, uint64_t>& BinaryBaseMap()
      30              : {
      31            0 :     static std::map<std::string, uint64_t> instance;
      32            0 :     return instance;
      33              : }
      34              : 
      35              : } // namespace
      36              : 
      37              : namespace AscendC {
      38              : constexpr int32_t BT_MAX = 24 * 1024;
      39              : 
      40            0 : const std::map<int, std::string>& GetCoreTypeMap()
      41              : {
      42              :     static const std::map<int, std::string> coreTypeMap = {
      43              :         {AscendC::AIC_TYPE, "AIC_"},
      44              :         {AscendC::AIV_TYPE, "AIV_"},
      45              :         {AscendC::MIX_TYPE, "CORE_"},
      46            0 :     };
      47            0 :     return coreTypeMap;
      48            0 : }
      49              : 
      50            0 : std::map<int, std::string>& GetSignalMessage()
      51              : {
      52              :     static std::map<int, std::string> g_signalMessage = {
      53            0 :         {SIGILL, "SIGILL Signal (Illegal instruction) catched"},
      54            0 :         {SIGBUS, "SIGBUS Signal (Bus error) catched"},
      55            0 :         {SIGFPE, "SIGFPE Signal (Floating point exception) catched"},
      56            0 :         {SIGSEGV, "SIGSEGV Signal (Invalid memory reference) catched"},
      57            0 :         {SIGPIPE, "SIGPIPE Signal (Broken pipe: write to pipe with no readers) catched"},
      58            0 :         {SIGABRT, "SIGABRT Signal (Abort Signal from abort) catched"},
      59            0 :     };
      60            0 :     return g_signalMessage;
      61            0 : }
      62              : 
      63              : struct BacktraceData {
      64              :     std::string exeObjName;
      65              :     std::ostringstream* outStream;
      66              : };
      67              : 
      68              : // parse the input msg and get the exec file name,
      69              : // input msg is like this: output/ascend/host/ubuntu20.04/x86_64/lib/xxxxxx
      70              : // the last / means the executed file name
      71            0 : std::string GetExecName(const std::string& msg)
      72              : {
      73            0 :     size_t lastSlashPos = msg.find_last_of('/');
      74            0 :     if (lastSlashPos != std::string::npos) {
      75            0 :         return msg.substr(lastSlashPos + 1);
      76              :     }
      77              : 
      78            0 :     return msg;
      79              : }
      80              : 
      81              : // execute addr2line cmd and get the output
      82            0 : std::string ExecCmd(const char* cmd)
      83              : {
      84            0 :     FILE* fp = popen(cmd, "r");
      85            0 :     if (fp) {
      86            0 :         char buffer[BT_MAX] = "";
      87            0 :         if (fgets(buffer, BT_MAX, fp) == nullptr) {
      88            0 :             return std::string("addr2line excuted failed.");
      89              :         }
      90            0 :         (void)pclose(fp);
      91            0 :         return std::string(buffer);
      92              :     }
      93            0 :     return std::string("?");
      94              : }
      95              : 
      96              : std::string GetExecPath();
      97              : std::string StackTrace();
      98              : bool IsValidBinary(const std::string& exceutePath);
      99              : 
     100              : namespace {
     101              : // callback function to process each frame
     102            0 : _Unwind_Reason_Code UnwindCallback(struct _Unwind_Context* context, void* arg)
     103              : {
     104              :     // get pc with unwind function
     105            0 :     int ipBeforeInsn = 0;
     106              :     static int32_t frameId = 0;
     107            0 :     uintptr_t pc = _Unwind_GetIPInfo(context, &ipBeforeInsn);
     108            0 :     BacktraceData* btData = reinterpret_cast<BacktraceData*>(arg);
     109            0 :     if (ipBeforeInsn == 0) {
     110            0 :         --pc;
     111              :     }
     112              : 
     113              :     Dl_info info;
     114            0 :     int32_t ret = dladdr(reinterpret_cast<void*>(pc), &info);
     115            0 :     if (ret == 0) {
     116            0 :         return _URC_NO_REASON;
     117              :     }
     118              : 
     119            0 :     std::string objName = GetExecName(info.dli_fname);
     120            0 :     if (BinaryBaseMap().count(objName) == 0) {
     121            0 :         return _URC_NO_REASON;
     122              :     }
     123              : 
     124            0 :     uint64_t baseAddr = BinaryBaseMap()[objName];
     125            0 :     uint64_t errorPC = static_cast<uint64_t>(pc) - baseAddr;
     126            0 :     std::vector<char> btCmd(BT_MAX);
     127            0 :     if (!IsValidBinary(info.dli_fname)) {
     128            0 :         return _URC_NO_REASON;
     129              :     }
     130              : 
     131            0 :     errno_t err = sprintf_s(btCmd.data(), BT_MAX, "addr2line -e %s -f -p -a -i -C 0x%lx", info.dli_fname, errorPC);
     132            0 :     if (err < 0) {
     133            0 :         return _URC_NO_REASON;
     134              :     }
     135            0 :     std::string result = ExecCmd(btCmd.data());
     136            0 :     *(btData->outStream) << "[#" << frameId << "] " << result;
     137            0 :     frameId++;
     138            0 :     return _URC_NO_REASON;
     139            0 : }
     140              : 
     141              : // translate cpu debug index to core name in v220
     142            0 : std::string ConvertCpuIdxToCoreName(int idx)
     143              : {
     144            0 :     const std::map<int, std::string>& coreTypeMap = GetCoreTypeMap();
     145            0 :     constexpr int subCoreAic = 0;
     146            0 :     constexpr int defaultTaskRation = 2;
     147            0 :     std::string coreName;
     148              :     // mix mode
     149            0 :     if (g_kernelMode == KernelMode::MIX_MODE) {
     150            0 :         int idxRes = idx % (defaultTaskRation + 1);
     151            0 :         int blockIdx = idx / (defaultTaskRation + 1);
     152            0 :         int subBlockIdx = 0;
     153            0 :         int flatIdx = 0;
     154            0 :         switch (idxRes) {
     155            0 :             case subCoreAic:
     156            0 :                 flatIdx = blockIdx;
     157            0 :                 coreName = coreTypeMap.at(AscendC::AIC_TYPE) + std::to_string(flatIdx);
     158            0 :                 break;
     159            0 :             default:
     160            0 :                 subBlockIdx = idxRes - 1;
     161            0 :                 flatIdx = blockIdx * defaultTaskRation + subBlockIdx;
     162            0 :                 coreName = coreTypeMap.at(AscendC::AIV_TYPE) + std::to_string(flatIdx);
     163            0 :                 break;
     164              :         }
     165            0 :         return coreName;
     166              :     }
     167              : 
     168              :     // unmix mode
     169            0 :     coreName = coreTypeMap.at(AscendC::MIX_TYPE) + std::to_string(idx);
     170            0 :     return coreName;
     171            0 : }
     172              : 
     173            0 : std::string GetMainExecName()
     174              : {
     175            0 :     std::string currentObj = GetExecPath();
     176            0 :     std::string exeName = GetExecName(currentObj);
     177            0 :     return exeName;
     178            0 : }
     179              : 
     180              : // record all binary name and base addr
     181            0 : int32_t DlCallback(struct dl_phdr_info* info, size_t size, void* data)
     182              : {
     183              :     (void)data;
     184              :     (void)size;
     185              :     static int32_t count = 0;
     186            0 :     if (std::strlen(info->dlpi_name) == 0) {
     187              :         // first frame dlpi name is empty, means the main execut obj self
     188            0 :         if (count == 0) {
     189            0 :             BinaryBaseMap().insert(std::make_pair(GetMainExecName(), info->dlpi_addr));
     190              :         }
     191              :     } else {
     192            0 :         BinaryBaseMap().insert(std::make_pair(GetExecName(info->dlpi_name), info->dlpi_addr));
     193              :     }
     194            0 :     count++;
     195            0 :     return 0;
     196              : }
     197              : } // namespace
     198              : // reduce the print content and avoid some mistakes
     199            0 : bool IsValidBinary(const std::string& exceutePath)
     200              : {
     201            0 :     std::vector<std::string> skipPath = {"/lib", "/usr/lib", "/usr/local/lib"};
     202            0 :     for (const std::string& path : skipPath) {
     203            0 :         size_t n = exceutePath.find(path);
     204              :         // remove system files debug info
     205            0 :         if (n == 0) {
     206            0 :             return false;
     207              :         }
     208              :     }
     209              : 
     210            0 :     std::vector<std::string> skipFile = {"linux-vdso", "libcpudebug_stubreg.so"};
     211            0 :     std::string objName = GetExecName(exceutePath);
     212            0 :     for (const std::string& file : skipFile) {
     213            0 :         size_t n = objName.find(file);
     214              :         // remove system files debug info
     215            0 :         if (n == 0) {
     216            0 :             return false;
     217              :         }
     218              :     }
     219              : 
     220            0 :     return true;
     221            0 : }
     222              : 
     223              : // generate error message
     224            0 : std::string GetExecPath()
     225              : {
     226              :     char result[BT_MAX];
     227            0 :     ssize_t count = readlink("/proc/self/exe", result, BT_MAX);
     228            0 :     return std::string(result, (count > 0) ? count : 0);
     229              : }
     230              : 
     231            0 : std::string StackTrace()
     232              : {
     233            0 :     dl_iterate_phdr(DlCallback, nullptr);
     234            0 :     std::ostringstream stacktraceStream;
     235            0 :     std::string exeName = GetMainExecName();
     236            0 :     BacktraceData btData = {exeName, &stacktraceStream};
     237            0 :     _Unwind_Backtrace(UnwindCallback, &btData);
     238              :     // return the backtrace info str
     239            0 :     std::string stackTrace = stacktraceStream.str();
     240            0 :     return stackTrace;
     241            0 : }
     242              : 
     243              : // generate core name from cpu debug index for all soc version
     244            0 : std::string GetCoreName(int idx)
     245              : {
     246            0 :     int coreIdx = idx;
     247            0 :     std::string coreName = "CORE_" + std::to_string(coreIdx);
     248            0 :     if (g_socVersion == SocVersion::VER_220 || g_socVersion == SocVersion::VER_310 ||
     249            0 :         g_socVersion == SocVersion::VER_510) {
     250            0 :         coreName = ConvertCpuIdxToCoreName(idx);
     251              :     }
     252            0 :     return coreName;
     253            0 : }
     254              : 
     255            0 : void BacktracePrint(int sig)
     256              : {
     257            0 :     int flatIdx = block_idx;
     258            0 :     const std::map<int, std::string>& coreTypeMap = GetCoreTypeMap();
     259            0 :     std::string coreName = coreTypeMap.at(AscendC::MIX_TYPE);
     260            0 :     if (g_socVersion == SocVersion::VER_220 || g_socVersion == SocVersion::VER_310 ||
     261            0 :         g_socVersion == SocVersion::VER_510) {
     262            0 :         if (g_kernelMode == KernelMode::MIX_MODE) {
     263            0 :             coreName = coreTypeMap.at(g_coreType);
     264            0 :             flatIdx = (g_coreType == AscendC::AIC_TYPE) ? block_idx : (block_idx * g_taskRation + sub_block_idx);
     265              :         }
     266              :     }
     267            0 :     coreName += std::to_string(flatIdx);
     268              :     // samples: [ERROR][AIV_0][pid 12] error happened! =========
     269            0 :     std::string ret = "[ERROR][" + coreName + "][pid ";
     270            0 :     ret += std::to_string(getpid());
     271            0 :     ret += "] error happened! ========= \n";
     272              :     // samples: SIGSEGV Signal (Invalid memory reference) catched, backtrace info:
     273            0 :     ret += GetSignalMessage()[sig] + ", backtrace info:\n";
     274            0 :     ret += StackTrace();
     275              :     // using process lock to keep content clear
     276            0 :     AscendC::KernelPrintLock::GetLock()->Lock();
     277            0 :     std::cout << ret << std::endl;
     278            0 :     AscendC::KernelPrintLock::GetLock()->Unlock();
     279            0 : }
     280              : } // namespace AscendC
        

Generated by: LCOV version 2.0-1