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 <algorithm>
11 : #include <cstring>
12 : #include <elf.h>
13 : #include <limits>
14 : #include <mutex>
15 : #include <sstream>
16 : #include "securec.h"
17 : #include "runtime/kernel.h"
18 : #include "kernel_symbol_locator.h"
19 : #include "kernel_info_collector.h"
20 : #include "kernel_source_symbolizer.h"
21 : #include "exception_info_common.h"
22 : #include "log/adx_log.h"
23 : #include "log/hdc_log.h"
24 :
25 : namespace Adx {
26 : namespace {
27 : std::mutex g_cacheMutex;
28 :
29 : // 符号过滤计数关系:
30 : // total = accepted + nonFunc + invalidSection + invalidName。
31 : struct SymbolFilterStats {
32 : // 从有效的 SHT_SYMTAB/SHT_DYNSYM 段读取到的符号总数。
33 : size_t total = 0;
34 : // 被接受用于函数定位的有效函数符号数。
35 : size_t accepted = 0;
36 : // 因 st_info 类型不是 STT_FUNC 被过滤的符号数。
37 : size_t nonFunc = 0;
38 : // 因 st_shndx 为 SHN_UNDEF 或超出 section header 范围被过滤的函数符号数。
39 : size_t invalidSection = 0;
40 : // 因 st_name 越界或符号名未在字符串表范围内以 '\\0' 结束被过滤的函数符号数。
41 : size_t invalidName = 0;
42 : };
43 :
44 : template <typename T>
45 195 : bool ReadStruct(const char* elf, size_t elfSize, size_t offset, T& out)
46 : {
47 195 : if (elf == nullptr || offset > elfSize || elfSize - offset < sizeof(T)) {
48 20 : return false;
49 : }
50 175 : return memcpy_s(&out, sizeof(T), elf + offset, sizeof(T)) == EOK;
51 : }
52 :
53 117 : bool IsAddOverflow(size_t lhs, size_t rhs) { return lhs > std::numeric_limits<size_t>::max() - rhs; }
54 :
55 90 : bool IsAddOverflow64(uint64_t lhs, uint64_t rhs)
56 : {
57 90 : return lhs > std::numeric_limits<uint64_t>::max() - rhs;
58 : }
59 :
60 15 : bool GetSymbolOffsetRange(const std::vector<KernelSymbol>& symbols, uint64_t& minOffset, uint64_t& maxEnd)
61 : {
62 15 : bool hasRange = false;
63 15 : minOffset = 0;
64 15 : maxEnd = 0;
65 105 : for (const KernelSymbol& symbol : symbols) {
66 90 : if (IsAddOverflow64(symbol.offset, symbol.size)) {
67 15 : continue;
68 : }
69 90 : const uint64_t symbolEnd = symbol.offset + symbol.size;
70 90 : if (!hasRange) {
71 15 : minOffset = symbol.offset;
72 15 : maxEnd = symbolEnd;
73 15 : hasRange = true;
74 15 : continue;
75 : }
76 75 : minOffset = std::min(minOffset, symbol.offset);
77 75 : maxEnd = std::max(maxEnd, symbolEnd);
78 : }
79 15 : return hasRange;
80 : }
81 :
82 6 : const KernelSymbol* FindBestMatchedSymbol(const std::vector<KernelSymbol>& symbols, uint64_t fixedPCOffset)
83 : {
84 6 : const KernelSymbol* matchedSymbol = nullptr;
85 42 : for (const auto& symbol : symbols) {
86 36 : if (fixedPCOffset < symbol.offset || fixedPCOffset - symbol.offset >= symbol.size) {
87 36 : continue;
88 : }
89 0 : if (matchedSymbol == nullptr || symbol.offset > matchedSymbol->offset ||
90 0 : (symbol.offset == matchedSymbol->offset && symbol.size < matchedSymbol->size)) {
91 0 : matchedSymbol = &symbol;
92 : }
93 : }
94 6 : return matchedSymbol;
95 : }
96 :
97 9 : void LogKernelSymbolSummary(
98 : const KernelSymbolSet& symbols, size_t parsedSymbolCount, const SymbolFilterStats& filterStats)
99 : {
100 9 : uint64_t minOffset = 0;
101 9 : uint64_t maxEnd = 0;
102 9 : const bool hasRange = GetSymbolOffsetRange(symbols.symbols, minOffset, maxEnd);
103 9 : IDE_LOGI("Parse kernel symbols success. parsedSymbolCount=%zu, normalizedSymbolCount=%zu, "
104 : "hasSymbolRange=%u, minSymbolOffset=0x%lx, maxSymbolEnd=0x%lx, symbolTotal=%zu, accepted=%zu, "
105 : "nonFunc=%zu, invalidSection=%zu, invalidName=%zu.",
106 : parsedSymbolCount, symbols.symbols.size(), static_cast<uint32_t>(hasRange), minOffset, maxEnd,
107 : filterStats.total, filterStats.accepted, filterStats.nonFunc, filterStats.invalidSection,
108 : filterStats.invalidName);
109 9 : }
110 :
111 21 : uint16_t Swap16(uint16_t value) { return static_cast<uint16_t>((value >> 8U) | (value << 8U)); }
112 :
113 31 : uint32_t Swap32(uint32_t value)
114 : {
115 31 : return ((value & 0x000000FFU) << 24U) | ((value & 0x0000FF00U) << 8U) | ((value & 0x00FF0000U) >> 8U) |
116 31 : ((value & 0xFF000000U) >> 24U);
117 : }
118 :
119 53 : uint64_t Swap64(uint64_t value)
120 : {
121 53 : return ((value & 0x00000000000000FFULL) << 56U) | ((value & 0x000000000000FF00ULL) << 40U) |
122 53 : ((value & 0x0000000000FF0000ULL) << 24U) | ((value & 0x00000000FF000000ULL) << 8U) |
123 53 : ((value & 0x000000FF00000000ULL) >> 8U) | ((value & 0x0000FF0000000000ULL) >> 24U) |
124 53 : ((value & 0x00FF000000000000ULL) >> 40U) | ((value & 0xFF00000000000000ULL) >> 56U);
125 : }
126 :
127 24 : bool IsSupportedElfData(uint8_t data) { return data == ELFDATANONE || data == ELFDATA2LSB || data == ELFDATA2MSB; }
128 :
129 24 : bool IsBigEndianElf(const Elf64_Ehdr& ehdr) { return ehdr.e_ident[EI_DATA] == ELFDATA2MSB; }
130 :
131 24 : bool IsHostBigEndian()
132 : {
133 24 : const uint16_t value = 0x0102U;
134 24 : const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
135 24 : return bytes[0] == 0x01U;
136 : }
137 :
138 24 : bool ShouldSwapElfBytes(const Elf64_Ehdr& ehdr) { return IsBigEndianElf(ehdr) != IsHostBigEndian(); }
139 :
140 12 : void NormalizeElfHeader(Elf64_Ehdr& ehdr, bool shouldSwap)
141 : {
142 12 : if (!shouldSwap) {
143 11 : return;
144 : }
145 1 : ehdr.e_type = Swap16(ehdr.e_type);
146 1 : ehdr.e_machine = Swap16(ehdr.e_machine);
147 1 : ehdr.e_version = Swap32(ehdr.e_version);
148 1 : ehdr.e_entry = Swap64(ehdr.e_entry);
149 1 : ehdr.e_phoff = Swap64(ehdr.e_phoff);
150 1 : ehdr.e_shoff = Swap64(ehdr.e_shoff);
151 1 : ehdr.e_flags = Swap32(ehdr.e_flags);
152 1 : ehdr.e_ehsize = Swap16(ehdr.e_ehsize);
153 1 : ehdr.e_phentsize = Swap16(ehdr.e_phentsize);
154 1 : ehdr.e_phnum = Swap16(ehdr.e_phnum);
155 1 : ehdr.e_shentsize = Swap16(ehdr.e_shentsize);
156 1 : ehdr.e_shnum = Swap16(ehdr.e_shnum);
157 1 : ehdr.e_shstrndx = Swap16(ehdr.e_shstrndx);
158 : }
159 :
160 46 : void NormalizeSectionHeader(Elf64_Shdr& shdr, bool shouldSwap)
161 : {
162 46 : if (!shouldSwap) {
163 42 : return;
164 : }
165 4 : shdr.sh_name = Swap32(shdr.sh_name);
166 4 : shdr.sh_type = Swap32(shdr.sh_type);
167 4 : shdr.sh_flags = Swap64(shdr.sh_flags);
168 4 : shdr.sh_addr = Swap64(shdr.sh_addr);
169 4 : shdr.sh_offset = Swap64(shdr.sh_offset);
170 4 : shdr.sh_size = Swap64(shdr.sh_size);
171 4 : shdr.sh_link = Swap32(shdr.sh_link);
172 4 : shdr.sh_info = Swap32(shdr.sh_info);
173 4 : shdr.sh_addralign = Swap64(shdr.sh_addralign);
174 4 : shdr.sh_entsize = Swap64(shdr.sh_entsize);
175 : }
176 :
177 117 : void NormalizeSymbol(Elf64_Sym& sym, bool shouldSwap)
178 : {
179 117 : if (!shouldSwap) {
180 104 : return;
181 : }
182 13 : sym.st_name = Swap32(sym.st_name);
183 13 : sym.st_shndx = Swap16(sym.st_shndx);
184 13 : sym.st_value = Swap64(sym.st_value);
185 13 : sym.st_size = Swap64(sym.st_size);
186 : }
187 :
188 12 : bool IsValidElfHeader(const Elf64_Ehdr& ehdr)
189 : {
190 24 : return std::memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0 && ehdr.e_ident[EI_CLASS] == ELFCLASS64 &&
191 24 : IsSupportedElfData(ehdr.e_ident[EI_DATA]) && ehdr.e_ehsize == sizeof(Elf64_Ehdr) &&
192 24 : ehdr.e_shentsize == sizeof(Elf64_Shdr) && ehdr.e_shoff != 0 && ehdr.e_shnum != 0;
193 : }
194 :
195 32 : bool IsRangeInsideElf(size_t offset, size_t size, size_t elfSize)
196 : {
197 32 : return offset <= elfSize && elfSize - offset >= size;
198 : }
199 :
200 20 : bool IsSectionInsideElf(const Elf64_Shdr& section, size_t elfSize)
201 : {
202 40 : if (section.sh_offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()) ||
203 20 : section.sh_size > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) {
204 0 : return false;
205 : }
206 20 : return IsRangeInsideElf(static_cast<size_t>(section.sh_offset), static_cast<size_t>(section.sh_size), elfSize);
207 : }
208 :
209 32 : bool ReadElfHeader(const char* elf, size_t elfSize, Elf64_Ehdr& ehdr)
210 : {
211 32 : if (!ReadStruct(elf, elfSize, 0, ehdr)) {
212 20 : return false;
213 : }
214 24 : if (std::memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
215 12 : !IsSupportedElfData(ehdr.e_ident[EI_DATA])) {
216 0 : return false;
217 : }
218 : // 与 runtime 保持一致:ELFDATA2MSB 按大端解析字段;ELFDATANONE 按小端处理。
219 12 : NormalizeElfHeader(ehdr, ShouldSwapElfBytes(ehdr));
220 12 : return IsValidElfHeader(ehdr);
221 : }
222 :
223 12 : bool ReadSectionHeaders(
224 : const char* elf, size_t elfSize, const Elf64_Ehdr& ehdr, bool shouldSwap, std::vector<Elf64_Shdr>& outShdrs)
225 : {
226 12 : const size_t shdrsSize = static_cast<size_t>(ehdr.e_shnum) * sizeof(Elf64_Shdr);
227 24 : if (ehdr.e_shoff > static_cast<uint64_t>(std::numeric_limits<size_t>::max()) ||
228 12 : !IsRangeInsideElf(static_cast<size_t>(ehdr.e_shoff), shdrsSize, elfSize)) {
229 0 : return false;
230 : }
231 12 : if (ehdr.e_shstrndx >= ehdr.e_shnum && ehdr.e_shstrndx != SHN_UNDEF) {
232 0 : return false;
233 : }
234 :
235 12 : outShdrs.clear();
236 12 : outShdrs.reserve(ehdr.e_shnum);
237 58 : for (uint16_t i = 0; i < ehdr.e_shnum; i++) {
238 46 : Elf64_Shdr shdr = {};
239 46 : const size_t offset = static_cast<size_t>(ehdr.e_shoff) + static_cast<size_t>(i) * sizeof(Elf64_Shdr);
240 46 : if (!ReadStruct(elf, elfSize, offset, shdr)) {
241 0 : return false;
242 : }
243 46 : NormalizeSectionHeader(shdr, shouldSwap);
244 46 : outShdrs.push_back(shdr);
245 : }
246 12 : return true;
247 : }
248 :
249 46 : bool IsSymbolTable(const Elf64_Shdr& section) { return section.sh_type == SHT_SYMTAB || section.sh_type == SHT_DYNSYM; }
250 :
251 11 : bool IsValidSymbolAndStringTable(
252 : size_t elfSize, const std::vector<Elf64_Shdr>& shdrs, const Elf64_Shdr& symtabShdr, const Elf64_Shdr*& strtabShdr)
253 : {
254 11 : if (!IsSectionInsideElf(symtabShdr, elfSize) || symtabShdr.sh_size == 0) {
255 0 : return false;
256 : }
257 11 : if (symtabShdr.sh_entsize != sizeof(Elf64_Sym) || (symtabShdr.sh_size % sizeof(Elf64_Sym)) != 0) {
258 1 : return false;
259 : }
260 10 : if (symtabShdr.sh_link >= shdrs.size()) {
261 0 : return false;
262 : }
263 :
264 10 : strtabShdr = &shdrs[symtabShdr.sh_link];
265 10 : if (strtabShdr->sh_type != SHT_STRTAB || strtabShdr->sh_size == 0) {
266 1 : return false;
267 : }
268 9 : return IsSectionInsideElf(*strtabShdr, elfSize);
269 : }
270 :
271 72 : bool GetSymbolSectionEnd(const Elf64_Sym& sym, const std::vector<Elf64_Shdr>& shdrs, uint64_t& sectionEnd)
272 : {
273 72 : if (sym.st_shndx >= shdrs.size()) {
274 0 : return false;
275 : }
276 72 : const Elf64_Shdr& section = shdrs[sym.st_shndx];
277 : // ET_REL 中 st_value 通常是 section 内偏移且 sh_addr 为 0;加载态镜像中 st_value 通常可与 sh_addr 比较。
278 72 : uint64_t sectionBase = section.sh_addr;
279 72 : if (sym.st_value < sectionBase) {
280 0 : sectionBase = 0;
281 : }
282 72 : if (sectionBase > std::numeric_limits<uint64_t>::max() - section.sh_size) {
283 0 : return false;
284 : }
285 72 : sectionEnd = sectionBase + section.sh_size;
286 72 : return sectionEnd > sym.st_value;
287 : }
288 :
289 117 : bool BuildKernelSymbol(
290 : const Elf64_Sym& sym, const std::vector<Elf64_Shdr>& shdrs, const char* strtab, size_t strtabSize,
291 : SymbolFilterStats& stats, KernelSymbol& outSymbol)
292 : {
293 117 : stats.total++;
294 117 : if (ELF64_ST_TYPE(sym.st_info) != STT_FUNC) {
295 18 : stats.nonFunc++;
296 18 : return false;
297 : }
298 99 : if (sym.st_shndx == SHN_UNDEF) {
299 9 : stats.invalidSection++;
300 9 : return false;
301 : }
302 90 : if (sym.st_shndx >= shdrs.size()) {
303 9 : stats.invalidSection++;
304 9 : return false;
305 : }
306 81 : if (sym.st_name >= strtabSize) {
307 9 : stats.invalidName++;
308 9 : return false;
309 : }
310 : // section 结束地址用于给 st_size 为 0 的符号补齐范围。
311 72 : (void)GetSymbolSectionEnd(sym, shdrs, outSymbol.sectionEnd);
312 :
313 72 : const char* strStart = strtab + sym.st_name;
314 72 : size_t remaining = strtabSize - sym.st_name;
315 72 : const char* strEnd = static_cast<const char*>(std::memchr(strStart, '\0', remaining));
316 72 : if (strEnd == nullptr) {
317 0 : stats.invalidName++;
318 0 : return false;
319 : }
320 :
321 72 : outSymbol.offset = sym.st_value;
322 72 : outSymbol.size = sym.st_size;
323 72 : outSymbol.sectionIndex = sym.st_shndx;
324 72 : outSymbol.bind = ELF64_ST_BIND(sym.st_info);
325 72 : outSymbol.visibility = ELF64_ST_VISIBILITY(sym.st_other);
326 72 : outSymbol.name.assign(strStart, strEnd - strStart);
327 72 : IDE_LOGD("Parse kernel symbol, name=%s, offset=0x%lx, size=0x%lx, sectionEnd=0x%lx, "
328 : "sectionIndex=%u, bind=%u, visibility=%u.",
329 : outSymbol.name.c_str(), outSymbol.offset, outSymbol.size, outSymbol.sectionEnd,
330 : static_cast<uint32_t>(outSymbol.sectionIndex), static_cast<uint32_t>(outSymbol.bind),
331 : static_cast<uint32_t>(outSymbol.visibility));
332 72 : stats.accepted++;
333 72 : return true;
334 : }
335 :
336 9 : bool ParseFunctionSymbols(
337 : const char* elf, size_t elfSize, const Elf64_Shdr& symtabShdr, const Elf64_Shdr& strtabShdr, bool shouldSwap,
338 : const std::vector<Elf64_Shdr>& shdrs, std::vector<KernelSymbol>& outSymbols, SymbolFilterStats& stats)
339 : {
340 9 : const size_t symCount = symtabShdr.sh_size / sizeof(Elf64_Sym);
341 9 : const char* strtab = elf + strtabShdr.sh_offset;
342 126 : for (size_t i = 0; i < symCount; i++) {
343 117 : if (IsAddOverflow(static_cast<size_t>(symtabShdr.sh_offset), i * sizeof(Elf64_Sym))) {
344 0 : return false;
345 : }
346 117 : Elf64_Sym sym = {};
347 117 : const size_t symOffset = static_cast<size_t>(symtabShdr.sh_offset) + i * sizeof(Elf64_Sym);
348 117 : if (!ReadStruct(elf, elfSize, symOffset, sym)) {
349 0 : return false;
350 : }
351 117 : NormalizeSymbol(sym, shouldSwap);
352 117 : KernelSymbol symbol = {};
353 117 : if (BuildKernelSymbol(sym, shdrs, strtab, static_cast<size_t>(strtabShdr.sh_size), stats, symbol)) {
354 72 : outSymbols.push_back(symbol);
355 : }
356 117 : }
357 9 : return true;
358 : }
359 :
360 63 : bool IsSameKernelSymbol(const KernelSymbol& lhs, const KernelSymbol& rhs)
361 : {
362 72 : return lhs.offset == rhs.offset && lhs.size == rhs.size && lhs.sectionIndex == rhs.sectionIndex &&
363 72 : lhs.name == rhs.name;
364 : }
365 :
366 9 : void SortKernelSymbols(std::vector<KernelSymbol>& symbols)
367 : {
368 : // 按地址排序,便于后续用同 section 内的下一个符号修正 zero-size 符号范围。
369 9 : std::sort(symbols.begin(), symbols.end(), [](const KernelSymbol& lhs, const KernelSymbol& rhs) {
370 162 : if (lhs.offset != rhs.offset) {
371 153 : return lhs.offset < rhs.offset;
372 : }
373 9 : if (lhs.size != rhs.size) {
374 0 : return lhs.size > rhs.size;
375 : }
376 9 : return lhs.name < rhs.name;
377 : });
378 9 : }
379 :
380 9 : void DeduplicateKernelSymbols(std::vector<KernelSymbol>& symbols)
381 : {
382 9 : std::vector<KernelSymbol> uniqueSymbols;
383 9 : uniqueSymbols.reserve(symbols.size());
384 81 : for (const KernelSymbol& symbol : symbols) {
385 : // 同一个函数可能同时出现在 .symtab 和 .dynsym 中。
386 72 : if (!uniqueSymbols.empty() && IsSameKernelSymbol(uniqueSymbols.back(), symbol)) {
387 9 : uniqueSymbols.back().sectionEnd = std::max(uniqueSymbols.back().sectionEnd, symbol.sectionEnd);
388 9 : continue;
389 : }
390 63 : uniqueSymbols.push_back(symbol);
391 : }
392 9 : symbols.swap(uniqueSymbols);
393 9 : }
394 :
395 9 : void FillZeroSizeSymbolRanges(std::vector<KernelSymbol>& symbols)
396 : {
397 72 : for (size_t i = 0; i < symbols.size(); i++) {
398 63 : if (symbols[i].size != 0) {
399 54 : continue;
400 : }
401 : // 参考 LLDB 策略:先用 section 结束地址作为最大范围,再用同 section 的下一个符号地址收缩范围。
402 9 : if (symbols[i].sectionEnd > symbols[i].offset) {
403 9 : symbols[i].size = symbols[i].sectionEnd - symbols[i].offset;
404 : }
405 9 : for (size_t j = i + 1; j < symbols.size(); j++) {
406 9 : if (symbols[j].sectionIndex == symbols[i].sectionIndex && symbols[j].offset > symbols[i].offset) {
407 9 : const uint64_t sizeToNextSymbol = symbols[j].offset - symbols[i].offset;
408 9 : if (symbols[i].size == 0 || sizeToNextSymbol < symbols[i].size) {
409 9 : symbols[i].size = sizeToNextSymbol;
410 : }
411 9 : break;
412 : }
413 : }
414 : }
415 9 : }
416 :
417 9 : void FilterValidKernelSymbols(const std::vector<KernelSymbol>& symbols, std::vector<KernelSymbol>& outSymbols)
418 : {
419 9 : outSymbols.clear();
420 9 : outSymbols.reserve(symbols.size());
421 72 : for (const KernelSymbol& symbol : symbols) {
422 63 : if (!symbol.name.empty() && symbol.size != 0) {
423 54 : outSymbols.push_back(symbol);
424 : }
425 : }
426 9 : }
427 :
428 9 : void NormalizeFunctionSymbols(std::vector<KernelSymbol>& symbols, std::vector<KernelSymbol>& outSymbols)
429 : {
430 9 : SortKernelSymbols(symbols);
431 9 : DeduplicateKernelSymbols(symbols);
432 9 : FillZeroSizeSymbolRanges(symbols);
433 9 : FilterValidKernelSymbols(symbols, outSymbols);
434 9 : }
435 :
436 12 : bool ParseSymbolTables(
437 : const char* elf, size_t elfSize, const std::vector<Elf64_Shdr>& shdrs, bool shouldSwap,
438 : std::vector<KernelSymbol>& parsedSymbols, SymbolFilterStats& filterStats, size_t& symbolTableCount,
439 : size_t& validSymbolTableCount)
440 : {
441 58 : for (const Elf64_Shdr& symtabShdr : shdrs) {
442 46 : if (!IsSymbolTable(symtabShdr)) {
443 37 : continue;
444 : }
445 11 : symbolTableCount++;
446 11 : const Elf64_Shdr* strtabShdr = nullptr;
447 11 : if (!IsValidSymbolAndStringTable(elfSize, shdrs, symtabShdr, strtabShdr)) {
448 2 : continue;
449 : }
450 9 : validSymbolTableCount++;
451 9 : if (!ParseFunctionSymbols(elf, elfSize, symtabShdr, *strtabShdr, shouldSwap, shdrs, parsedSymbols,
452 : filterStats)) {
453 0 : IDE_LOGW("ParseElfSymbols failed, invalid ELF symbols, symOffset=%lu, symSize=%lu.",
454 : symtabShdr.sh_offset, symtabShdr.sh_size);
455 0 : return false;
456 : }
457 : }
458 12 : return true;
459 : }
460 :
461 : // 分类汇总用:(oFilePath, fixedPCOffset) 相同的多个异常 core 归为一组。
462 : struct SummaryGroup {
463 : std::string oFilePath;
464 : uint64_t fixedPCOffset = 0;
465 : bool hasSymbol = false;
466 : std::string symbolName;
467 : uint64_t symbolOffset = 0;
468 : SymbolizeResult src;
469 : std::vector<const ErrorLocation*> cores;
470 : };
471 :
472 : // 按 (oFilePath, fixedPCOffset) 聚类:命中已有组则追加 core,否则新建组并拷贝定位信息。
473 1 : std::vector<SummaryGroup> BuildSummaryGroups(const std::vector<ErrorLocation>& locations)
474 : {
475 1 : std::vector<SummaryGroup> groups;
476 5 : for (const ErrorLocation& loc : locations) {
477 4 : SummaryGroup* target = nullptr;
478 7 : for (SummaryGroup& g : groups) {
479 4 : if (g.oFilePath == loc.oFilePath && g.fixedPCOffset == loc.fixedPCOffset) {
480 1 : target = &g;
481 1 : break;
482 : }
483 : }
484 4 : if (target == nullptr) {
485 3 : groups.emplace_back();
486 3 : target = &groups.back();
487 3 : target->oFilePath = loc.oFilePath;
488 3 : target->fixedPCOffset = loc.fixedPCOffset;
489 3 : target->hasSymbol = loc.hasSymbol;
490 3 : target->symbolName = loc.symbolName;
491 3 : target->symbolOffset = loc.symbolOffset;
492 3 : target->src = loc.src;
493 : }
494 4 : target->cores.push_back(&loc);
495 : }
496 1 : return groups;
497 0 : }
498 :
499 : // 打印单个分组:core 列表、symbol+偏移、func、source 行号,缺失信息统一显示 unknown。
500 3 : void PrintSummaryGroup(size_t index, const SummaryGroup& g)
501 : {
502 3 : std::ostringstream coresOss;
503 7 : for (size_t c = 0; c < g.cores.size(); ++c) {
504 4 : if (c != 0) {
505 1 : coresOss << ",";
506 : }
507 4 : coresOss << "{id=" << g.cores[c]->coreId << ",type=" << g.cores[c]->coreType << "}";
508 : }
509 3 : std::ostringstream symbolOss;
510 3 : if (g.hasSymbol) {
511 1 : symbolOss << g.symbolName << "+0x" << std::hex << g.symbolOffset;
512 : } else {
513 2 : symbolOss << "unknown";
514 : }
515 3 : const std::string sourceStr = g.src.ok
516 5 : ? (g.src.srcFile + ":" + std::to_string(g.src.srcLine) + ":" + std::to_string(g.src.srcColumn))
517 9 : : "unknown";
518 3 : IDE_LOGE("[Dump][Exception][Symbolize] Group[%zu] oFile=%s fixedPCOffset=0x%lx symbol=%s "
519 : "source=%s cores=[%s]",
520 : index, g.oFilePath.empty() ? "unknown" : g.oFilePath.c_str(), g.fixedPCOffset,
521 : symbolOss.str().c_str(), sourceStr.c_str(), coresOss.str().c_str());
522 3 : }
523 : } // namespace
524 :
525 : std::unordered_map<rtBinHandle, KernelSymbolSet> KernelSymbolLocator::cache_;
526 :
527 34 : KernelSymbolLocator::KernelSymbolLocator() : initialized_(false) {}
528 34 : KernelSymbolLocator::~KernelSymbolLocator() = default;
529 :
530 74 : void KernelSymbolLocator::ClearCache()
531 : {
532 74 : std::lock_guard<std::mutex> lock(g_cacheMutex);
533 74 : cache_.clear();
534 74 : }
535 :
536 34 : void KernelSymbolLocator::ResetState()
537 : {
538 34 : kernelSymbols_ = KernelSymbolSet();
539 34 : kernelDeviceStartPC_ = 0;
540 34 : hasKernelDeviceStartPC_ = false;
541 34 : initialized_ = false;
542 34 : oFilePath_.clear();
543 34 : }
544 :
545 4 : void KernelSymbolLocator::SetOFilePath(const std::string& oFilePath)
546 : {
547 4 : oFilePath_ = oFilePath;
548 4 : }
549 :
550 5 : void KernelSymbolLocator::UpdateStartPCFromDeviceAddr(rtBinHandle binHandle)
551 : {
552 5 : void* devAddr = nullptr;
553 5 : int32_t ret = ExceptionInfoCommon::GetKernelDeviceAddr(binHandle, devAddr);
554 5 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS && devAddr != nullptr, return,
555 : "Get kernel device address failed, skip updating startPC, binHandle=%p.", binHandle);
556 :
557 1 : kernelDeviceStartPC_ = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(devAddr));
558 1 : hasKernelDeviceStartPC_ = true;
559 1 : IDE_LOGI("Update kernel startPC from device address, binHandle=%p, startPC=0x%lx.", binHandle,
560 : kernelDeviceStartPC_);
561 : }
562 :
563 3 : int32_t KernelSymbolLocator::InitFromBinHandle(rtBinHandle binHandle)
564 : {
565 3 : ResetState();
566 3 : IDE_CTRL_VALUE_WARN(binHandle != nullptr, return ADUMP_FAILED, "binHandle is null.");
567 : {
568 2 : std::lock_guard<std::mutex> lock(g_cacheMutex);
569 2 : auto it = cache_.find(binHandle);
570 2 : if (it != cache_.end()) {
571 1 : kernelSymbols_ = it->second;
572 1 : initialized_ = true;
573 1 : return ADUMP_SUCCESS;
574 : }
575 2 : }
576 1 : std::string binData;
577 1 : uint32_t binSize = 0;
578 1 : int32_t ret = ExceptionInfoCommon::GetBinDataFromHandle(binHandle, binData, binSize);
579 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "Get Kernel bin data failed for ParseElfSymbols");
580 :
581 1 : KernelSymbolSet symbols;
582 1 : ret = ParseElfSymbols(binData.data(), binData.size(), symbols);
583 1 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "ParseElfSymbols failed.");
584 1 : kernelSymbols_ = symbols;
585 : {
586 1 : std::lock_guard<std::mutex> lock(g_cacheMutex);
587 1 : cache_[binHandle] = symbols;
588 1 : }
589 1 : initialized_ = true;
590 1 : return ADUMP_SUCCESS;
591 1 : }
592 :
593 31 : int32_t KernelSymbolLocator::InitFromBinBuffer(const std::string& binData)
594 : {
595 31 : ResetState();
596 31 : IDE_CTRL_VALUE_WARN(!binData.empty(), return ADUMP_FAILED, "Kernel bin data is empty.");
597 :
598 30 : int32_t ret = ParseElfSymbols(binData.data(), binData.size(), kernelSymbols_);
599 30 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "ParseElfSymbols failed.");
600 :
601 8 : initialized_ = true;
602 8 : return ADUMP_SUCCESS;
603 : }
604 :
605 32 : int32_t KernelSymbolLocator::ParseElfSymbols(const char* elf, size_t elfSize, KernelSymbolSet& outSymbols)
606 : {
607 32 : Elf64_Ehdr ehdr = {};
608 32 : IDE_CTRL_VALUE_WARN(ReadElfHeader(elf, elfSize, ehdr), return ADUMP_FAILED,
609 : "ParseElfSymbols failed, invalid ELF header, elfSize=%zu.", elfSize);
610 :
611 12 : const bool shouldSwap = ShouldSwapElfBytes(ehdr);
612 12 : std::vector<Elf64_Shdr> shdrs;
613 12 : IDE_CTRL_VALUE_WARN(ReadSectionHeaders(elf, elfSize, ehdr, shouldSwap, shdrs), return ADUMP_FAILED,
614 : "ParseElfSymbols failed, invalid ELF section headers, shoff=%lu, shnum=%u.", ehdr.e_shoff, ehdr.e_shnum);
615 :
616 12 : std::vector<KernelSymbol> parsedSymbols;
617 12 : SymbolFilterStats filterStats;
618 12 : size_t symbolTableCount = 0;
619 12 : size_t validSymbolTableCount = 0;
620 12 : IDE_CTRL_VALUE_WARN(ParseSymbolTables(elf, elfSize, shdrs, shouldSwap, parsedSymbols, filterStats,
621 : symbolTableCount, validSymbolTableCount), return ADUMP_FAILED, "ParseElfSymbols failed.");
622 :
623 12 : IDE_CTRL_VALUE_WARN(symbolTableCount != 0, return ADUMP_FAILED,
624 : "ParseElfSymbols failed, no SHT_SYMTAB or SHT_DYNSYM section found.");
625 11 : IDE_CTRL_VALUE_WARN(validSymbolTableCount != 0, return ADUMP_FAILED,
626 : "ParseElfSymbols failed, no valid symbol table found, symbolTableCount=%zu.", symbolTableCount);
627 :
628 9 : std::vector<KernelSymbol> normalizedSymbols;
629 9 : NormalizeFunctionSymbols(parsedSymbols, normalizedSymbols);
630 9 : IDE_CTRL_VALUE_WARN(!normalizedSymbols.empty(), return ADUMP_FAILED,
631 : "ParseElfSymbols failed, empty function symbols, validSymbolTableCount=%zu, symbolTotal=%zu, "
632 : "accepted=%zu, nonFunc=%zu, invalidSection=%zu, invalidName=%zu.",
633 : validSymbolTableCount, filterStats.total, filterStats.accepted, filterStats.nonFunc,
634 : filterStats.invalidSection, filterStats.invalidName);
635 :
636 9 : outSymbols.symbols.swap(normalizedSymbols);
637 9 : LogKernelSymbolSummary(outSymbols, parsedSymbols.size(), filterStats);
638 9 : return ADUMP_SUCCESS;
639 12 : }
640 :
641 8 : bool KernelSymbolLocator::GetCorrectedStartPC(const rtExceptionErrRegInfo_t& coreInfo, uint64_t& startPC) const
642 : {
643 8 : startPC = coreInfo.startPC;
644 8 : if (hasKernelDeviceStartPC_) {
645 1 : startPC = kernelDeviceStartPC_;
646 1 : return true;
647 : }
648 7 : return false;
649 : }
650 :
651 7 : void KernelSymbolLocator::PrintErrorForCore(rtExceptionErrRegInfo_t coreInfo, ErrorLocation& outLocation)
652 : {
653 7 : outLocation.coreId = coreInfo.coreId;
654 7 : outLocation.coreType = static_cast<uint32_t>(coreInfo.coreType);
655 7 : outLocation.oFilePath = oFilePath_;
656 : // hasSymbol/skipped 只在特定分支置 true,入口先复位,避免调用方复用同一 ErrorLocation 时残留脏值。
657 7 : outLocation.hasSymbol = false;
658 7 : outLocation.skipped = false;
659 :
660 7 : uint32_t coreType = static_cast<uint32_t>(coreInfo.coreType);
661 7 : IDE_LOGE("[Dump][Exception] Error register information. coreId=%u, coreType=%u, %s",
662 : coreInfo.coreId, coreType, GetErrorRegisters(coreInfo).c_str());
663 7 : uint64_t fixedCurrentPC = FixPcByErrorRegs(coreInfo);
664 7 : uint64_t fixedStartPC = coreInfo.startPC;
665 7 : if (GetCorrectedStartPC(coreInfo, fixedStartPC)) {
666 0 : IDE_LOGI("Correct startPC by kernel address. coreId=%u, coreType=%u, originalStartPC=0x%lx, "
667 : "fixedStartPC=0x%lx.", coreInfo.coreId, coreType, coreInfo.startPC, fixedStartPC);
668 : }
669 7 : if (fixedCurrentPC < fixedStartPC) {
670 1 : IDE_LOGE("coreId=%u, coreType=%u, fixedCurrentPC=0x%lx < fixedStartPC=0x%lx, "
671 : "originalCurrentPC=0x%lx, originalStartPC=0x%lx, skip lookup symbol.",
672 : coreInfo.coreId, coreType, fixedCurrentPC, fixedStartPC, coreInfo.currentPC, coreInfo.startPC);
673 1 : outLocation.skipped = true;
674 1 : return;
675 : }
676 :
677 6 : const uint64_t fixedPCOffset = fixedCurrentPC - fixedStartPC;
678 6 : outLocation.fixedPCOffset = fixedPCOffset;
679 6 : IDE_LOGE("[Dump][Exception] Error PC information. coreId=%u, coreType=%u, originalStartPC=0x%lx, "
680 : "fixedStartPC=0x%lx, originalCurrentPC=0x%lx, fixedCurrentPC=0x%lx, fixedPCOffset=0x%lx.",
681 : coreInfo.coreId, coreType, coreInfo.startPC, fixedStartPC, coreInfo.currentPC, fixedCurrentPC,
682 : fixedPCOffset);
683 :
684 : // 源码解析不在此逐核进行:偏移已回填 outLocation.fixedPCOffset,由 SymbolizeCollectedLocations
685 : // 收齐所有核后对同一 .o 一次性批量 symbolize,避免每核各起一个 llvm-symbolizer 进程放大超时。
686 6 : MatchSymbolForCore(coreInfo, fixedPCOffset, outLocation);
687 : }
688 :
689 6 : void KernelSymbolLocator::MatchSymbolForCore(const rtExceptionErrRegInfo_t& coreInfo, uint64_t fixedPCOffset,
690 : ErrorLocation& outLocation)
691 : {
692 6 : const uint32_t coreType = static_cast<uint32_t>(coreInfo.coreType);
693 6 : const KernelSymbol* matchedSymbol = FindBestMatchedSymbol(kernelSymbols_.symbols, fixedPCOffset);
694 6 : if (matchedSymbol != nullptr) {
695 0 : outLocation.hasSymbol = true;
696 0 : outLocation.symbolName = matchedSymbol->name;
697 0 : outLocation.symbolOffset = fixedPCOffset - matchedSymbol->offset;
698 0 : IDE_LOGE("[Dump][Exception] Error symbol information. coreId=%u, coreType=%u, "
699 : "symbol=%s+0x%lx.", coreInfo.coreId, coreType, matchedSymbol->name.c_str(),
700 : outLocation.symbolOffset);
701 0 : return;
702 : }
703 :
704 6 : uint64_t minSymbolOffset = 0;
705 6 : uint64_t maxSymbolEnd = 0;
706 6 : const bool hasSymbolRange = GetSymbolOffsetRange(kernelSymbols_.symbols, minSymbolOffset, maxSymbolEnd);
707 6 : IDE_LOGE("[Dump][Exception] Not found error symbol information. coreId=%u, coreType=%u, "
708 : "symbolCount=%zu, hasSymbolRange=%u, minSymbolOffset=0x%lx, maxSymbolEnd=0x%lx.",
709 : coreInfo.coreId, coreType, kernelSymbols_.symbols.size(),
710 : static_cast<uint32_t>(hasSymbolRange), minSymbolOffset, maxSymbolEnd);
711 : }
712 :
713 5 : void KernelSymbolLocator::SymbolizeCollectedLocations(std::vector<ErrorLocation>& locations) const
714 : {
715 5 : if (oFilePath_.empty() || !KernelSourceSymbolizer::IsAvailable()) {
716 5 : return;
717 : }
718 : // 收集所有未跳过 core 的偏移;idxMap 记录第 k 个偏移对应 locations 中的下标,便于按序回填。
719 0 : std::vector<uint64_t> offsets;
720 0 : std::vector<size_t> idxMap;
721 0 : for (size_t i = 0; i < locations.size(); ++i) {
722 0 : if (!locations[i].skipped) {
723 0 : offsets.push_back(locations[i].fixedPCOffset);
724 0 : idxMap.push_back(i);
725 : }
726 : }
727 0 : if (offsets.empty()) {
728 0 : return;
729 : }
730 : // 同一 .o 的全部偏移由一个 llvm-symbolizer 进程一次解析,最坏耗时收敛为单次超时。
731 0 : std::vector<SymbolizeResult> results;
732 0 : if (!KernelSourceSymbolizer::Symbolize(oFilePath_, offsets, results)) {
733 0 : IDE_LOGW("Symbolize kernel source failed for all cores, oFile=%s, offsetCount=%zu.",
734 : oFilePath_.c_str(), offsets.size());
735 0 : return;
736 : }
737 0 : for (size_t k = 0; k < idxMap.size() && k < results.size(); ++k) {
738 0 : locations[idxMap[k]].src = results[k];
739 : }
740 0 : }
741 :
742 6 : int32_t KernelSymbolLocator::LocateErrorSymbols(const ExceptionRegInfo& exceptionRegInfo,
743 : std::vector<ErrorLocation>& outLocations)
744 : {
745 6 : IDE_CTRL_VALUE_WARN(initialized_, return ADUMP_FAILED, "KernelSymbolLocator not initialized.");
746 :
747 5 : IDE_CTRL_VALUE_WARN(
748 : exceptionRegInfo.errRegInfo != nullptr && exceptionRegInfo.coreNum != 0, return ADUMP_FAILED,
749 : "Exception register info is null or core num is zero.");
750 :
751 : // 先逐核定位偏移与符号,再对同一 .o 的所有偏移一次性批量 symbolize,避免逐核各起进程放大超时。
752 10 : for (uint32_t i = 0; i < exceptionRegInfo.coreNum; i++) {
753 6 : ErrorLocation loc;
754 6 : PrintErrorForCore(exceptionRegInfo.errRegInfo[i], loc);
755 6 : outLocations.push_back(loc);
756 6 : }
757 4 : SymbolizeCollectedLocations(outLocations);
758 4 : return ADUMP_SUCCESS;
759 : }
760 :
761 3 : int32_t KernelSymbolLocator::LocateErrorSymbolsForCore(
762 : uint32_t coreId, uint32_t coreType, ExceptionRegInfo exceptionRegInfo, ErrorLocation& outLocation)
763 : {
764 3 : IDE_CTRL_VALUE_WARN(initialized_, return ADUMP_FAILED, "KernelSymbolLocator not initialized.");
765 :
766 2 : IDE_CTRL_VALUE_WARN(exceptionRegInfo.errRegInfo != nullptr && exceptionRegInfo.coreNum != 0,
767 : return ADUMP_FAILED, "Exception register info is null or core num is zero.");
768 :
769 2 : const rtExceptionErrRegInfo_t* coreInfo = nullptr;
770 4 : for (uint32_t i = 0; i < exceptionRegInfo.coreNum; i++) {
771 3 : if (exceptionRegInfo.errRegInfo[i].coreId == coreId &&
772 1 : exceptionRegInfo.errRegInfo[i].coreType == static_cast<rtCoreType_t>(coreType)) {
773 1 : coreInfo = &exceptionRegInfo.errRegInfo[i];
774 1 : break;
775 : }
776 : }
777 :
778 2 : IDE_CTRL_VALUE_WARN(coreInfo != nullptr, return ADUMP_FAILED,
779 : "Core exception register info is not found, coreId=%u, coreType=%u.", coreId, coreType);
780 :
781 : // 先定位偏移与符号,再对该核偏移做一次 symbolize(单核路径每个 .o 本就是一次进程调用)。
782 1 : PrintErrorForCore(*coreInfo, outLocation);
783 3 : std::vector<ErrorLocation> single{outLocation};
784 1 : SymbolizeCollectedLocations(single);
785 1 : outLocation = single[0];
786 1 : return ADUMP_SUCCESS;
787 2 : }
788 :
789 2 : void KernelSymbolLocator::PrintClassificationSummary(const std::vector<ErrorLocation>& locations)
790 : {
791 2 : if (locations.empty()) {
792 1 : return;
793 : }
794 : // 按 (oFilePath, fixedPCOffset) 聚类:同一 .o 同一偏移的多核归为一组。
795 1 : const std::vector<SummaryGroup> groups = BuildSummaryGroups(locations);
796 1 : IDE_LOGE("[Dump][Exception][Symbolize] classification summary. cores=%zu, groups=%zu.",
797 : locations.size(), groups.size());
798 4 : for (size_t i = 0; i < groups.size(); ++i) {
799 3 : PrintSummaryGroup(i, groups[i]);
800 : }
801 1 : }
802 :
803 9 : uint64_t KernelSymbolLocator::FixPcByErrorRegs(const rtExceptionErrRegInfo_t& coreInfo)
804 : {
805 9 : PcFixerInterface* fixer = PcFixerFactory::GetInstance();
806 9 : if (fixer == nullptr) {
807 1 : return coreInfo.currentPC;
808 : }
809 8 : return fixer->FixPc(coreInfo.currentPC, coreInfo.errReg, RT_ERR_REG_NUMS);
810 : }
811 :
812 7 : std::string KernelSymbolLocator::GetErrorRegisters(const rtExceptionErrRegInfo_t& coreInfo)
813 : {
814 7 : PcFixerInterface* fixer = PcFixerFactory::GetInstance();
815 7 : if (fixer == nullptr) {
816 0 : return "";
817 : }
818 7 : return fixer->GetErrorRegisters(coreInfo.errReg, RT_ERR_REG_NUMS);
819 : }
820 :
821 7 : std::string KernelSymbolLocator::ResolveOFilePath(const std::string& hostOPath)
822 : {
823 7 : if (hostOPath.empty()) {
824 2 : return "";
825 : }
826 : // _host.o 含 .debug_line 时直接使用;否则留空,由调用方决定是否回退到 kernel_meta 的 .o。
827 6 : if (KernelSourceSymbolizer::HasDebugLine(hostOPath)) {
828 1 : return hostOPath;
829 : }
830 5 : IDE_LOGW("Host kernel .o has no .debug_line, source location unavailable, oFile=%s.", hostOPath.c_str());
831 10 : return "";
832 : }
833 :
834 59 : void KernelSymbolLocator::DumpErrorSymbols(const rtExceptionInfo& exception, ExceptionRegInfo& exceptionRegInfo,
835 : const std::string& dumpPath)
836 : {
837 59 : rtExceptionArgsInfo_t exceptionArgsInfo{};
838 59 : int32_t ret = ExceptionInfoCommon::GetExceptionInfo(exception, exceptionArgsInfo);
839 117 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return, "Get exception args info failed, skip dump error symbols.");
840 :
841 59 : std::string binData;
842 59 : uint32_t binSize = 0;
843 59 : const rtExceptionKernelInfo_t& kernelInfo = exceptionArgsInfo.exceptionKernelInfo;
844 59 : ret = ExceptionInfoCommon::GetBinDataFromHandle(kernelInfo.bin, binData, binSize);
845 59 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return, "Get kernel bin data failed, skip dump error symbols.");
846 :
847 20 : KernelSymbolLocator locator;
848 20 : ret = locator.InitFromBinBuffer(binData);
849 20 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return, "Parse kernel symbols failed, skip dump error symbols.");
850 1 : locator.UpdateStartPCFromDeviceAddr(kernelInfo.bin);
851 :
852 : // _host.o 已由调用方(DumpHostKernelBinBeforeSymbolize / 回调路径)提前无条件落盘,
853 : // 此处只复用其路径决定实际 symbolize 用的 .o,不再重复落盘:避免把落盘可靠性绑定到
854 : // 本函数前面的符号解析步骤(GetBinData/InitFromBinBuffer 失败时提前 return 会漏落盘)。
855 1 : KernelInfoCollector collector;
856 1 : collector.LoadKernelInfo(exceptionArgsInfo);
857 1 : std::string hostOPath = collector.GetHostOFilePath(dumpPath);
858 : // hostOPath 为空说明 kernelName 缺失/路径拼接失败,符号解析将无 .o 可用,仅告警不阻断后续流程。
859 1 : if (hostOPath.empty()) {
860 0 : IDE_LOGW("Host .o path is empty, symbolize may fall back without source location.");
861 : } else {
862 1 : locator.SetOFilePath(ResolveOFilePath(hostOPath));
863 : }
864 :
865 1 : std::vector<ErrorLocation> locations;
866 1 : ret = locator.LocateErrorSymbols(exceptionRegInfo, locations);
867 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return, "Locate kernel error symbols failed, ret=%d.", ret);
868 : // 未找到 llvm-symbolizer 时不打印聚类汇总(无源码信息时该汇总无增量价值)。
869 1 : if (KernelSourceSymbolizer::IsAvailable()) {
870 0 : PrintClassificationSummary(locations);
871 : }
872 78 : }
873 :
874 50 : void KernelSymbolLocator::DumpErrorSymbols(const rtExceptionInfo& exception, const std::string& dumpPath)
875 : {
876 50 : ExceptionRegInfo exceptionRegInfo{0, nullptr};
877 50 : if (ExceptionInfoCommon::GetExceptionRegInfo(exception, exceptionRegInfo) == ADUMP_SUCCESS) {
878 49 : DumpErrorSymbols(exception, exceptionRegInfo, dumpPath);
879 : }
880 50 : }
881 :
882 : } // namespace Adx
|