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