LCOV - code coverage report
Current view: top level - adump/exception - kernel_symbol_locator.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 91.4 % 523 478
Test Date: 2026-08-31 10:09:28 Functions: 100.0 % 62 62

            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
        

Generated by: LCOV version 2.0-1