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 : }
|