• 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         LOGE("val is nullptr or size(%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             LOGU("alignBytes: %zu, alignedAddr: %" PRIx64 "", alignBytes, static_cast<uint64_t>(alignedAddr));
72             if (!ReadMem(alignedAddr, &tmpVal)) {
73                 return bytesRead;
74             }
75             uintptr_t valp = static_cast<uintptr_t>(tmpVal);
76             size_t copyBytes = std::min(static_cast<size_t>(alignBytes_) - alignBytes, size);
77             if (memcpy_s(val, copyBytes, reinterpret_cast<uint8_t*>(&valp) + alignBytes, copyBytes) != 0) {
78                 return bytesRead;
79             }
80             tmpAddr += copyBytes;
81             val = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(val) + copyBytes);
82             size -= copyBytes;
83             bytesRead += copyBytes;
84         }
85     }
86     for (size_t i = 0; i < size / sizeof(uintptr_t); i++) {
87         if (!ReadMem(tmpAddr, &tmpVal) || memcpy_s(val, sizeof(uintptr_t), &tmpVal, sizeof(uintptr_t)) != 0) {
88             return bytesRead;
89         }
90         val = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(val) + sizeof(uintptr_t));
91         tmpAddr += sizeof(uintptr_t);
92         bytesRead += sizeof(uintptr_t);
93     }
94     size_t leftOver = size & (sizeof(uintptr_t) - 1);
95     if (leftOver) {
96         if (!ReadMem(tmpAddr, &tmpVal) || memcpy_s(val, leftOver, &tmpVal, leftOver) != 0) {
97             return bytesRead;
98         }
99         tmpAddr += leftOver;
100         bytesRead += leftOver;
101     }
102     if (incre) {
103         addr = tmpAddr;
104     }
105     return bytesRead;
106 }
107 
ReadU8(uintptr_t & addr,uint8_t * val,bool incre)108 bool DfxMemory::ReadU8(uintptr_t& addr, uint8_t *val, bool incre)
109 {
110     if (Read(addr, val, sizeof(uint8_t), incre) == sizeof(uint8_t)) {
111         return true;
112     }
113     return false;
114 }
115 
ReadU16(uintptr_t & addr,uint16_t * val,bool incre)116 bool DfxMemory::ReadU16(uintptr_t& addr, uint16_t *val, bool incre)
117 {
118     if (Read(addr, val, sizeof(uint16_t), incre) == sizeof(uint16_t)) {
119         return true;
120     }
121     return false;
122 }
123 
ReadU32(uintptr_t & addr,uint32_t * val,bool incre)124 bool DfxMemory::ReadU32(uintptr_t& addr, uint32_t *val, bool incre)
125 {
126     if (Read(addr, val, sizeof(uint32_t), incre) == sizeof(uint32_t)) {
127         return true;
128     }
129     return false;
130 }
131 
ReadU64(uintptr_t & addr,uint64_t * val,bool incre)132 bool DfxMemory::ReadU64(uintptr_t& addr, uint64_t *val, bool incre)
133 {
134     if (Read(addr, val, sizeof(uint64_t), incre) == sizeof(uint64_t)) {
135         return true;
136     }
137     return false;
138 }
139 
ReadUptr(uintptr_t & addr,uintptr_t * val,bool incre)140 bool DfxMemory::ReadUptr(uintptr_t& addr, uintptr_t *val, bool incre)
141 {
142     if (Read(addr, val, sizeof(uintptr_t), incre) == sizeof(uintptr_t)) {
143         return true;
144     }
145     return false;
146 }
147 
ReadString(uintptr_t & addr,std::string * str,size_t maxSize,bool incre)148 bool DfxMemory::ReadString(uintptr_t& addr, std::string* str, size_t maxSize, bool incre)
149 {
150     if (str == nullptr) {
151         return false;
152     }
153     char buf[NAME_BUF_LEN];
154     size_t size = 0;
155     uintptr_t ptr = addr;
156     for (size_t offset = 0; offset < maxSize; offset += size) {
157         size_t readn = std::min(sizeof(buf), maxSize - offset);
158         ptr = ptr + offset;
159         size = Read(ptr, buf, readn, false);
160         if (size == 0) {
161             return false;
162         }
163         size_t length = strnlen(buf, size);
164         if (length < size) {
165             if (offset == 0) {
166                 str->assign(buf, length);
167                 return true;
168             } else {
169                 str->assign(offset + length, '\0');
170                 Read(addr, (void*)str->data(), str->size(), false);
171                 return true;
172             }
173         }
174     }
175     if (incre && str != nullptr) {
176         addr += str->size();
177     }
178     return false;
179 }
180 
ReadPrel31(uintptr_t & addr,uintptr_t * val)181 bool DfxMemory::ReadPrel31(uintptr_t& addr, uintptr_t *val)
182 {
183     uintptr_t offset;
184     if (!ReadUptr(addr, &offset, false)) {
185         return false;
186     }
187     offset = static_cast<uintptr_t>(static_cast<int32_t>(offset << 1) >> 1);
188     *val = addr + offset;
189     return true;
190 }
191 
ReadUleb128(uintptr_t & addr)192 uint64_t DfxMemory::ReadUleb128(uintptr_t& addr)
193 {
194     uint64_t val = 0;
195     uint64_t shift = 0;
196     uint8_t u8 = 0;
197     do {
198         if (!ReadU8(addr, &u8, true)) {
199             break;
200         }
201 
202         val |= static_cast<uint64_t>(u8 & 0x7f) << shift;
203         shift += SEVEN_BIT_OFFSET;
204     } while (u8 & 0x80);
205     return val;
206 }
207 
ReadSleb128(uintptr_t & addr)208 int64_t DfxMemory::ReadSleb128(uintptr_t& addr)
209 {
210     uint64_t val = 0;
211     uint64_t shift = 0;
212     uint8_t byte = 0;
213     do {
214         if (!ReadU8(addr, &byte, true)) {
215             break;
216         }
217 
218         val |= static_cast<uint64_t>(byte & 0x7f) << shift;
219         shift += SEVEN_BIT_OFFSET;
220     } while (byte & 0x80);
221 
222     if ((byte & 0x40) != 0) {
223         val |= (-1ULL) << shift;
224     }
225     return static_cast<int64_t>(val);
226 }
227 
GetEncodedSize(uint8_t encoding)228 size_t DfxMemory::GetEncodedSize(uint8_t encoding)
229 {
230     switch (encoding & 0x0f) {
231         case DW_EH_PE_absptr:
232             return sizeof(uintptr_t);
233         case DW_EH_PE_udata1:
234         case DW_EH_PE_sdata1:
235             return 1;
236         case DW_EH_PE_udata2:
237         case DW_EH_PE_sdata2:
238             return TWO_BYTE_SIZE;
239         case DW_EH_PE_udata4:
240         case DW_EH_PE_sdata4:
241             return FOUR_BYTE_SIZE;
242         case DW_EH_PE_udata8:
243         case DW_EH_PE_sdata8:
244             return EIGHT_BYTE_SIZE;
245         case DW_EH_PE_uleb128:
246         case DW_EH_PE_sleb128:
247         default:
248             return 0;
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         ReadUptr(addr, &val, true);
264         return val;
265     }
266 
267     switch (encoding & DW_EH_PE_FORMAT_MASK) {
268         case DW_EH_PE_absptr:
269             ReadUptr(addr, &val, true);
270             return val;
271         case DW_EH_PE_uleb128:
272             val = static_cast<uintptr_t>(ReadUleb128(addr));
273             break;
274         case DW_EH_PE_sleb128:
275             val = static_cast<uintptr_t>(ReadSleb128(addr));
276             break;
277         case DW_EH_PE_udata1: {
278             uint8_t tmp = 0;
279             ReadU8(addr, &tmp, true);
280             val = static_cast<uintptr_t>(tmp);
281         }
282             break;
283         case DW_EH_PE_sdata1: {
284             int8_t tmp = 0;
285             ReadS8(addr, &tmp, true);
286             val = static_cast<uintptr_t>(tmp);
287         }
288             break;
289         case DW_EH_PE_udata2: {
290             uint16_t tmp = 0;
291             ReadU16(addr, &tmp, true);
292             val = static_cast<uintptr_t>(tmp);
293         }
294             break;
295         case DW_EH_PE_sdata2: {
296             int16_t tmp = 0;
297             ReadS16(addr, &tmp, true);
298             val = static_cast<uintptr_t>(tmp);
299         }
300             break;
301         case DW_EH_PE_udata4: {
302             uint32_t tmp = 0;
303             ReadU32(addr, &tmp, true);
304             val = static_cast<uintptr_t>(tmp);
305         }
306             break;
307         case DW_EH_PE_sdata4: {
308             int32_t tmp = 0;
309             ReadS32(addr, &tmp, true);
310             val = static_cast<uintptr_t>(tmp);
311         }
312             break;
313         case DW_EH_PE_udata8: {
314             uint64_t tmp = 0;
315             ReadU64(addr, &tmp, true);
316             val = static_cast<uintptr_t>(tmp);
317         }
318             break;
319         case DW_EH_PE_sdata8: {
320             int64_t tmp = 0;
321             ReadS64(addr, &tmp, true);
322             val = static_cast<uintptr_t>(tmp);
323         }
324             break;
325         default:
326             LOGW("Unexpected encoding format 0x%x", encoding & DW_EH_PE_FORMAT_MASK);
327             break;
328     }
329 
330     switch (encoding & DW_EH_PE_APPL_MASK) {
331         case DW_EH_PE_pcrel:
332             val += startAddr;
333             break;
334         case DW_EH_PE_textrel:
335             LOGE("%s", "XXX For now we don't support text-rel values");
336             break;
337         case DW_EH_PE_datarel:
338             val += dataOffset_;
339             break;
340         case DW_EH_PE_funcrel:
341             val += funcOffset_;
342             break;
343         default:
344             break;
345     }
346 
347     if (encoding & DW_EH_PE_indirect) {
348         uintptr_t indirectAddr = val;
349         ReadUptr(indirectAddr, &val, true);
350     }
351     return val;
352 }
353 #if is_ohos && !is_mingw
ReadProcMemByPid(const pid_t pid,const uint64_t addr,void * data,size_t size)354 size_t DfxMemory::ReadProcMemByPid(const pid_t pid, const uint64_t addr, void* data, size_t size)
355 {
356     constexpr size_t maxSize = 64;
357     struct iovec RemoteIovs[maxSize];
358 
359     uint64_t cur = addr;
360     size_t totalRead = 0;
361     struct iovec dataIov = {
362         .iov_base = &reinterpret_cast<uint8_t*>(data)[totalRead],
363         .iov_len = size,
364     };
365     size_t iovecsIndex = 0;
366     while (size > 0) {
367         if (cur >= UINTPTR_MAX) {
368             return totalRead;
369         }
370         RemoteIovs[iovecsIndex].iov_base = reinterpret_cast<void*>(cur);
371         uintptr_t misalign = cur & static_cast<uint64_t>(getpagesize() - 1);
372         size_t iovLen = std::min(getpagesize() - misalign, size);
373 
374         size -= iovLen;
375         if (__builtin_add_overflow(cur, iovLen, &cur)) {
376             return totalRead;
377         }
378 
379         RemoteIovs[iovecsIndex].iov_len = iovLen;
380         ++iovecsIndex;
381         if (iovecsIndex >= maxSize || size <= 0) {
382             ssize_t count = process_vm_readv(pid, &dataIov, 1, RemoteIovs, iovecsIndex, 0);
383             if (count == -1) {
384                 return totalRead;
385             }
386             totalRead += static_cast<size_t>(count);
387             if (iovecsIndex >= maxSize) {
388                 iovecsIndex -= maxSize;
389             }
390             dataIov.iov_base = &reinterpret_cast<uint8_t*>(data)[totalRead];
391             dataIov.iov_len = size;
392         }
393     }
394 
395     return totalRead;
396 }
397 #endif
398 } // namespace HiviewDFX
399 } // namespace OHOS
400