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