1 /*
2 * Copyright (c) 2021 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 #define HILOG_TAG "CallStack"
16
17 #include "call_stack.h"
18
19 #include <string>
20 #if HAVE_LIBUNWIND
21 #include <libunwind.h>
22 extern "C" {
23 #include <libunwind_i.h>
24 }
25 #endif
26
27 #include "register.h"
28 #ifdef target_cpu_arm
29 // reg size is int (unw_word_t)
30 #define UNW_WORD_PFLAG "x"
31 #else
32 // reg size is long (unw_word_t)
33 #define UNW_WORD_PFLAG "zx"
34 #endif
35 namespace OHOS {
36 namespace Developtools {
37 namespace NativeDaemon {
38 #if HAVE_LIBUNWIND
39 const std::map<unw_error_t, const std::string> UNW_ERROR_MAP = {
40 {UNW_ESUCCESS, std::to_string(UNW_ESUCCESS)},
41 {UNW_EUNSPEC, std::to_string(UNW_EUNSPEC)},
42 {UNW_ENOMEM, std::to_string(UNW_ENOMEM)},
43 {UNW_EBADREG, std::to_string(UNW_EBADREG)},
44 {UNW_EREADONLYREG, std::to_string(UNW_EREADONLYREG)},
45 {UNW_ESTOPUNWIND, std::to_string(UNW_ESTOPUNWIND)},
46 {UNW_EINVALIDIP, std::to_string(UNW_EINVALIDIP)},
47 {UNW_EBADFRAME, std::to_string(UNW_EBADFRAME)},
48 {UNW_EINVAL, std::to_string(UNW_EINVAL)},
49 {UNW_EBADVERSION, std::to_string(UNW_EBADVERSION)},
50 {UNW_ENOINFO, std::to_string(UNW_ENOINFO)},
51 };
GetUnwErrorName(int error)52 const std::string CallStack::GetUnwErrorName(int error)
53 {
54 if (UNW_ERROR_MAP.count(static_cast<unw_error_t>(-error)) > 0) {
55 return UNW_ERROR_MAP.at(static_cast<unw_error_t>(-error));
56 } else {
57 return "UNKNOW_UNW_ERROR";
58 }
59 }
60
dumpUDI(unw_dyn_info_t & di)61 void CallStack::dumpUDI(unw_dyn_info_t &di)
62 {
63 HLOGV("unwind_table info: ");
64 HLOGV(" di.start_ip: 0x%016" UNW_WORD_PFLAG "", di.start_ip);
65 HLOGV(" di.end_ip: 0x%016" UNW_WORD_PFLAG "", di.end_ip);
66 HLOGV(" di.u.rti.segbase: 0x%016" UNW_WORD_PFLAG "", di.u.rti.segbase);
67 HLOGV(" di.u.rti.table_data: 0x%016" UNW_WORD_PFLAG "", di.u.rti.table_data);
68 HLOGV(" di.u.rti.table_len: 0x%016" UNW_WORD_PFLAG "", di.u.rti.table_len);
69 }
70
fillUDI(unw_dyn_info_t & di,SymbolsFile & symbolsFile,const MemMapItem & mmap,const VirtualThread & thread)71 bool CallStack::fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, const MemMapItem &mmap,
72 const VirtualThread &thread)
73 {
74 uint64_t fdeTableElfOffset = 0;
75 uint64_t fdeTableSize = 0;
76 uint64_t ehFrameHdrElfOffset = 0;
77 uint64_t SectionVaddr = 0;
78 uint64_t SectionSize = 0;
79 uint64_t SectionFileOffset = 0;
80 di.start_ip = mmap.begin_;
81 di.end_ip = mmap.end_;
82 #ifndef target_cpu_arm
83 if ((UNW_INFO_FORMAT_REMOTE_TABLE == di.format) &&
84 symbolsFile.GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize)) {
85 /*
86 unw_word_t name_ptr; // addr. of table name (e.g., library name)
87 unw_word_t segbase; // segment base
88 unw_word_t table_len; // must be a multiple of sizeof(unw_word_t)!
89 unw_word_t table_data;
90 */
91 /*
92 all the rti addr is offset of the elf file
93 begin - page offset = elf file base addr in vaddr user space
94 begin - page offset + elf offset = vaddr in real word.(for this thread)
95 */
96
97 // segbase is file offset .
98 /*
99 00200000-00344000 r--p 00000000 08:02 46404365
100 00344000-005c4000 r-xp 00143000 08:02 46404365
101
102 LOAD 0x00000000001439c0 0x00000000003449c0 0x00000000003449c0
103 0x000000000027f3c0 0x000000000027f3c0 R E 0x1000
104
105 GNU_EH_FRAME 0x00000000000f3248 0x00000000002f3248 0x00000000002f3248
106 0x000000000000bb04 0x000000000000bb04 R 0x4
107
108 */
109 const MemMapItem *ehFrameMmap = thread.FindMapByFileInfo(mmap.name_, ehFrameHdrElfOffset);
110
111 if (ehFrameMmap == nullptr) {
112 HLOGE("no ehframe mmap found.");
113 return false;
114 }
115
116 di.u.rti.segbase = ehFrameMmap->begin_ + ehFrameHdrElfOffset - ehFrameMmap->pageoffset_;
117 di.u.rti.table_data = ehFrameMmap->begin_ + fdeTableElfOffset - ehFrameMmap->pageoffset_;
118 di.u.rti.table_len = fdeTableSize / sizeof(unw_word_t);
119
120 HLOGV(" map pageoffset: 0x%016" PRIx64 "", mmap.pageoffset_);
121 HLOGV(" ehFrameHdrElfOffset: 0x%016" PRIx64 "", ehFrameHdrElfOffset);
122 HLOGV(" fdeTableElfOffset: 0x%016" PRIx64 "", fdeTableElfOffset);
123 HLOGV(" fdeTableSize: 0x%016" PRIx64 "", fdeTableSize);
124 return true;
125 }
126 #else
127 if ((UNW_INFO_FORMAT_ARM_EXIDX == di.format) &&
128 symbolsFile.GetSectionInfo(ARM_EXIDX, SectionVaddr, SectionSize, SectionFileOffset)) {
129 const MemMapItem *targetMmap = thread.FindMapByFileInfo(mmap.name_, SectionFileOffset);
130 if (targetMmap == nullptr) {
131 HLOGE("no debug mmap found.");
132 return false;
133 }
134 HLOGV(" begin: %" PRIx64 " offset:%" PRIx64 "", targetMmap->begin_,
135 targetMmap->pageoffset_);
136
137 di.u.rti.table_data = targetMmap->begin_ + SectionFileOffset - targetMmap->pageoffset_;
138 di.u.rti.table_len = SectionSize;
139 HLOGV(" SectionName: %s", std::string(ARM_EXIDX).c_str());
140 HLOGV(" SectionVaddrt: 0x%016" PRIx64 "", SectionVaddr);
141 HLOGV(" SectionFileOffset 0x%016" PRIx64 "", SectionFileOffset);
142 HLOGV(" SectionSize: 0x%016" PRIx64 "", SectionSize);
143
144 // GetSectionInfo return true, but SectionVaddr || SectionSize is 0 ???
145 HLOG_ASSERT(SectionVaddr != 0 && SectionSize != 0);
146 return true;
147 }
148 #endif
149 return false;
150 }
151
152 /*
153 https://www.nongnu.org/libunwind/man/libunwind-dynamic(3).html
154 */
FindUnwindTable(SymbolsFile * symbolsFile,const MemMapItem & mmap,UnwindInfo * unwindInfoPtr,unw_addr_space_t as,unw_word_t ip,unw_proc_info_t * pi,int need_unwind_info,void * arg)155 int CallStack::FindUnwindTable(SymbolsFile *symbolsFile, const MemMapItem &mmap,
156 UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip,
157 unw_proc_info_t *pi, int need_unwind_info, void *arg)
158 {
159 HLOGV("try seach debug info at %s", symbolsFile->filePath_.c_str());
160 auto &dynInfoProcessMap = unwindInfoPtr->callStack.unwindDynInfoMap_;
161 // all the thread in same process have same mmap and symbols
162 if (dynInfoProcessMap.find(unwindInfoPtr->thread.pid_) == dynInfoProcessMap.end()) {
163 dynInfoProcessMap.emplace(unwindInfoPtr->thread.pid_, dsoUnwDynInfoMap {});
164 }
165 dsoUnwDynInfoMap &dynFileMap = dynInfoProcessMap[unwindInfoPtr->thread.pid_];
166 // find use dso name as key
167 if (dynFileMap.find(symbolsFile->filePath_) == dynFileMap.end()) {
168 // we make a option empty value first
169 std::optional<unw_dyn_info_t> &odi = dynFileMap[symbolsFile->filePath_];
170
171 unw_dyn_info_t newdi;
172 memset_s(&newdi, sizeof(unw_dyn_info_t), 0, sizeof(unw_dyn_info_t));
173 #ifdef target_cpu_arm
174 // arm use .ARM.exidx , not use ehframe
175 newdi.format = UNW_INFO_FORMAT_ARM_EXIDX;
176 #else
177 // otherwise we use EH FRAME
178 newdi.format = UNW_INFO_FORMAT_REMOTE_TABLE;
179 #endif
180 if (fillUDI(newdi, *symbolsFile, mmap, unwindInfoPtr->thread)) {
181 dumpUDI(newdi);
182 odi = newdi;
183 }
184 }
185
186 HLOG_ASSERT(dynInfoProcessMap.find(unwindInfoPtr->thread.pid_) != dynInfoProcessMap.end());
187 HLOG_ASSERT_MESSAGE(dynFileMap.find(symbolsFile->filePath_) != dynFileMap.end(), "%s",
188 symbolsFile->filePath_.c_str());
189 std::optional<unw_dyn_info_t> &odi =
190 dynInfoProcessMap.at(unwindInfoPtr->thread.pid_).at(symbolsFile->filePath_);
191
192 if (odi.has_value()) {
193 unw_dyn_info_t &di = odi.value();
194 /*
195 we dont use dwarf_search_unwind_table
196 because in arm it will search two function:
197 1 arm_search_unwind_table first
198 2 dwarf_search_unwind_table
199
200 see libunwind_i.h for arm
201 define tdep_search_unwind_table UNW_OBJ(search_unwind_table)
202
203 */
204 int ret = static_cast<unw_error_t>(
205 tdep_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg));
206
207 HLOGM("search_unwind_table ret %d:%s", ret, GetUnwErrorName(ret).c_str());
208
209 if (UNW_ESUCCESS != ret) {
210 if (UNW_ENOINFO != ret) {
211 HLOGW("search_unwind_table ret error %d:%s", ret, GetUnwErrorName(ret).c_str());
212 }
213 return -UNW_EUNSPEC;
214 } else {
215 return UNW_ESUCCESS;
216 }
217 } else {
218 HLOGW("no debug info found for thread %d:%s", unwindInfoPtr->thread.tid_,
219 unwindInfoPtr->thread.name_.c_str());
220 return -UNW_EUNSPEC;
221 }
222 }
223
FindProcInfo(unw_addr_space_t as,unw_word_t ip,unw_proc_info_t * pi,int need_unwind_info,void * arg)224 int CallStack::FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
225 int need_unwind_info, void *arg)
226 {
227 UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg);
228
229 HLOGM("need_unwind_info ret %d ip %" UNW_WORD_PFLAG "", need_unwind_info, ip);
230 const MemMapItem *mmap = unwindInfoPtr->thread.FindMapByAddr(ip);
231 if (mmap != nullptr) {
232 SymbolsFile *symbolsFile = unwindInfoPtr->thread.FindSymbolsFileByMap(*mmap);
233 if (symbolsFile != nullptr) {
234 return FindUnwindTable(symbolsFile, *mmap, unwindInfoPtr, as, ip, pi, need_unwind_info,
235 arg);
236 } else {
237 HLOGW("no symbols file found for thread %d:%s", unwindInfoPtr->thread.tid_,
238 unwindInfoPtr->thread.name_.c_str());
239 }
240 } else {
241 HLOGE("ip 0x%016" UNW_WORD_PFLAG " not found in thread %d:%s", ip,
242 unwindInfoPtr->thread.tid_, unwindInfoPtr->thread.name_.c_str());
243 }
244
245 return -UNW_EUNSPEC;
246 }
247
ReadVirtualThreadMemory(UnwindInfo & unwindInfoPtr,unw_word_t addr,unw_word_t * data)248 bool CallStack::ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, unw_word_t addr,
249 unw_word_t *data)
250 {
251 auto process = unwindInfoPtr.callStack.porcessMemoryMap_.find(unwindInfoPtr.thread.pid_);
252 if (process != unwindInfoPtr.callStack.porcessMemoryMap_.end()) {
253 auto memory = process->second.find(addr);
254 if (memory != process->second.end()) {
255 *data = memory->second;
256 return true;
257 }
258 }
259
260 if (unwindInfoPtr.thread.ReadRoMemory(addr, (uint8_t *)data, sizeof(unw_word_t))) {
261 unwindInfoPtr.callStack.porcessMemoryMap_[unwindInfoPtr.thread.pid_][addr] = *data;
262 return true;
263 } else {
264 return false;
265 }
266 }
267
AccessMem(unw_addr_space_t as,unw_word_t addr,unw_word_t * valuePoint,int writeOperation,void * arg)268 int CallStack::AccessMem([[maybe_unused]] unw_addr_space_t as, unw_word_t addr,
269 unw_word_t *valuePoint, int writeOperation, void *arg)
270 {
271 UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg);
272 size_t stackOffset = 0;
273 *valuePoint = 0;
274 HLOGDUMMY("try access addr 0x%" UNW_WORD_PFLAG " ", addr);
275
276 HLOG_ASSERT(writeOperation == 0);
277
278 /* Check overflow. */
279 if (addr + sizeof(unw_word_t) < addr) {
280 HLOGE("address overfolw at 0x%" UNW_WORD_PFLAG " increase 0x%zu", addr, sizeof(unw_word_t));
281 return -UNW_EUNSPEC;
282 }
283
284 if (addr < unwindInfoPtr->callStack.stackPoint_ or
285 addr + sizeof(unw_word_t) >= unwindInfoPtr->callStack.stackEnd_) {
286 if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, valuePoint)) {
287 HLOGM("access_mem addr %p get val 0x%" UNW_WORD_PFLAG ", from mmap",
288 reinterpret_cast<void *>(addr), *valuePoint);
289 } else {
290 HLOGW("access_mem addr %p failed, from mmap, ", reinterpret_cast<void *>(addr));
291 HLOGW("stack range 0x%" PRIx64 " - 0x%" PRIx64 "(0x%" PRIx64 ")",
292 unwindInfoPtr->callStack.stackPoint_, unwindInfoPtr->callStack.stackEnd_,
293 unwindInfoPtr->callStack.stackEnd_ - unwindInfoPtr->callStack.stackPoint_);
294 return -UNW_EUNSPEC;
295 }
296 } else {
297 stackOffset = addr - unwindInfoPtr->callStack.stackPoint_;
298 *valuePoint = *(unw_word_t *)&unwindInfoPtr->callStack.stack_[stackOffset];
299 HLOGM("access_mem addr %p val %" UNW_WORD_PFLAG ", from stack offset %zu",
300 reinterpret_cast<void *>(addr), *valuePoint, stackOffset);
301 }
302
303 return UNW_ESUCCESS;
304 }
305
AccessReg(unw_addr_space_t as,unw_regnum_t regnum,unw_word_t * valuePoint,int writeOperation,void * arg)306 int CallStack::AccessReg([[maybe_unused]] unw_addr_space_t as, unw_regnum_t regnum,
307 unw_word_t *valuePoint, int writeOperation, void *arg)
308 {
309 UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg);
310 uint64_t val;
311 size_t perfRegIndex = LibunwindRegIdToPerfReg(regnum);
312 if (perfRegIndex < PERF_REG_ARM64_X29) {
313 // libunwind not access other regs
314 HLOGE("access_reg not expected %d", regnum);
315 }
316 /* Don't support write, I suspect we don't need it. */
317 if (writeOperation) {
318 HLOGE("access_reg %d", regnum);
319 return -UNW_EINVAL;
320 }
321
322 if (unwindInfoPtr->callStack.regsNum_ == 0) {
323 return -UNW_EUNSPEC;
324 }
325 if (!RegisterGetValue(val, unwindInfoPtr->callStack.regs_, perfRegIndex,
326 unwindInfoPtr->callStack.regsNum_)) {
327 HLOGE("can't read reg %zu", perfRegIndex);
328 return -UNW_EUNSPEC;
329 }
330 *valuePoint = (unw_word_t)val;
331 HLOGV("reg %d:%s, val 0x%" UNW_WORD_PFLAG "", regnum, RegisterGetName(perfRegIndex).c_str(),
332 *valuePoint);
333 return UNW_ESUCCESS;
334 }
335
PutUnwindInfo(unw_addr_space_t as,unw_proc_info_t * pi,void * arg)336 void CallStack::PutUnwindInfo([[maybe_unused]] unw_addr_space_t as,
337 [[maybe_unused]] unw_proc_info_t *pi, [[maybe_unused]] void *arg)
338 {
339 }
340
AccessFpreg(unw_addr_space_t as,unw_regnum_t num,unw_fpreg_t * val,int writeOperation,void * arg)341 int CallStack::AccessFpreg([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_regnum_t num,
342 [[maybe_unused]] unw_fpreg_t *val, [[maybe_unused]] int writeOperation,
343 [[maybe_unused]] void *arg)
344 {
345 return -UNW_EINVAL;
346 }
347
GetDynInfoListAaddr(unw_addr_space_t as,unw_word_t * dil_vaddr,void * arg)348 int CallStack::GetDynInfoListAaddr([[maybe_unused]] unw_addr_space_t as,
349 [[maybe_unused]] unw_word_t *dil_vaddr,
350 [[maybe_unused]] void *arg)
351 {
352 return -UNW_ENOINFO;
353 }
354
Resume(unw_addr_space_t as,unw_cursor_t * cu,void * arg)355 int CallStack::Resume([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_cursor_t *cu,
356 [[maybe_unused]] void *arg)
357 {
358 return -UNW_EINVAL;
359 }
360
getProcName(unw_addr_space_t as,unw_word_t addr,char * bufp,size_t buf_len,unw_word_t * offp,void * arg)361 int CallStack::getProcName([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_word_t addr,
362 [[maybe_unused]] char *bufp, [[maybe_unused]] size_t buf_len,
363 [[maybe_unused]] unw_word_t *offp, [[maybe_unused]] void *arg)
364 {
365 return -UNW_EINVAL;
366 }
367
UnwindStep(unw_cursor_t & c,std::vector<CallFrame> & callStack,size_t maxStackLevel)368 void CallStack::UnwindStep(unw_cursor_t &c, std::vector<CallFrame> &callStack, size_t maxStackLevel)
369 {
370 while (callStack.size() < maxStackLevel) {
371 int ret = unw_step(&c);
372 if (ret > 0) {
373 unw_word_t ip = 0;
374 unw_word_t sp = 0;
375 unw_get_reg(&c, UNW_REG_IP, &ip);
376 unw_get_reg(&c, UNW_REG_SP, &sp);
377
378 if (ip == 0) {
379 HLOGD("ip == 0 something is wrong. break");
380 break;
381 }
382
383 /*
384 * Decrement the IP for any non-activation frames.
385 * this is required to properly find the srcline
386 * for caller frames.
387 * See also the documentation for dwfl_frame_pc(),
388 * which this code tries to replicate.
389 */
390 if (unw_is_signal_frame(&c) <= 0) {
391 --ip;
392 }
393 HLOGV("unwind:%zu: ip 0x%" UNW_WORD_PFLAG " sp 0x%" UNW_WORD_PFLAG "", callStack.size(),
394 ip, sp);
395 if (callStack.back().ip_ == ip && callStack.back().sp_ == sp) {
396 HLOGW("we found a same frame, stop here");
397 break;
398 }
399 callStack.emplace_back(ip, sp);
400 } else {
401 HLOGV("no more frame step found. ret %d:%s", ret, GetUnwErrorName(ret).c_str());
402 break;
403 }
404 }
405 }
406 #endif
407
GetIpSP(uint64_t & ip,uint64_t & sp,const u64 * regs,size_t regNum) const408 bool CallStack::GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const
409 {
410 if (regNum > 0) {
411 if (!RegisterGetSPValue(sp, arch_, regs, regNum)) {
412 HLOGW("unable get sp");
413 return false;
414 }
415 if (!RegisterGetIPValue(ip, arch_, regs, regNum)) {
416 HLOGW("unable get ip");
417 return false;
418 }
419 if (ip != 0) {
420 return true;
421 }
422 } else {
423 HLOGW("reg size is 0");
424 return false;
425 }
426 return false;
427 }
428
429 #if HAVE_LIBUNWIND
DoUnwind(const VirtualThread & thread,std::vector<CallFrame> & callStack,size_t maxStackLevel)430 bool CallStack::DoUnwind(const VirtualThread &thread, std::vector<CallFrame> &callStack,
431 size_t maxStackLevel)
432 {
433 unw_addr_space_t addr_space;
434 UnwindInfo unwindInfo = {
435 .thread = thread,
436 .callStack = *this,
437 };
438 unw_cursor_t c;
439 if (unwindAddrSpaceMap_.count(thread.tid_) == 0) {
440 addr_space = unw_create_addr_space(&accessors_, 0);
441 if (!addr_space) {
442 HLOGE("Can't create unwind vaddress space.");
443 return false;
444 }
445 unwindAddrSpaceMap_.emplace(thread.tid_, addr_space);
446 unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL);
447 unw_flush_cache(addr_space, 0, 0);
448 } else {
449 addr_space = unwindAddrSpaceMap_.at(thread.tid_);
450 }
451
452 int ret = unw_init_remote(&c, addr_space, &unwindInfo);
453 if (ret) {
454 HLOGE("unwind error %d:%s see unw_error_t.", ret, GetUnwErrorName(ret).c_str());
455 return false;
456 } else {
457 UnwindStep(c, callStack, maxStackLevel);
458 }
459 return true;
460 }
461 #endif
462
UnwindCallStack(const VirtualThread & thread,u64 * regs,u64 regsNum,const u8 * stack,u64 stackSize,std::vector<CallFrame> & callStack,size_t maxStackLevel)463 bool CallStack::UnwindCallStack(const VirtualThread &thread, u64 *regs, u64 regsNum,
464 const u8 *stack, u64 stackSize, std::vector<CallFrame> &callStack,
465 size_t maxStackLevel)
466 {
467 regs_ = regs;
468 regsNum_ = regsNum;
469 stack_ = stack;
470 stackSize_ = stackSize;
471
472 arch_ = buildArchType;
473 UpdateRegForABI(arch_, regs_);
474 if (!RegisterGetSPValue(stackPoint_, arch_, regs_, regsNum_)) {
475 HLOGE("RegisterGetSPValue failed");
476 return false;
477 } else {
478 stackEnd_ = stackPoint_ + stackSize_;
479 }
480
481 uint64_t ip = 0;
482 uint64_t sp = 0;
483 if (!GetIpSP(ip, sp, regs_, regsNum_)) {
484 HLOGW("unable get sp or sp , unable unwind");
485 return false;
486 } else {
487 if (ip != 0) {
488 HLOGV("unwind:%zu: ip 0x%" PRIx64 " sp 0x%" PRIx64 "", callStack.size(), ip, sp);
489 callStack.emplace_back(ip, sp);
490 }
491 }
492
493 /*
494 * If we need more than one entry, do the DWARF
495 * unwind itself.
496 */
497 if (maxStackLevel - 1 > 0) {
498 return DoUnwind(thread, callStack, maxStackLevel);
499 }
500 return true;
501 }
502
503 /*
504 we should have CallStack cache for each thread
505
506 0. A -> B -> C -> E -> F
507 1. C -> E -> F
508 2. B -> C
509 3. A -> B -> C
510 4. B -> G -> H
511 5. J -> C
512
513 0 is our cache
514 1 2 3... is from record
515
516 use expendLimit to setup how may frame match is needs
517
518 */
519
CallStack()520 CallStack::CallStack() {}
521
~CallStack()522 CallStack::~CallStack()
523 {
524 #if HAVE_LIBUNWIND
525 for (auto &pair : unwindAddrSpaceMap_) {
526 unw_destroy_addr_space(pair.second);
527 }
528 #endif
529 }
530 } // namespace NativeDaemon
531 } // namespace Developtools
532 } // namespace OHOS