• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023-2025 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_errors.h"
21 #include "dfx_log.h"
22 #include "dfx_util.h"
23 #include "dwarf_define.h"
24 
25 namespace OHOS {
26 namespace HiviewDFX {
27 namespace {
28 #undef LOG_DOMAIN
29 #undef LOG_TAG
30 #define LOG_DOMAIN 0xD002D11
31 #define LOG_TAG "DfxMemory"
32 
33 static const int SEVEN_BIT_OFFSET = 7;
34 static const int TWO_BYTE_SIZE = 2;
35 static const int FOUR_BYTE_SIZE = 4;
36 static const int EIGHT_BYTE_SIZE = 8;
37 }
38 
39 #if is_ohos && ! is_mingw
DfxMemory(const UnwindType & unwindType,std::shared_ptr<UnwindAccessors> accessors)40 DfxMemory::DfxMemory(const UnwindType& unwindType, std::shared_ptr<UnwindAccessors> accessors)
41 {
42     switch (unwindType) {
43         case UNWIND_TYPE_LOCAL:
44             acc_ = std::make_shared<DfxAccessorsLocal>();
45             break;
46         case UNWIND_TYPE_REMOTE:
47             acc_ = std::make_shared<DfxAccessorsRemote>();
48             break;
49         case UNWIND_TYPE_CUSTOMIZE:
50             if (accessors != nullptr) {
51                 acc_ = std::make_shared<DfxAccessorsCustomize>(accessors);
52             }
53             break;
54         case UNWIND_TYPE_CUSTOMIZE_LOCAL:
55             if (accessors != nullptr) {
56                 acc_ = std::make_shared<DfxAccessorsCustomize>(accessors);
57             }
58             break;
59         default:
60             break;
61     }
62 }
63 #endif
64 
ReadReg(int regIdx,uintptr_t * val)65 bool DfxMemory::ReadReg(int regIdx, uintptr_t* val)
66 {
67     if (acc_ != nullptr && acc_->AccessReg(regIdx, val, ctx_) == UNW_ERROR_NONE) {
68         return true;
69     }
70     return false;
71 }
72 
ReadMem(uintptr_t addr,uintptr_t * val)73 bool DfxMemory::ReadMem(uintptr_t addr, uintptr_t* val)
74 {
75     if (acc_ != nullptr && acc_->AccessMem(addr, val, ctx_) == UNW_ERROR_NONE) {
76         return true;
77     }
78     return false;
79 }
80 
Read(uintptr_t & addr,void * val,size_t size,bool incre)81 size_t DfxMemory::Read(uintptr_t& addr, void* val, size_t size, bool incre)
82 {
83     uintptr_t tmpAddr = addr;
84     uint64_t maxSize;
85     if (val == nullptr || __builtin_add_overflow(tmpAddr, size, &maxSize)) {
86         DFXLOGE("val is nullptr or size(%{public}zu) overflow", size);
87         return 0;
88     }
89     size_t bytesRead = 0;
90     uintptr_t tmpVal;
91     if (alignAddr_ && (alignBytes_ != 0)) {
92         size_t alignBytes = tmpAddr & (static_cast<size_t>(alignBytes_) - 1);
93         if (alignBytes != 0) {
94             uintptr_t alignedAddr = tmpAddr & (~(static_cast<uintptr_t>(alignBytes_)) - 1);
95             DFXLOGU("alignBytes: %{public}zu, alignedAddr: %{public}" PRIx64 "", alignBytes,
96                 static_cast<uint64_t>(alignedAddr));
97             if (!ReadMem(alignedAddr, &tmpVal)) {
98                 return bytesRead;
99             }
100             uintptr_t valp = static_cast<uintptr_t>(tmpVal);
101             size_t copyBytes = std::min(static_cast<size_t>(alignBytes_) - alignBytes, size);
102             if (memcpy_s(val, size, reinterpret_cast<uint8_t*>(&valp) + alignBytes, copyBytes) != 0) {
103                 return bytesRead;
104             }
105             tmpAddr += copyBytes;
106             val = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(val) + copyBytes);
107             size -= copyBytes;
108             bytesRead += copyBytes;
109         }
110     }
111     for (size_t i = 0; i < size / sizeof(uintptr_t); i++) {
112         if (!ReadMem(tmpAddr, &tmpVal) || memcpy_s(val, sizeof(uintptr_t), &tmpVal, sizeof(uintptr_t)) != 0) {
113             return bytesRead;
114         }
115         val = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(val) + sizeof(uintptr_t));
116         tmpAddr += sizeof(uintptr_t);
117         bytesRead += sizeof(uintptr_t);
118     }
119     size_t leftOver = size & (sizeof(uintptr_t) - 1);
120     if (leftOver) {
121         if (!ReadMem(tmpAddr, &tmpVal) || memcpy_s(val, leftOver, &tmpVal, leftOver) != 0) {
122             return bytesRead;
123         }
124         tmpAddr += leftOver;
125         bytesRead += leftOver;
126     }
127     if (incre) {
128         addr = tmpAddr;
129     }
130     return bytesRead;
131 }
132 
ReadString(uintptr_t & addr,std::string * str,size_t maxSize,bool incre)133 bool DfxMemory::ReadString(uintptr_t& addr, std::string* str, size_t maxSize, bool incre)
134 {
135     if (str == nullptr) {
136         return false;
137     }
138     char buf[NAME_BUF_LEN];
139     size_t size = 0;
140     uintptr_t ptr = addr;
141     for (size_t offset = 0; offset < maxSize; offset += size) {
142         size_t readn = std::min(sizeof(buf), maxSize - offset);
143         ptr = addr + offset;
144         size = Read(ptr, buf, readn, false);
145         if (size == 0) {
146             return false;
147         }
148         size_t length = strnlen(buf, size);
149         if (length < size) {
150             if (offset == 0) {
151                 str->assign(buf, length);
152                 return true;
153             } else {
154                 str->assign(offset + length, '\0');
155                 Read(addr, (void*)str->data(), str->size(), false);
156                 return true;
157             }
158         }
159     }
160     if (incre && str != nullptr) {
161         addr += str->size();
162     }
163     return false;
164 }
165 
ReadPrel31(uintptr_t & addr,uintptr_t * val)166 bool DfxMemory::ReadPrel31(uintptr_t& addr, uintptr_t* val)
167 {
168     uintptr_t offset;
169     if (!Read<uintptr_t>(addr, &offset, false)) {
170         return false;
171     }
172     offset = static_cast<uintptr_t>(static_cast<int32_t>(offset << 1) >> 1);
173     *val = addr + offset;
174     return true;
175 }
176 
ReadUleb128(uintptr_t & addr)177 uint64_t DfxMemory::ReadUleb128(uintptr_t& addr)
178 {
179     uint64_t val = 0;
180     uint64_t shift = 0;
181     uint8_t u8 = 0;
182     do {
183         if (!Read<uint8_t>(addr, &u8, true)) {
184             break;
185         }
186 
187         val |= static_cast<uint64_t>(u8 & 0x7f) << shift;
188         shift += SEVEN_BIT_OFFSET;
189     } while (u8 & 0x80);
190     return val;
191 }
192 
ReadSleb128(uintptr_t & addr)193 int64_t DfxMemory::ReadSleb128(uintptr_t& addr)
194 {
195     uint64_t val = 0;
196     uint64_t shift = 0;
197     uint8_t byte = 0;
198     do {
199         if (!Read<uint8_t>(addr, &byte, true)) {
200             break;
201         }
202 
203         val |= static_cast<uint64_t>(byte & 0x7f) << shift;
204         shift += SEVEN_BIT_OFFSET;
205     } while (byte & 0x80);
206 
207     if ((byte & 0x40) != 0) {
208         val |= (-1ULL) << shift;
209     }
210     return static_cast<int64_t>(val);
211 }
212 
GetEncodedSize(uint8_t encoding)213 size_t DfxMemory::GetEncodedSize(uint8_t encoding)
214 {
215     switch (encoding & 0x0f) {
216         case DW_EH_PE_absptr:
217             return sizeof(uintptr_t);
218         case DW_EH_PE_udata1:
219         case DW_EH_PE_sdata1:
220             return 1;
221         case DW_EH_PE_udata2:
222         case DW_EH_PE_sdata2:
223             return TWO_BYTE_SIZE;
224         case DW_EH_PE_udata4:
225         case DW_EH_PE_sdata4:
226             return FOUR_BYTE_SIZE;
227         case DW_EH_PE_udata8:
228         case DW_EH_PE_sdata8:
229             return EIGHT_BYTE_SIZE;
230         case DW_EH_PE_uleb128:
231         case DW_EH_PE_sleb128:
232         default:
233             return 0;
234     }
235 }
236 
ReadFormatEncodedValue(uintptr_t & addr,uintptr_t & val,uint8_t formatEncoding)237 void DfxMemory::ReadFormatEncodedValue(uintptr_t& addr, uintptr_t& val, uint8_t formatEncoding)
238 {
239     switch (formatEncoding) {
240         case DW_EH_PE_uleb128:
241             val = static_cast<uintptr_t>(ReadUleb128(addr));
242             break;
243         case DW_EH_PE_sleb128:
244             val = static_cast<uintptr_t>(ReadSleb128(addr));
245             break;
246         case DW_EH_PE_udata1:
247             val = static_cast<uintptr_t>(ReadValue<uint8_t>(addr, true));
248             break;
249         case DW_EH_PE_sdata1:
250             val = static_cast<uintptr_t>(ReadValue<int8_t>(addr, true));
251             break;
252         case DW_EH_PE_udata2:
253             val = static_cast<uintptr_t>(ReadValue<uint16_t>(addr, true));
254             break;
255         case DW_EH_PE_sdata2:
256             val = static_cast<uintptr_t>(ReadValue<int16_t>(addr, true));
257             break;
258         case DW_EH_PE_udata4:
259             val = static_cast<uintptr_t>(ReadValue<uint32_t>(addr, true));
260             break;
261         case DW_EH_PE_sdata4:
262             val = static_cast<uintptr_t>(ReadValue<int32_t>(addr, true));
263             break;
264         case DW_EH_PE_udata8:
265             val = static_cast<uintptr_t>(ReadValue<uint64_t>(addr, true));
266             break;
267         case DW_EH_PE_sdata8:
268             val = static_cast<uintptr_t>(ReadValue<int64_t>(addr, true));
269             break;
270         default:
271             DFXLOGW("Unexpected encoding format 0x%{public}x", formatEncoding);
272             break;
273     }
274 }
275 
ReadEncodedValue(uintptr_t & addr,uint8_t encoding)276 uintptr_t DfxMemory::ReadEncodedValue(uintptr_t& addr, uint8_t encoding)
277 {
278     uintptr_t startAddr = addr;
279     uintptr_t val = 0;
280     if (encoding == DW_EH_PE_omit) {
281         return val;
282     } else if (encoding == DW_EH_PE_aligned) {
283         if (__builtin_add_overflow(addr, sizeof(uintptr_t) - 1, &addr)) {
284             return val;
285         }
286         addr &= -sizeof(uintptr_t);
287         Read<uintptr_t>(addr, &val, true);
288         return val;
289     }
290 
291     uint8_t formatEncoding = encoding & DW_EH_PE_FORMAT_MASK;
292     if (formatEncoding == DW_EH_PE_absptr) {
293         Read<uintptr_t>(addr, &val, true);
294         return val;
295     } else {
296         ReadFormatEncodedValue(addr, val, formatEncoding);
297     }
298 
299     switch (encoding & DW_EH_PE_APPL_MASK) {
300         case DW_EH_PE_pcrel:
301             val += startAddr;
302             break;
303         case DW_EH_PE_textrel:
304             DFXLOGE("XXX For now we don't support text-rel values");
305             break;
306         case DW_EH_PE_datarel:
307             val += dataOffset_;
308             break;
309         case DW_EH_PE_funcrel:
310             val += funcOffset_;
311             break;
312         default:
313             break;
314     }
315 
316     if (encoding & DW_EH_PE_indirect) {
317         uintptr_t indirectAddr = val;
318         Read<uintptr_t>(indirectAddr, &val, true);
319     }
320     return val;
321 }
322 
323 #if is_ohos && !is_mingw
ReadProcMemByPid(const pid_t pid,const uint64_t addr,void * data,size_t size)324 size_t DfxMemory::ReadProcMemByPid(const pid_t pid, const uint64_t addr, void* data, size_t size)
325 {
326     return OHOS::HiviewDFX::ReadProcMemByPid(pid, addr, data, size);
327 }
328 #endif
329 
GetMapByPc(uintptr_t pc,std::shared_ptr<DfxMap> & map) const330 int DfxMemory::GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map) const
331 {
332     if (acc_ == nullptr) {
333         return UNW_ERROR_INVALID_MEMORY;
334     }
335     return acc_->GetMapByPc(pc, map, ctx_);
336 }
337 
FindUnwindTable(uintptr_t pc,UnwindTableInfo & uti) const338 int DfxMemory::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti) const
339 {
340     if (acc_ == nullptr) {
341         return UNW_ERROR_INVALID_MEMORY;
342     }
343     return acc_->FindUnwindTable(pc, uti, ctx_);
344 }
345 } // namespace HiviewDFX
346 } // namespace OHOS
347