LCOV - code coverage report
Current view: top level - adump/exception - exception_dumper.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.4 % 373 311
Test Date: 2026-08-31 10:09:28 Functions: 94.1 % 34 32

            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 <set>
      11              : #include <cctype>
      12              : #include <cstring>
      13              : #include <algorithm>
      14              : #include "log/adx_log.h"
      15              : #include "path.h"
      16              : #include "dump_manager.h"
      17              : #include "dump_config_converter.h"
      18              : #include "sys_utils.h"
      19              : #include "dump_args.h"
      20              : #include "dump_args_callback.h"
      21              : #include "dump_file.h"
      22              : #include "exception_info_common.h"
      23              : #include "kernel_symbol_locator.h"
      24              : #include "kernel_info_collector.h"
      25              : #include "kernel_source_symbolizer.h"
      26              : #include "exception_dumper.h"
      27              : 
      28              : namespace Adx {
      29              : namespace {
      30              : constexpr char DEFAULT_DUMP_PATH[] = "./";
      31              : constexpr char EXTRA_DUMP_PATH[] = "/extra-info/data-dump/";
      32              : constexpr size_t MAX_DUMP_OP_NUM = (2048U * 2048U) / 20U;
      33              : 
      34           24 : static bool IsSafeKernelDisplayName(const char* name)
      35              : {
      36          188 :     for (size_t i = 0; i < MAX_KERNELNAME_LEN && name[i] != '\0'; ++i) {
      37          168 :         char c = name[i];
      38          168 :         if (c == '/' || c == '\\' || c < 0x20 || c == 0x7F) {
      39            4 :             return false;
      40              :         }
      41              :     }
      42           40 :     return std::string(name).find("..") == std::string::npos;
      43              : }
      44              : 
      45           13 : bool ValidateKernelName(const ExceptionDumpInfo& info)
      46              : {
      47           13 :     if (strnlen(info.kernelName, MAX_KERNELNAME_LEN) == MAX_KERNELNAME_LEN ||
      48           13 :         strnlen(info.kernelDisplayName, MAX_KERNELNAME_LEN) == MAX_KERNELNAME_LEN) {
      49            0 :         return false;
      50              :     }
      51              : 
      52           13 :     if (!IsSafeKernelDisplayName(info.kernelName) || !IsSafeKernelDisplayName(info.kernelDisplayName)) {
      53            4 :         return false;
      54              :     }
      55            9 :     return true;
      56              : }
      57              : 
      58           19 : bool IsValidExceptionDumpMode(ExceptionDumpMode dumpMode)
      59              : {
      60           19 :     return dumpMode == ExceptionDumpMode::DUMP_MODE_NONE || dumpMode == ExceptionDumpMode::DUMP_MODE_OVERWRITE ||
      61           19 :            dumpMode == ExceptionDumpMode::DUMP_MODE_ADDITIONAL;
      62              : }
      63              : } // namespace
      64              : 
      65              : uint64_t* g_dynamicChunk = nullptr;
      66              : uint64_t* g_staticChunk = nullptr;
      67              : 
      68           58 : ExceptionDumper::~ExceptionDumper()
      69              : {
      70           58 :     if (g_dynamicChunk != nullptr) {
      71           19 :         delete[] g_dynamicChunk;
      72           19 :         g_dynamicChunk = nullptr;
      73              :     }
      74              : 
      75           58 :     if (g_staticChunk != nullptr) {
      76           19 :         delete[] g_staticChunk;
      77           19 :         g_staticChunk = nullptr;
      78              :     }
      79           58 :     KernelSymbolLocator::ClearCache();
      80           58 :     destructionFlag_ = true;
      81           58 : }
      82              : 
      83           58 : bool ExceptionDumper::InitArgsExceptionMemory() const
      84              : {
      85           58 :     if (g_dynamicChunk == nullptr) {
      86      7547161 :         g_dynamicChunk = new (std::nothrow) uint64_t[DYNAMIC_RING_CHUNK_SIZE + DFX_MAX_TENSOR_NUM + RESERVE_SPACE]();
      87           19 :         if (g_dynamicChunk == nullptr) {
      88            0 :             return false;
      89              :         }
      90              :     }
      91              : 
      92           58 :     if (g_staticChunk == nullptr) {
      93      2566425 :         g_staticChunk = new (std::nothrow) uint64_t[STATIC_RING_CHUNK_SIZE + DFX_MAX_TENSOR_NUM + RESERVE_SPACE]();
      94           19 :         if (g_staticChunk == nullptr) {
      95            0 :             return false;
      96              :         }
      97              :     }
      98           58 :     return true;
      99              : }
     100              : 
     101          123 : bool ExceptionDumper::IsRepeatEnableException(DumpType type, const DumpConfig& dumpConfig)
     102              : {
     103          123 :     if (type == DumpType::ARGS_EXCEPTION || type == DumpType::EXCEPTION || type == DumpType::AIC_ERR_DETAIL_DUMP) {
     104           56 :         std::string dumpStatus = dumpConfig.dumpStatus;
     105           56 :         std::transform(dumpStatus.begin(), dumpStatus.end(), dumpStatus.begin(), ::tolower);
     106           56 :         if (dumpStatus != "on") {
     107           11 :             return false;
     108              :         }
     109           45 :         return IsEnabledExceptionDump();
     110           56 :     }
     111           67 :     return false;
     112              : }
     113              : 
     114          135 : bool ExceptionDumper::IsEnabledExceptionDump() const
     115              : {
     116          135 :     return coredumpStatus_ || exceptionStatus_ || argsExceptionStatus_;
     117              : }
     118              : 
     119           87 : int32_t ExceptionDumper::ExceptionDumperInit(DumpType dumpType, const DumpConfig& dumpConfig)
     120              : {
     121           87 :     bool status = false;
     122           87 :     if (!setting_.InitDumpStatus(dumpConfig.dumpStatus, status)) {
     123            1 :         IDE_LOGE("The value of dumpStatus: %s is invalid.", dumpConfig.dumpStatus.c_str());
     124            1 :         return ADUMP_FAILED;
     125              :     }
     126              : 
     127              :     // status = false means turn off, flag = false means not start, print warning when not start but want to turn off
     128           86 :     if (dumpType == DumpType::EXCEPTION) {
     129           22 :         IDE_CTRL_VALUE_WARN(status || exceptionStatus_, return ADUMP_SUCCESS, "dump type %d not start.", dumpType);
     130           21 :         exceptionStatus_ = status;
     131           64 :     } else if (dumpType == DumpType::ARGS_EXCEPTION) {
     132           58 :         IDE_CTRL_VALUE_WARN(status || argsExceptionStatus_, return ADUMP_SUCCESS, "dump type %d not start.", dumpType);
     133           54 :         IDE_CTRL_VALUE_FAILED(InitArgsExceptionMemory(), return ADUMP_FAILED, "Init args exception memory failed.");
     134           54 :         if (status && !argsExceptionStatus_) {
     135           48 :             IDE_CTRL_VALUE_WARN(
     136              :                 LoadTensorPluginLib() == ADUMP_SUCCESS, return ADUMP_FAILED, "Load tensor custom plugin failed.");
     137              :         }
     138           54 :         argsExceptionStatus_ = status;
     139              :     } else {
     140              :         // detail exception dump can not off
     141            6 :         if (status == false) {
     142              :             static bool havePrint = false;
     143            2 :             if (!havePrint) {
     144            1 :                 IDE_RUN_LOGI("Can not turn off detail exception dump.");
     145            1 :                 havePrint = true;
     146              :             }
     147            2 :             IDE_LOGW("Can not turn off detail exception dump.");
     148            2 :             return ADUMP_SUCCESS;
     149              :         }
     150            4 :         IDE_CTRL_VALUE_FAILED(InitArgsExceptionMemory(), return ADUMP_FAILED, "Init args exception memory failed.");
     151            4 :         coredumpStatus_ = true;
     152              :     }
     153              : 
     154           79 :     SetDumpPath(dumpConfig.dumpPath);
     155           79 :     return ADUMP_SUCCESS;
     156              : }
     157              : 
     158           71 : std::string ExceptionDumper::GetDumpSceneName() const
     159              : {
     160           71 :     if (coredumpStatus_) {
     161            3 :         return ADUMP_DUMP_EXCEPTION_AIC_ERR_DETAIL;
     162           68 :     } else if (exceptionStatus_) {
     163           10 :         return ADUMP_DUMP_EXCEPTION_AIC_ERR_NORM;
     164           58 :     } else if (argsExceptionStatus_) {
     165           58 :         return ADUMP_DUMP_EXCEPTION_AIC_ERR_BRIEF;
     166              :     } else {
     167            0 :         return "unknown";
     168              :     }
     169              : }
     170              : 
     171           92 : int32_t ExceptionDumper::DumpException(const rtExceptionInfo& exception)
     172              : {
     173           92 :     IDE_CTRL_VALUE_WARN(!destructionFlag_, return ADUMP_FAILED, "ExceptionDumper has been destructed.");
     174           92 :     IDE_CTRL_VALUE_WARN(
     175              :         ExceptionInfoCommon::IsSupportExceptionDump(exception), return ADUMP_FAILED, "Exception is not need to dump.");
     176           78 :     IDE_CTRL_VALUE_WARN(IsEnabledExceptionDump(), return ADUMP_FAILED, "Not enable exception dump.");
     177           76 :     std::string dumpPath = CreateDeviceDumpPath(exception.deviceid);
     178           76 :     if (dumpPath.empty()) {
     179            5 :         return ADUMP_FAILED;
     180              :     }
     181              : 
     182           71 :     const std::string dumpScene = GetDumpSceneName();
     183           71 :     const std::string exceptionType = ExceptionInfoCommon::GetExceptionTaskTypeName(exception);
     184           71 :     const std::string kernelName = ExceptionInfoCommon::GetExceptionKernelName(exception);
     185           71 :     IDE_LOGE(
     186              :         "[Dump][Exception] Begin to dump exception. dumpScene=%s, deviceId=%u, streamId=%u, taskId=%u, "
     187              :         "exceptionType=%d(%s), kernelName=%s.",
     188              :         dumpScene.c_str(), exception.deviceid, exception.streamid, exception.taskid,
     189              :         static_cast<int32_t>(exception.expandInfo.type), exceptionType.c_str(), kernelName.c_str());
     190              : 
     191           71 :     if (coredumpStatus_) {
     192            3 :         return DumpDetailException(exception, dumpPath);
     193           68 :     } else if (exceptionStatus_) {
     194           10 :         return DumpNormalException(exception, dumpPath);
     195              :     } else {
     196           58 :         return DumpArgsException(exception, dumpPath);
     197              :     }
     198           76 : }
     199              : 
     200           79 : void ExceptionDumper::SetDumpPath(const std::string& dumpPath)
     201              : {
     202           96 :     dumpPath_ = dumpPath.empty() ? DEFAULT_DUMP_PATH : dumpPath;
     203           79 :     IDE_LOGI("Update exception dump path: %s", dumpPath_.c_str());
     204           79 : }
     205              : 
     206            4 : void ExceptionDumper::AddDumpOperator(const OperatorInfo& opInfo)
     207              : {
     208            4 :     OperatorInfoV2 dumpOperator = {};
     209            4 :     DumpManager::Instance().ConvertOperatorInfo(opInfo, dumpOperator);
     210            4 :     AddDumpOperatorV2(dumpOperator);
     211            4 : }
     212              : 
     213          118 : void ExceptionDumper::AddDumpOperatorV2(const OperatorInfoV2& opInfo)
     214              : {
     215          118 :     const std::lock_guard<std::mutex> lock(mutex_);
     216          118 :     if (opInfo.agingFlag) {
     217            6 :         agingOperators_.emplace_back(opInfo);
     218            6 :         if (agingOperators_.size() > MAX_DUMP_OP_NUM) {
     219            0 :             agingOperators_.pop_front();
     220              :         }
     221              :     } else {
     222          112 :         uint32_t maxStreamCount = 0;
     223          112 :         uint32_t maxTaskCount = 0;
     224          112 :         rtGetMaxStreamAndTask(0, &maxStreamCount, &maxTaskCount);
     225          112 :         auto& taskDeque = residentOperators_[opInfo.deviceId][opInfo.streamId];
     226          112 :         taskDeque.emplace_back(opInfo);
     227          112 :         if (taskDeque.size() > maxTaskCount) {
     228            2 :             taskDeque.pop_front();
     229              :         }
     230              :     }
     231          118 :     IDE_LOGI("Dump operator size, aging: %zu, resident: %zu", agingOperators_.size(), residentOperators_.size());
     232          118 : }
     233              : 
     234            9 : int32_t ExceptionDumper::DelDumpOperator(uint32_t deviceId, uint32_t streamId)
     235              : {
     236            9 :     const std::lock_guard<std::mutex> lock(mutex_);
     237            9 :     auto it = residentOperators_.find(deviceId);
     238            9 :     if (it != residentOperators_.end()) {
     239            8 :         it->second.erase(streamId);
     240            8 :         if (it->second.empty()) {
     241            8 :             residentOperators_.erase(deviceId);
     242              :         }
     243              :     }
     244            9 :     return ADUMP_SUCCESS;
     245            9 : }
     246              : 
     247          106 : std::string ExceptionDumper::CreateDumpPath(Path& dumpPath) const
     248              : {
     249          126 :     IDE_CTRL_VALUE_FAILED(dumpPath.CreateDirectory(true), return "", "Create path[%s] failed", dumpPath.GetCString());
     250          104 :     IDE_CTRL_VALUE_FAILED(
     251              :         dumpPath.RealPath(), return "", "Get RealPath of [%s] failed, strerror=%s", dumpPath.GetCString(),
     252              :         strerror(errno));
     253           92 :     return dumpPath.GetString();
     254              : }
     255              : 
     256          100 : std::string ExceptionDumper::CreateDeviceDumpPath(uint32_t deviceId) const
     257              : {
     258              :     // Create device dump path when exception call-backed
     259          100 :     std::string dumpPath = dumpPath_.empty() ? DEFAULT_DUMP_PATH : dumpPath_;
     260          100 :     Path deviceDumpPath(dumpPath);
     261          100 :     deviceDumpPath.Append(EXTRA_DUMP_PATH).Append(std::to_string(deviceId));
     262          200 :     return CreateDumpPath(deviceDumpPath);
     263          100 : }
     264              : 
     265           24 : int32_t ExceptionDumper::GetExceptionDumpPath(std::string& path)
     266              : {
     267           24 :     int32_t deviceId = 0;
     268           24 :     const rtError_t rtRet = rtGetDevice(&deviceId);
     269           24 :     IDE_CTRL_VALUE_FAILED(
     270              :         rtRet == RT_ERROR_NONE, return ADUMP_FAILED,
     271              :         "rtGetDevice failed when get the exception root dump path, ret=%d.", static_cast<int32_t>(rtRet));
     272              : 
     273           24 :     path = CreateDeviceDumpPath(static_cast<uint32_t>(deviceId));
     274           24 :     IDE_CTRL_VALUE_FAILED(!path.empty(), return ADUMP_FAILED, "exception dump root path is not ready.");
     275           18 :     return ADUMP_SUCCESS;
     276              : }
     277              : 
     278           15 : int32_t ExceptionDumper::SaveExceptionInfo(
     279              :     const std::string& fileName, const std::string& userTag, const std::vector<TensorInfo>& tensors)
     280              : {
     281           15 :     std::string rootPath;
     282           15 :     IDE_CTRL_VALUE_FAILED(
     283              :         GetExceptionDumpPath(rootPath) == ADUMP_SUCCESS, return ADUMP_FAILED,
     284              :         "[SaveExceptionInfo] get exception dump root path failed.");
     285              : 
     286           12 :     std::string realFilePath;
     287           12 :     IDE_CTRL_VALUE_FAILED(
     288              :         Path::BuildFullPathUnderRoot(rootPath, fileName, realFilePath), return ADUMP_FAILED,
     289              :         "[SaveExceptionInfo] build full file path failed.");
     290              : 
     291           12 :     realFilePath += ".custom." + SysUtils::GetCurrentTimeWithMillisecond();
     292              : 
     293           12 :     int32_t devId = 0;
     294           12 :     const rtError_t rtRet = rtGetDevice(&devId);
     295           12 :     IDE_CTRL_VALUE_FAILED(
     296              :         rtRet == RT_ERROR_NONE, return ADUMP_FAILED, "[SaveExceptionInfo] rtGetDevice failed, ret=%d.",
     297              :         static_cast<int32_t>(rtRet));
     298              : 
     299           12 :     DumpFile dumpFile(static_cast<uint32_t>(devId), realFilePath);
     300           12 :     dumpFile.SetHeader(Path(realFilePath).GetFileName());
     301           12 :     if (!userTag.empty()) {
     302           18 :         dumpFile.SetOpAttr("user_tag", userTag);
     303              :     }
     304              : 
     305           12 :     std::vector<std::string> record;
     306           12 :     dumpFile.SetTensors(tensors, record);
     307              : 
     308           12 :     IDE_CTRL_VALUE_FAILED(
     309              :         dumpFile.Dump(record) == ADUMP_SUCCESS, return ADUMP_FAILED,
     310              :         "[SaveExceptionInfo] dump exception info to file failed, file: %s", realFilePath.c_str());
     311              : 
     312            9 :     (void)mmChmod(realFilePath.c_str(), M_IRUSR);
     313            9 :     IDE_LOGE("[Dump][Exception] dump custom exception to file, file: %s", realFilePath.c_str());
     314            9 :     return ADUMP_SUCCESS;
     315           15 : }
     316              : 
     317            6 : std::string ExceptionDumper::CreateExtraDumpPath()
     318              : {
     319              :     // Create extra dump path for tensor custom dump data
     320            6 :     std::string dumpPath = dumpPath_.empty() ? DEFAULT_DUMP_PATH : dumpPath_;
     321            6 :     Path extraDumpPath(dumpPath);
     322            6 :     extraDumpPath.Append(EXTRA_DUMP_PATH);
     323            6 :     extraDumpPath_ = CreateDumpPath(extraDumpPath);
     324           12 :     return extraDumpPath_;
     325            6 : }
     326              : 
     327            7 : const char* ExceptionDumper::GetExtraDumpCPath() const
     328              : {
     329            7 :     return extraDumpPath_.empty() ? nullptr : extraDumpPath_.c_str();
     330              : }
     331              : 
     332            0 : bool ExceptionDumper::FindExceptionOperator(const rtExceptionInfo& exception, DumpOperator& excOp)
     333              : {
     334            0 :     OpIdentity excOpIdentiy(exception.deviceid, exception.taskid, exception.streamid);
     335            0 :     if (exception.expandInfo.type == RT_EXCEPTION_FFTS_PLUS) {
     336            0 :         uint32_t contextId = static_cast<uint32_t>(exception.expandInfo.u.fftsPlusInfo.contextId);
     337            0 :         uint32_t threadId = static_cast<uint32_t>(exception.expandInfo.u.fftsPlusInfo.threadId);
     338            0 :         IDE_LOGI("ffts+ op context id: %u, thread id: %u.", contextId, threadId);
     339            0 :         excOpIdentiy.contextId = contextId;
     340              :     }
     341              : 
     342            0 :     const std::lock_guard<std::mutex> lock(mutex_);
     343            0 :     IDE_LOGI(
     344              :         "Dump op size, aging:%zu, resident:%zu, target: %s", agingOperators_.size(), residentOperators_.size(),
     345              :         excOpIdentiy.GetString().c_str());
     346            0 :     for (const auto& op : agingOperators_) {
     347            0 :         if (op.IsBelongTo(excOpIdentiy)) {
     348            0 :             IDE_LOGI("Find exception op in aging list: %s", excOpIdentiy.GetString().c_str());
     349            0 :             excOp = op;
     350            0 :             return true;
     351              :         }
     352              :     }
     353              : 
     354            0 :     if (residentOperators_.find(excOpIdentiy.deviceId) != residentOperators_.end()) {
     355            0 :         auto& streamMap = residentOperators_[excOpIdentiy.deviceId];
     356            0 :         if (streamMap.find(excOpIdentiy.streamId) != streamMap.end()) {
     357            0 :             auto& taskDeque = streamMap[excOpIdentiy.streamId];
     358            0 :             for (const auto& op : taskDeque) {
     359            0 :                 if (op.IsBelongTo(excOpIdentiy)) {
     360            0 :                     IDE_LOGI("Find exception op in resident list: %s", excOpIdentiy.GetString().c_str());
     361            0 :                     excOp = op;
     362            0 :                     return true;
     363              :                 }
     364              :             }
     365              :         }
     366              :     }
     367              : 
     368            0 :     IDE_LOGW("Not find dump operator, target: %s", excOpIdentiy.GetString().c_str());
     369            0 :     return false;
     370            0 : }
     371              : 
     372           49 : void ExceptionDumper::DumpHostKernelBinBeforeSymbolize(
     373              :     const rtExceptionInfo& exception, const std::string& dumpPath) const
     374              : {
     375           49 :     rtExceptionArgsInfo_t exceptionArgsInfo{};
     376           49 :     int32_t ret = ExceptionInfoCommon::GetExceptionInfo(exception, exceptionArgsInfo);
     377           49 :     IDE_CTRL_VALUE_WARN(
     378              :         ret == ADUMP_SUCCESS, return, "Get exception args info failed, skip early dump host kernel bin.");
     379              : 
     380           49 :     KernelInfoCollector collector;
     381           49 :     collector.LoadKernelInfo(exceptionArgsInfo);
     382           49 :     ret = collector.LoadKernelBinBuffer();
     383           49 :     IDE_CTRL_VALUE_WARN(
     384              :         ret == ADUMP_SUCCESS, return, "Load kernel bin buffer failed, skip early dump host kernel bin.");
     385              : 
     386              :     // 提前无条件同步落 _host.o(只依赖 kernel bin buffer,不依赖 ELF 符号解析),
     387              :     // 保证符号表损坏等场景下 _host.o 仍能落盘供事后分析;DumpHostKernelBin 幂等,
     388              :     // 后续 symbolize/慢搜索路径复用已落盘文件不会重复写。
     389           49 :     std::string hostOPath;
     390           49 :     (void)collector.DumpHostKernelBin(dumpPath, hostOPath);
     391           49 : }
     392              : 
     393           10 : int32_t ExceptionDumper::DumpNormalException(const rtExceptionInfo& exception, const std::string& dumpPath)
     394              : {
     395           10 :     return DumpExceptionWithCallbacks(exception, dumpPath, &ExceptionDumper::DumpNormalExceptionDefault);
     396              : }
     397              : 
     398            1 : int32_t ExceptionDumper::DumpNormalExceptionDefault(const rtExceptionInfo& exception, const std::string& dumpPath)
     399              : {
     400            1 :     IDE_CTRL_VALUE_WARN(
     401              :         ExceptionInfoCommon::IsSupportDefaultExceptionDump(exception), return ADUMP_FAILED,
     402              :         "Exception is not support default dump.");
     403              :     // 先无条件提前落 _host.o,再符号化(symbolize 复用已落盘文件,不重复落盘)。
     404            0 :     DumpHostKernelBinBeforeSymbolize(exception, dumpPath);
     405            0 :     KernelSymbolLocator::DumpErrorSymbols(exception, dumpPath);
     406            0 :     DumpOperator excOp;
     407            0 :     bool find = FindExceptionOperator(exception, excOp);
     408            0 :     if (!find) {
     409            0 :         return ADUMP_SUCCESS;
     410              :     }
     411              : 
     412            0 :     rtExceptionArgsInfo_t exceptionArgsInfo{};
     413            0 :     if (ExceptionInfoCommon::GetExceptionInfo(exception, exceptionArgsInfo) != ADUMP_SUCCESS) {
     414            0 :         IDE_LOGW("Get exception args info failed.");
     415            0 :         return ADUMP_FAILED;
     416              :     }
     417            0 :     (void)excOp.RefreshAddrs(exceptionArgsInfo);
     418            0 :     (void)excOp.LogExceptionInfo(exceptionArgsInfo);
     419            0 :     (void)excOp.CopyOpKernelFile();
     420              : 
     421            0 :     const int32_t ret = excOp.DumpException(exception.deviceid, dumpPath);
     422            0 :     if (ret != ADUMP_SUCCESS) {
     423            0 :         return ADUMP_FAILED;
     424              :     }
     425            0 :     return ADUMP_SUCCESS;
     426            0 : }
     427              : 
     428           50 : int32_t ExceptionDumper::DumpArgsExceptionDefault(const rtExceptionInfo& exception, const std::string& dumpPath)
     429              : {
     430           50 :     IDE_CTRL_VALUE_WARN(
     431              :         ExceptionInfoCommon::IsSupportDefaultExceptionDump(exception), return ADUMP_FAILED,
     432              :         "Exception is not support default dump.");
     433              :     // 先无条件提前落 _host.o,再符号化(symbolize 复用已落盘文件,不重复落盘)。
     434           49 :     DumpHostKernelBinBeforeSymbolize(exception, dumpPath);
     435           49 :     KernelSymbolLocator::DumpErrorSymbols(exception, dumpPath);
     436           49 :     DumpArgs args;
     437           49 :     if (args.LoadArgsExceptionInfo(exception) != ADUMP_SUCCESS) {
     438           31 :         return ADUMP_FAILED;
     439              :     }
     440              : 
     441           18 :     if (args.DumpArgsExceptionInfo(exception.deviceid, dumpPath) != ADUMP_SUCCESS) {
     442            0 :         return ADUMP_FAILED;
     443              :     }
     444           18 :     return ADUMP_SUCCESS;
     445           49 : }
     446              : 
     447           67 : int32_t ExceptionDumper::DumpExceptionWithCallbacks(
     448              :     const rtExceptionInfo& exception, const std::string& dumpPath,
     449              :     int32_t (ExceptionDumper::*defaultDump)(const rtExceptionInfo&, const std::string&))
     450              : {
     451           67 :     ExceptionDumpMode dumpMode = ExceptionDumpMode::DUMP_MODE_NONE;
     452           67 :     std::vector<ExceptionDumpInfo> dumpInfos;
     453           67 :     int32_t invokeRet = InvokeCallbacks(exception, dumpInfos, dumpMode);
     454           67 :     if (invokeRet != ADUMP_SUCCESS) {
     455            1 :         return invokeRet;
     456              :     }
     457           66 :     if (dumpMode == ExceptionDumpMode::DUMP_MODE_OVERWRITE) {
     458            7 :         if (dumpInfos.empty()) {
     459            3 :             IDE_LOGE("OVERWRITE mode with empty callback data after validation, reject.");
     460            3 :             return ADUMP_FAILED;
     461              :         }
     462            4 :         IDE_LOGI("DumpMode of callbacks is OVERWRITE, skip default dump, dump callback data only.");
     463            4 :         DumpCallbackData(exception, dumpInfos, dumpPath);
     464            4 :         return ADUMP_SUCCESS;
     465              :     }
     466              : 
     467           59 :     if (dumpMode == ExceptionDumpMode::DUMP_MODE_ADDITIONAL && !dumpInfos.empty()) {
     468            4 :         IDE_LOGI("DumpMode of callbacks is ADDITIONAL, dump callback data and default.");
     469            4 :         DumpCallbackData(exception, dumpInfos, dumpPath);
     470              :     }
     471              : 
     472           59 :     return (this->*defaultDump)(exception, dumpPath);
     473           67 : }
     474              : 
     475           57 : int32_t ExceptionDumper::DumpArgsExceptionInner(const rtExceptionInfo& exception, const std::string& dumpPath)
     476              : {
     477           57 :     return DumpExceptionWithCallbacks(exception, dumpPath, &ExceptionDumper::DumpArgsExceptionDefault);
     478              : }
     479              : 
     480           67 : int32_t ExceptionDumper::InvokeCallbacks(
     481              :     const rtExceptionInfo& exception, std::vector<ExceptionDumpInfo>& dumpInfos, ExceptionDumpMode& dumpMode)
     482              : {
     483           67 :     dumpMode = ExceptionDumpMode::DUMP_MODE_NONE;
     484           67 :     dumpInfos.clear();
     485              : 
     486           67 :     std::lock_guard<std::recursive_mutex> lock(callbackMutex_);
     487           67 :     if (callbacks_.empty()) {
     488           50 :         IDE_LOGI("No exception callbacks registered.");
     489           50 :         return ADUMP_SUCCESS;
     490              :     }
     491              : 
     492           17 :     ExceptionRegInfo exceptionRegInfo{0, nullptr};
     493           17 :     int32_t ret = ExceptionInfoCommon::GetExceptionRegInfo(exception, exceptionRegInfo);
     494           17 :     IDE_CTRL_VALUE_WARN(
     495              :         ret == ADUMP_SUCCESS, return ADUMP_FAILED, "GetExceptionRegInfo failed, ret=%d, coreNum=%u.", ret,
     496              :         exceptionRegInfo.coreNum);
     497              : 
     498           16 :     uint32_t maxDumpSize = exceptionRegInfo.coreNum == 0 ? 1 : exceptionRegInfo.coreNum;
     499           16 :     IDE_LOGI("Exception callbacks size=%zu, maxDumpSize=%u.", callbacks_.size(), maxDumpSize);
     500              : 
     501           70 :     for (auto& callback : callbacks_) {
     502           19 :         std::vector<ExceptionDumpInfo> cbDumpInfos(maxDumpSize);
     503              : 
     504           19 :         uint32_t cbDumpRealSize = 0;
     505           19 :         ExceptionDumpMode cbDumpMode = ExceptionDumpMode::DUMP_MODE_NONE;
     506              : 
     507           19 :         uint32_t ret = callback(
     508              :             reinterpret_cast<void*>(const_cast<rtExceptionInfo*>(&exception)), cbDumpInfos.data(), maxDumpSize,
     509              :             &cbDumpRealSize, &cbDumpMode);
     510           19 :         if (ret != ADUMP_SUCCESS) {
     511            0 :             IDE_LOGW("Callback execute failed. ret=%u", ret);
     512            0 :             continue;
     513              :         }
     514           19 :         if (!IsValidExceptionDumpMode(cbDumpMode)) {
     515            1 :             IDE_LOGW("Callback dumpMode invalid. dumpMode=%u", static_cast<uint32_t>(cbDumpMode));
     516            1 :             continue;
     517              :         }
     518           18 :         if (cbDumpRealSize == 0 || cbDumpRealSize > maxDumpSize) {
     519            5 :             IDE_LOGW("Callback dumpRealSize invalid. maxDumpSize=%u, dumpRealSize=%u", maxDumpSize, cbDumpRealSize);
     520            5 :             continue;
     521              :         }
     522              : 
     523           13 :         IDE_LOGI("Callback dumpRealSize=%u, dumpMode=%d.", cbDumpRealSize, cbDumpMode);
     524           26 :         for (uint32_t i = 0; i < cbDumpRealSize; ++i) {
     525           13 :             if (!ValidateKernelName(cbDumpInfos[i])) {
     526            4 :                 IDE_LOGW("Invalid kernelName/kernelDisplayName in callback data, skip. index=%u", i);
     527            4 :                 continue;
     528              :             }
     529            9 :             dumpInfos.push_back(cbDumpInfos[i]);
     530              :         }
     531              : 
     532              :         // 多回调聚合时取优先级最高者:ADDITIONAL > OVERWRITE > NONE
     533           13 :         if (static_cast<uint32_t>(cbDumpMode) > static_cast<uint32_t>(dumpMode)) {
     534           13 :             dumpMode = cbDumpMode;
     535              :         }
     536           19 :     }
     537              : 
     538           16 :     IDE_LOGI("Callback final dumpMode=%d, dumpInfo total size=%zu.", dumpMode, dumpInfos.size());
     539           16 :     return ADUMP_SUCCESS;
     540           67 : }
     541              : 
     542            1 : void ExceptionDumper::DumpCallbackData(
     543              :     const rtExceptionInfo& exception, const std::vector<ExceptionDumpInfo>& dumpInfos, const std::string& dumpPath)
     544              : {
     545              :     // 收集每个回调 info(单核) 的定位结果,循环结束后按 (.o, 偏移) 聚类打印。
     546            1 :     std::vector<ErrorLocation> allLocations;
     547            3 :     for (const auto& info : dumpInfos) {
     548            1 :         IDE_LOGE(
     549              :             "[Dump][Exception] Begin to dump callback exception. coreType=%u, coreId=%u, "
     550              :             "argAddr=%p, argSize=%u, binHandle=%p, extraTensorNum=%u, kernelName=%s.",
     551              :             info.coreType, info.coreId, info.argAddr, info.argSize, info.bin, info.extraTensorNum, info.kernelName);
     552            1 :         IDE_LOGE("[Dump][Exception] Callback exception. kernelDisplayName=%s.", info.kernelDisplayName);
     553            1 :         DumpArgsCallback argsCallback(exception, info, dumpPath);
     554            1 :         int32_t ret = argsCallback.DumpDfxArgs();
     555            1 :         if (ret != ADUMP_SUCCESS) {
     556            0 :             IDE_LOGW("Dump callback args failed.");
     557              :         }
     558              : 
     559            1 :         ret = argsCallback.DumpExtraTensors();
     560            1 :         if (ret != ADUMP_SUCCESS) {
     561            0 :             IDE_LOGW("Dump callback extra tensor failed.");
     562              :         }
     563              : 
     564            1 :         ret = argsCallback.Dump();
     565            1 :         if (ret != ADUMP_SUCCESS) {
     566            0 :             IDE_LOGW("Dump callback data to file failed.");
     567              :         }
     568              : 
     569              :         // 先落 _host.o(同步),DumpKernelErrorSymbols 内定位偏移后对其批量 symbolize。
     570            1 :         ret = argsCallback.DumpKernelBin();
     571            1 :         if (ret != ADUMP_SUCCESS) {
     572            0 :             IDE_LOGW("Dump callback kernel bin failed.");
     573              :         }
     574              : 
     575            1 :         ErrorLocation location;
     576            1 :         ret = argsCallback.DumpKernelErrorSymbols(location);
     577            1 :         if (ret != ADUMP_SUCCESS) {
     578            0 :             IDE_LOGW("Dump callback kernel error symbols failed.");
     579              :         } else {
     580            1 :             allLocations.push_back(location);
     581              :         }
     582              : 
     583            1 :         IDE_LOGI("Dump callback data finished, kernelName=%s.", info.kernelName);
     584            1 :     }
     585              :     // 各 core 的源码解析已在 DumpKernelErrorSymbols → 批量 symbolize 内完成并回填,
     586              :     // 此处只在工具可用时统一打印聚类汇总(工具不可用时汇总无源码信息、无增量价值)。
     587            1 :     if (KernelSourceSymbolizer::IsAvailable()) {
     588            0 :         KernelSymbolLocator::PrintClassificationSummary(allLocations);
     589              :     }
     590            1 :     KernelSymbolLocator::ClearCache();
     591            1 :     IDE_LOGI("Dump all callback data success.");
     592            1 : }
     593              : 
     594            5 : void ExceptionDumper::ExceptionModeDowngrade() { coredumpEnableComplete_ = false; }
     595              : 
     596            0 : void ExceptionDumper::Exit() const
     597              : {
     598            0 :     IDE_LOGE("The process exits.");
     599            0 :     AdxLogFlush();
     600              : #ifndef __ADUMP_LLT
     601              :     _exit(EXIT_FAILURE);
     602              : #endif
     603            0 : }
     604              : 
     605              : #ifdef __ADUMP_LLT
     606          654 : void ExceptionDumper::Reset()
     607              : {
     608          654 :     const std::lock_guard<std::mutex> lock(mutex_);
     609          654 :     agingOperators_.clear();
     610          654 :     residentOperators_.clear();
     611          654 :     exceptionStatus_ = false;
     612          654 :     argsExceptionStatus_ = false;
     613          654 :     coredumpStatus_ = false;
     614          654 :     coredumpEnableComplete_ = true;
     615          654 : }
     616              : #endif
     617              : 
     618           44 : int32_t ExceptionDumper::RegisterExceptionDumpCallback(ExceptionDumpCallback callback)
     619              : {
     620           44 :     if (callback == nullptr) {
     621            7 :         IDE_LOGE("Register callback is nullptr.");
     622            7 :         return ADUMP_INPUT_FAILED;
     623              :     }
     624              : 
     625           37 :     const std::lock_guard<std::recursive_mutex> lock(callbackMutex_);
     626           77 :     for (auto& cb : callbacks_) {
     627            8 :         if (cb == callback) {
     628            5 :             IDE_LOGW("Callback already registered.");
     629            5 :             return ADUMP_SUCCESS;
     630              :         }
     631              :     }
     632           32 :     callbacks_.push_back(callback);
     633           32 :     IDE_LOGI("Callback registered, total=%zu.", callbacks_.size());
     634           32 :     return ADUMP_SUCCESS;
     635           37 : }
     636              : 
     637           21 : int32_t ExceptionDumper::UnregisterExceptionDumpCallback(ExceptionDumpCallback callback)
     638              : {
     639           21 :     if (callback == nullptr) {
     640            7 :         IDE_LOGE("Unregister callback is nullptr.");
     641            7 :         return ADUMP_INPUT_FAILED;
     642              :     }
     643              : 
     644           14 :     const std::lock_guard<std::recursive_mutex> lock(callbackMutex_);
     645           28 :     for (auto it = callbacks_.begin(); it != callbacks_.end(); ++it) {
     646           10 :         if (*it == callback) {
     647           20 :             callbacks_.erase(it);
     648           10 :             IDE_LOGI("Callback unregistered, total=%zu.", callbacks_.size());
     649           10 :             return ADUMP_SUCCESS;
     650              :         }
     651              :     }
     652            4 :     IDE_LOGW("Callback not found.");
     653            4 :     return ADUMP_SUCCESS;
     654           14 : }
     655              : 
     656              : } // namespace Adx
        

Generated by: LCOV version 2.0-1