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