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