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