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 ¤tLine, 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
|