• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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