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