• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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