1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dfx_memory.h"
17 #include <algorithm>
18 #include <securec.h>
19 #include "dfx_define.h"
20 #include "dfx_log.h"
21 #include "dwarf_define.h"
22
23 namespace OHOS {
24 namespace HiviewDFX {
25 namespace {
26 #undef LOG_DOMAIN
27 #undef LOG_TAG
28 #define LOG_DOMAIN 0xD002D11
29 #define LOG_TAG "DfxMemory"
30
31 static const int SEVEN_BIT_OFFSET = 7;
32 static const int TWO_BYTE_SIZE = 2;
33 static const int FOUR_BYTE_SIZE = 4;
34 static const int EIGHT_BYTE_SIZE = 8;
35 }
36
ReadReg(int regIdx,uintptr_t * val)37 bool DfxMemory::ReadReg(int regIdx, uintptr_t *val)
38 {
39 if (acc_ != nullptr && acc_->AccessReg(regIdx, val, ctx_) == UNW_ERROR_NONE) {
40 return true;
41 }
42 return false;
43 }
44
ReadMem(uintptr_t addr,uintptr_t * val)45 bool DfxMemory::ReadMem(uintptr_t addr, uintptr_t *val)
46 {
47 if (acc_ != nullptr && acc_->AccessMem(addr, val, ctx_) == UNW_ERROR_NONE) {
48 return true;
49 }
50 return false;
51 }
52
Read(uintptr_t & addr,void * val,size_t size,bool incre)53 size_t DfxMemory::Read(uintptr_t& addr, void* val, size_t size, bool incre)
54 {
55 uintptr_t tmpAddr = addr;
56 uint64_t maxSize;
57 if (val == nullptr || __builtin_add_overflow(tmpAddr, size, &maxSize)) {
58 LOGE("val is nullptr or size(%zu) overflow", size);
59 return 0;
60 }
61 size_t bytesRead = 0;
62 uintptr_t tmpVal;
63 if (alignAddr_ && (alignBytes_ != 0)) {
64 size_t alignBytes = tmpAddr & (static_cast<size_t>(alignBytes_) - 1);
65 if (alignBytes != 0) {
66 uintptr_t alignedAddr = tmpAddr & (~(static_cast<uintptr_t>(alignBytes_)) - 1);
67 LOGU("alignBytes: %zu, alignedAddr: %" PRIx64 "", alignBytes, static_cast<uint64_t>(alignedAddr));
68 if (!ReadMem(alignedAddr, &tmpVal)) {
69 return bytesRead;
70 }
71 uintptr_t valp = static_cast<uintptr_t>(tmpVal);
72 size_t copyBytes = std::min(static_cast<size_t>(alignBytes_) - alignBytes, size);
73 if (memcpy_s(val, copyBytes, reinterpret_cast<uint8_t*>(&valp) + alignBytes, copyBytes) != 0) {
74 return bytesRead;
75 }
76 tmpAddr += copyBytes;
77 val = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(val) + copyBytes);
78 size -= copyBytes;
79 bytesRead += copyBytes;
80 }
81 }
82 for (size_t i = 0; i < size / sizeof(uintptr_t); i++) {
83 if (!ReadMem(tmpAddr, &tmpVal) || memcpy_s(val, sizeof(uintptr_t), &tmpVal, sizeof(uintptr_t)) != 0) {
84 return bytesRead;
85 }
86 val = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(val) + sizeof(uintptr_t));
87 tmpAddr += sizeof(uintptr_t);
88 bytesRead += sizeof(uintptr_t);
89 }
90 size_t leftOver = size & (sizeof(uintptr_t) - 1);
91 if (leftOver) {
92 if (!ReadMem(tmpAddr, &tmpVal) || memcpy_s(val, leftOver, &tmpVal, leftOver) != 0) {
93 return bytesRead;
94 }
95 tmpAddr += leftOver;
96 bytesRead += leftOver;
97 }
98 if (incre) {
99 addr = tmpAddr;
100 }
101 return bytesRead;
102 }
103
ReadU8(uintptr_t & addr,uint8_t * val,bool incre)104 bool DfxMemory::ReadU8(uintptr_t& addr, uint8_t *val, bool incre)
105 {
106 if (Read(addr, val, sizeof(uint8_t), incre) == sizeof(uint8_t)) {
107 return true;
108 }
109 return false;
110 }
111
ReadU16(uintptr_t & addr,uint16_t * val,bool incre)112 bool DfxMemory::ReadU16(uintptr_t& addr, uint16_t *val, bool incre)
113 {
114 if (Read(addr, val, sizeof(uint16_t), incre) == sizeof(uint16_t)) {
115 return true;
116 }
117 return false;
118 }
119
ReadU32(uintptr_t & addr,uint32_t * val,bool incre)120 bool DfxMemory::ReadU32(uintptr_t& addr, uint32_t *val, bool incre)
121 {
122 if (Read(addr, val, sizeof(uint32_t), incre) == sizeof(uint32_t)) {
123 return true;
124 }
125 return false;
126 }
127
ReadU64(uintptr_t & addr,uint64_t * val,bool incre)128 bool DfxMemory::ReadU64(uintptr_t& addr, uint64_t *val, bool incre)
129 {
130 if (Read(addr, val, sizeof(uint64_t), incre) == sizeof(uint64_t)) {
131 return true;
132 }
133 return false;
134 }
135
ReadUptr(uintptr_t & addr,uintptr_t * val,bool incre)136 bool DfxMemory::ReadUptr(uintptr_t& addr, uintptr_t *val, bool incre)
137 {
138 if (Read(addr, val, sizeof(uintptr_t), incre) == sizeof(uintptr_t)) {
139 return true;
140 }
141 return false;
142 }
143
ReadString(uintptr_t & addr,std::string * str,size_t maxSize,bool incre)144 bool DfxMemory::ReadString(uintptr_t& addr, std::string* str, size_t maxSize, bool incre)
145 {
146 char buf[NAME_BUF_LEN];
147 size_t size = 0;
148 uintptr_t ptr = addr;
149 for (size_t offset = 0; offset < maxSize; offset += size) {
150 size_t readn = std::min(sizeof(buf), maxSize - offset);
151 ptr = ptr + offset;
152 size = Read(ptr, buf, readn, false);
153 if (size == 0) {
154 return false;
155 }
156 size_t length = strnlen(buf, size);
157 if (length < size) {
158 if (offset == 0) {
159 str->assign(buf, length);
160 return true;
161 } else {
162 str->assign(offset + length, '\0');
163 Read(addr, (void*)str->data(), str->size(), false);
164 return true;
165 }
166 }
167 }
168 if (incre) {
169 addr += str->size();
170 }
171 return false;
172 }
173
ReadPrel31(uintptr_t & addr,uintptr_t * val)174 bool DfxMemory::ReadPrel31(uintptr_t& addr, uintptr_t *val)
175 {
176 uintptr_t offset;
177 if (!ReadUptr(addr, &offset, false)) {
178 return false;
179 }
180 offset = static_cast<uintptr_t>(static_cast<int32_t>(offset << 1) >> 1);
181 *val = addr + offset;
182 return true;
183 }
184
ReadUleb128(uintptr_t & addr)185 uint64_t DfxMemory::ReadUleb128(uintptr_t& addr)
186 {
187 uint64_t val = 0;
188 uint64_t shift = 0;
189 uint8_t u8 = 0;
190 do {
191 if (!ReadU8(addr, &u8, true)) {
192 break;
193 }
194
195 val |= static_cast<uint64_t>(u8 & 0x7f) << shift;
196 shift += SEVEN_BIT_OFFSET;
197 } while (u8 & 0x80);
198 return val;
199 }
200
ReadSleb128(uintptr_t & addr)201 int64_t DfxMemory::ReadSleb128(uintptr_t& addr)
202 {
203 uint64_t val = 0;
204 uint64_t shift = 0;
205 uint8_t byte = 0;
206 do {
207 if (!ReadU8(addr, &byte, true)) {
208 break;
209 }
210
211 val |= static_cast<uint64_t>(byte & 0x7f) << shift;
212 shift += SEVEN_BIT_OFFSET;
213 } while (byte & 0x80);
214
215 if ((byte & 0x40) != 0) {
216 val |= (-1ULL) << shift;
217 }
218 return static_cast<int64_t>(val);
219 }
220
GetEncodedSize(uint8_t encoding)221 size_t DfxMemory::GetEncodedSize(uint8_t encoding)
222 {
223 switch (encoding & 0x0f) {
224 case DW_EH_PE_absptr:
225 return sizeof(uintptr_t);
226 case DW_EH_PE_udata1:
227 case DW_EH_PE_sdata1:
228 return 1;
229 case DW_EH_PE_udata2:
230 case DW_EH_PE_sdata2:
231 return TWO_BYTE_SIZE;
232 case DW_EH_PE_udata4:
233 case DW_EH_PE_sdata4:
234 return FOUR_BYTE_SIZE;
235 case DW_EH_PE_udata8:
236 case DW_EH_PE_sdata8:
237 return EIGHT_BYTE_SIZE;
238 case DW_EH_PE_uleb128:
239 case DW_EH_PE_sleb128:
240 default:
241 return 0;
242 }
243 }
244
ReadEncodedValue(uintptr_t & addr,uint8_t encoding)245 uintptr_t DfxMemory::ReadEncodedValue(uintptr_t& addr, uint8_t encoding)
246 {
247 uintptr_t startAddr = addr;
248 uintptr_t val = 0;
249 if (encoding == DW_EH_PE_omit) {
250 return val;
251 } else if (encoding == DW_EH_PE_aligned) {
252 if (__builtin_add_overflow(addr, sizeof(uintptr_t) - 1, &addr)) {
253 return val;
254 }
255 addr &= -sizeof(uintptr_t);
256 ReadUptr(addr, &val, true);
257 return val;
258 }
259
260 switch (encoding & DW_EH_PE_FORMAT_MASK) {
261 case DW_EH_PE_absptr:
262 ReadUptr(addr, &val, true);
263 return val;
264 case DW_EH_PE_uleb128:
265 val = static_cast<uintptr_t>(ReadUleb128(addr));
266 break;
267 case DW_EH_PE_sleb128:
268 val = static_cast<uintptr_t>(ReadSleb128(addr));
269 break;
270 case DW_EH_PE_udata1: {
271 uint8_t tmp = 0;
272 ReadU8(addr, &tmp, true);
273 val = static_cast<uintptr_t>(tmp);
274 }
275 break;
276 case DW_EH_PE_sdata1: {
277 int8_t tmp = 0;
278 ReadS8(addr, &tmp, true);
279 val = static_cast<uintptr_t>(tmp);
280 }
281 break;
282 case DW_EH_PE_udata2: {
283 uint16_t tmp = 0;
284 ReadU16(addr, &tmp, true);
285 val = static_cast<uintptr_t>(tmp);
286 }
287 break;
288 case DW_EH_PE_sdata2: {
289 int16_t tmp = 0;
290 ReadS16(addr, &tmp, true);
291 val = static_cast<uintptr_t>(tmp);
292 }
293 break;
294 case DW_EH_PE_udata4: {
295 uint32_t tmp = 0;
296 ReadU32(addr, &tmp, true);
297 val = static_cast<uintptr_t>(tmp);
298 }
299 break;
300 case DW_EH_PE_sdata4: {
301 int32_t tmp = 0;
302 ReadS32(addr, &tmp, true);
303 val = static_cast<uintptr_t>(tmp);
304 }
305 break;
306 case DW_EH_PE_udata8: {
307 uint64_t tmp = 0;
308 ReadU64(addr, &tmp, true);
309 val = static_cast<uintptr_t>(tmp);
310 }
311 break;
312 case DW_EH_PE_sdata8: {
313 int64_t tmp = 0;
314 ReadS64(addr, &tmp, true);
315 val = static_cast<uintptr_t>(tmp);
316 }
317 break;
318 default:
319 LOGW("Unexpected encoding format 0x%x", encoding & DW_EH_PE_FORMAT_MASK);
320 break;
321 }
322
323 switch (encoding & DW_EH_PE_APPL_MASK) {
324 case DW_EH_PE_pcrel:
325 val += startAddr;
326 break;
327 case DW_EH_PE_textrel:
328 LOGE("XXX For now we don't support text-rel values");
329 break;
330 case DW_EH_PE_datarel:
331 val += dataOffset_;
332 break;
333 case DW_EH_PE_funcrel:
334 val += funcOffset_;
335 break;
336 default:
337 break;
338 }
339
340 if (encoding & DW_EH_PE_indirect) {
341 uintptr_t indirectAddr = val;
342 ReadUptr(indirectAddr, &val, true);
343 }
344 return val;
345 }
346 } // namespace HiviewDFX
347 } // namespace OHOS
348