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

Generated by: LCOV version 2.0-1