LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace/stacktrace_dumper - scd_elf.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.2 % 195 168
Test Date: 2026-08-31 10:07:06 Functions: 100.0 % 15 15

            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              : 
      11              : #include "scd_elf.h"
      12              : #include <elf.h>
      13              : #include <link.h>
      14              : #include <sys/types.h>
      15              : #include "adiag_utils.h"
      16              : #include "scd_log.h"
      17              : #include "scd_dwarf.h"
      18              : 
      19              : #define SCD_ELF_FDE_ENTRY_SIZE 8U
      20              : #define SCD_ELF_SH_NAME_LENGTH 128U
      21              : #define SCD_UINTPTR_MAX ((uintptr_t)(-1))
      22              : #define SCD_PF_X ((uint32_t)(PF_X))
      23              : 
      24           18 : uintptr_t ScdElfGetLoadBias(const ScdElf* elf) { return elf->loadBias; }
      25              : 
      26            4 : size_t ScdElfGetFdeNum(const ScdElf* elf) { return elf->ehFrameHdrSize / SCD_ELF_FDE_ENTRY_SIZE; }
      27              : 
      28              : /**
      29              :  * @brief       get function info based on pc
      30              :  * @param [in]  elf:        elf info
      31              :  * @param [in]  pc:         program counter
      32              :  * @param [out] funcName:   function name
      33              :  * @param [in]  len:        function name buffer length
      34              :  * @param [out] funcOffset: function offset in file
      35              :  * @return      NA
      36              :  */
      37           10 : void ScdElfGetFunctionInfo(ScdElf* elf, uintptr_t pc, char* funcName, size_t len, size_t* funcOffset)
      38              : {
      39           20 :     SCD_CHK_PTR_ACTION(elf, return);
      40           10 :     SCD_CHK_PTR_ACTION(funcName, return);
      41           10 :     SCD_CHK_PTR_ACTION(funcOffset, return);
      42           10 :     struct ListHead* pos = NULL;
      43           10 :     struct AdiagListNode* node = NULL;
      44           10 :     ScdDlSymbol* symbols = NULL;
      45           10 :     char buf[SCD_FUNC_NAME_LENGTH] = {0};
      46              :     // traverse all symbol section to find function symbol
      47           10 :     LIST_FOR_EACH(pos, &elf->symbolList.list)
      48              :     {
      49           10 :         node = LIST_ENTRY(pos, struct AdiagListNode, list);
      50           10 :         if (node == NULL) {
      51            0 :             return;
      52              :         }
      53           10 :         symbols = (ScdDlSymbol*)node->data;
      54         6570 :         for (size_t offset = symbols->symOffset; offset < symbols->symEnd; offset += symbols->symEntrySize) {
      55         6570 :             ElfW(Sym)* sym = (ElfW(Sym)*)ScdMemoryGetAddr(elf->memory, offset, sizeof(ElfW(Sym)));
      56         6570 :             if (sym == NULL) {
      57            0 :                 break;
      58              :             }
      59              :             // filter function symbol
      60         6570 :             if ((sym->st_shndx == SHN_UNDEF) || (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)) {
      61         1070 :                 continue;
      62              :             }
      63              : 
      64         5500 :             size_t startOffset = sym->st_value + elf->memory->data + elf->loadBias;
      65         5500 :             size_t endOffset = startOffset + sym->st_size;
      66         5500 :             if ((pc < startOffset) || (pc >= endOffset)) {
      67         5490 :                 continue;
      68              :             }
      69              :             // st_name is the offset of symbol name in string table
      70           10 :             size_t strOffset = symbols->strOffset + sym->st_name;
      71           10 :             if (strOffset >= symbols->strEnd) {
      72            0 :                 continue;
      73              :             }
      74              : 
      75           10 :             if (ScdMemoryReadString(
      76           10 :                     elf->memory, strOffset, buf, SCD_MIN(SCD_FUNC_NAME_LENGTH, symbols->strEnd - strOffset)) == 0) {
      77            0 :                 continue;
      78              :             }
      79              : 
      80           10 :             errno_t err = memcpy_s(funcName, len, buf, SCD_MIN(strlen(buf) + 1U, len));
      81           10 :             if (err != EOK) {
      82            2 :                 SCD_DLOG_ERR("memcpy_s failed, err=%d.", (int32_t)err);
      83            2 :                 return;
      84              :             }
      85            8 :             *funcOffset = pc - startOffset;
      86            8 :             return;
      87              :         }
      88              :     }
      89              : }
      90              : 
      91            4 : TraStatus ScdElfStep(ScdElf* elf, uintptr_t pc, ScdRegs* regs, bool isFirstStack)
      92              : {
      93            4 :     if (elf->ehFrameHdrOffset == 0) {
      94            0 :         STACKTRACE_LOG_RUN("elf of pc(0x%llx) does not have eh_frame_hdr section.", pc);
      95            0 :         return TRACE_FAILURE;
      96              :     }
      97            4 :     ScdDwarf dwarf = {0};
      98            4 :     const ScdDwarfStepArgs args = {ScdRegsGetSp(regs), SCD_UINTPTR_MAX, isFirstStack};
      99            4 :     dwarf.memory = elf->memory;
     100            4 :     dwarf.ehFrameHdrOffset = elf->ehFrameHdrOffset;
     101            4 :     dwarf.loadBias = elf->loadBias;
     102            4 :     SCD_DLOG_DBG("dwarf.ehFrameHdrOffset = 0x%llx, dwarf.loadBias = 0x%llx.", dwarf.ehFrameHdrOffset, dwarf.loadBias);
     103            4 :     dwarf.fdeCount = ScdElfGetFdeNum(elf);
     104              :     uintptr_t nextPc;
     105              :     // when the address read from the elf file is compared with the address in the memory, bias offset is required
     106              :     // pc is the address in the memory, so it needs to be subtracted by the bias offset
     107            4 :     TraStatus ret = ScdDwarfStep(&dwarf, regs, &args, pc - dwarf.loadBias, &nextPc);
     108            4 :     ScdRegsSetPc(regs, nextPc);
     109            4 :     return ret;
     110              : }
     111              : 
     112           24 : STATIC TraStatus ScdElfParseProgramHeaders(ScdElf* elf, ElfW(Ehdr) * ehdr)
     113              : {
     114           24 :     size_t phSize = (size_t)ehdr->e_phnum * (size_t)ehdr->e_phentsize;
     115          108 :     for (size_t i = 0; i < phSize; i += ehdr->e_phentsize) {
     116          102 :         ElfW(Phdr)* phdr = (ElfW(Phdr)*)ScdMemoryGetAddr(elf->memory, ehdr->e_phoff + i, sizeof(ElfW(Phdr)));
     117          102 :         SCD_CHK_PTR_ACTION(phdr, return TRACE_FAILURE);
     118              : 
     119           84 :         switch (phdr->p_type) {
     120           24 :             case PT_LOAD:
     121           24 :                 if ((phdr->p_flags & SCD_PF_X) == 0) {
     122           18 :                     continue;
     123              :                 }
     124            6 :                 if (elf->loadBiasSave == false) {
     125            6 :                     elf->loadBias = phdr->p_vaddr - phdr->p_offset;
     126            6 :                     elf->loadBiasSave = true;
     127              :                 }
     128            6 :                 break;
     129            6 :             case PT_GNU_EH_FRAME:
     130            6 :                 elf->ehFrameHdrOffset = phdr->p_offset;
     131            6 :                 elf->ehFrameHdrSize = phdr->p_memsz;
     132            6 :                 elf->ehFrameHdrLoadBias = phdr->p_vaddr - phdr->p_offset;
     133            6 :                 break;
     134            6 :             case PT_DYNAMIC:
     135            6 :                 elf->dynamicOffset = phdr->p_offset;
     136            6 :                 elf->dynamicSize = phdr->p_memsz;
     137            6 :                 break;
     138           48 :             default:
     139           48 :                 break;
     140              :         }
     141              :     }
     142            6 :     return TRACE_SUCCESS;
     143              : }
     144              : 
     145            6 : STATIC TraStatus ScdElfGetStringSectionHeader(ScdElf* elf, ElfW(Ehdr) * ehdr, size_t* secOffset, size_t* secSize)
     146              : {
     147            6 :     ElfW(Shdr)* shdr = ScdMemoryGetAddr(
     148            6 :         elf->memory, ehdr->e_shoff + (uintptr_t)ehdr->e_shstrndx * (uintptr_t)ehdr->e_shentsize, sizeof(ElfW(Shdr)));
     149            6 :     if (shdr == NULL) {
     150            0 :         SCD_DLOG_ERR("read memory failed, get string table section header failed.");
     151            0 :         return TRACE_FAILURE;
     152              :     }
     153            6 :     *secOffset = shdr->sh_offset;
     154            6 :     *secSize = shdr->sh_size;
     155            6 :     return TRACE_SUCCESS;
     156              : }
     157              : 
     158           24 : STATIC void ScdElfHandleNote(ScdElf* elf, ElfW(Shdr) * shdr, size_t secOffset, size_t secSize)
     159              : {
     160           24 :     if (shdr->sh_name >= secSize) {
     161            0 :         return;
     162              :     }
     163           24 :     char name[SCD_ELF_SH_NAME_LENGTH] = {0};
     164           24 :     if (ScdMemoryReadString(elf->memory, secOffset + shdr->sh_name, name, sizeof(name)) == 0) {
     165            0 :         return;
     166              :     }
     167           24 :     if (strcmp(name, ".note.gnu.build-id") == 0) {
     168            6 :         elf->buildIdOffset = shdr->sh_offset;
     169            6 :         elf->buildIdSize = shdr->sh_size;
     170              :     }
     171           24 :     return;
     172              : }
     173              : 
     174            6 : STATIC TraStatus ScdElfHandleDynsym(ScdElf* elf, ElfW(Ehdr) * ehdr, ElfW(Shdr) * shdr)
     175              : {
     176            6 :     if (shdr->sh_link >= ehdr->e_shnum) {
     177            0 :         return TRACE_SUCCESS;
     178              :     }
     179            6 :     ElfW(Shdr)* strShdr = (ElfW(Shdr)*)ScdMemoryGetAddr(
     180            6 :         elf->memory, ehdr->e_shoff + (uintptr_t)shdr->sh_link * (uintptr_t)ehdr->e_shentsize, sizeof(ElfW(Shdr)));
     181            6 :     SCD_CHK_PTR_ACTION(strShdr, return TRACE_FAILURE);
     182              : 
     183            6 :     if (strShdr->sh_type != SHT_STRTAB) {
     184            0 :         return TRACE_SUCCESS;
     185              :     }
     186            6 :     ScdDlSymbol* symbol = (ScdDlSymbol*)AdiagMalloc(sizeof(ScdDlSymbol));
     187            6 :     SCD_CHK_PTR_ACTION(symbol, return TRACE_FAILURE);
     188              : 
     189            6 :     symbol->symOffset = shdr->sh_offset;
     190            6 :     symbol->symEnd = shdr->sh_offset + shdr->sh_size;
     191            6 :     symbol->symEntrySize = shdr->sh_entsize;
     192            6 :     symbol->strOffset = strShdr->sh_offset;
     193            6 :     symbol->strEnd = strShdr->sh_offset + strShdr->sh_size;
     194              : 
     195            6 :     AdiagStatus adiagRet = AdiagListInsert(&elf->symbolList, symbol);
     196            6 :     if (adiagRet != ADIAG_SUCCESS) {
     197            0 :         SCD_DLOG_ERR("add symbol to list failed.");
     198            0 :         ADIAG_SAFE_FREE(symbol);
     199            0 :         return TRACE_FAILURE;
     200              :     }
     201            6 :     return TRACE_SUCCESS;
     202              : }
     203              : 
     204          264 : STATIC TraStatus ScdElfHandleProgbits(ScdElf* elf, ElfW(Shdr) * shdr, size_t secOffset, size_t secSize)
     205              : {
     206          264 :     if (shdr->sh_name >= secSize) {
     207            0 :         return TRACE_SUCCESS;
     208              :     }
     209          264 :     char name[SCD_ELF_SH_NAME_LENGTH] = {0};
     210          264 :     if (ScdMemoryReadString(elf->memory, secOffset + shdr->sh_name, name, sizeof(name)) == 0) {
     211            0 :         SCD_DLOG_ERR("read memory failed, get SHT_PROGBITS section failed.");
     212            0 :         return TRACE_FAILURE;
     213              :     }
     214          264 :     if (strcmp(name, ".eh_frame") == 0) {
     215            6 :         elf->ehFrameOffset = shdr->sh_offset;
     216            6 :         elf->ehFrameSize = shdr->sh_size;
     217            6 :         elf->ehFrameLoadBias = shdr->sh_addr - shdr->sh_offset;
     218          258 :     } else if (strcmp(name, ".eh_frame_hdr") == 0 && elf->ehFrameHdrOffset == 0) {
     219            0 :         elf->ehFrameHdrOffset = shdr->sh_offset;
     220            0 :         elf->ehFrameHdrSize = shdr->sh_size;
     221            0 :         elf->ehFrameHdrLoadBias = shdr->sh_addr - shdr->sh_offset;
     222              :     } else {
     223              :         ;
     224              :     }
     225          264 :     return TRACE_SUCCESS;
     226              : }
     227              : 
     228            6 : STATIC TraStatus ScdElfParseSectionHeaders(ScdElf* elf, ElfW(Ehdr) * ehdr)
     229              : {
     230            6 :     size_t secOffset = 0;
     231            6 :     size_t secSize = 0;
     232              :     // get section header entry that contains the section names
     233            6 :     if (ehdr->e_shstrndx < ehdr->e_shnum) {
     234            6 :         if (ScdElfGetStringSectionHeader(elf, ehdr, &secOffset, &secSize) != TRACE_SUCCESS) {
     235            0 :             return TRACE_FAILURE;
     236              :         }
     237              :     }
     238            6 :     size_t ehSize = (size_t)ehdr->e_shnum * (size_t)ehdr->e_shentsize;
     239          384 :     for (size_t i = ehdr->e_shentsize; i < ehSize; i += ehdr->e_shentsize) {
     240          378 :         ElfW(Shdr)* shdr = (ElfW(Shdr)*)ScdMemoryGetAddr(elf->memory, ehdr->e_shoff + i, sizeof(ElfW(Shdr)));
     241          378 :         if (shdr == NULL) {
     242            0 :             SCD_DLOG_ERR("read memory failed, get section[%zu] failed.", i);
     243            0 :             return TRACE_FAILURE;
     244              :         }
     245          378 :         switch (shdr->sh_type) {
     246           24 :             case SHT_NOTE: {
     247           24 :                 ScdElfHandleNote(elf, shdr, secOffset, secSize);
     248           24 :                 break;
     249              :             }
     250            6 :             case SHT_SYMTAB:
     251              :             case SHT_DYNSYM: {
     252            6 :                 if (ScdElfHandleDynsym(elf, ehdr, shdr) != TRACE_SUCCESS) {
     253            0 :                     return TRACE_FAILURE;
     254              :                 }
     255            6 :                 break;
     256              :             }
     257          264 :             case SHT_PROGBITS: {
     258          264 :                 if (ScdElfHandleProgbits(elf, shdr, secOffset, secSize) != TRACE_SUCCESS) {
     259            0 :                     return TRACE_FAILURE;
     260              :                 }
     261          264 :                 break;
     262              :             }
     263           84 :             default:
     264           84 :                 break;
     265              :         }
     266              :     }
     267            6 :     return TRACE_SUCCESS;
     268              : }
     269              : 
     270           42 : STATIC TraStatus ScdElfCheckValid(ElfW(Ehdr) * ehdr)
     271              : {
     272              :     // check magic
     273           42 :     if (strncmp((const char*)ehdr->e_ident, (const char*)ELFMAG, SELFMAG) != 0) {
     274           18 :         SCD_DLOG_ERR("elf valid check failed, ehdr->e_ident = %s.", ehdr->e_ident);
     275           18 :         return TRACE_FAILURE;
     276              :     }
     277              : 
     278           24 :     return TRACE_SUCCESS;
     279              : }
     280              : 
     281           60 : STATIC TraStatus ScdElfParse(ScdElf* elf)
     282              : {
     283              :     // get ELF header
     284           60 :     ElfW(Ehdr)* ehdr = (ElfW(Ehdr)*)ScdMemoryGetAddr(elf->memory, 0, sizeof(ElfW(Ehdr)));
     285           60 :     SCD_CHK_PTR_ACTION(ehdr, return TRACE_FAILURE);
     286              : 
     287           42 :     TraStatus ret = ScdElfCheckValid(ehdr);
     288           42 :     if (ret != TRACE_SUCCESS) {
     289           18 :         return TRACE_FAILURE;
     290              :     }
     291              : 
     292           24 :     ret = ScdElfParseProgramHeaders(elf, ehdr);
     293           24 :     if (ret != TRACE_SUCCESS) {
     294           18 :         return TRACE_FAILURE;
     295              :     }
     296              : 
     297            6 :     ret = ScdElfParseSectionHeaders(elf, ehdr);
     298            6 :     if (ret != TRACE_SUCCESS) {
     299            0 :         return TRACE_FAILURE;
     300              :     }
     301              : 
     302            6 :     return TRACE_SUCCESS;
     303              : }
     304              : 
     305              : /**
     306              :  * @brief       load elf info from memory
     307              :  * @param [in]  elf:       elf info
     308              :  * @param [in]  pid:       process id
     309              :  * @param [in]  memory:    dynamic library memory
     310              :  * @return      TraStatus
     311              :  */
     312           60 : TraStatus ScdElfLoad(ScdElf* elf, int32_t pid, ScdMemory* memory)
     313              : {
     314           60 :     SCD_CHK_PTR_ACTION(elf, return TRACE_FAILURE);
     315           60 :     elf->pid = pid;
     316           60 :     elf->memory = memory;
     317              : 
     318           60 :     TraStatus ret = ScdElfParse(elf);
     319           60 :     if (ret != TRACE_SUCCESS) {
     320           54 :         return TRACE_FAILURE;
     321              :     }
     322              : 
     323            6 :     return TRACE_SUCCESS;
     324              : }
     325              : 
     326              : /**
     327              :  * @brief       init elf info
     328              :  * @param [in]  elf:       elf info
     329              :  * @return      TraStatus
     330              :  */
     331         1183 : TraStatus ScdElfInit(ScdElf* elf)
     332              : {
     333         1183 :     (void)memset_s(elf, sizeof(ScdElf), 0, sizeof(ScdElf));
     334         1183 :     elf->loadBiasSave = false;
     335         1183 :     return AdiagListInit(&elf->symbolList);
     336              : }
     337              : 
     338              : /**
     339              :  * @brief       uinit elf info
     340              :  * @param [in]  elf:       elf info
     341              :  * @return      NA
     342              :  */
     343           24 : void ScdElfUninit(ScdElf* elf)
     344              : {
     345           24 :     ScdDlSymbol* node = (ScdDlSymbol*)AdiagListTakeOut(&elf->symbolList);
     346           30 :     while (node != NULL) {
     347            6 :         ADIAG_SAFE_FREE(node);
     348            6 :         node = (ScdDlSymbol*)AdiagListTakeOut(&elf->symbolList);
     349              :     }
     350           24 : }
        

Generated by: LCOV version 2.0-1