LCOV - code coverage report
Current view: top level - atrace/utrace/stacktrace - stacktrace_unwind_inner.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 97.2 % 145 141
Test Date: 2026-08-31 10:07:06 Functions: 100.0 % 7 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 "stacktrace_unwind_inner.h"
      12              : #include <stdlib.h>
      13              : #include <pthread.h>
      14              : #include <fcntl.h>
      15              : #include <string.h>
      16              : #include <link.h>
      17              : #include "adiag_utils.h"
      18              : #include "securec.h"
      19              : #include "stacktrace_unwind.h"
      20              : #include "stacktrace_fp.h"
      21              : #include "stacktrace_signal.h"
      22              : #include "stddef.h"
      23              : #include "trace_system_api.h"
      24              : #include "stacktrace_dumper/scd_memory.h"
      25              : #include "scd_log.h"
      26              : 
      27              : /**
      28              :  * @brief       read N bytes from src and move src forward N bytes
      29              :  * @param [in]  src  src addr
      30              :  * @param [out] dst  dst addr
      31              :  * @param [in]  size size to be read
      32              :  *
      33              :  * @return read size, return 0 if failed
      34              :  */
      35        56276 : size_t TraceReadBytes(ScdDwarf* dwarf, const uint8_t** src, void* dst, size_t size)
      36              : {
      37        56276 :     size_t ret = ScdMemoryRead(dwarf->memory, (uintptr_t)(*src), dst, size);
      38        56276 :     if (ret == 0) {
      39           36 :         SCD_DLOG_ERR("memory read failed");
      40           36 :         return 0;
      41              :     }
      42        56240 :     *src += size;
      43        56240 :     return size;
      44              : }
      45              : 
      46              : /**
      47              :  * @brief 从字节流中读取LEB128编码的数值, LEB128类型编码过程: (只介绍保存负数,正数如ULEB128)
      48              :  *               1.从一整数低字节开始分段,1段7位
      49              :  *               2.将这7位作为一个字节,如果几个高字节的是0XFF,则舍去但是,如从低位起一个0xFF的后一字节第7为0
      50              :  *                 则保留该字节并改为0x7f保存,如第7位是1,这舍去该字节,后一字节最高位置1
      51              :  *               ULEB128类型解码过程:
      52              :  *               1.从低地址开始读,若最高位0停止读
      53              :  *               2.每次读的数据高位数据,每次偏移7的倍数倍并与前面的数或运算作为高位
      54              :  *               3.判断最后读出来的字节第七位是否为1,若为1表是负数,则上述结果高位置1
      55              :  * @param [in]  byteStream 字节流指针
      56              :  * @param [out] psvVal 存储读取到的数值的指针
      57              :  *
      58              :  * @return 返回读取到的数值后的字节流指针
      59              :  */
      60         2286 : const uint8_t* TraceReadLeb128(ScdDwarf* dwarf, const uint8_t* byteStream, intptr_t* psvVal)
      61              : {
      62         2286 :     uint32_t shift = 0;
      63              :     uint8_t ucByte;
      64              :     uintptr_t result;
      65         2286 :     uint32_t byteCount = 0;
      66         2286 :     const uint8_t* byteStreamTmp = byteStream;
      67         2286 :     result = 0;
      68              : 
      69              :     do {
      70         2286 :         size_t size = TraceReadBytes(dwarf, &byteStreamTmp, &ucByte, sizeof(uint8_t));
      71         2286 :         SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read byte failed");
      72         2286 :         result |= ((uintptr_t)ucByte & TRACE_GET_LOW_BIT_VALUE) << shift;
      73         2286 :         shift += TRACE_MOVE_BIT_COUNT;
      74         2286 :         byteCount++;
      75         2286 :     } while (((ucByte & TRACE_GET_HIG_BIT_VALUE) != 0) && (byteCount < TRACE_MAX_LEB_BYRE));
      76              : 
      77              :     /* 如果最后一个字节的第7bit不为0时,表示该数是个负数,要转换为实际负数值
      78              :      * 同时保证移位数小于64 */
      79         2286 :     if ((shift < 8U * sizeof(uintptr_t)) && ((ucByte & 0x40U) != 0)) { /* 8表示偏移位数,0x40 */
      80         1152 :         result |= TRACE_LOW_BIT_ZERO(((size_t)1L) << shift);
      81              :     }
      82              : 
      83         2286 :     *psvVal = (intptr_t)result;
      84         2286 :     return byteStreamTmp;
      85              : }
      86              : 
      87              : /**
      88              :  *  @brief 读取Uleb128类型的数据,ULEB128类型编码过程:
      89              :  *               1.从一整数低字节开始分段,1段7位
      90              :  *               2.将这7位作为一个字节,如果几个高字节的是0,则舍去
      91              :  *               3.将新的字节组成字节流,从低字节开始除了最后一个字节,其余最高1
      92              :  *               4.最后一个字节的最高位为0,表示字节流结束
      93              :  *               ULEB128类型解码过程:
      94              :  *               1.从低地址开始读,若最高位0停止读
      95              :  *               2.每次读的数据高位数据,每次偏移7的倍数倍并与前面的数或运算作为高位
      96              :  *
      97              :  * @param [in] byteStream 输入的字节流
      98              :  * @param [out] val 存储读取到的数据
      99              :  * @return 返回读取到的数据后的字节流位置
     100              :  */
     101         2340 : const uint8_t* TraceReadUleb128(ScdDwarf* dwarf, const uint8_t* byteStream, uintptr_t* val)
     102              : {
     103         2340 :     uint32_t shift = 0;
     104              :     uint8_t ucByte;
     105         2340 :     uintptr_t result = 0;
     106         2340 :     uint32_t byteCount = 0;
     107         2340 :     const uint8_t* byteStreamTmp = byteStream;
     108              : 
     109              :     /* Uleb128类型处理方式,在64bit机器上该类型最大10byte(10*7 > 8*8)
     110              :      * 低字节开始读,若字节最高位为0停止读,取每次读的字节低七位作为数据的低七位
     111              :      */
     112              :     do {
     113         2340 :         size_t size = TraceReadBytes(dwarf, &byteStreamTmp, &ucByte, sizeof(uint8_t));
     114         2340 :         SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read byte failed");
     115         2340 :         result |= ((uintptr_t)ucByte & TRACE_GET_LOW_BIT_VALUE) << shift;
     116         2340 :         shift += TRACE_MOVE_BIT_COUNT;
     117         2340 :         byteCount++;
     118         2340 :     } while (((ucByte & TRACE_GET_HIG_BIT_VALUE) != 0) && (byteCount < TRACE_MAX_LEB_BYRE));
     119              : 
     120         2340 :     *val = result;
     121         2340 :     return byteStreamTmp;
     122              : }
     123              : 
     124        23688 : static uint32_t TraceEncDataHighbitParse(const uint8_t encode, const uintptr_t srcAddr, uintptr_t* resultPtr)
     125              : {
     126        23688 :     uintptr_t result = *resultPtr;
     127              : 
     128              :     /* 若编码格式与指针有关,该地址保存的是偏移值 */
     129        23688 :     if (TRACE_MDBIT3_ENCODE(encode) == DW_EH_PE_PCREL) {
     130            0 :         result = result + srcAddr;
     131              :     }
     132              : 
     133              :     /* 若编码类型的最高位是1,表示该地址表示的内容也是个地址,要保证地址合法性 */
     134        23688 :     if (TRACE_HIBIT1_ENCODE(encode) == DW_EH_PE_INDIRECT) {
     135            0 :         result = *(uintptr_t*)result;
     136              :     }
     137              : 
     138        23688 :     *resultPtr = result;
     139              : 
     140        23688 :     return 0;
     141              : }
     142              : 
     143        23984 : static const uint8_t* TraceEncDataLowbitParse(
     144              :     ScdDwarf* dwarf, const uint8_t encode, const uint8_t* segAddr, uintptr_t* resultPtr)
     145              : {
     146        23984 :     uint16_t uint16Value = 0;
     147        23984 :     int16_t int16Value = 0;
     148        23984 :     int32_t int32Value = 0;
     149        23984 :     uint32_t uint32Value = 0;
     150        23984 :     uint64_t uint64Value = 0;
     151        23984 :     int64_t int64Value = 0;
     152        23984 :     intptr_t intptrValue = 0;
     153        23984 :     const uint8_t* segAddrTmp = segAddr;
     154        23984 :     size_t size = 0;
     155              : 
     156              :     /* 对编码类型的低4位进行分别处理 */
     157        23984 :     switch (TRACE_LOBIT4_ENCODE(encode)) {
     158         4626 :         case DW_EH_PE_ABSPTR:
     159         4626 :             size = TraceReadBytes(dwarf, &segAddrTmp, resultPtr, sizeof(uintptr_t));
     160         4626 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     161         4608 :             break;
     162           18 :         case DW_EH_PE_ULEB128:
     163           18 :             segAddrTmp = TraceReadUleb128(dwarf, segAddrTmp, resultPtr);
     164           18 :             SCD_CHK_EXPR_ACTION(segAddrTmp == NULL, return NULL, "read uleb128 failed");
     165           18 :             break;
     166         4644 :         case DW_EH_PE_UDATA2:
     167         4644 :             size = TraceReadBytes(dwarf, &segAddrTmp, &uint16Value, sizeof(uint16_t));
     168         4644 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     169         4644 :             *resultPtr = (uintptr_t)uint16Value;
     170         4644 :             break;
     171          328 :         case DW_EH_PE_UDATA4:
     172          328 :             size = TraceReadBytes(dwarf, &segAddrTmp, &uint32Value, sizeof(uint32_t));
     173          328 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     174          328 :             *resultPtr = (uintptr_t)uint32Value;
     175          328 :             break;
     176         4644 :         case DW_EH_PE_UDATA8:
     177         4644 :             size = TraceReadBytes(dwarf, &segAddrTmp, &uint64Value, sizeof(uint64_t));
     178         4644 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     179         4644 :             *resultPtr = (uintptr_t)uint64Value;
     180         4644 :             break;
     181              :         /* 在FDE里该编码类型几乎不存在,其所占字节与cpubit有关 */
     182         4608 :         case DW_EH_PE_SIGNED:
     183         4608 :             size = TraceReadBytes(dwarf, &segAddrTmp, resultPtr, sizeof(uintptr_t));
     184         4608 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     185         4608 :             break;
     186           18 :         case DW_EH_PE_SLEB128:
     187           18 :             segAddrTmp = TraceReadLeb128(dwarf, segAddrTmp, &intptrValue);
     188           18 :             SCD_CHK_EXPR_ACTION(segAddrTmp == NULL, return NULL, "read leb128 failed");
     189           18 :             *resultPtr = (uintptr_t)intptrValue;
     190           18 :             break;
     191         4644 :         case DW_EH_PE_DATA2:
     192         4644 :             size = TraceReadBytes(dwarf, &segAddrTmp, &int16Value, sizeof(int16_t));
     193         4644 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     194         4644 :             *resultPtr = (uintptr_t)int16Value;
     195         4644 :             break;
     196          328 :         case DW_EH_PE_DATA4:
     197          328 :             size = TraceReadBytes(dwarf, &segAddrTmp, &int32Value, sizeof(int32_t));
     198          328 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     199          328 :             *resultPtr = (uintptr_t)int32Value;
     200          328 :             break;
     201           18 :         case DW_EH_PE_DATA8:
     202           18 :             size = TraceReadBytes(dwarf, &segAddrTmp, &int64Value, sizeof(int64_t));
     203           18 :             SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     204           18 :             *resultPtr = (uintptr_t)int64Value;
     205           18 :             break;
     206          108 :         default:
     207          108 :             *resultPtr = 0;
     208          108 :             segAddrTmp = NULL;
     209          108 :             break;
     210              :     }
     211        23966 :     return segAddrTmp;
     212              : }
     213              : 
     214              : /**
     215              :  * @brief 读取并解码值
     216              :  *
     217              :  * @param [in]   encode 编码类型
     218              :  * @param [in]   byteAddr 字节地址
     219              :  * @param [out]  val 解码后的值
     220              :  *
     221              :  * @return 返回执行后的地址
     222              :  */
     223        51668 : const uint8_t* TraceReadEncodeValue(ScdDwarf* dwarf, const uint8_t encode, const uint8_t* byteAddr, uintptr_t* val)
     224              : {
     225        51668 :     uintptr_t result = 0;
     226              :     uintptr_t srcAddr;
     227              :     uintptr_t alignAddr;
     228        51668 :     const uint8_t* byteAddrTmp = byteAddr;
     229              : 
     230        51668 :     if (encode == DW_EH_PE_OMIT) {
     231           18 :         SCD_DLOG_ERR("encode is DW_EH_PE_OMIT");
     232           18 :         return NULL;
     233              :     }
     234        51650 :     srcAddr = (uintptr_t)byteAddrTmp;
     235        51650 :     if (encode == DW_EH_PE_ALIGNED) {
     236              :         /* 地址高对齐 */
     237        27666 :         alignAddr = (uintptr_t)byteAddrTmp;
     238        27666 :         alignAddr = TRACE_UNWIND_HALIGN(alignAddr);
     239        27666 :         size_t size = TraceReadBytes(dwarf, (const uint8_t**)(&alignAddr), &result, sizeof(uintptr_t));
     240        27666 :         SCD_CHK_EXPR_ACTION(size == 0, return NULL, "read bytes failed");
     241        27666 :         byteAddrTmp = (const uint8_t*)alignAddr;
     242              :     } else {
     243              :         /* 对编码类型的低4位进行分别处理 */
     244        23984 :         byteAddrTmp = TraceEncDataLowbitParse(dwarf, encode, byteAddrTmp, &result);
     245        23984 :         TRACE_UNWIND_PARSE_ADDR_CHECK_OR_RETURN(byteAddrTmp);
     246              : 
     247        23858 :         if (result != 0) {
     248              :             /* 对编码类型的高4位进行分别处理 */
     249        23688 :             if (TraceEncDataHighbitParse(encode, srcAddr, &result) != 0) {
     250            0 :                 SCD_DLOG_ERR("TraceEncDataHighbitParse failed");
     251            0 :                 return NULL;
     252              :             }
     253              :         }
     254              :     }
     255        51524 :     *val = result;
     256        51524 :     return byteAddrTmp;
     257              : }
     258              : 
     259              : /**
     260              :  * 获取编码值的大小
     261              :  *
     262              :  * @param encode 编码类型
     263              :  * @return 编码值的大小
     264              :  */
     265         4590 : size_t TraceEncValueSizeGet(uint8_t encode)
     266              : {
     267         4590 :     size_t encSize = 0;
     268              : 
     269         4590 :     switch (encode & 0x07U) { /* 0x07 */
     270          576 :         case DW_EH_PE_ABSPTR:
     271          576 :             encSize = sizeof(void*);
     272          576 :             break;
     273          576 :         case DW_EH_PE_UDATA2:
     274          576 :             encSize = sizeof(uint16_t);
     275          576 :             break;
     276          576 :         case DW_EH_PE_UDATA4:
     277          576 :             encSize = sizeof(uint32_t);
     278          576 :             break;
     279          576 :         case DW_EH_PE_UDATA8:
     280          576 :             encSize = sizeof(uint64_t);
     281          576 :             break;
     282         2286 :         default:
     283         2286 :             break;
     284              :     }
     285              : 
     286         4590 :     return encSize;
     287              : }
        

Generated by: LCOV version 2.0-1