LCOV - code coverage report
Current view: top level - adump/exception - kernel_symbol_locator.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 91.0 % 502 457
Test Date: 2026-08-17 09:38:02 Functions: 100.0 % 59 59

            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
        

Generated by: LCOV version 2.0-1