LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace/stacktrace_dumper - scd_dwarf.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 69.4 % 307 213
Test Date: 2026-08-31 10:07:06 Functions: 92.3 % 13 12

            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_dwarf.h"
      12              : #include "scd_log.h"
      13              : #include "stacktrace_unwind.h"
      14              : #include "stacktrace_unwind_reg.h"
      15              : #include "stacktrace_unwind_instr.h"
      16              : #include "stacktrace_unwind_inner.h"
      17              : #include "scd_maps.h"
      18              : 
      19              : #define TRACE_MAX_AUG_STR_LEN 0x08U // max length of augmentation string in CIE
      20              : // .eh_frame_hdr section
      21              : typedef struct TraceUnwindEhFrameHdrInfo {
      22              :     uint8_t version;       // eh_frame_hdr version, must be 1
      23              :     uint8_t ehframeptrEnc; // the encode type of eh_frame_hdr
      24              :     uint8_t fdeCountEnc;   // the encode type of FDE count
      25              :     uint8_t tabEnc;        // the encode type of binary search table
      26              :     uint8_t searchTblFlag; // the flag of table present 1:present 0:no present
      27              :     uint8_t reserved[3];   // the reserved
      28              :     uintptr_t frameAddr;   // eh_frame section start addr
      29              :     size_t fdeCount;       // FDE count in binary search table
      30              :     uintptr_t tblStatAddr; // the binary search table addr
      31              : } TraceUnwindEhFrameHdrInfo;
      32              : // FDE entry in the binary search table
      33              : typedef struct FdeEntry {
      34              :     int32_t initLocOffset; // location addr offset relative to eh_frame_hdr addr
      35              :     int32_t fdeTableOffset;
      36              : } FdeEntry;
      37              : 
      38              : typedef struct FDECtrlBlock {
      39              :     uintptr_t funcStart;
      40              :     uintptr_t unwindEntryAddr;
      41              : } FDECtrlBlock;
      42              : // the first few filed of an FDE
      43              : typedef struct TraceEhFrameFde {
      44              :     uint32_t fdeLengh;
      45              :     uint32_t cieOffset;
      46              :     uint8_t pcBegin[16];
      47              : } TraceEhFrameFde;
      48              : // the first few filed of an CIE
      49              : typedef struct TraceEhFrameCie {
      50              :     uint32_t cieLengh;       // the length of CIE except itself
      51              :     uint32_t cieId;          // the ID of CIE, must be 0
      52              :     uint8_t version;         // the version of CIE
      53              :     int8_t augmentation[15]; // the string of Augmentation
      54              : } TraceEhFrameCie;
      55              : 
      56              : /**
      57              :  * @brief           get cie address by offset
      58              :  * @param [in]      offset:         offset address
      59              :  * @return          cie address
      60              :  */
      61           54 : STATIC INLINE uintptr_t GetCieAddressByOffset(uint32_t* offset) { return (uintptr_t)(offset) - (*offset); }
      62              : 
      63           42 : STATIC INLINE uintptr_t GetAddrByOffset(uintptr_t addr, intptr_t offset)
      64              : {
      65           42 :     if (offset >= 0) {
      66           42 :         return addr + (uintptr_t)offset;
      67              :     }
      68            0 :     uintptr_t absOffset = (uintptr_t)(-offset);
      69            0 :     if (absOffset > addr) {
      70            0 :         return 0;
      71              :     }
      72            0 :     return addr - absOffset;
      73              : }
      74              : 
      75              : /**
      76              :  * @brief extract eh_frame_hdr section
      77              :  *
      78              :  * @param [in]  ehFrameHdrAddr eh_frame_hdr addr
      79              :  * @param [out] ehFrameHdrInfo eh_frame_hdr information
      80              :  *
      81              :  * @return      : !=0 failure; ==0 success
      82              :  */
      83           40 : STATIC TraStatus TraceParseFrameHdrAddr(ScdDwarf* dwarf, TraceUnwindEhFrameHdrInfo* ehFrameHdrInfo)
      84              : {
      85           40 :     const uint8_t* addr = (uint8_t*)(dwarf->memory->data + dwarf->ehFrameHdrOffset);
      86           40 :     ehFrameHdrInfo->version = *addr;
      87           40 :     addr++;
      88           40 :     ehFrameHdrInfo->ehframeptrEnc = *addr;
      89           40 :     addr++;
      90           40 :     ehFrameHdrInfo->fdeCountEnc = *addr;
      91           40 :     addr++;
      92           40 :     ehFrameHdrInfo->tabEnc = *addr;
      93           40 :     addr++;
      94           40 :     if (ehFrameHdrInfo->version != 1) {
      95           18 :         SCD_DLOG_ERR("[ERROR] invalid version %d", ehFrameHdrInfo->version);
      96           18 :         return TRACE_FAILURE;
      97              :     }
      98           22 :     addr = TraceReadEncodeValue(dwarf, ehFrameHdrInfo->ehframeptrEnc, addr, &ehFrameHdrInfo->frameAddr);
      99           22 :     if (addr == NULL) {
     100           18 :         SCD_DLOG_ERR("read encode value frame addr failed");
     101           18 :         return TRACE_FAILURE;
     102              :     }
     103              : 
     104              :     uintptr_t fdeItem;
     105            4 :     if (TRACE_IS_HDR_TBL_PRESENT(ehFrameHdrInfo)) {
     106            4 :         addr = TraceReadEncodeValue(dwarf, ehFrameHdrInfo->fdeCountEnc, addr, &fdeItem);
     107            4 :         if ((addr == NULL) || (fdeItem == 0)) {
     108            4 :             SCD_DLOG_ERR("read encode value fde item failed");
     109            4 :             return TRACE_FAILURE;
     110              :         }
     111            0 :         ehFrameHdrInfo->fdeCount = (size_t)fdeItem;
     112            0 :         ehFrameHdrInfo->tblStatAddr = (uintptr_t)addr;
     113            0 :         ehFrameHdrInfo->searchTblFlag = 1;
     114              :     } else {
     115            0 :         ehFrameHdrInfo->searchTblFlag = 0;
     116              :     }
     117            0 :     SCD_DLOG_INF(
     118              :         "[eh_frame_hdr info] version: %u, ehframeptrEnc: %u, fdeCountEnc: %u, tabEnc: %u, searchTblFlag: %u",
     119              :         ehFrameHdrInfo->version, ehFrameHdrInfo->ehframeptrEnc, ehFrameHdrInfo->fdeCountEnc, ehFrameHdrInfo->tabEnc,
     120              :         ehFrameHdrInfo->searchTblFlag);
     121            0 :     return TRACE_SUCCESS;
     122              : }
     123              : 
     124           54 : STATIC const uint8_t* TraceParseCIEAug(
     125              :     ScdDwarf* dwarf, const char* augStr, const uint8_t* instr, uint32_t idx, uintptr_t* retIns,
     126              :     TraceFrameRegStateInfo* frameRegState)
     127              : {
     128              :     size_t encSize;
     129           54 :     uintptr_t retBegIns = 0;
     130              :     uintptr_t ulebTmp;
     131           54 :     const uint8_t* tmpInstr = instr;
     132           54 :     uint32_t indexTmp = idx;
     133              : 
     134              :     /* Check for the presence of 'z' in the augmentation string, which indicates
     135              :      * the presence of additional information that affects the instruction range */
     136           54 :     if (augStr[indexTmp] == 'z') {
     137            0 :         tmpInstr = TraceReadUleb128(dwarf, tmpInstr, &ulebTmp);
     138            0 :         SCD_CHK_EXPR_ACTION(tmpInstr == NULL, return NULL, "read uleb128 failed");
     139            0 :         retBegIns = (uintptr_t)tmpInstr + ulebTmp;
     140            0 :         frameRegState->optFlag = 1;
     141            0 :         indexTmp++;
     142              :     }
     143              : 
     144           72 :     while (augStr[indexTmp] != '\0') {
     145              :         // 'L' indicates a local static anonymous namespace, not processed here
     146           36 :         if (augStr[indexTmp] == 'L') {
     147            0 :             indexTmp++;
     148            0 :             tmpInstr++;
     149           36 :         } else if (augStr[indexTmp] == 'P') {
     150              :             // 'P' indicates a procedure linkage table (PLT) entry, not processed here
     151            0 :             uint8_t ucPEnc = *tmpInstr;
     152            0 :             tmpInstr++;
     153            0 :             encSize = TraceEncValueSizeGet(ucPEnc);
     154            0 :             SCD_CHK_EXPR_ACTION(encSize == 0, return NULL, "get enc value size failed");
     155            0 :             tmpInstr += encSize;
     156            0 :             TRACE_UNWIND_PARSE_ADDR_CHECK_OR_RETURN(tmpInstr);
     157            0 :             indexTmp++;
     158           36 :         } else if (augStr[indexTmp] == 'R') { // 'R' indicates a range,
     159           18 :             frameRegState->fdeEnc = *tmpInstr;
     160           18 :             tmpInstr++;
     161           18 :             frameRegState->flag = 1;
     162           18 :             indexTmp++;
     163           18 :         } else if (*(const char*)tmpInstr == 'S') { // 'S' indicates a signal frame
     164            0 :             frameRegState->sigFrmFlag = 1;
     165            0 :             indexTmp++;
     166              :         } else {
     167              :             /* If an unrecognized augmentation string is encountered, and there is no 'z',
     168              :              * the function returns early, indicating that the CST contains an unhandled string */
     169           18 :             if (retBegIns == 0) {
     170           18 :                 return NULL;
     171              :             } else {
     172            0 :                 break;
     173              :             }
     174              :         }
     175              :     }
     176           36 :     *retIns = retBegIns;
     177           36 :     return tmpInstr;
     178              : }
     179              : 
     180              : STATIC TraStatus
     181           72 : TraceParseCie(ScdDwarf* dwarf, uintptr_t cieAddr, TraceAddrRange* initIns, TraceFrameRegStateInfo* frameRegState)
     182              : {
     183           72 :     TraceEhFrameCie* ehFrameCIEHdr = (TraceEhFrameCie*)cieAddr;
     184           72 :     const uint8_t* skipAug = NULL;
     185           72 :     char ucAugStr[TRACE_MAX_AUG_STR_LEN + 1U] = {0};
     186           72 :     uint32_t idx = 0;
     187           72 :     skipAug = (const uint8_t*)ehFrameCIEHdr->augmentation;
     188          144 :     for (size_t i = 0; i < TRACE_MAX_AUG_STR_LEN; i++) {
     189          144 :         size_t size = TraceReadBytes(dwarf, &skipAug, &ucAugStr[i], sizeof(uint8_t));
     190          144 :         SCD_CHK_EXPR_ACTION(size == 0, return TRACE_FAILURE, "read byte failed");
     191          126 :         if (ucAugStr[i] == '\0') {
     192           54 :             break;
     193              :         }
     194              :     }
     195           54 :     if (ucAugStr[0] == 'e' && ucAugStr[1] == 'h') {
     196           18 :         skipAug += sizeof(void*);
     197           18 :         idx += 2U; // add 2 for size "eh"
     198              :     }
     199              :     uintptr_t ulebTmp;
     200              :     intptr_t svLebTmp;
     201           54 :     skipAug = TraceReadUleb128(dwarf, skipAug, &ulebTmp);
     202           54 :     SCD_CHK_EXPR_ACTION(skipAug == NULL, return TRACE_FAILURE, "read uleb128 failed");
     203           54 :     frameRegState->codeAlign = ulebTmp;
     204           54 :     skipAug = TraceReadLeb128(dwarf, skipAug, &svLebTmp);
     205           54 :     SCD_CHK_EXPR_ACTION(skipAug == NULL, return TRACE_FAILURE, "read leb128 failed");
     206           54 :     frameRegState->dataAlign = svLebTmp;
     207           54 :     if (ehFrameCIEHdr->version == 1) {
     208            0 :         ulebTmp = (uintptr_t)(*(uint8_t*)(uintptr_t)skipAug);
     209            0 :         skipAug++;
     210              :     } else {
     211           54 :         skipAug = TraceReadUleb128(dwarf, skipAug, &ulebTmp);
     212           54 :         SCD_CHK_EXPR_ACTION(skipAug == NULL, return TRACE_FAILURE, "read uleb128 failed");
     213              :     }
     214           54 :     frameRegState->retColumn = ulebTmp;
     215           54 :     uintptr_t retIns = 0;
     216           54 :     skipAug = TraceParseCIEAug(dwarf, ucAugStr, skipAug, idx, &retIns, frameRegState);
     217           54 :     SCD_CHK_EXPR_ACTION(skipAug == NULL, return TRACE_FAILURE, "parse CIE aug failed");
     218              : 
     219              :     // When 'z' appears, the unwind instruction address can be directly obtained through the ret pointer.
     220           36 :     initIns->start = (retIns != 0) ? retIns : (uintptr_t)skipAug;
     221           36 :     initIns->end = (uintptr_t)(cieAddr + ehFrameCIEHdr->cieLengh + sizeof(uint32_t));
     222           36 :     SCD_DLOG_INF(
     223              :         "[CIE info] addr : 0x%lx, Length : 0x%x, Extended cieId : %u, version : %u, initIns [0x%lx-0x%lx],"
     224              :         "codeAlign:0x%lx, dataAlign:%ld,",
     225              :         cieAddr, ehFrameCIEHdr->cieLengh, ehFrameCIEHdr->cieId, ehFrameCIEHdr->version, initIns->start, initIns->end,
     226              :         frameRegState->codeAlign, frameRegState->dataAlign);
     227           36 :     return TRACE_SUCCESS;
     228              : }
     229              : 
     230           54 : STATIC TraStatus TraceParseFde(
     231              :     ScdDwarf* dwarf, uintptr_t fdeAddr, TraceFrameRegStateInfo* frameRegState, TraceAddrRange* initIns,
     232              :     TraceAddrRange* ins)
     233              : {
     234              :     uintptr_t cieEntry;
     235           54 :     const uint8_t* addr = NULL;
     236              :     uintptr_t funStart;
     237              :     uintptr_t range;
     238           54 :     TraceEhFrameFde* pstFDEHeadInfo = (TraceEhFrameFde*)fdeAddr;
     239           54 :     cieEntry = GetCieAddressByOffset(&pstFDEHeadInfo->cieOffset);
     240           54 :     TraStatus ret = TraceParseCie(dwarf, cieEntry, initIns, frameRegState);
     241           54 :     if (ret != TRACE_SUCCESS) {
     242           18 :         SCD_DLOG_ERR("parse CIE failed, ret %d", ret);
     243           18 :         return ret;
     244              :     }
     245           36 :     addr = pstFDEHeadInfo->pcBegin;
     246           36 :     if (frameRegState->flag == 0) {
     247           18 :         funStart = *(uintptr_t*)(uintptr_t)addr;
     248           18 :         addr += sizeof(void*);
     249           18 :         range = *(uintptr_t*)(uintptr_t)addr;
     250           18 :         addr += sizeof(void*);
     251              :     } else {
     252              :         // 使用FDE编码解析PC Begin和PC Range
     253           18 :         uint8_t ucFdeEnc = frameRegState->fdeEnc;
     254           18 :         addr = TraceReadEncodeValue(dwarf, ucFdeEnc, addr, &funStart);
     255           18 :         if (addr == NULL) {
     256           18 :             SCD_DLOG_ERR("invalid addr");
     257           18 :             return TRACE_FAILURE;
     258              :         }
     259            0 :         addr = TraceReadEncodeValue(dwarf, TRACE_LOBIT4_ENCODE(ucFdeEnc), addr, (uintptr_t*)&range); /* 0x0f */
     260            0 :         if (addr == NULL) {
     261            0 :             SCD_DLOG_ERR("invalid addr");
     262            0 :             return TRACE_FAILURE;
     263              :         }
     264              :     }
     265           18 :     frameRegState->pc = funStart;
     266           18 :     frameRegState->range = range;
     267              : 
     268           18 :     uintptr_t ulebTmp = 0;
     269           18 :     if (frameRegState->optFlag == 1) {
     270            0 :         addr = TraceReadUleb128(dwarf, addr, &ulebTmp);
     271            0 :         SCD_CHK_EXPR_ACTION(addr == NULL, return TRACE_FAILURE, "read uleb128 failed");
     272              :     }
     273              : 
     274           18 :     ins->start = (uintptr_t)(addr + ulebTmp);
     275           18 :     ulebTmp = (uintptr_t)(fdeAddr + pstFDEHeadInfo->fdeLengh + sizeof(uint32_t));
     276           18 :     ins->end = ulebTmp;
     277           18 :     SCD_DLOG_INF(
     278              :         "[FDE info] Length:0x%x,CIE Pointer:0x%x,pcBegin:0x%lx,funStart: 0x%lx,range: 0x%lx,ins [0x%lx-0x%lx]",
     279              :         pstFDEHeadInfo->fdeLengh, pstFDEHeadInfo->cieOffset, (uintptr_t)pstFDEHeadInfo->pcBegin, funStart, range,
     280              :         ulebTmp, ulebTmp + pstFDEHeadInfo->fdeLengh);
     281           18 :     return TRACE_SUCCESS;
     282              : }
     283              : 
     284           54 : STATIC void TraceGetCFAAddr(
     285              :     ScdDwarf* dwarf, TraceFrameRegStateInfo* frameRegState, ScdRegs* regs, const ScdDwarfStepArgs* args,
     286              :     uintptr_t* cfaAddrPtr)
     287              : {
     288           54 :     uintptr_t cfaAddr = 0;
     289              :     intptr_t offset;
     290              :     uintptr_t regNum;
     291              :     uintptr_t insLen;
     292              :     uintptr_t expResult;
     293              :     uintptr_t storeReg;
     294           54 :     const uint8_t* expOpAddr = NULL;
     295              : 
     296           54 :     switch (frameRegState->frameStateInfo.cfaHow) {
     297            0 :         case VOS_CFA_REG_OFFSET:
     298            0 :             regNum = frameRegState->frameStateInfo.cfaReg;
     299            0 :             offset = frameRegState->frameStateInfo.cfaOffset;
     300            0 :             storeReg = regs->r[regNum & REG_VAILD_MASK];
     301            0 :             if (storeReg == 0) {
     302            0 :                 return;
     303              :             } else {
     304            0 :                 SCD_DLOG_INF("CFA Addr = reg[%ld]: %lx + offset : %ld", regNum, storeReg, offset);
     305            0 :                 cfaAddr = storeReg + (uintptr_t)offset;
     306              :             }
     307            0 :             break;
     308           36 :         case VOS_CFA_EXP:
     309              :             /* expression 分支走dw_op指令解析流程 */
     310           36 :             expOpAddr = frameRegState->frameStateInfo.cfaExp;
     311           36 :             expOpAddr = TraceReadUleb128(dwarf, expOpAddr, &insLen);
     312           36 :             SCD_CHK_EXPR_ACTION(expOpAddr == NULL, return, "read uleb128 failed");
     313           18 :             (void)TraceStackOpExc(dwarf, expOpAddr, expOpAddr + insLen, regs, &expResult, 0, args);
     314           18 :             cfaAddr = expResult;
     315              : 
     316           18 :             break;
     317           18 :         default:
     318           18 :             break;
     319              :     }
     320           36 :     *cfaAddrPtr = cfaAddr;
     321           36 :     return;
     322              : }
     323              : 
     324          144 : STATIC TraStatus CallStackRegUpdate(
     325              :     ScdDwarf* dwarf, uint32_t idx, ScdRegs* pstCoreRegsOld, ScdRegs* coreRegs, uintptr_t cfaAddr,
     326              :     TraceStagRegInfo* pstRegInfo, const ScdDwarfStepArgs* args)
     327              : {
     328              :     uintptr_t regNum;
     329          144 :     uintptr_t expResult = 0;
     330          144 :     const uint8_t* expOpAddr = NULL;
     331          144 :     uintptr_t insLen = 0;
     332              :     uintptr_t regAddr;
     333              :     size_t size;
     334              :     TraStatus ret;
     335          144 :     SCD_DLOG_DBG("CallStackRegUpdate reg[%d] %d", idx, pstRegInfo->regHow);
     336          144 :     switch (pstRegInfo->regHow) {
     337            0 :         case REG_SAVED_OFFSET:
     338            0 :             regAddr = GetAddrByOffset(cfaAddr, pstRegInfo->regLoc.offset);
     339            0 :             SCD_CHK_EXPR_ACTION(regAddr == 0, return TRACE_FAILURE, "invalid offset %llx", pstRegInfo->regLoc.offset);
     340              :             /* 当前使用eh_frame进行unwind推栈的有x86_64、arm64和ilp32,寄存器大小都为64位,因此使用VOS_UINT64取内容
     341              :              * ScdMemoryRead(NULL, ...) uses global handler (ScdMemoryRemoteRead via ptrace).
     342              :              * Safe here: this function is only called from dumper subprocess context
     343              :              * (ScdProcessDump -> ScdDwarfStep), where ptrace is available. */
     344            0 :             size = ScdMemoryRead(NULL, regAddr, &coreRegs->r[idx & REG_VAILD_MASK], sizeof(uint64_t));
     345            0 :             SCD_CHK_EXPR_ACTION(size == 0, return TRACE_FAILURE, "scd read memory failed 0x%llx", regAddr);
     346            0 :             SCD_DLOG_INF(
     347              :                 "REG_SAVED_OFFSET reg %u addr:%lx value:%lx offset : %ld", idx, regAddr,
     348              :                 coreRegs->r[idx & REG_VAILD_MASK], pstRegInfo->regLoc.offset);
     349            0 :             break;
     350           18 :         case REG_SAVED_VAL_OFFSET:
     351           18 :             regAddr = GetAddrByOffset(cfaAddr, pstRegInfo->regLoc.offset);
     352           18 :             SCD_CHK_EXPR_ACTION(regAddr == 0, return TRACE_FAILURE, "invalid offset %llx", pstRegInfo->regLoc.offset);
     353           18 :             coreRegs->r[idx & REG_VAILD_MASK] = (uintptr_t)regAddr;
     354           18 :             SCD_DLOG_INF("REG_SAVED_VAL_OFFSET %u %lx", idx, coreRegs->r[idx & REG_VAILD_MASK]);
     355           18 :             break;
     356           18 :         case REG_SAVED_REG:
     357           18 :             regNum = pstRegInfo->regLoc.reg;
     358           18 :             expResult = pstCoreRegsOld->r[regNum & REG_VAILD_MASK];
     359           18 :             coreRegs->r[idx & REG_VAILD_MASK] = expResult;
     360           18 :             SCD_DLOG_INF("REG_SAVED_REG %u %lx", idx, coreRegs->r[idx & REG_VAILD_MASK]);
     361           18 :             break;
     362           36 :         case REG_SAVED_EXP:
     363           36 :             expOpAddr = TraceReadUleb128(dwarf, pstRegInfo->regLoc.valExp, &insLen);
     364           36 :             SCD_CHK_EXPR_ACTION(expOpAddr == NULL, return TRACE_FAILURE, "read uleb128 failed");
     365           36 :             ret = TraceStackOpExc(dwarf, expOpAddr, expOpAddr + insLen, pstCoreRegsOld, &expResult, cfaAddr, args);
     366           36 :             SCD_CHK_EXPR_ACTION(ret != TRACE_SUCCESS, return ret, "stack op exec for add %p failed", expOpAddr);
     367              :             /* 异常到正常中间转接函数的unwind指令,由本层SP求出上层所有寄存器(包括SP)
     368              :              * 当求sp时不要覆盖,以免无法求8-16号寄存器 最后SP可有CFA求得
     369              :              * ScdMemoryRead(NULL, ...) uses global handler (ScdMemoryRemoteRead via ptrace).
     370              :              * Safe here: this function is only called from dumper subprocess context
     371              :              * (ScdProcessDump -> ScdDwarfStep), where ptrace is available. */
     372           36 :             if ((idx != VOS_R_SP) && (expResult != 0)) {
     373           18 :                 size = ScdMemoryRead(NULL, expResult, &coreRegs->r[idx & REG_VAILD_MASK], sizeof(uint64_t));
     374           18 :                 SCD_CHK_EXPR_ACTION(size == 0, return TRACE_FAILURE, "scd read memory failed 0x%llx", expResult);
     375              :             }
     376           36 :             SCD_DLOG_INF("REG_SAVED_EXP %u %lx", idx, coreRegs->r[idx & REG_VAILD_MASK]);
     377           36 :             break;
     378           18 :         case REG_SAVED_VAL_EXP:
     379           18 :             expOpAddr = TraceReadUleb128(dwarf, pstRegInfo->regLoc.valExp, &insLen);
     380           18 :             ret = TraceStackOpExc(dwarf, expOpAddr, expOpAddr + insLen, pstCoreRegsOld, &expResult, cfaAddr, args);
     381           18 :             SCD_CHK_EXPR_ACTION(ret != TRACE_SUCCESS, return ret, "stack op exec for add %p failed", expOpAddr);
     382           18 :             coreRegs->r[idx & REG_VAILD_MASK] = expResult;
     383           18 :             SCD_DLOG_INF("REG_SAVED_VAL_EXP %u %lx", idx, coreRegs->r[idx & REG_VAILD_MASK]);
     384           18 :             break;
     385           54 :         case REG_UNSAVED:
     386              :         case REG_UNDEFINED:
     387              :         default:
     388           54 :             break;
     389              :     }
     390          144 :     return TRACE_SUCCESS;
     391              : }
     392              : 
     393           54 : static inline bool TraceCheckStackAddrValid(uintptr_t cfaAddr, const ScdDwarfStepArgs* args)
     394              : {
     395           54 :     return cfaAddr >= args->stackMinAddr && cfaAddr < args->stackMaxAddr;
     396              : }
     397              : 
     398              : STATIC TraStatus
     399           54 : TraceUnwinRegUpdate(ScdDwarf* dwarf, TraceFrameRegStateInfo* frameRegState, ScdRegs* regs, const ScdDwarfStepArgs* args)
     400              : {
     401              :     ScdRegs oldCoreRegArray;
     402           54 :     uintptr_t cfaAddr = 0;
     403           54 :     TraceGetCFAAddr(dwarf, frameRegState, regs, args, &cfaAddr);
     404           54 :     if (!TraceCheckStackAddrValid((uintptr_t)cfaAddr, args)) {
     405           54 :         SCD_DLOG_ERR("[CFA Addr] : %lx", cfaAddr);
     406           54 :         return TRACE_FAILURE;
     407              :     }
     408            0 :     SCD_DLOG_INF("[CFA Addr] : %lx", cfaAddr);
     409            0 :     for (uint32_t i = 0; i < TRACE_CORE_REG_NUM; i++) {
     410            0 :         oldCoreRegArray.r[i] = regs->r[i];
     411              :     }
     412            0 :     for (uint32_t i = 0; i < TRACE_CORE_REG_NUM; i++) {
     413            0 :         TraceStagRegInfo* regInfo = &(frameRegState->frameStateInfo.regInfo[i & REG_VAILD_MASK]);
     414            0 :         TraStatus ret = CallStackRegUpdate(dwarf, i, &oldCoreRegArray, regs, cfaAddr, regInfo, args);
     415            0 :         SCD_CHK_EXPR_ACTION(ret != TRACE_SUCCESS, return ret, "call stack register update failed");
     416              :     }
     417            0 :     if (frameRegState->frameStateInfo.regInfo[frameRegState->retColumn & REG_VAILD_MASK].regHow == REG_UNDEFINED) {
     418            0 :         regs->r[frameRegState->retColumn & REG_VAILD_MASK] = 0;
     419              :     }
     420            0 :     regs->r[VOS_R_SP] = cfaAddr;
     421            0 :     return TRACE_SUCCESS;
     422              : }
     423              : 
     424           20 : STATIC TraStatus TraceCallstackParse(
     425              :     ScdDwarf* dwarf, uintptr_t pc, const ScdDwarfStepArgs* args, ScdRegs* regs, TraceFrameRegStateInfo* frameRegState,
     426              :     FDECtrlBlock* ctrlBlock)
     427              : {
     428              :     TraStatus ret;
     429           20 :     uintptr_t fdeAddr = ctrlBlock->unwindEntryAddr;
     430              :     TraceAddrRange initIns;
     431              :     TraceAddrRange ins;
     432           20 :     frameRegState->retColumn = 0;
     433           20 :     bool isFDEtable = false;
     434           20 :     ret = TraceParseFde(dwarf, fdeAddr, frameRegState, &initIns, &ins);
     435           20 :     if (ret != TRACE_SUCCESS) {
     436            4 :         SCD_DLOG_ERR("TraceParseFde failed");
     437            4 :         return ret;
     438              :     }
     439           16 :     if (pc < frameRegState->pc || pc > frameRegState->pc + frameRegState->range) {
     440            4 :         SCD_DLOG_ERR(
     441              :             "pc %llx is out of FDE range [%llx, %llx], possible missing CFI", pc, frameRegState->pc,
     442              :             frameRegState->pc + frameRegState->range);
     443            4 :         return TRACE_FAILURE;
     444              :     }
     445           12 :     frameRegState->ret = pc;
     446           12 :     ret = TraceUnwindParseFn(dwarf, &initIns, frameRegState, isFDEtable);
     447           12 :     if (ret != TRACE_SUCCESS) {
     448            4 :         SCD_DLOG_ERR("TraceUnwindParseFn failed");
     449            4 :         return ret;
     450              :     }
     451              : 
     452            8 :     isFDEtable = true;
     453            8 :     ret = TraceUnwindParseFn(dwarf, &ins, frameRegState, isFDEtable);
     454            8 :     if (ret != TRACE_SUCCESS) {
     455            4 :         SCD_DLOG_ERR("TraceUnwindParseFn failed");
     456            4 :         return ret;
     457              :     }
     458            4 :     ret = TraceUnwinRegUpdate(dwarf, frameRegState, regs, args);
     459            4 :     if (ret != TRACE_SUCCESS) {
     460            4 :         SCD_DLOG_ERR("TraceUnwinRegUpdate failed");
     461            4 :         return ret;
     462              :     }
     463            0 :     return TRACE_SUCCESS;
     464              : }
     465              : 
     466            0 : STATIC FdeEntry* TraceSearchFdeOffsetTable(ScdDwarf* dwarf, uintptr_t tblStatAddr, uintptr_t pc)
     467              : {
     468              :     // pc may be smaller than enFrameAddr
     469            0 :     uintptr_t enFrameAddr = dwarf->memory->data + dwarf->ehFrameHdrOffset;
     470            0 :     FdeEntry* fdeItem = (FdeEntry*)tblStatAddr;
     471            0 :     size_t left = 0;
     472            0 :     size_t right = dwarf->fdeCount;
     473            0 :     size_t mid = (left + right) >> 1;
     474            0 :     uintptr_t midLocAddr = 0;
     475            0 :     SCD_DLOG_DBG("search pc 0x%llx", pc);
     476            0 :     while (left < right) {
     477            0 :         midLocAddr = GetAddrByOffset(enFrameAddr, fdeItem[mid].initLocOffset);
     478            0 :         SCD_DLOG_DBG(
     479              :             "search in range [%d, %d], compare [%d] 0x%llx, offset 0x%x,", left, right, mid, midLocAddr,
     480              :             fdeItem[mid].initLocOffset);
     481            0 :         if (pc == midLocAddr) {
     482            0 :             SCD_DLOG_DBG("match fde[%d], start pc 0x%llx", mid, midLocAddr);
     483            0 :             return &fdeItem[mid];
     484              :         }
     485            0 :         if (pc < midLocAddr) {
     486            0 :             right = mid;
     487              :         } else {
     488            0 :             left = mid + 1U;
     489              :         }
     490            0 :         mid = (left + right) >> 1U;
     491              :     }
     492            0 :     mid = right > 0U ? right - 1U : 0U;
     493            0 :     SCD_DLOG_DBG("match fde[%d], start pc 0x%llx", mid, midLocAddr);
     494            0 :     return &fdeItem[mid];
     495              : }
     496              : 
     497              : /**
     498              :  * @brief   get next pc by dwarf and regs
     499              :  *
     500              :  * @param [in]  dwarf   The dwarf information of the dynamic library where the current PC is located
     501              :  * @param [in]  regs    register information of current frame
     502              :  * @param [in]  args    step arguments
     503              :  * @param [in]  pc      current pc
     504              :  * @param [out] nextPc  pc of next frame
     505              :  *
     506              :  * @return      : !=0 failure; ==0 success
     507              :  */
     508           24 : TraStatus ScdDwarfStep(ScdDwarf* dwarf, ScdRegs* regs, const ScdDwarfStepArgs* args, uintptr_t pc, uintptr_t* nextPc)
     509              : {
     510              :     FDECtrlBlock ctrlBlock;
     511           24 :     TraceFrameRegStateInfo frameRegState = {0};
     512           24 :     SCD_DLOG_INF("scd dwarf step with pc 0x%llx", pc);
     513           24 :     SCD_DLOG_INF("[eh_frame_hdr addr] : %llx, size %zu", dwarf->memory->data, dwarf->memory->size);
     514              :     TraceUnwindEhFrameHdrInfo ehFrameHdrInfo;
     515           24 :     if (TraceParseFrameHdrAddr(dwarf, &ehFrameHdrInfo) != TRACE_SUCCESS) {
     516            8 :         return TRACE_FAILURE;
     517              :     }
     518              :     // get fde by search table
     519           16 :     if (ehFrameHdrInfo.searchTblFlag == 1U) {
     520           12 :         SCD_DLOG_INF("has search table");
     521           12 :         uintptr_t ehFramrHdrAddr = dwarf->memory->data + dwarf->ehFrameHdrOffset;
     522           12 :         FdeEntry* entry = TraceSearchFdeOffsetTable(dwarf, ehFrameHdrInfo.tblStatAddr, pc);
     523           12 :         uintptr_t tmpAddr = GetAddrByOffset(ehFramrHdrAddr, entry->fdeTableOffset);
     524           12 :         SCD_CHK_EXPR_ACTION(tmpAddr == 0, return TRACE_FAILURE, "invalid offset %d", entry->fdeTableOffset);
     525           12 :         ctrlBlock.unwindEntryAddr = tmpAddr;
     526           12 :         tmpAddr = GetAddrByOffset(ehFramrHdrAddr, entry->initLocOffset);
     527           12 :         SCD_CHK_EXPR_ACTION(tmpAddr == 0, return TRACE_FAILURE, "invalid offset %d", entry->initLocOffset);
     528           12 :         ctrlBlock.funcStart = tmpAddr;
     529           12 :         SCD_DLOG_INF("[unwindEntryAddr] : %lx, funcStart : %lx", ctrlBlock.unwindEntryAddr, ctrlBlock.funcStart);
     530              :     } else {
     531              :         // process no search table
     532            4 :         STACKTRACE_LOG_ERR("no search table.");
     533            4 :         return TRACE_FAILURE;
     534              :     }
     535           12 :     uintptr_t tempSp = regs->r[VOS_R_SP];
     536           12 :     TraStatus ret = TraceCallstackParse(dwarf, pc, args, regs, &frameRegState, &ctrlBlock);
     537           12 :     if (ret != TRACE_SUCCESS) {
     538           12 :         SCD_DLOG_ERR("call TraceCallstackParse failed");
     539           12 :         return TRACE_FAILURE;
     540              :     }
     541            0 :     *nextPc = regs->r[frameRegState.retColumn];
     542            0 :     if (*nextPc == 0) {
     543            0 :         SCD_DLOG_INF("next pc is 0, finished");
     544            0 :         return TRACE_SUCCESS;
     545              :     }
     546            0 :     if ((args->isFirstStack == false) && (tempSp == regs->r[VOS_R_SP])) {
     547            0 :         SCD_DLOG_INF("sp has not been changed");
     548            0 :         *nextPc = 0;
     549            0 :         return TRACE_SUCCESS;
     550              :     }
     551            0 :     SCD_DLOG_INF("[next pc addr] : 0x%lx", *nextPc);
     552            0 :     return TRACE_SUCCESS;
     553              : }
        

Generated by: LCOV version 2.0-1