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: 18.3 % 197 36
Test Date: 2026-07-28 10:53:44 Functions: 46.7 % 15 7

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

Generated by: LCOV version 2.0-1