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 "dump_args_callback.h"
12 : #include "dfx_args_parser.h"
13 : #include "dump_memory.h"
14 : #include "exception_info_common.h"
15 : #include "kernel_symbol_locator.h"
16 : #include "str_utils.h"
17 : #include "log/adx_log.h"
18 : #include "log/hdc_log.h"
19 :
20 : namespace Adx {
21 :
22 25 : DumpArgsCallback::DumpArgsCallback(const rtExceptionInfo &exception, const ExceptionDumpInfo &info,
23 25 : const std::string &dumpPath)
24 25 : : exception_(exception),
25 25 : info_(info),
26 25 : dumpPath_(dumpPath),
27 75 : dumpFilePath_(dumpPath + "/" +
28 100 : std::string(info.kernelDisplayName[0] != '\0' ? info.kernelDisplayName : "exception_info") + "." +
29 100 : std::to_string(exception.streamid) + "." + std::to_string(exception.taskid) + "." +
30 100 : std::to_string(info.coreType) + "." + std::to_string(info.coreId) + "." +
31 50 : SysUtils::GetCurrentTimeWithMillisecond()),
32 50 : dumpFile_(exception.deviceid, dumpFilePath_)
33 : {
34 25 : }
35 :
36 4 : int32_t DumpArgsCallback::DumpKernelBin()
37 : {
38 4 : std::string kernelName(info_.kernelName);
39 4 : if (info_.bin == nullptr || kernelName.empty()) {
40 3 : return ADUMP_SUCCESS;
41 : }
42 1 : IDE_LOGI("Dump kernel bin file. bin=%p, kernelName=%s", info_.bin, kernelName.c_str());
43 1 : KernelInfoCollector collector;
44 1 : int32_t ret = collector.InitFromBinHandle(info_.bin, kernelName);
45 1 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
46 : "Init for dump kernel bin failed. ret=%d, bin=%p, kernelName=%s.", ret, info_.bin, kernelName.c_str());
47 :
48 1 : std::string hostOPath;
49 1 : ret = collector.DumpHostKernelBin(dumpPath_, hostOPath);
50 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
51 : "DumpHostKernelBin failed, kernelName=%s.", kernelName.c_str());
52 :
53 1 : ret = collector.StartCollectKernel(dumpPath_);
54 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
55 : "StartCollectKernel failed, kernelName=%s.", kernelName.c_str());
56 :
57 1 : IDE_LOGI("DumpKernelBin success, kernelName=%s.", kernelName.c_str());
58 1 : return ADUMP_SUCCESS;
59 4 : }
60 :
61 6 : int32_t DumpArgsCallback::DumpKernelErrorSymbols(ErrorLocation &outLocation)
62 : {
63 6 : if (info_.bin == nullptr) {
64 2 : return ADUMP_SUCCESS;
65 : }
66 4 : KernelSymbolLocator locator;
67 4 : int32_t ret = locator.InitFromBinHandle(info_.bin);
68 4 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
69 : "KernelSymbolLocator InitFromBinHandle failed for callback exception. ret=%d", ret);
70 3 : locator.UpdateStartPCFromDeviceAddr(info_.bin);
71 :
72 : // 回调路径的 _host.o 已由 DumpKernelBin 同步落盘,此处复用其路径决定 symbolize 用的 .o。
73 : // kernelName 是定长数组成员,不会为 nullptr;std::string 构造依赖其内部 '\0' 结尾。
74 3 : KernelInfoCollector collector;
75 6 : if (collector.InitFromBinHandle(info_.bin, std::string(info_.kernelName)) == ADUMP_SUCCESS) {
76 3 : const std::string hostOPath = collector.GetHostOFilePath(dumpPath_);
77 3 : locator.SetOFilePath(KernelSymbolLocator::ResolveOFilePath(hostOPath));
78 3 : }
79 :
80 3 : ExceptionRegInfo exceptionRegInfo{0, nullptr};
81 3 : ret = ExceptionInfoCommon::GetExceptionRegInfo(exception_, exceptionRegInfo);
82 3 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
83 : "Get exception register information failed for callback exception. ret=%d", ret);
84 :
85 : // 构建 ErrorLocation:LocateErrorSymbolsForCore 内部定位偏移后对该 .o 批量 symbolize 并回填 src。
86 2 : ret = locator.LocateErrorSymbolsForCore(info_.coreId, info_.coreType, exceptionRegInfo, outLocation);
87 2 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
88 : "LocateErrorSymbolsForCore failed for callback exception. ret=%d, coreId=%u, coreType=%u.",
89 : ret, info_.coreId, info_.coreType);
90 :
91 1 : return ADUMP_SUCCESS;
92 4 : }
93 :
94 3 : int32_t DumpArgsCallback::QueryDfxIsTikInfo(rtFuncHandle funcHandle)
95 : {
96 3 : size_t isTikSize = 0;
97 3 : rtError_t rtRet = rtFunctionGetMetaInfoSize(funcHandle, RT_FUNCTION_TYPE_L0_EXCEPTION_DFX_IS_TIK, &isTikSize);
98 3 : if (rtRet != RT_ERROR_NONE || isTikSize == 0 || isTikSize < sizeof(uint32_t)) {
99 1 : IDE_LOGW("rtFunctionGetMetaInfoSize for dfxIsTik failed, will set dfxIsTik with false. "
100 : "rtRet=%d, kernelName=%s", rtRet, info_.kernelName);
101 1 : return ADUMP_FAILED;
102 : }
103 :
104 2 : std::vector<uint8_t> isTikBuffer(isTikSize);
105 2 : rtRet = rtFunctionGetMetaInfo(funcHandle, RT_FUNCTION_TYPE_L0_EXCEPTION_DFX_IS_TIK,
106 2 : isTikBuffer.data(), isTikSize);
107 2 : if (rtRet != RT_ERROR_NONE) {
108 1 : IDE_LOGW("rtFunctionGetMetaInfo for isTik failed, will set dfxIsTik with false. "
109 : "ret=%d, kernelName=%s, isTikSize=%zu.", rtRet, info_.kernelName, isTikSize);
110 1 : return ADUMP_FAILED;
111 : }
112 :
113 1 : uint32_t isTik = 0;
114 1 : isTik = *reinterpret_cast<uint32_t*>(isTikBuffer.data());
115 1 : isTik_ = (isTik == 1U) ? true : false;
116 1 : IDE_LOGI("Query dfxIsTik info success. kernelName=%s, dfxIsTik=%u", info_.kernelName, isTik);
117 1 : return ADUMP_SUCCESS;
118 2 : }
119 :
120 7 : int32_t DumpArgsCallback::QueryDfxInfo(std::vector<uint8_t> &dfxBuffer)
121 : {
122 7 : rtFuncHandle funcHandle = nullptr;
123 7 : rtError_t rtRet = rtBinaryGetFunctionByName(info_.bin, info_.kernelName, &funcHandle);
124 7 : IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE && funcHandle != nullptr, return ADUMP_FAILED,
125 : "rtBinaryGetFunctionByName failed, ret=%d, bin=%p, kernelName=%s.", rtRet, info_.bin, info_.kernelName);
126 :
127 6 : size_t dfxSize = 0;
128 6 : rtRet = rtFunctionGetMetaInfoSize(funcHandle, RT_FUNCTION_TYPE_DFX_TYPE, &dfxSize);
129 6 : IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE && dfxSize > 0, return ADUMP_FAILED,
130 : "rtFunctionGetMetaInfoSize failed, ret=%d, kernelName=%s, dfxSize=%zu.", rtRet, info_.kernelName, dfxSize);
131 5 : IDE_CTRL_VALUE_FAILED(dfxSize <= UINT16_MAX, return ADUMP_FAILED,
132 : "Dfx size exceeds uint16_t max, dfxSize=%zu", dfxSize);
133 :
134 4 : dfxBuffer.resize(dfxSize);
135 4 : rtRet = rtFunctionGetMetaInfo(funcHandle, RT_FUNCTION_TYPE_DFX_TYPE, dfxBuffer.data(), dfxSize);
136 4 : IDE_CTRL_VALUE_FAILED(rtRet == RT_ERROR_NONE, return ADUMP_FAILED,
137 : "rtFunctionGetMetaInfo failed, ret=%d, kernelName=%s, dfxSize=%zu.", rtRet, info_.kernelName, dfxSize);
138 :
139 3 : (void)QueryDfxIsTikInfo(funcHandle);
140 :
141 3 : IDE_LOGI("Query kernel dfx args info success. kernelName=%s, dfxSize=%zu, isTik=%d",
142 : info_.kernelName, dfxSize, isTik_);
143 3 : return ADUMP_SUCCESS;
144 : }
145 :
146 9 : int32_t DumpArgsCallback::DumpDfxArgs()
147 : {
148 : // kernelName 是定长数组成员,不会为 nullptr,直接判首字节是否为空串。
149 9 : if (info_.argAddr == nullptr || info_.argSize == 0 || info_.bin == nullptr ||
150 7 : info_.kernelName[0] == '\0') {
151 2 : return ADUMP_SUCCESS;
152 : }
153 :
154 7 : IDE_LOGI("Begin to dump dfx args tensors. argAddr=%p, argSize=%u, bin=%p, kernelName=%s",
155 : info_.argAddr, info_.argSize, info_.bin, info_.kernelName);
156 :
157 7 : int32_t ret = QueryDfxInfo(dfxBuffer_);
158 7 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "Query kernel dfx info failed.");
159 :
160 3 : DfxArgsParser parser;
161 3 : ret = parser.Init(info_.argAddr, info_.argSize, dfxBuffer_.data(), static_cast<uint16_t>(dfxBuffer_.size()));
162 3 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "Dfx args parser init failed.");
163 :
164 3 : parser.SetIsTik(isTik_);
165 3 : ret = parser.InitTensorModeInfo();
166 3 : IDE_CHECK_RET(ret, return ADUMP_FAILED);
167 :
168 0 : ret = parser.ParseAll();
169 0 : IDE_CHECK_RET(ret, return ADUMP_FAILED);
170 :
171 0 : tensorBuffer_ = parser.GetTensors();
172 0 : workspaces_ = parser.GetWorkspaces();
173 0 : logRecord_ = parser.GetLogRecords();
174 :
175 0 : IDE_LOGI("Dfx args tensors are parsed finished. tensor size=%zu, workspace size=%zu.",
176 : tensorBuffer_.size(), workspaces_.size());
177 :
178 0 : dumpFile_.SetTensorBuffer(tensorBuffer_);
179 0 : dumpFile_.SetWorkspaces(workspaces_);
180 :
181 0 : IDE_LOGI("End to dump dfx args tensors.");
182 0 : return ADUMP_SUCCESS;
183 3 : }
184 :
185 6 : int32_t DumpArgsCallback::DumpExtraTensors()
186 : {
187 6 : if (info_.extraTensorNum == 0) {
188 2 : return ADUMP_SUCCESS;
189 : }
190 4 : if (info_.extraTensorNum > EXCEPTION_DUMP_MAX_TENSOR_NUM) {
191 1 : IDE_LOGE("Extra tensor size exceeds the maximum limit. realSize=%u, maxSize=%u",
192 : info_.extraTensorNum, EXCEPTION_DUMP_MAX_TENSOR_NUM);
193 1 : return ADUMP_FAILED;
194 : }
195 :
196 3 : IDE_LOGI("Begin to dump extra tensors. extra tensor size=%u", info_.extraTensorNum);
197 :
198 3 : const uint32_t baseOffset = static_cast<uint32_t>(tensorBuffer_.size() + workspaces_.size());
199 3 : std::vector<TensorInfo> tensors(info_.extraTensor, info_.extraTensor + info_.extraTensorNum);
200 9 : for (uint32_t i = 0; i < info_.extraTensorNum; ++i) {
201 6 : tensors[i].argsOffSet = baseOffset + i;
202 : }
203 3 : dumpFile_.SetTensors(tensors, logRecord_);
204 :
205 3 : IDE_LOGI("End to dump extra tensors.");
206 3 : return ADUMP_SUCCESS;
207 3 : }
208 :
209 6 : int32_t DumpArgsCallback::Dump()
210 : {
211 6 : int32_t ret = dumpFile_.Dump(logRecord_);
212 6 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED,
213 : "[Dump][Exception] Write callback exception to file failed, file: %s", dumpFilePath_.c_str());
214 :
215 5 : (void)mmChmod(dumpFilePath_.c_str(), M_IRUSR); // readonly, 400
216 5 : IDE_LOGE("[Dump][Exception] dump exception to file, file: %s", dumpFilePath_.c_str());
217 5 : return ADUMP_SUCCESS;
218 : }
219 :
220 0 : void DumpArgsCallback::RecordDumpLog(const std::string &log)
221 : {
222 0 : IDE_LOGE("%s", log.c_str());
223 0 : logRecord_.emplace_back(log + "\n");
224 0 : }
225 :
226 : } // namespace Adx
|