LCOV - code coverage report
Current view: top level - adump/exception - kernel_info_collector.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 95.5 % 222 212
Test Date: 2026-07-28 10:54:24 Functions: 100.0 % 15 15

            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              : #include <elf.h>
      11              : #include <functional>
      12              : #include <fstream>
      13              : #include <mutex>
      14              : #include <memory>
      15              : #include <string>
      16              : #include <stack>
      17              : #include <thread>
      18              : #include <dirent.h>
      19              : #include <sys/stat.h>
      20              : #include "path.h"
      21              : #include "file.h"
      22              : #include "sys_utils.h"
      23              : #include "str_utils.h"
      24              : #include "log/adx_log.h"
      25              : #include "log/hdc_log.h"
      26              : #include "extra_config.h"
      27              : #include "thread_manager.h"
      28              : #include "adump_dsmi.h"
      29              : #include "runtime/base.h"
      30              : #include "exception_info_common.h"
      31              : #include "kernel_symbol_locator.h"
      32              : #include "kernel_info_collector.h"
      33              : 
      34              : namespace Adx {
      35              : namespace {
      36              : const std::set<char> INVALID_FILE_NAME_CHAR = {' ', '.', '/', '\\'};
      37              : constexpr uint64_t JSON_SUFFIX_LEN = 5;  // length of ".json"
      38              : }  // namespace
      39              : 
      40           32 : int32_t StartCollectKernelAsync(std::shared_ptr<KernelInfoCollector> collector, const std::string &dumpPath) {
      41           32 :     int32_t ret = collector->LoadKernelBinBuffer();
      42           32 :     IDE_LOGD("Start collecting kernel file.");
      43           64 :     std::thread collectKernel([collector, dumpPath](){  
      44           32 :         int32_t tid = mmGetTid();
      45           32 :         ThreadManager::Instance().TaskAdd(tid);
      46           32 :         (void)collector->StartCollectKernel(dumpPath);
      47           32 :         ThreadManager::Instance().TaskDone(tid);
      48           32 :     });
      49           32 :     collectKernel.detach();
      50           32 :     return ret;
      51           32 : }
      52              : 
      53           83 : void KernelInfoCollector::LoadKernelInfo(const rtExceptionArgsInfo &argsInfo)
      54              : {
      55           83 :     kernelBinHandle_ = nullptr;
      56           83 :     kernelBinData_.clear();
      57           83 :     kernelBinSize_ = 0;
      58           83 :     kernelName_.clear();
      59              : 
      60           83 :     kernelBinHandle_ = argsInfo.exceptionKernelInfo.bin;  // binHandle
      61           83 :     kernelBinSize_ = argsInfo.exceptionKernelInfo.binSize;
      62           83 :     if ((argsInfo.exceptionKernelInfo.kernelName != nullptr) && (argsInfo.exceptionKernelInfo.kernelNameSize != 0)) {
      63           50 :         kernelName_ = std::string(argsInfo.exceptionKernelInfo.kernelName, argsInfo.exceptionKernelInfo.kernelNameSize);
      64              :     }
      65           83 :     IDE_LOGI("Kernel handle: %p, kernel size: %u, name addr: %p, name size: %u, kernel name: %s", kernelBinHandle_,
      66              :              kernelBinSize_, argsInfo.exceptionKernelInfo.kernelName, argsInfo.exceptionKernelInfo.kernelNameSize,
      67              :              kernelName_.c_str());
      68           83 : }
      69              : 
      70            1 : int32_t KernelInfoCollector::InitFromBinHandle(rtBinHandle BinHandle, const std::string &kernelName)
      71              : {
      72            1 :     kernelBinHandle_ = BinHandle;
      73            1 :     kernelName_ = kernelName;
      74              : 
      75            1 :     return LoadKernelBinBuffer();
      76              : }
      77              : 
      78           35 : int32_t KernelInfoCollector::LoadKernelBinBuffer()
      79              : {
      80           35 :     if (kernelBinHandle_ == nullptr) {
      81           12 :         return ADUMP_SUCCESS;
      82              :     }
      83           23 :     std::string binData;
      84           23 :     uint32_t binSize = 0;
      85           23 :     int32_t ret = ExceptionInfoCommon::GetBinDataFromHandle(kernelBinHandle_, binData, binSize);
      86           23 :     if (ret != ADUMP_SUCCESS) {
      87            2 :         kernelBinData_ = "";
      88            2 :         return ADUMP_FAILED;
      89              :     }
      90           21 :     kernelBinSize_ = binSize;
      91           21 :     kernelBinData_ = binData;
      92           21 :     return ADUMP_SUCCESS;
      93           23 : }
      94              : 
      95           31 : std::string KernelInfoCollector::GetProcessedKernelName() const
      96              : {
      97           31 :     return ExceptionInfoCommon::GetKernelNameWithoutMixSuffix(kernelName_);
      98              : }
      99              : 
     100           35 : int32_t KernelInfoCollector::StartCollectKernel(const std::string &dumpPath) const
     101              : {
     102           35 :     if (kernelName_.empty() || kernelBinHandle_ == nullptr || kernelBinSize_ == 0) {
     103           12 :         IDE_LOGI("Kernel name or kernel bin is empty, skip dump kernel.");
     104           12 :         return ADUMP_SUCCESS;
     105              :     }
     106              : 
     107           23 :     std::string kernelName = GetProcessedKernelName();
     108              : 
     109              :     // dump host kernel
     110           23 :     int32_t ret = ADUMP_SUCCESS;
     111           23 :     if (DumpHostKernelBin(kernelName, dumpPath) != ADUMP_SUCCESS) {
     112            3 :         IDE_LOGE("Dump host kernel bin failed.");
     113            3 :         ret = ADUMP_FAILED;
     114              :     }
     115              : 
     116           23 :     if (CollectKernelFile(kernelName, dumpPath) != ADUMP_SUCCESS) {
     117            6 :         IDE_LOGE("Collect kernel file failed.");
     118            6 :         ret = ADUMP_FAILED;
     119              :     }
     120           23 :     return ret;
     121           23 : }
     122              : 
     123       139001 : bool KernelInfoCollector::ContainsString(const std::string &filePath, const std::string &targetString) const
     124              : {
     125       139001 :     Path jsonFilePath(filePath);
     126       139050 :     if (!jsonFilePath.RealPath()) {
     127            0 :         IDE_LOGD("The json file path[%s] is invalid, please check the path.", jsonFilePath.GetCString());
     128            0 :         return false;
     129              :     }
     130              : 
     131       138927 :     std::ifstream file(jsonFilePath.GetString());
     132       139018 :     if (!file.is_open()) {
     133        10667 :         IDE_LOGD("The json file path[%s] open failed, please check the permission.", jsonFilePath.GetCString());
     134        10667 :         return false;
     135              :     }
     136       128273 :     std::string line;
     137    110213103 :     while (std::getline(file, line)) {
     138    110306522 :         if (line.find(targetString) == std::string::npos) {
     139    110399588 :             continue;
     140              :         }
     141            0 :         if (IsTargetLine(line, "kernelName", targetString)) {
     142           10 :             file.close();
     143           10 :             return true;
     144              :         }
     145              :     }
     146       100527 :     file.close();
     147       128328 :     return false;
     148       139005 : }
     149              : 
     150           16 : bool KernelInfoCollector::IsTargetLine(const std::string &currentLine, const std::string &key,
     151              :                                        const std::string &value) const
     152              : {
     153           16 :     size_t curPlace = 0;
     154           16 :     if (GetFirstItem(currentLine, curPlace) != key) {
     155            6 :         return false;
     156              :     }
     157           10 :     if (GetFirstItem(currentLine, curPlace) != value) {
     158            0 :         return false;
     159              :     }
     160           10 :     return true;
     161              : }
     162              : 
     163           26 : std::string KernelInfoCollector::GetFirstItem(const std::string &curLine, size_t &curPlace) const
     164              : {
     165           26 :     size_t head = curLine.find_first_of('"', curPlace);
     166           26 :     if (head == std::string::npos) {
     167            0 :         return "";
     168              :     }
     169           26 :     size_t end = curLine.find_first_of('"', head + 1);
     170           26 :     if (end == std::string::npos) {
     171            0 :         return "";
     172              :     }
     173           26 :     curPlace = end + 1;
     174           26 :     return StrUtils::Trim(curLine.substr(head + 1, end - head - 1));
     175              : }
     176              : 
     177           85 : std::string KernelInfoCollector::SearchJsonFiles(const std::string &rootPath, const std::string &targetString) const
     178              : {
     179           85 :     std::stack<std::string> directories;
     180           85 :     directories.push(rootPath);
     181              : 
     182        45123 :     while (!directories.empty()) {
     183        44980 :         std::string currentDir = directories.top();
     184        44997 :         directories.pop();
     185              : 
     186        44953 :         DIR *dir = opendir(currentDir.c_str());
     187        45040 :         if (!dir) {
     188           28 :             IDE_LOGW("Unable to open directory[%s].", currentDir.c_str());
     189           28 :             continue;
     190              :         }
     191              : 
     192              :         struct dirent *entry;
     193       606196 :         while ((entry = readdir(dir)) != nullptr) {
     194       560878 :             std::string name = entry->d_name;
     195      1028773 :             if (name == "." || name == ".." ||
     196       469416 :                 ((currentDir == "./") && (name.find("kernel_meta") == std::string::npos))) {
     197        90104 :                 continue;
     198              :             }
     199              : 
     200       468394 :             std::string fullPath = currentDir + "/" + name;
     201              :             struct stat fileStat;
     202       470372 :             if (stat(fullPath.c_str(), &fileStat) == -1) {
     203            1 :                 IDE_LOGD("Unable to stat file[%s].", fullPath.c_str());
     204            1 :                 continue;
     205              :             }
     206              : 
     207       471408 :             if (S_ISDIR(fileStat.st_mode)) {
     208        45010 :                 directories.push(fullPath);
     209        44985 :                 continue;
     210              :             }
     211       851680 :             if (!S_ISREG(fileStat.st_mode) || name.size() <= JSON_SUFFIX_LEN ||
     212       851709 :                 name.substr(name.size() - JSON_SUFFIX_LEN) != ".json") {
     213       287219 :                 continue;
     214              :             }
     215              : 
     216              :             // If the file is a JSON file, check whether the file contains the target character string.
     217       139065 :             if (ContainsString(fullPath, targetString)) {
     218           10 :                 (void)closedir(dir);
     219           10 :                 return fullPath;
     220              :             }
     221      1032261 :         }
     222              : 
     223        45493 :         (void)closedir(dir);
     224        45307 :     }
     225              : 
     226           73 :     IDE_LOGI("Can not find kernel file in %s, targetString: %s", rootPath.c_str(), targetString.c_str());
     227          150 :     return "";
     228           83 : }
     229              : 
     230              : /**
     231              :  * @brief       : dump the kernel bin file runtime load from host
     232              :  * @param [in]  : kernelName    kernel name get from runtime removed the _mix_aic and _mix_aiv fields
     233              :  * @param [in]  : dumpPath      path of the exception dump file
     234              :  * @return      : ADUMP_SUCCESS succeed; ADUMP_FAILED failed
     235              :  */
     236           23 : int32_t KernelInfoCollector::DumpHostKernelBin(const std::string &kernelName, const std::string &dumpPath) const
     237              : {
     238           23 :     if (kernelBinData_.empty()) {
     239            2 :         IDE_LOGE("Kernel bin data is empty.");
     240            2 :         return ADUMP_FAILED;
     241              :     }
     242           21 :     Path hostKernelBinPath(dumpPath);
     243           21 :     std::string hostKernelBinName = StrUtils::Replace(kernelName, INVALID_FILE_NAME_CHAR, '_') + "_host.o";
     244           21 :     hostKernelBinPath.Concat(hostKernelBinName);
     245           21 :     File hostKernelBinFile(hostKernelBinPath.GetString(), M_WRONLY | M_CREAT | M_TRUNC);
     246           21 :     int32_t ret = hostKernelBinFile.IsFileOpen();
     247           21 :     if (ret != ADUMP_SUCCESS) {
     248            0 :         IDE_LOGE("Open host kernel bin file[%s] failed.", hostKernelBinPath.GetCString());
     249            0 :         return ADUMP_FAILED;
     250              :     }
     251              :     static std::mutex KernelBinLock;
     252           21 :     std::lock_guard<std::mutex> lock(KernelBinLock);
     253           21 :     auto writeSize = hostKernelBinFile.Write(kernelBinData_.c_str(), static_cast<int64_t>(kernelBinSize_));
     254           21 :     if (writeSize < 0) {
     255            1 :         IDE_LOGE("Write host kernel bin file[%s] failed.", hostKernelBinPath.GetCString());
     256            1 :         return ADUMP_FAILED;
     257              :     }
     258           20 :     IDE_LOGE("[Dump][Exception] dump host kernel to file, file: %s", hostKernelBinPath.GetCString());
     259           20 :     (void)mmChmod(hostKernelBinPath.GetCString(), M_IRUSR);  // 安全要求,落盘文件置为最小权限:用户只读, 400
     260              : 
     261           20 :     return ADUMP_SUCCESS;
     262           21 : }
     263              : 
     264           13 : std::vector<std::string> KernelInfoCollector::SplitString(const std::string &str, char delimiter) const
     265              : {
     266           13 :     std::vector<std::string> result;
     267           13 :     std::stringstream ss(str);
     268           13 :     std::string item;
     269              : 
     270           39 :     while (std::getline(ss, item, delimiter)) {
     271           26 :         result.push_back(item);
     272              :     }
     273              : 
     274           13 :     return result;
     275           13 : }
     276              : 
     277              : /*
     278              :     按照指定的路径优先级来进行.o和.json文件搜索
     279              : */
     280           31 : std::vector<std::string> KernelInfoCollector::GetSearchPath() const
     281              : {
     282           31 :     std::string envStr;
     283           31 :     std::vector<std::string> searchPath;
     284              : 
     285           31 :     ADX_GET_ENV(MM_ENV_ASCEND_CACHE_PATH, envStr);
     286           31 :     if (!envStr.empty()) {
     287           13 :         searchPath.emplace_back(envStr);
     288           13 :         IDE_LOGI("Add ASCEND_CACHE_PATH[%s] to search path.", envStr.c_str());
     289              :     }
     290              : 
     291           31 :     ADX_GET_ENV(MM_ENV_HOME, envStr);
     292           31 :     if (!envStr.empty()) {
     293           26 :         envStr += "/atc_data";
     294           26 :         searchPath.emplace_back(envStr);
     295           26 :         IDE_LOGI("Add HOME[%s] to search path.", envStr.c_str());
     296              :     }
     297              :     
     298              :     // custom install path
     299           31 :     ADX_GET_ENV(MM_ENV_ASCEND_CUSTOM_OPP_PATH, envStr);
     300           31 :     if (!envStr.empty()) {
     301           13 :         std::vector<std::string> customPaths = SplitString(envStr, ':');
     302           39 :         for (const auto &customPath : customPaths) {
     303           26 :             searchPath.emplace_back(customPath);
     304           26 :             IDE_LOGI("Add ASCEND_CUSTOM_OPP_PATH[%s] to search path.", customPath.c_str());
     305              :         }
     306           13 :     }
     307              : 
     308           31 :     ADX_GET_ENV(MM_ENV_ASCEND_OPP_PATH, envStr);
     309           31 :     if (!envStr.empty()) {
     310           26 :         std::string vendorsPath = envStr + "/vendors";
     311           26 :         searchPath.emplace_back(vendorsPath);
     312           26 :         IDE_LOGI("Add ASCEND_OPP_PATH[%s] to search path.", vendorsPath.c_str());
     313              : 
     314           26 :         std::string buildInPath = envStr + "/built-in";
     315           26 :         searchPath.emplace_back(buildInPath);
     316           26 :         IDE_LOGI("Add ASCEND_OPP_PATH[%s] to search path.", buildInPath.c_str());
     317           26 :     }
     318              : 
     319              :     // kernel meta generate in current path
     320           31 :     searchPath.emplace_back("./");
     321           31 :     IDE_LOGI("Add current path[./] to search path.");
     322              : 
     323           31 :     ADX_GET_ENV(MM_ENV_ASCEND_WORK_PATH, envStr);
     324           31 :     if (!envStr.empty()) {
     325           11 :         envStr += "/kernel_meta";
     326           11 :         searchPath.emplace_back(envStr);
     327              :     }
     328           31 :     IDE_LOGI("Add current path[%s] to search path.", envStr.c_str());
     329              : 
     330           31 :     return searchPath;
     331           31 : }
     332              : 
     333           23 : int32_t KernelInfoCollector::CollectKernelFile(const std::string &kernelName, const std::string &dumpPath) const
     334              : {
     335           23 :     std::vector<std::string> searchPath = GetSearchPath();
     336              : 
     337           23 :     bool failFlag = false;
     338           98 :     for (const auto &path : searchPath) {
     339           82 :         std::string jsonFilePath = SearchJsonFiles(path, kernelName);
     340           82 :         if (jsonFilePath.empty()) {
     341           75 :             continue;
     342              :         }
     343              : 
     344            7 :         Path jsonPath(jsonFilePath);
     345            7 :         Path dumpJsonPath(dumpPath);
     346            7 :         dumpJsonPath.Concat(jsonPath.GetFileName());
     347              :         static std::mutex KernelfileLock;
     348            7 :         std::lock_guard<std::mutex> lock(KernelfileLock);
     349            7 :         if (File::Copy(jsonFilePath, dumpJsonPath.GetString()) != ADUMP_SUCCESS) {
     350            0 :             IDE_LOGE("Copy kernel file[%s] to dump path[%s] failed.", jsonFilePath.c_str(), dumpJsonPath.GetCString());
     351            0 :             failFlag = true;
     352              :         } else {
     353            7 :             IDE_LOGE("[Dump][Exception] dump kernel json to file, file: %s", dumpJsonPath.GetCString());
     354            7 :             (void)mmChmod(dumpJsonPath.GetCString(), M_IRUSR);  // 安全要求,落盘文件置为最小权限:用户只读, 400
     355              :         }
     356              : 
     357            7 :         std::string kernelBinPath = jsonFilePath.substr(0, jsonFilePath.size() - JSON_SUFFIX_LEN) + ".o";
     358            7 :         Path kernelPath(kernelBinPath);
     359            7 :         Path dumpKernelPath(dumpPath);
     360            7 :         dumpKernelPath.Concat(kernelPath.GetFileName());
     361            7 :         if (File::Copy(kernelBinPath, dumpKernelPath.GetString()) != ADUMP_SUCCESS) {
     362            6 :             IDE_LOGE("Copy kernel file[%s] to dump path[%s] failed.", kernelBinPath.c_str(),
     363              :                      dumpKernelPath.GetCString());
     364            6 :             failFlag = true;
     365              :         } else {
     366            1 :             IDE_LOGE("[Dump][Exception] dump kernel to file, file: %s", dumpKernelPath.GetCString());
     367            1 :             (void)mmChmod(dumpKernelPath.GetCString(), M_IRUSR);  // 安全要求,落盘文件置为最小权限:用户只读, 400
     368              :         }
     369            7 :         break;
     370           89 :     }
     371           23 :     if (failFlag) {
     372            6 :         return ADUMP_FAILED;
     373              :     }
     374              : 
     375           17 :     return ADUMP_SUCCESS;
     376           23 : }
     377              : 
     378              : }  // namespace Adx
        

Generated by: LCOV version 2.0-1