LCOV - code coverage report
Current view: top level - adump/exception - kernel_symbol_locator.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 94.0 % 400 376
Test Date: 2026-07-28 10:54:24 Functions: 100.0 % 52 52

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

Generated by: LCOV version 2.0-1