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 "securec.h"
16 : #include "runtime/kernel.h"
17 : #include "kernel_symbol_locator.h"
18 : #include "exception_info_common.h"
19 : #include "log/adx_log.h"
20 : #include "log/hdc_log.h"
21 :
22 : namespace Adx {
23 : namespace {
24 : std::mutex g_cacheMutex;
25 :
26 : // 符号过滤计数关系:
27 : // total = accepted + nonFunc + invalidSection + invalidName。
28 : struct SymbolFilterStats {
29 : // 从有效的 SHT_SYMTAB/SHT_DYNSYM 段读取到的符号总数。
30 : size_t total = 0;
31 : // 被接受用于函数定位的有效函数符号数。
32 : size_t accepted = 0;
33 : // 因 st_info 类型不是 STT_FUNC 被过滤的符号数。
34 : size_t nonFunc = 0;
35 : // 因 st_shndx 为 SHN_UNDEF 或超出 section header 范围被过滤的函数符号数。
36 : size_t invalidSection = 0;
37 : // 因 st_name 越界或符号名未在字符串表范围内以 '\\0' 结束被过滤的函数符号数。
38 : size_t invalidName = 0;
39 : };
40 :
41 : template <typename T>
42 195 : bool ReadStruct(const char* elf, size_t elfSize, size_t offset, T& out)
43 : {
44 195 : if (elf == nullptr || offset > elfSize || elfSize - offset < sizeof(T)) {
45 20 : return false;
46 : }
47 175 : return memcpy_s(&out, sizeof(T), elf + offset, sizeof(T)) == EOK;
48 : }
49 :
50 117 : bool IsAddOverflow(size_t lhs, size_t rhs) { return lhs > std::numeric_limits<size_t>::max() - rhs; }
51 :
52 90 : bool IsAddOverflow64(uint64_t lhs, uint64_t rhs)
53 : {
54 90 : return lhs > std::numeric_limits<uint64_t>::max() - rhs;
55 : }
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 105 : 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 42 : 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("Parse kernel symbols success. parsedSymbolCount=%zu, normalizedSymbolCount=%zu, "
101 : "hasSymbolRange=%u, minSymbolOffset=0x%lx, maxSymbolEnd=0x%lx, symbolTotal=%zu, accepted=%zu, "
102 : "nonFunc=%zu, invalidSection=%zu, invalidName=%zu.",
103 : parsedSymbolCount, symbols.symbols.size(), static_cast<uint32_t>(hasRange), minOffset, maxEnd,
104 : filterStats.total, filterStats.accepted, filterStats.nonFunc, filterStats.invalidSection,
105 : filterStats.invalidName);
106 9 : }
107 :
108 21 : uint16_t Swap16(uint16_t value) { return static_cast<uint16_t>((value >> 8U) | (value << 8U)); }
109 :
110 31 : uint32_t Swap32(uint32_t value)
111 : {
112 31 : return ((value & 0x000000FFU) << 24U) | ((value & 0x0000FF00U) << 8U) | ((value & 0x00FF0000U) >> 8U) |
113 31 : ((value & 0xFF000000U) >> 24U);
114 : }
115 :
116 53 : uint64_t Swap64(uint64_t value)
117 : {
118 53 : return ((value & 0x00000000000000FFULL) << 56U) | ((value & 0x000000000000FF00ULL) << 40U) |
119 53 : ((value & 0x0000000000FF0000ULL) << 24U) | ((value & 0x00000000FF000000ULL) << 8U) |
120 53 : ((value & 0x000000FF00000000ULL) >> 8U) | ((value & 0x0000FF0000000000ULL) >> 24U) |
121 53 : ((value & 0x00FF000000000000ULL) >> 40U) | ((value & 0xFF00000000000000ULL) >> 56U);
122 : }
123 :
124 24 : bool IsSupportedElfData(uint8_t data) { return data == ELFDATANONE || data == ELFDATA2LSB || data == ELFDATA2MSB; }
125 :
126 24 : bool IsBigEndianElf(const Elf64_Ehdr& ehdr) { return ehdr.e_ident[EI_DATA] == ELFDATA2MSB; }
127 :
128 24 : bool IsHostBigEndian()
129 : {
130 24 : const uint16_t value = 0x0102U;
131 24 : const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
132 24 : return bytes[0] == 0x01U;
133 : }
134 :
135 24 : bool ShouldSwapElfBytes(const Elf64_Ehdr& ehdr) { return IsBigEndianElf(ehdr) != IsHostBigEndian(); }
136 :
137 12 : void NormalizeElfHeader(Elf64_Ehdr& ehdr, bool shouldSwap)
138 : {
139 12 : if (!shouldSwap) {
140 11 : return;
141 : }
142 1 : ehdr.e_type = Swap16(ehdr.e_type);
143 1 : ehdr.e_machine = Swap16(ehdr.e_machine);
144 1 : ehdr.e_version = Swap32(ehdr.e_version);
145 1 : ehdr.e_entry = Swap64(ehdr.e_entry);
146 1 : ehdr.e_phoff = Swap64(ehdr.e_phoff);
147 1 : ehdr.e_shoff = Swap64(ehdr.e_shoff);
148 1 : ehdr.e_flags = Swap32(ehdr.e_flags);
149 1 : ehdr.e_ehsize = Swap16(ehdr.e_ehsize);
150 1 : ehdr.e_phentsize = Swap16(ehdr.e_phentsize);
151 1 : ehdr.e_phnum = Swap16(ehdr.e_phnum);
152 1 : ehdr.e_shentsize = Swap16(ehdr.e_shentsize);
153 1 : ehdr.e_shnum = Swap16(ehdr.e_shnum);
154 1 : ehdr.e_shstrndx = Swap16(ehdr.e_shstrndx);
155 : }
156 :
157 46 : void NormalizeSectionHeader(Elf64_Shdr& shdr, bool shouldSwap)
158 : {
159 46 : if (!shouldSwap) {
160 42 : return;
161 : }
162 4 : shdr.sh_name = Swap32(shdr.sh_name);
163 4 : shdr.sh_type = Swap32(shdr.sh_type);
164 4 : shdr.sh_flags = Swap64(shdr.sh_flags);
165 4 : shdr.sh_addr = Swap64(shdr.sh_addr);
166 4 : shdr.sh_offset = Swap64(shdr.sh_offset);
167 4 : shdr.sh_size = Swap64(shdr.sh_size);
168 4 : shdr.sh_link = Swap32(shdr.sh_link);
169 4 : shdr.sh_info = Swap32(shdr.sh_info);
170 4 : shdr.sh_addralign = Swap64(shdr.sh_addralign);
171 4 : shdr.sh_entsize = Swap64(shdr.sh_entsize);
172 : }
173 :
174 117 : void NormalizeSymbol(Elf64_Sym& sym, bool shouldSwap)
175 : {
176 117 : if (!shouldSwap) {
177 104 : return;
178 : }
179 13 : sym.st_name = Swap32(sym.st_name);
180 13 : sym.st_shndx = Swap16(sym.st_shndx);
181 13 : sym.st_value = Swap64(sym.st_value);
182 13 : sym.st_size = Swap64(sym.st_size);
183 : }
184 :
185 12 : bool IsValidElfHeader(const Elf64_Ehdr& ehdr)
186 : {
187 24 : return std::memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0 && ehdr.e_ident[EI_CLASS] == ELFCLASS64 &&
188 24 : IsSupportedElfData(ehdr.e_ident[EI_DATA]) && ehdr.e_ehsize == sizeof(Elf64_Ehdr) &&
189 24 : ehdr.e_shentsize == sizeof(Elf64_Shdr) && ehdr.e_shoff != 0 && ehdr.e_shnum != 0;
190 : }
191 :
192 32 : bool IsRangeInsideElf(size_t offset, size_t size, size_t elfSize)
193 : {
194 32 : return offset <= elfSize && elfSize - offset >= size;
195 : }
196 :
197 20 : bool IsSectionInsideElf(const Elf64_Shdr& section, size_t elfSize)
198 : {
199 40 : if (section.sh_offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()) ||
200 20 : section.sh_size > static_cast<uint64_t>(std::numeric_limits<size_t>::max())) {
201 0 : return false;
202 : }
203 20 : return IsRangeInsideElf(static_cast<size_t>(section.sh_offset), static_cast<size_t>(section.sh_size), elfSize);
204 : }
205 :
206 32 : bool ReadElfHeader(const char* elf, size_t elfSize, Elf64_Ehdr& ehdr)
207 : {
208 32 : if (!ReadStruct(elf, elfSize, 0, ehdr)) {
209 20 : return false;
210 : }
211 24 : if (std::memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
212 12 : !IsSupportedElfData(ehdr.e_ident[EI_DATA])) {
213 0 : return false;
214 : }
215 : // 与 runtime 保持一致:ELFDATA2MSB 按大端解析字段;ELFDATANONE 按小端处理。
216 12 : NormalizeElfHeader(ehdr, ShouldSwapElfBytes(ehdr));
217 12 : return IsValidElfHeader(ehdr);
218 : }
219 :
220 12 : bool ReadSectionHeaders(
221 : const char* elf, size_t elfSize, const Elf64_Ehdr& ehdr, bool shouldSwap, std::vector<Elf64_Shdr>& outShdrs)
222 : {
223 12 : const size_t shdrsSize = static_cast<size_t>(ehdr.e_shnum) * sizeof(Elf64_Shdr);
224 24 : if (ehdr.e_shoff > static_cast<uint64_t>(std::numeric_limits<size_t>::max()) ||
225 12 : !IsRangeInsideElf(static_cast<size_t>(ehdr.e_shoff), shdrsSize, elfSize)) {
226 0 : return false;
227 : }
228 12 : if (ehdr.e_shstrndx >= ehdr.e_shnum && ehdr.e_shstrndx != SHN_UNDEF) {
229 0 : return false;
230 : }
231 :
232 12 : outShdrs.clear();
233 12 : outShdrs.reserve(ehdr.e_shnum);
234 58 : for (uint16_t i = 0; i < ehdr.e_shnum; i++) {
235 46 : Elf64_Shdr shdr = {};
236 46 : const size_t offset = static_cast<size_t>(ehdr.e_shoff) + static_cast<size_t>(i) * sizeof(Elf64_Shdr);
237 46 : if (!ReadStruct(elf, elfSize, offset, shdr)) {
238 0 : return false;
239 : }
240 46 : NormalizeSectionHeader(shdr, shouldSwap);
241 46 : outShdrs.push_back(shdr);
242 : }
243 12 : return true;
244 : }
245 :
246 46 : bool IsSymbolTable(const Elf64_Shdr& section) { return section.sh_type == SHT_SYMTAB || section.sh_type == SHT_DYNSYM; }
247 :
248 11 : bool IsValidSymbolAndStringTable(
249 : size_t elfSize, const std::vector<Elf64_Shdr>& shdrs, const Elf64_Shdr& symtabShdr, const Elf64_Shdr*& strtabShdr)
250 : {
251 11 : if (!IsSectionInsideElf(symtabShdr, elfSize) || symtabShdr.sh_size == 0) {
252 0 : return false;
253 : }
254 11 : if (symtabShdr.sh_entsize != sizeof(Elf64_Sym) || (symtabShdr.sh_size % sizeof(Elf64_Sym)) != 0) {
255 1 : return false;
256 : }
257 10 : if (symtabShdr.sh_link >= shdrs.size()) {
258 0 : return false;
259 : }
260 :
261 10 : strtabShdr = &shdrs[symtabShdr.sh_link];
262 10 : if (strtabShdr->sh_type != SHT_STRTAB || strtabShdr->sh_size == 0) {
263 1 : return false;
264 : }
265 9 : return IsSectionInsideElf(*strtabShdr, elfSize);
266 : }
267 :
268 72 : bool GetSymbolSectionEnd(const Elf64_Sym& sym, const std::vector<Elf64_Shdr>& shdrs, uint64_t& sectionEnd)
269 : {
270 72 : if (sym.st_shndx >= shdrs.size()) {
271 0 : return false;
272 : }
273 72 : const Elf64_Shdr& section = shdrs[sym.st_shndx];
274 : // ET_REL 中 st_value 通常是 section 内偏移且 sh_addr 为 0;加载态镜像中 st_value 通常可与 sh_addr 比较。
275 72 : uint64_t sectionBase = section.sh_addr;
276 72 : if (sym.st_value < sectionBase) {
277 0 : sectionBase = 0;
278 : }
279 72 : if (sectionBase > std::numeric_limits<uint64_t>::max() - section.sh_size) {
280 0 : return false;
281 : }
282 72 : sectionEnd = sectionBase + section.sh_size;
283 72 : return sectionEnd > sym.st_value;
284 : }
285 :
286 117 : bool BuildKernelSymbol(
287 : const Elf64_Sym& sym, const std::vector<Elf64_Shdr>& shdrs, const char* strtab, size_t strtabSize,
288 : SymbolFilterStats& stats, KernelSymbol& outSymbol)
289 : {
290 117 : stats.total++;
291 117 : if (ELF64_ST_TYPE(sym.st_info) != STT_FUNC) {
292 18 : stats.nonFunc++;
293 18 : return false;
294 : }
295 99 : if (sym.st_shndx == SHN_UNDEF) {
296 9 : stats.invalidSection++;
297 9 : return false;
298 : }
299 90 : if (sym.st_shndx >= shdrs.size()) {
300 9 : stats.invalidSection++;
301 9 : return false;
302 : }
303 81 : if (sym.st_name >= strtabSize) {
304 9 : stats.invalidName++;
305 9 : return false;
306 : }
307 : // section 结束地址用于给 st_size 为 0 的符号补齐范围。
308 72 : (void)GetSymbolSectionEnd(sym, shdrs, outSymbol.sectionEnd);
309 :
310 72 : const char* strStart = strtab + sym.st_name;
311 72 : size_t remaining = strtabSize - sym.st_name;
312 72 : const char* strEnd = static_cast<const char*>(std::memchr(strStart, '\0', remaining));
313 72 : if (strEnd == nullptr) {
314 0 : stats.invalidName++;
315 0 : return false;
316 : }
317 :
318 72 : outSymbol.offset = sym.st_value;
319 72 : outSymbol.size = sym.st_size;
320 72 : outSymbol.sectionIndex = sym.st_shndx;
321 72 : outSymbol.bind = ELF64_ST_BIND(sym.st_info);
322 72 : outSymbol.visibility = ELF64_ST_VISIBILITY(sym.st_other);
323 72 : outSymbol.name.assign(strStart, strEnd - strStart);
324 72 : IDE_LOGD("Parse kernel symbol, name=%s, offset=0x%lx, size=0x%lx, sectionEnd=0x%lx, "
325 : "sectionIndex=%u, bind=%u, visibility=%u.",
326 : outSymbol.name.c_str(), outSymbol.offset, outSymbol.size, outSymbol.sectionEnd,
327 : static_cast<uint32_t>(outSymbol.sectionIndex), static_cast<uint32_t>(outSymbol.bind),
328 : static_cast<uint32_t>(outSymbol.visibility));
329 72 : stats.accepted++;
330 72 : return true;
331 : }
332 :
333 9 : bool ParseFunctionSymbols(
334 : const char* elf, size_t elfSize, const Elf64_Shdr& symtabShdr, const Elf64_Shdr& strtabShdr, bool shouldSwap,
335 : const std::vector<Elf64_Shdr>& shdrs, std::vector<KernelSymbol>& outSymbols, SymbolFilterStats& stats)
336 : {
337 9 : const size_t symCount = symtabShdr.sh_size / sizeof(Elf64_Sym);
338 9 : const char* strtab = elf + strtabShdr.sh_offset;
339 126 : for (size_t i = 0; i < symCount; i++) {
340 117 : if (IsAddOverflow(static_cast<size_t>(symtabShdr.sh_offset), i * sizeof(Elf64_Sym))) {
341 0 : return false;
342 : }
343 117 : Elf64_Sym sym = {};
344 117 : const size_t symOffset = static_cast<size_t>(symtabShdr.sh_offset) + i * sizeof(Elf64_Sym);
345 117 : if (!ReadStruct(elf, elfSize, symOffset, sym)) {
346 0 : return false;
347 : }
348 117 : NormalizeSymbol(sym, shouldSwap);
349 117 : KernelSymbol symbol = {};
350 117 : if (BuildKernelSymbol(sym, shdrs, strtab, static_cast<size_t>(strtabShdr.sh_size), stats, symbol)) {
351 72 : outSymbols.push_back(symbol);
352 : }
353 117 : }
354 9 : return true;
355 : }
356 :
357 63 : bool IsSameKernelSymbol(const KernelSymbol& lhs, const KernelSymbol& rhs)
358 : {
359 72 : return lhs.offset == rhs.offset && lhs.size == rhs.size && lhs.sectionIndex == rhs.sectionIndex &&
360 72 : lhs.name == rhs.name;
361 : }
362 :
363 9 : void SortKernelSymbols(std::vector<KernelSymbol>& symbols)
364 : {
365 : // 按地址排序,便于后续用同 section 内的下一个符号修正 zero-size 符号范围。
366 9 : std::sort(symbols.begin(), symbols.end(), [](const KernelSymbol& lhs, const KernelSymbol& rhs) {
367 162 : if (lhs.offset != rhs.offset) {
368 153 : return lhs.offset < rhs.offset;
369 : }
370 9 : if (lhs.size != rhs.size) {
371 0 : return lhs.size > rhs.size;
372 : }
373 9 : return lhs.name < rhs.name;
374 : });
375 9 : }
376 :
377 9 : void DeduplicateKernelSymbols(std::vector<KernelSymbol>& symbols)
378 : {
379 9 : std::vector<KernelSymbol> uniqueSymbols;
380 9 : uniqueSymbols.reserve(symbols.size());
381 81 : for (const KernelSymbol& symbol : symbols) {
382 : // 同一个函数可能同时出现在 .symtab 和 .dynsym 中。
383 72 : if (!uniqueSymbols.empty() && IsSameKernelSymbol(uniqueSymbols.back(), symbol)) {
384 9 : uniqueSymbols.back().sectionEnd = std::max(uniqueSymbols.back().sectionEnd, symbol.sectionEnd);
385 9 : continue;
386 : }
387 63 : uniqueSymbols.push_back(symbol);
388 : }
389 9 : symbols.swap(uniqueSymbols);
390 9 : }
391 :
392 9 : void FillZeroSizeSymbolRanges(std::vector<KernelSymbol>& symbols)
393 : {
394 72 : for (size_t i = 0; i < symbols.size(); i++) {
395 63 : if (symbols[i].size != 0) {
396 54 : continue;
397 : }
398 : // 参考 LLDB 策略:先用 section 结束地址作为最大范围,再用同 section 的下一个符号地址收缩范围。
399 9 : if (symbols[i].sectionEnd > symbols[i].offset) {
400 9 : symbols[i].size = symbols[i].sectionEnd - symbols[i].offset;
401 : }
402 9 : for (size_t j = i + 1; j < symbols.size(); j++) {
403 9 : if (symbols[j].sectionIndex == symbols[i].sectionIndex && symbols[j].offset > symbols[i].offset) {
404 9 : const uint64_t sizeToNextSymbol = symbols[j].offset - symbols[i].offset;
405 9 : if (symbols[i].size == 0 || sizeToNextSymbol < symbols[i].size) {
406 9 : symbols[i].size = sizeToNextSymbol;
407 : }
408 9 : break;
409 : }
410 : }
411 : }
412 9 : }
413 :
414 9 : void FilterValidKernelSymbols(const std::vector<KernelSymbol>& symbols, std::vector<KernelSymbol>& outSymbols)
415 : {
416 9 : outSymbols.clear();
417 9 : outSymbols.reserve(symbols.size());
418 72 : for (const KernelSymbol& symbol : symbols) {
419 63 : if (!symbol.name.empty() && symbol.size != 0) {
420 54 : outSymbols.push_back(symbol);
421 : }
422 : }
423 9 : }
424 :
425 9 : void NormalizeFunctionSymbols(std::vector<KernelSymbol>& symbols, std::vector<KernelSymbol>& outSymbols)
426 : {
427 9 : SortKernelSymbols(symbols);
428 9 : DeduplicateKernelSymbols(symbols);
429 9 : FillZeroSizeSymbolRanges(symbols);
430 9 : FilterValidKernelSymbols(symbols, outSymbols);
431 9 : }
432 :
433 12 : bool ParseSymbolTables(
434 : const char* elf, size_t elfSize, const std::vector<Elf64_Shdr>& shdrs, bool shouldSwap,
435 : std::vector<KernelSymbol>& parsedSymbols, SymbolFilterStats& filterStats, size_t& symbolTableCount,
436 : size_t& validSymbolTableCount)
437 : {
438 58 : for (const Elf64_Shdr& symtabShdr : shdrs) {
439 46 : if (!IsSymbolTable(symtabShdr)) {
440 37 : continue;
441 : }
442 11 : symbolTableCount++;
443 11 : const Elf64_Shdr* strtabShdr = nullptr;
444 11 : if (!IsValidSymbolAndStringTable(elfSize, shdrs, symtabShdr, strtabShdr)) {
445 2 : continue;
446 : }
447 9 : validSymbolTableCount++;
448 9 : if (!ParseFunctionSymbols(elf, elfSize, symtabShdr, *strtabShdr, shouldSwap, shdrs, parsedSymbols,
449 : filterStats)) {
450 0 : IDE_LOGW("ParseElfSymbols failed, invalid ELF symbols, symOffset=%lu, symSize=%lu.",
451 : symtabShdr.sh_offset, symtabShdr.sh_size);
452 0 : return false;
453 : }
454 : }
455 12 : return true;
456 : }
457 : } // namespace
458 :
459 : std::unordered_map<rtBinHandle, KernelSymbolSet> KernelSymbolLocator::cache_;
460 :
461 33 : KernelSymbolLocator::KernelSymbolLocator() : initialized_(false) {}
462 33 : KernelSymbolLocator::~KernelSymbolLocator() = default;
463 :
464 73 : void KernelSymbolLocator::ClearCache()
465 : {
466 73 : std::lock_guard<std::mutex> lock(g_cacheMutex);
467 73 : cache_.clear();
468 73 : }
469 :
470 34 : void KernelSymbolLocator::ResetState()
471 : {
472 34 : kernelSymbols_ = KernelSymbolSet();
473 34 : kernelDeviceStartPC_ = 0;
474 34 : hasKernelDeviceStartPC_ = false;
475 34 : initialized_ = false;
476 34 : }
477 :
478 5 : void KernelSymbolLocator::UpdateStartPCFromDeviceAddr(rtBinHandle binHandle)
479 : {
480 5 : void* devAddr = nullptr;
481 5 : int32_t ret = ExceptionInfoCommon::GetKernelDeviceAddr(binHandle, devAddr);
482 5 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS && devAddr != nullptr, return,
483 : "Get kernel device address failed, skip updating startPC, binHandle=%p.", binHandle);
484 :
485 1 : kernelDeviceStartPC_ = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(devAddr));
486 1 : hasKernelDeviceStartPC_ = true;
487 1 : IDE_LOGI("Update kernel startPC from device address, binHandle=%p, startPC=0x%lx.", binHandle,
488 : kernelDeviceStartPC_);
489 : }
490 :
491 3 : int32_t KernelSymbolLocator::InitFromBinHandle(rtBinHandle binHandle)
492 : {
493 3 : ResetState();
494 3 : IDE_CTRL_VALUE_WARN(binHandle != nullptr, return ADUMP_FAILED, "binHandle is null.");
495 : {
496 2 : std::lock_guard<std::mutex> lock(g_cacheMutex);
497 2 : auto it = cache_.find(binHandle);
498 2 : if (it != cache_.end()) {
499 1 : kernelSymbols_ = it->second;
500 1 : initialized_ = true;
501 1 : return ADUMP_SUCCESS;
502 : }
503 2 : }
504 1 : std::string binData;
505 1 : uint32_t binSize = 0;
506 1 : int32_t ret = ExceptionInfoCommon::GetBinDataFromHandle(binHandle, binData, binSize);
507 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "Get Kernel bin data failed for ParseElfSymbols");
508 :
509 1 : KernelSymbolSet symbols;
510 1 : ret = ParseElfSymbols(binData.data(), binData.size(), symbols);
511 1 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "ParseElfSymbols failed.");
512 1 : kernelSymbols_ = symbols;
513 : {
514 1 : std::lock_guard<std::mutex> lock(g_cacheMutex);
515 1 : cache_[binHandle] = symbols;
516 1 : }
517 1 : initialized_ = true;
518 1 : return ADUMP_SUCCESS;
519 1 : }
520 :
521 31 : int32_t KernelSymbolLocator::InitFromBinBuffer(const std::string& binData)
522 : {
523 31 : ResetState();
524 31 : IDE_CTRL_VALUE_WARN(!binData.empty(), return ADUMP_FAILED, "Kernel bin data is empty.");
525 :
526 30 : int32_t ret = ParseElfSymbols(binData.data(), binData.size(), kernelSymbols_);
527 30 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return ADUMP_FAILED, "ParseElfSymbols failed.");
528 :
529 8 : initialized_ = true;
530 8 : return ADUMP_SUCCESS;
531 : }
532 :
533 32 : int32_t KernelSymbolLocator::ParseElfSymbols(const char* elf, size_t elfSize, KernelSymbolSet& outSymbols)
534 : {
535 32 : Elf64_Ehdr ehdr = {};
536 32 : IDE_CTRL_VALUE_WARN(ReadElfHeader(elf, elfSize, ehdr), return ADUMP_FAILED,
537 : "ParseElfSymbols failed, invalid ELF header, elfSize=%zu.", elfSize);
538 :
539 12 : const bool shouldSwap = ShouldSwapElfBytes(ehdr);
540 12 : std::vector<Elf64_Shdr> shdrs;
541 12 : IDE_CTRL_VALUE_WARN(ReadSectionHeaders(elf, elfSize, ehdr, shouldSwap, shdrs), return ADUMP_FAILED,
542 : "ParseElfSymbols failed, invalid ELF section headers, shoff=%lu, shnum=%u.", ehdr.e_shoff, ehdr.e_shnum);
543 :
544 12 : std::vector<KernelSymbol> parsedSymbols;
545 12 : SymbolFilterStats filterStats;
546 12 : size_t symbolTableCount = 0;
547 12 : size_t validSymbolTableCount = 0;
548 12 : IDE_CTRL_VALUE_WARN(ParseSymbolTables(elf, elfSize, shdrs, shouldSwap, parsedSymbols, filterStats,
549 : symbolTableCount, validSymbolTableCount), return ADUMP_FAILED, "ParseElfSymbols failed.");
550 :
551 12 : IDE_CTRL_VALUE_WARN(symbolTableCount != 0, return ADUMP_FAILED,
552 : "ParseElfSymbols failed, no SHT_SYMTAB or SHT_DYNSYM section found.");
553 11 : IDE_CTRL_VALUE_WARN(validSymbolTableCount != 0, return ADUMP_FAILED,
554 : "ParseElfSymbols failed, no valid symbol table found, symbolTableCount=%zu.", symbolTableCount);
555 :
556 9 : std::vector<KernelSymbol> normalizedSymbols;
557 9 : NormalizeFunctionSymbols(parsedSymbols, normalizedSymbols);
558 9 : IDE_CTRL_VALUE_WARN(!normalizedSymbols.empty(), return ADUMP_FAILED,
559 : "ParseElfSymbols failed, empty function symbols, validSymbolTableCount=%zu, symbolTotal=%zu, "
560 : "accepted=%zu, nonFunc=%zu, invalidSection=%zu, invalidName=%zu.",
561 : validSymbolTableCount, filterStats.total, filterStats.accepted, filterStats.nonFunc,
562 : filterStats.invalidSection, filterStats.invalidName);
563 :
564 9 : outSymbols.symbols.swap(normalizedSymbols);
565 9 : LogKernelSymbolSummary(outSymbols, parsedSymbols.size(), filterStats);
566 9 : return ADUMP_SUCCESS;
567 12 : }
568 :
569 8 : bool KernelSymbolLocator::GetCorrectedStartPC(const rtExceptionErrRegInfo_t& coreInfo, uint64_t& startPC) const
570 : {
571 8 : startPC = coreInfo.startPC;
572 8 : if (hasKernelDeviceStartPC_) {
573 1 : startPC = kernelDeviceStartPC_;
574 1 : return true;
575 : }
576 7 : return false;
577 : }
578 :
579 7 : void KernelSymbolLocator::PrintErrorForCore(rtExceptionErrRegInfo_t coreInfo)
580 : {
581 7 : uint32_t coreType = static_cast<uint32_t>(coreInfo.coreType);
582 7 : IDE_LOGE("[Dump][Exception] Error register information. coreId=%u, coreType=%u, %s",
583 : coreInfo.coreId, coreType, GetErrorRegisters(coreInfo).c_str());
584 7 : uint64_t fixedCurrentPC = FixPcByErrorRegs(coreInfo);
585 7 : uint64_t fixedStartPC = coreInfo.startPC;
586 7 : if (GetCorrectedStartPC(coreInfo, fixedStartPC)) {
587 0 : IDE_LOGI("Correct startPC by kernel address. coreId=%u, coreType=%u, originalStartPC=0x%lx, "
588 : "fixedStartPC=0x%lx.", coreInfo.coreId, coreType, coreInfo.startPC, fixedStartPC);
589 : }
590 :
591 7 : if (fixedCurrentPC < fixedStartPC) {
592 1 : IDE_LOGE("coreId=%u, coreType=%u, fixedCurrentPC=0x%lx < fixedStartPC=0x%lx, "
593 : "originalCurrentPC=0x%lx, originalStartPC=0x%lx, skip lookup symbol.",
594 : coreInfo.coreId, coreType, fixedCurrentPC, fixedStartPC, coreInfo.currentPC, coreInfo.startPC);
595 1 : return;
596 : }
597 :
598 6 : const uint64_t fixedPCOffset = fixedCurrentPC - fixedStartPC;
599 6 : IDE_LOGE("[Dump][Exception] Error PC information. coreId=%u, coreType=%u, originalStartPC=0x%lx, "
600 : "fixedStartPC=0x%lx, originalCurrentPC=0x%lx, fixedCurrentPC=0x%lx, fixedPCOffset=0x%lx.",
601 : coreInfo.coreId, coreType, coreInfo.startPC, fixedStartPC, coreInfo.currentPC, fixedCurrentPC,
602 : fixedPCOffset);
603 :
604 6 : const KernelSymbol* matchedSymbol = FindBestMatchedSymbol(kernelSymbols_.symbols, fixedPCOffset);
605 6 : if (matchedSymbol != nullptr) {
606 0 : IDE_LOGE("[Dump][Exception] Error symbol information. coreId=%u, coreType=%u, "
607 : "symbol=%s+0x%lx.", coreInfo.coreId, coreType, matchedSymbol->name.c_str(),
608 : fixedPCOffset - matchedSymbol->offset);
609 0 : return;
610 : }
611 :
612 6 : uint64_t minSymbolOffset = 0;
613 6 : uint64_t maxSymbolEnd = 0;
614 6 : const bool hasSymbolRange = GetSymbolOffsetRange(kernelSymbols_.symbols, minSymbolOffset, maxSymbolEnd);
615 6 : IDE_LOGE("[Dump][Exception] Not found error symbol information. coreId=%u, coreType=%u, "
616 : "symbolCount=%zu, hasSymbolRange=%u, minSymbolOffset=0x%lx, maxSymbolEnd=0x%lx.",
617 : coreInfo.coreId, coreType, kernelSymbols_.symbols.size(),
618 : static_cast<uint32_t>(hasSymbolRange), minSymbolOffset, maxSymbolEnd);
619 : }
620 :
621 6 : int32_t KernelSymbolLocator::LocateAndPrintErrorSymbols(const ExceptionRegInfo& exceptionRegInfo)
622 : {
623 6 : IDE_CTRL_VALUE_WARN(initialized_, return ADUMP_FAILED, "KernelSymbolLocator not initialized.");
624 :
625 5 : IDE_CTRL_VALUE_WARN(
626 : exceptionRegInfo.errRegInfo != nullptr && exceptionRegInfo.coreNum != 0, return ADUMP_FAILED,
627 : "Exception register info is null or core num is zero.");
628 :
629 10 : for (uint32_t i = 0; i < exceptionRegInfo.coreNum; i++) {
630 6 : PrintErrorForCore(exceptionRegInfo.errRegInfo[i]);
631 : }
632 4 : return ADUMP_SUCCESS;
633 : }
634 :
635 3 : int32_t KernelSymbolLocator::LocateAndPrintErrorSymbolsForCore(
636 : uint32_t coreId, uint32_t coreType, ExceptionRegInfo exceptionRegInfo)
637 : {
638 3 : IDE_CTRL_VALUE_WARN(initialized_, return ADUMP_FAILED, "KernelSymbolLocator not initialized.");
639 :
640 2 : IDE_CTRL_VALUE_WARN(exceptionRegInfo.errRegInfo != nullptr && exceptionRegInfo.coreNum != 0,
641 : return ADUMP_FAILED, "Exception register info is null or core num is zero.");
642 :
643 2 : const rtExceptionErrRegInfo_t* coreInfo = nullptr;
644 4 : for (uint32_t i = 0; i < exceptionRegInfo.coreNum; i++) {
645 3 : if (exceptionRegInfo.errRegInfo[i].coreId == coreId &&
646 1 : exceptionRegInfo.errRegInfo[i].coreType == static_cast<rtCoreType_t>(coreType)) {
647 1 : coreInfo = &exceptionRegInfo.errRegInfo[i];
648 1 : break;
649 : }
650 : }
651 :
652 2 : IDE_CTRL_VALUE_WARN(coreInfo != nullptr, return ADUMP_FAILED,
653 : "Core exception register info is not found, coreId=%u, coreType=%u.", coreId, coreType);
654 :
655 1 : PrintErrorForCore(*coreInfo);
656 1 : return ADUMP_SUCCESS;
657 : }
658 :
659 9 : uint64_t KernelSymbolLocator::FixPcByErrorRegs(const rtExceptionErrRegInfo_t& coreInfo)
660 : {
661 9 : PcFixerInterface* fixer = PcFixerFactory::GetInstance();
662 9 : if (fixer == nullptr) {
663 1 : return coreInfo.currentPC;
664 : }
665 8 : return fixer->FixPc(coreInfo.currentPC, coreInfo.errReg, RT_ERR_REG_NUMS);
666 : }
667 :
668 7 : std::string KernelSymbolLocator::GetErrorRegisters(const rtExceptionErrRegInfo_t& coreInfo)
669 : {
670 7 : PcFixerInterface* fixer = PcFixerFactory::GetInstance();
671 7 : if (fixer == nullptr) {
672 0 : return "";
673 : }
674 7 : return fixer->GetErrorRegisters(coreInfo.errReg, RT_ERR_REG_NUMS);
675 : }
676 :
677 58 : void KernelSymbolLocator::DumpErrorSymbols(const rtExceptionInfo& exception, ExceptionRegInfo& exceptionRegInfo)
678 : {
679 58 : rtExceptionArgsInfo_t exceptionArgsInfo{};
680 58 : int32_t ret = ExceptionInfoCommon::GetExceptionInfo(exception, exceptionArgsInfo);
681 115 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return, "Get exception args info failed, skip dump error symbols.");
682 :
683 58 : std::string binData;
684 58 : uint32_t binSize = 0;
685 58 : const rtExceptionKernelInfo_t& kernelInfo = exceptionArgsInfo.exceptionKernelInfo;
686 58 : ret = ExceptionInfoCommon::GetBinDataFromHandle(kernelInfo.bin, binData, binSize);
687 58 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return, "Get kernel bin data failed, skip dump error symbols.");
688 :
689 19 : KernelSymbolLocator locator;
690 19 : ret = locator.InitFromBinBuffer(binData);
691 19 : IDE_CTRL_VALUE_FAILED(ret == ADUMP_SUCCESS, return, "Parse kernel symbols failed, skip dump error symbols.");
692 1 : locator.UpdateStartPCFromDeviceAddr(kernelInfo.bin);
693 :
694 1 : ret = locator.LocateAndPrintErrorSymbols(exceptionRegInfo);
695 1 : IDE_CTRL_VALUE_WARN(ret == ADUMP_SUCCESS, return, "Locate kernel error symbols failed, ret=%d.", ret);
696 76 : }
697 :
698 49 : void KernelSymbolLocator::DumpErrorSymbols(const rtExceptionInfo& exception)
699 : {
700 49 : ExceptionRegInfo exceptionRegInfo{0, nullptr};
701 49 : if (ExceptionInfoCommon::GetExceptionRegInfo(exception, exceptionRegInfo) == ADUMP_SUCCESS) {
702 48 : DumpErrorSymbols(exception, exceptionRegInfo);
703 : }
704 49 : }
705 :
706 : } // namespace Adx
|