148f512ceSopenharmony_ci/* 248f512ceSopenharmony_ci * Copyright (c) 2021-2023 Huawei Device Co., Ltd. 348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 448f512ceSopenharmony_ci * you may not use this file except in compliance with the License. 548f512ceSopenharmony_ci * You may obtain a copy of the License at 648f512ceSopenharmony_ci * 748f512ceSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 848f512ceSopenharmony_ci * 948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and 1348f512ceSopenharmony_ci * limitations under the License. 1448f512ceSopenharmony_ci */ 1548f512ceSopenharmony_ci#define HILOG_TAG "CallStack" 1648f512ceSopenharmony_ci 1748f512ceSopenharmony_ci#include "callstack.h" 1848f512ceSopenharmony_ci 1948f512ceSopenharmony_ci#include <dlfcn.h> 2048f512ceSopenharmony_ci#include <pthread.h> 2148f512ceSopenharmony_ci#include <iostream> 2248f512ceSopenharmony_ci 2348f512ceSopenharmony_ci#include <string> 2448f512ceSopenharmony_ci#include <utility> 2548f512ceSopenharmony_ci#if HAVE_LIBUNWIND 2648f512ceSopenharmony_ci#include <libunwind.h> 2748f512ceSopenharmony_ci#include <libunwind_i.h> 2848f512ceSopenharmony_ci#endif 2948f512ceSopenharmony_ci 3048f512ceSopenharmony_ci#include "dfx_regs.h" 3148f512ceSopenharmony_ci#include "hiperf_hilog.h" 3248f512ceSopenharmony_ci#include "register.h" 3348f512ceSopenharmony_ci 3448f512ceSopenharmony_ci#ifdef target_cpu_arm 3548f512ceSopenharmony_ci// reg size is int (unw_word_t) 3648f512ceSopenharmony_ci#define UNW_WORD_PFLAG "x" 3748f512ceSopenharmony_ci#else 3848f512ceSopenharmony_ci// reg size is long (unw_word_t) 3948f512ceSopenharmony_ci#define UNW_WORD_PFLAG "zx" 4048f512ceSopenharmony_ci#endif 4148f512ceSopenharmony_cinamespace OHOS { 4248f512ceSopenharmony_cinamespace Developtools { 4348f512ceSopenharmony_cinamespace HiPerf { 4448f512ceSopenharmony_ciusing namespace OHOS::HiviewDFX; 4548f512ceSopenharmony_ci 4648f512ceSopenharmony_cibool CallStack::ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, ADDR_TYPE vaddr, ADDR_TYPE *data) 4748f512ceSopenharmony_ci{ 4848f512ceSopenharmony_ci if (__builtin_expect(unwindInfoPtr.thread.pid_ == unwindInfoPtr.callStack.lastPid_ && 4948f512ceSopenharmony_ci vaddr == unwindInfoPtr.callStack.lastAddr_, true)) { 5048f512ceSopenharmony_ci *data = unwindInfoPtr.callStack.lastData_; 5148f512ceSopenharmony_ci return true; 5248f512ceSopenharmony_ci } 5348f512ceSopenharmony_ci 5448f512ceSopenharmony_ci if (unwindInfoPtr.thread.ReadRoMemory(vaddr, reinterpret_cast<uint8_t*>(data), sizeof(ADDR_TYPE))) { 5548f512ceSopenharmony_ci unwindInfoPtr.callStack.lastPid_ = unwindInfoPtr.thread.pid_; 5648f512ceSopenharmony_ci unwindInfoPtr.callStack.lastAddr_ = vaddr; 5748f512ceSopenharmony_ci unwindInfoPtr.callStack.lastData_ = *data; 5848f512ceSopenharmony_ci return true; 5948f512ceSopenharmony_ci } else { 6048f512ceSopenharmony_ci unwindInfoPtr.callStack.lastPid_ = -1; 6148f512ceSopenharmony_ci unwindInfoPtr.callStack.lastAddr_ = 0; 6248f512ceSopenharmony_ci return false; 6348f512ceSopenharmony_ci } 6448f512ceSopenharmony_ci} 6548f512ceSopenharmony_ci 6648f512ceSopenharmony_ci#if HAVE_LIBUNWIND 6748f512ceSopenharmony_ciconst std::map<unw_error_t, const std::string> UNW_ERROR_MAP = { 6848f512ceSopenharmony_ci {UNW_ESUCCESS, std::to_string(UNW_ESUCCESS)}, 6948f512ceSopenharmony_ci {UNW_EUNSPEC, std::to_string(UNW_EUNSPEC)}, 7048f512ceSopenharmony_ci {UNW_ENOMEM, std::to_string(UNW_ENOMEM)}, 7148f512ceSopenharmony_ci {UNW_EBADREG, std::to_string(UNW_EBADREG)}, 7248f512ceSopenharmony_ci {UNW_EREADONLYREG, std::to_string(UNW_EREADONLYREG)}, 7348f512ceSopenharmony_ci {UNW_ESTOPUNWIND, std::to_string(UNW_ESTOPUNWIND)}, 7448f512ceSopenharmony_ci {UNW_EINVALIDIP, std::to_string(UNW_EINVALIDIP)}, 7548f512ceSopenharmony_ci {UNW_EBADFRAME, std::to_string(UNW_EBADFRAME)}, 7648f512ceSopenharmony_ci {UNW_EINVAL, std::to_string(UNW_EINVAL)}, 7748f512ceSopenharmony_ci {UNW_EBADVERSION, std::to_string(UNW_EBADVERSION)}, 7848f512ceSopenharmony_ci {UNW_ENOINFO, std::to_string(UNW_ENOINFO)}, 7948f512ceSopenharmony_ci}; 8048f512ceSopenharmony_ciconst std::string CallStack::GetUnwErrorName(int error) 8148f512ceSopenharmony_ci{ 8248f512ceSopenharmony_ci if (UNW_ERROR_MAP.count(static_cast<unw_error_t>(-error)) > 0) { 8348f512ceSopenharmony_ci return UNW_ERROR_MAP.at(static_cast<unw_error_t>(-error)); 8448f512ceSopenharmony_ci } else { 8548f512ceSopenharmony_ci return "UNKNOW_UNW_ERROR"; 8648f512ceSopenharmony_ci } 8748f512ceSopenharmony_ci} 8848f512ceSopenharmony_ci 8948f512ceSopenharmony_civoid CallStack::dumpUDI(unw_dyn_info_t &di) 9048f512ceSopenharmony_ci{ 9148f512ceSopenharmony_ci HLOGV("unwind_table info: "); 9248f512ceSopenharmony_ci HLOGV(" di.start_ip: 0x%016" UNW_WORD_PFLAG "", di.start_ip); 9348f512ceSopenharmony_ci HLOGV(" di.end_ip: 0x%016" UNW_WORD_PFLAG "", di.end_ip); 9448f512ceSopenharmony_ci HLOGV(" di.u.rti.segbase: 0x%016" UNW_WORD_PFLAG "", di.u.rti.segbase); 9548f512ceSopenharmony_ci HLOGV(" di.u.rti.table_data: 0x%016" UNW_WORD_PFLAG "", di.u.rti.table_data); 9648f512ceSopenharmony_ci HLOGV(" di.u.rti.table_len: 0x%016" UNW_WORD_PFLAG "", di.u.rti.table_len); 9748f512ceSopenharmony_ci} 9848f512ceSopenharmony_ci 9948f512ceSopenharmony_cibool CallStack::fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, std::shared_ptr<DfxMap> map, 10048f512ceSopenharmony_ci const VirtualThread &thread) 10148f512ceSopenharmony_ci{ 10248f512ceSopenharmony_ci di.start_ip = map->begin; 10348f512ceSopenharmony_ci di.end_ip = map->end; 10448f512ceSopenharmony_ci#ifndef target_cpu_arm 10548f512ceSopenharmony_ci uint64_t fdeTableElfOffset; 10648f512ceSopenharmony_ci uint64_t fdeTableSize; 10748f512ceSopenharmony_ci uint64_t ehFrameHdrElfOffset; 10848f512ceSopenharmony_ci if ((UNW_INFO_FORMAT_REMOTE_TABLE == di.format) && 10948f512ceSopenharmony_ci symbolsFile.GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize)) { 11048f512ceSopenharmony_ci /* 11148f512ceSopenharmony_ci unw_word_t name_ptr; // addr. of table name (e.g., library name) 11248f512ceSopenharmony_ci unw_word_t segbase; // segment base 11348f512ceSopenharmony_ci unw_word_t table_len; // must be a multiple of sizeof(unw_word_t)! 11448f512ceSopenharmony_ci unw_word_t table_data; 11548f512ceSopenharmony_ci */ 11648f512ceSopenharmony_ci /* 11748f512ceSopenharmony_ci all the rti addr is offset of the elf file 11848f512ceSopenharmony_ci begin - page offset = elf file base addr in vaddr user space 11948f512ceSopenharmony_ci begin - page offset + elf offset = vaddr in real word.(for this thread) 12048f512ceSopenharmony_ci */ 12148f512ceSopenharmony_ci 12248f512ceSopenharmony_ci // segbase is file offset . 12348f512ceSopenharmony_ci /* 12448f512ceSopenharmony_ci 00200000-00344000 r--p 00000000 08:02 46404365 12548f512ceSopenharmony_ci 00344000-005c4000 r-xp 00143000 08:02 46404365 12648f512ceSopenharmony_ci 12748f512ceSopenharmony_ci LOAD 0x00000000001439c0 0x00000000003449c0 0x00000000003449c0 12848f512ceSopenharmony_ci 0x000000000027f3c0 0x000000000027f3c0 R E 0x1000 12948f512ceSopenharmony_ci 13048f512ceSopenharmony_ci GNU_EH_FRAME 0x00000000000f3248 0x00000000002f3248 0x00000000002f3248 13148f512ceSopenharmony_ci 0x000000000000bb04 0x000000000000bb04 R 0x4 13248f512ceSopenharmony_ci 13348f512ceSopenharmony_ci */ 13448f512ceSopenharmony_ci auto ehFrameMap = thread.FindMapByFileInfo(map->name, ehFrameHdrElfOffset); 13548f512ceSopenharmony_ci if (ehFrameMap == nullptr) { 13648f512ceSopenharmony_ci HLOGE("no ehframe map found."); 13748f512ceSopenharmony_ci return false; 13848f512ceSopenharmony_ci } 13948f512ceSopenharmony_ci 14048f512ceSopenharmony_ci di.u.rti.segbase = ehFrameMap->begin + ehFrameHdrElfOffset - ehFrameMap->offset; 14148f512ceSopenharmony_ci di.u.rti.table_data = ehFrameMap->begin + fdeTableElfOffset - ehFrameMap->offset; 14248f512ceSopenharmony_ci di.u.rti.table_len = fdeTableSize / sizeof(uintptr_t); 14348f512ceSopenharmony_ci 14448f512ceSopenharmony_ci HLOGV(" map pageoffset: 0x%016" PRIx64 "", map->offset); 14548f512ceSopenharmony_ci HLOGV(" ehFrameHdrElfOffset: 0x%016" PRIx64 "", ehFrameHdrElfOffset); 14648f512ceSopenharmony_ci HLOGV(" fdeTableElfOffset: 0x%016" PRIx64 "", fdeTableElfOffset); 14748f512ceSopenharmony_ci HLOGV(" fdeTableSize: 0x%016" PRIx64 "", fdeTableSize); 14848f512ceSopenharmony_ci return true; 14948f512ceSopenharmony_ci } else { 15048f512ceSopenharmony_ci HLOGD("SymbolsFile::GetHDRSectionInfo() failed"); 15148f512ceSopenharmony_ci } 15248f512ceSopenharmony_ci#else 15348f512ceSopenharmony_ci uint64_t SectionVaddr; 15448f512ceSopenharmony_ci uint64_t SectionSize; 15548f512ceSopenharmony_ci uint64_t SectionFileOffset; 15648f512ceSopenharmony_ci if ((UNW_INFO_FORMAT_ARM_EXIDX == di.format) && 15748f512ceSopenharmony_ci symbolsFile.GetSectionInfo(ARM_EXIDX, SectionVaddr, SectionSize, SectionFileOffset)) { 15848f512ceSopenharmony_ci auto targetMap = thread.FindMapByFileInfo(map->name, SectionFileOffset); 15948f512ceSopenharmony_ci if (targetMap == nullptr) { 16048f512ceSopenharmony_ci HLOGE("no debug map found."); 16148f512ceSopenharmony_ci return false; 16248f512ceSopenharmony_ci } 16348f512ceSopenharmony_ci HLOGV(" begin: %" PRIx64 " offset:%" PRIx64 "", targetMap->begin, 16448f512ceSopenharmony_ci targetMap->offset); 16548f512ceSopenharmony_ci 16648f512ceSopenharmony_ci di.u.rti.table_data = targetMap->begin + SectionFileOffset - targetMap->offset; 16748f512ceSopenharmony_ci di.u.rti.table_len = SectionSize; 16848f512ceSopenharmony_ci HLOGV(" SectionName: %s", std::string(ARM_EXIDX).c_str()); 16948f512ceSopenharmony_ci HLOGV(" SectionVaddrt: 0x%016" PRIx64 "", SectionVaddr); 17048f512ceSopenharmony_ci HLOGV(" SectionFileOffset 0x%016" PRIx64 "", SectionFileOffset); 17148f512ceSopenharmony_ci HLOGV(" SectionSize: 0x%016" PRIx64 "", SectionSize); 17248f512ceSopenharmony_ci 17348f512ceSopenharmony_ci // GetSectionInfo return true, but SectionVaddr || SectionSize is 0 ??? 17448f512ceSopenharmony_ci HLOG_ASSERT(SectionVaddr != 0 && SectionSize != 0); 17548f512ceSopenharmony_ci return true; 17648f512ceSopenharmony_ci } else { 17748f512ceSopenharmony_ci HLOGD("SymbolsFile::GetSectionInfo() failed"); 17848f512ceSopenharmony_ci } 17948f512ceSopenharmony_ci#endif 18048f512ceSopenharmony_ci return false; 18148f512ceSopenharmony_ci} 18248f512ceSopenharmony_ci 18348f512ceSopenharmony_ci/* 18448f512ceSopenharmony_ci https://www.nongnu.org/libunwind/man/libunwind-dynamic(3).html 18548f512ceSopenharmony_ci*/ 18648f512ceSopenharmony_ciint CallStack::FindUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, 18748f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, 18848f512ceSopenharmony_ci unw_proc_info_t *pi, int need_unwind_info, void *arg) 18948f512ceSopenharmony_ci{ 19048f512ceSopenharmony_ci HLOGM("try search debug info at %s", symbolsFile->filePath_.c_str()); 19148f512ceSopenharmony_ci auto &dynInfoProcessMap = unwindInfoPtr->callStack.unwindTableInfoMap_; 19248f512ceSopenharmony_ci // all the thread in same process have same map and symbols 19348f512ceSopenharmony_ci if (dynInfoProcessMap.find(unwindInfoPtr->thread.pid_) == dynInfoProcessMap.end()) { 19448f512ceSopenharmony_ci dynInfoProcessMap.emplace(unwindInfoPtr->thread.pid_, dsoUnwDynInfoMap {}); 19548f512ceSopenharmony_ci } 19648f512ceSopenharmony_ci dsoUnwDynInfoMap &dynFileMap = dynInfoProcessMap[unwindInfoPtr->thread.pid_]; 19748f512ceSopenharmony_ci // find use dso name as key 19848f512ceSopenharmony_ci if (dynFileMap.find(symbolsFile->filePath_) == dynFileMap.end()) { 19948f512ceSopenharmony_ci unw_dyn_info_t newdi; 20048f512ceSopenharmony_ci if (memset_s(&newdi, sizeof(unw_dyn_info_t), 0, sizeof(unw_dyn_info_t)) != EOK) { 20148f512ceSopenharmony_ci HLOGE("memset_s() failed"); 20248f512ceSopenharmony_ci return -UNW_EUNSPEC; 20348f512ceSopenharmony_ci } 20448f512ceSopenharmony_ci#ifdef target_cpu_arm 20548f512ceSopenharmony_ci // arm use .ARM.exidx , not use ehframe 20648f512ceSopenharmony_ci newdi.format = UNW_INFO_FORMAT_ARM_EXIDX; 20748f512ceSopenharmony_ci#else 20848f512ceSopenharmony_ci // otherwise we use EH FRAME 20948f512ceSopenharmony_ci newdi.format = UNW_INFO_FORMAT_REMOTE_TABLE; 21048f512ceSopenharmony_ci#endif 21148f512ceSopenharmony_ci if (fillUDI(newdi, *symbolsFile, map, unwindInfoPtr->thread)) { 21248f512ceSopenharmony_ci dumpUDI(newdi); 21348f512ceSopenharmony_ci // we make a option empty value first 21448f512ceSopenharmony_ci std::optional<unw_dyn_info_t> &odi = dynFileMap[symbolsFile->filePath_]; 21548f512ceSopenharmony_ci odi = newdi; 21648f512ceSopenharmony_ci } else { 21748f512ceSopenharmony_ci HLOGV("fillUDI failed()"); 21848f512ceSopenharmony_ci return -UNW_EUNSPEC; 21948f512ceSopenharmony_ci } 22048f512ceSopenharmony_ci } 22148f512ceSopenharmony_ci 22248f512ceSopenharmony_ci HLOG_ASSERT(dynInfoProcessMap.find(unwindInfoPtr->thread.pid_) != dynInfoProcessMap.end()); 22348f512ceSopenharmony_ci HLOG_ASSERT_MESSAGE(dynFileMap.find(symbolsFile->filePath_) != dynFileMap.end(), "%s", 22448f512ceSopenharmony_ci symbolsFile->filePath_.c_str()); 22548f512ceSopenharmony_ci std::optional<unw_dyn_info_t> &odi = 22648f512ceSopenharmony_ci dynInfoProcessMap.at(unwindInfoPtr->thread.pid_).at(symbolsFile->filePath_); 22748f512ceSopenharmony_ci 22848f512ceSopenharmony_ci if (odi.has_value()) { 22948f512ceSopenharmony_ci unw_dyn_info_t &di = odi.value(); 23048f512ceSopenharmony_ci /* 23148f512ceSopenharmony_ci we don't use dwarf_search_unwind_table 23248f512ceSopenharmony_ci because in arm it will search two function: 23348f512ceSopenharmony_ci 1 arm_search_unwind_table first 23448f512ceSopenharmony_ci 2 dwarf_search_unwind_table 23548f512ceSopenharmony_ci 23648f512ceSopenharmony_ci see libunwind_i.h for arm 23748f512ceSopenharmony_ci define tdep_search_unwind_table UNW_OBJ(search_unwind_table) 23848f512ceSopenharmony_ci 23948f512ceSopenharmony_ci */ 24048f512ceSopenharmony_ci int ret = static_cast<unw_error_t>( 24148f512ceSopenharmony_ci tdep_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg)); 24248f512ceSopenharmony_ci 24348f512ceSopenharmony_ci HLOGM("search_unwind_table ret %d:%s", ret, GetUnwErrorName(ret).c_str()); 24448f512ceSopenharmony_ci 24548f512ceSopenharmony_ci if (UNW_ESUCCESS != ret) { 24648f512ceSopenharmony_ci if (UNW_ENOINFO != ret) { 24748f512ceSopenharmony_ci HLOGW("search_unwind_table ret error %d:%s", ret, GetUnwErrorName(ret).c_str()); 24848f512ceSopenharmony_ci } 24948f512ceSopenharmony_ci return -UNW_EUNSPEC; 25048f512ceSopenharmony_ci } else { 25148f512ceSopenharmony_ci return UNW_ESUCCESS; 25248f512ceSopenharmony_ci } 25348f512ceSopenharmony_ci } else { 25448f512ceSopenharmony_ci HLOGW("no debug info found for thread %d:%s", unwindInfoPtr->thread.tid_, 25548f512ceSopenharmony_ci unwindInfoPtr->thread.name_.c_str()); 25648f512ceSopenharmony_ci return -UNW_EUNSPEC; 25748f512ceSopenharmony_ci } 25848f512ceSopenharmony_ci} 25948f512ceSopenharmony_ci 26048f512ceSopenharmony_ciint CallStack::FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 26148f512ceSopenharmony_ci int need_unwind_info, void *arg) 26248f512ceSopenharmony_ci{ 26348f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg); 26448f512ceSopenharmony_ci 26548f512ceSopenharmony_ci HLOGM("need_unwind_info ret %d ip %" UNW_WORD_PFLAG "", need_unwind_info, ip); 26648f512ceSopenharmony_ci auto map = unwindInfoPtr->thread.FindMapByAddr(ip); 26748f512ceSopenharmony_ci if (map != nullptr) { 26848f512ceSopenharmony_ci SymbolsFile *symbolsFile = unwindInfoPtr->thread.FindSymbolsFileByMap(map); 26948f512ceSopenharmony_ci if (symbolsFile != nullptr) { 27048f512ceSopenharmony_ci return FindUnwindTable(symbolsFile, map, unwindInfoPtr, as, ip, pi, need_unwind_info, arg); 27148f512ceSopenharmony_ci } else { 27248f512ceSopenharmony_ci HLOGW("no symbols file found for thread %d:%s", unwindInfoPtr->thread.tid_, 27348f512ceSopenharmony_ci unwindInfoPtr->thread.name_.c_str()); 27448f512ceSopenharmony_ci } 27548f512ceSopenharmony_ci } else { 27648f512ceSopenharmony_ci HLOGE("ip 0x%016" UNW_WORD_PFLAG " not found in thread %d:%s", ip, 27748f512ceSopenharmony_ci unwindInfoPtr->thread.tid_, unwindInfoPtr->thread.name_.c_str()); 27848f512ceSopenharmony_ci } 27948f512ceSopenharmony_ci 28048f512ceSopenharmony_ci return -UNW_EUNSPEC; 28148f512ceSopenharmony_ci} 28248f512ceSopenharmony_ci 28348f512ceSopenharmony_ciint CallStack::AccessMem([[maybe_unused]] unw_addr_space_t as, unw_word_t addr, 28448f512ceSopenharmony_ci unw_word_t *valuePoint, int writeOperation, void *arg) 28548f512ceSopenharmony_ci{ 28648f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg); 28748f512ceSopenharmony_ci *valuePoint = 0; 28848f512ceSopenharmony_ci 28948f512ceSopenharmony_ci /* Check overflow. */ 29048f512ceSopenharmony_ci if (addr + sizeof(unw_word_t) < addr) { 29148f512ceSopenharmony_ci HLOGE("address overfolw at 0x%" UNW_WORD_PFLAG " increase 0x%zu", addr, sizeof(unw_word_t)); 29248f512ceSopenharmony_ci return -UNW_EUNSPEC; 29348f512ceSopenharmony_ci } 29448f512ceSopenharmony_ci 29548f512ceSopenharmony_ci if (addr < unwindInfoPtr->callStack.stackPoint_ or 29648f512ceSopenharmony_ci addr + sizeof(unw_word_t) >= unwindInfoPtr->callStack.stackEnd_) { 29748f512ceSopenharmony_ci if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, valuePoint)) { 29848f512ceSopenharmony_ci HLOGM("access_mem addr get val 0x%" UNW_WORD_PFLAG ", from mmap", *valuePoint); 29948f512ceSopenharmony_ci } else { 30048f512ceSopenharmony_ci HLOGW("access_mem addr failed, from mmap, STACK RANGE 0x%" PRIx64 "- 0x%" PRIx64 "(0x%" PRIx64 ")", 30148f512ceSopenharmony_ci unwindInfoPtr->callStack.stackPoint_, unwindInfoPtr->callStack.stackEnd_, 30248f512ceSopenharmony_ci unwindInfoPtr->callStack.stackEnd_ - unwindInfoPtr->callStack.stackPoint_); 30348f512ceSopenharmony_ci return -UNW_EUNSPEC; 30448f512ceSopenharmony_ci } 30548f512ceSopenharmony_ci } else { 30648f512ceSopenharmony_ci size_t stackOffset = addr - unwindInfoPtr->callStack.stackPoint_; 30748f512ceSopenharmony_ci *valuePoint = *(unw_word_t *)&unwindInfoPtr->callStack.stack_[stackOffset]; 30848f512ceSopenharmony_ci HLOGM("access_mem addr %p val %" UNW_WORD_PFLAG ", from stack offset %zu", 30948f512ceSopenharmony_ci reinterpret_cast<void *>(addr), *valuePoint, stackOffset); 31048f512ceSopenharmony_ci } 31148f512ceSopenharmony_ci 31248f512ceSopenharmony_ci return UNW_ESUCCESS; 31348f512ceSopenharmony_ci} 31448f512ceSopenharmony_ci 31548f512ceSopenharmony_ciint CallStack::AccessReg([[maybe_unused]] unw_addr_space_t as, unw_regnum_t regnum, 31648f512ceSopenharmony_ci unw_word_t *valuePoint, int writeOperation, void *arg) 31748f512ceSopenharmony_ci{ 31848f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg); 31948f512ceSopenharmony_ci uint64_t val; 32048f512ceSopenharmony_ci int perfRegIndex = LibunwindRegIdToPerfReg(regnum); 32148f512ceSopenharmony_ci if (perfRegIndex < 0) { 32248f512ceSopenharmony_ci HLOGE("can't read reg %d", perfRegIndex); 32348f512ceSopenharmony_ci return perfRegIndex; 32448f512ceSopenharmony_ci } 32548f512ceSopenharmony_ci /* Don't support write, I suspect we don't need it. */ 32648f512ceSopenharmony_ci if (writeOperation) { 32748f512ceSopenharmony_ci HLOGE("access_reg %d", regnum); 32848f512ceSopenharmony_ci return -UNW_EINVAL; 32948f512ceSopenharmony_ci } 33048f512ceSopenharmony_ci 33148f512ceSopenharmony_ci if (unwindInfoPtr->callStack.regsNum_ == 0) { 33248f512ceSopenharmony_ci return -UNW_EUNSPEC; 33348f512ceSopenharmony_ci } 33448f512ceSopenharmony_ci 33548f512ceSopenharmony_ci if (!RegisterGetValue(val, unwindInfoPtr->callStack.regs_, static_cast<size_t>(perfRegIndex), 33648f512ceSopenharmony_ci unwindInfoPtr->callStack.regsNum_)) { 33748f512ceSopenharmony_ci HLOGE("can't read reg %d", perfRegIndex); 33848f512ceSopenharmony_ci return -UNW_EUNSPEC; 33948f512ceSopenharmony_ci } 34048f512ceSopenharmony_ci 34148f512ceSopenharmony_ci *valuePoint = (unw_word_t)val; 34248f512ceSopenharmony_ci HLOGM("reg %d:%s, val 0x%" UNW_WORD_PFLAG "", regnum, RegisterGetName(static_cast<size_t>(perfRegIndex)).c_str(), 34348f512ceSopenharmony_ci *valuePoint); 34448f512ceSopenharmony_ci return UNW_ESUCCESS; 34548f512ceSopenharmony_ci} 34648f512ceSopenharmony_ci 34748f512ceSopenharmony_civoid CallStack::PutUnwindInfo([[maybe_unused]] unw_addr_space_t as, 34848f512ceSopenharmony_ci [[maybe_unused]] unw_proc_info_t *pi, [[maybe_unused]] void *arg) 34948f512ceSopenharmony_ci{ 35048f512ceSopenharmony_ci} 35148f512ceSopenharmony_ci 35248f512ceSopenharmony_ciint CallStack::AccessFpreg([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_regnum_t num, 35348f512ceSopenharmony_ci [[maybe_unused]] unw_fpreg_t *val, [[maybe_unused]] int writeOperation, 35448f512ceSopenharmony_ci [[maybe_unused]] void *arg) 35548f512ceSopenharmony_ci{ 35648f512ceSopenharmony_ci return -UNW_EINVAL; 35748f512ceSopenharmony_ci} 35848f512ceSopenharmony_ci 35948f512ceSopenharmony_ciint CallStack::GetDynInfoListAaddr([[maybe_unused]] unw_addr_space_t as, 36048f512ceSopenharmony_ci [[maybe_unused]] unw_word_t *dil_vaddr, 36148f512ceSopenharmony_ci [[maybe_unused]] void *arg) 36248f512ceSopenharmony_ci{ 36348f512ceSopenharmony_ci return -UNW_ENOINFO; 36448f512ceSopenharmony_ci} 36548f512ceSopenharmony_ci 36648f512ceSopenharmony_ciint CallStack::Resume([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_cursor_t *cu, 36748f512ceSopenharmony_ci [[maybe_unused]] void *arg) 36848f512ceSopenharmony_ci{ 36948f512ceSopenharmony_ci return -UNW_EINVAL; 37048f512ceSopenharmony_ci} 37148f512ceSopenharmony_ci 37248f512ceSopenharmony_ciint CallStack::getProcName([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_word_t addr, 37348f512ceSopenharmony_ci [[maybe_unused]] char *bufp, [[maybe_unused]] size_t buf_len, 37448f512ceSopenharmony_ci [[maybe_unused]] unw_word_t *offp, [[maybe_unused]] void *arg) 37548f512ceSopenharmony_ci{ 37648f512ceSopenharmony_ci return -UNW_EINVAL; 37748f512ceSopenharmony_ci} 37848f512ceSopenharmony_ci 37948f512ceSopenharmony_civoid CallStack::UnwindStep(unw_cursor_t &c, std::vector<DfxFrame> &callStack, size_t maxStackLevel) 38048f512ceSopenharmony_ci{ 38148f512ceSopenharmony_ci while (callStack.size() < maxStackLevel) { 38248f512ceSopenharmony_ci int ret = unw_step(&c); 38348f512ceSopenharmony_ci if (ret > 0) { 38448f512ceSopenharmony_ci unw_word_t ip; 38548f512ceSopenharmony_ci unw_word_t sp; 38648f512ceSopenharmony_ci unw_get_reg(&c, UNW_REG_IP, &ip); 38748f512ceSopenharmony_ci unw_get_reg(&c, UNW_REG_SP, &sp); 38848f512ceSopenharmony_ci 38948f512ceSopenharmony_ci if (ip == 0) { 39048f512ceSopenharmony_ci HLOGD("ip == 0 something is wrong. break"); 39148f512ceSopenharmony_ci break; 39248f512ceSopenharmony_ci } 39348f512ceSopenharmony_ci 39448f512ceSopenharmony_ci /* 39548f512ceSopenharmony_ci * Decrement the IP for any non-activation frames. 39648f512ceSopenharmony_ci * this is required to properly find the srcline 39748f512ceSopenharmony_ci * for caller frames. 39848f512ceSopenharmony_ci * See also the documentation for dwfl_frame_pc(), 39948f512ceSopenharmony_ci * which this code tries to replicate. 40048f512ceSopenharmony_ci */ 40148f512ceSopenharmony_ci if (unw_is_signal_frame(&c) <= 0) { 40248f512ceSopenharmony_ci --ip; 40348f512ceSopenharmony_ci } 40448f512ceSopenharmony_ci HLOGV("unwind:%zu: ip 0x%" UNW_WORD_PFLAG " sp 0x%" UNW_WORD_PFLAG "", callStack.size(), 40548f512ceSopenharmony_ci ip, sp); 40648f512ceSopenharmony_ci if (callStack.back().pc == ip && callStack.back().sp == sp) { 40748f512ceSopenharmony_ci HLOGW("we found a same frame, stop here"); 40848f512ceSopenharmony_ci break; 40948f512ceSopenharmony_ci } 41048f512ceSopenharmony_ci callStack.emplace_back(ip, sp); 41148f512ceSopenharmony_ci } else { 41248f512ceSopenharmony_ci HLOGV("no more frame step found. ret %d:%s", ret, GetUnwErrorName(ret).c_str()); 41348f512ceSopenharmony_ci break; 41448f512ceSopenharmony_ci } 41548f512ceSopenharmony_ci } 41648f512ceSopenharmony_ci} 41748f512ceSopenharmony_ci#endif 41848f512ceSopenharmony_ci 41948f512ceSopenharmony_cibool CallStack::GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const 42048f512ceSopenharmony_ci{ 42148f512ceSopenharmony_ci if (regNum > 0) { 42248f512ceSopenharmony_ci CHECK_TRUE(!RegisterGetSPValue(sp, arch_, regs, regNum), false, 1, "unable get sp"); 42348f512ceSopenharmony_ci CHECK_TRUE(!RegisterGetIPValue(ip, arch_, regs, regNum), false, 1, "unable get ip"); 42448f512ceSopenharmony_ci if (ip != 0) { 42548f512ceSopenharmony_ci return true; 42648f512ceSopenharmony_ci } 42748f512ceSopenharmony_ci } else { 42848f512ceSopenharmony_ci HLOGW("reg size is 0"); 42948f512ceSopenharmony_ci return false; 43048f512ceSopenharmony_ci } 43148f512ceSopenharmony_ci return false; 43248f512ceSopenharmony_ci} 43348f512ceSopenharmony_ci 43448f512ceSopenharmony_ci#if HAVE_LIBUNWIND 43548f512ceSopenharmony_cibool CallStack::DoUnwind(const VirtualThread &thread, std::vector<DfxFrame> &callStack, 43648f512ceSopenharmony_ci size_t maxStackLevel) 43748f512ceSopenharmony_ci{ 43848f512ceSopenharmony_ci unw_addr_space_t addr_space; 43948f512ceSopenharmony_ci UnwindInfo unwindInfo = { 44048f512ceSopenharmony_ci .thread = thread, 44148f512ceSopenharmony_ci .callStack = *this, 44248f512ceSopenharmony_ci }; 44348f512ceSopenharmony_ci unw_cursor_t c; 44448f512ceSopenharmony_ci if (unwindAddrSpaceMap_.count(thread.tid_) == 0) { 44548f512ceSopenharmony_ci addr_space = unw_create_addr_space(&accessors_, 0); 44648f512ceSopenharmony_ci if (!addr_space) { 44748f512ceSopenharmony_ci HLOGE("Can't create unwind vaddress space."); 44848f512ceSopenharmony_ci return false; 44948f512ceSopenharmony_ci } 45048f512ceSopenharmony_ci unwindAddrSpaceMap_.emplace(thread.tid_, addr_space); 45148f512ceSopenharmony_ci unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); 45248f512ceSopenharmony_ci unw_flush_cache(addr_space, 0, 0); 45348f512ceSopenharmony_ci } else { 45448f512ceSopenharmony_ci addr_space = unwindAddrSpaceMap_.at(thread.tid_); 45548f512ceSopenharmony_ci } 45648f512ceSopenharmony_ci 45748f512ceSopenharmony_ci int ret = unw_init_remote(&c, addr_space, &unwindInfo); 45848f512ceSopenharmony_ci if (ret) { 45948f512ceSopenharmony_ci HLOGE("unwind error %d:%s see unw_error_t.", ret, GetUnwErrorName(ret).c_str()); 46048f512ceSopenharmony_ci return false; 46148f512ceSopenharmony_ci } else { 46248f512ceSopenharmony_ci UnwindStep(c, callStack, maxStackLevel); 46348f512ceSopenharmony_ci } 46448f512ceSopenharmony_ci return true; 46548f512ceSopenharmony_ci} 46648f512ceSopenharmony_ci#endif 46748f512ceSopenharmony_ci 46848f512ceSopenharmony_cibool CallStack::UnwindCallStack(const VirtualThread &thread, bool abi32, u64 *regs, u64 regsNum, 46948f512ceSopenharmony_ci const u8 *stack, u64 stackSize, std::vector<DfxFrame> &callStack, 47048f512ceSopenharmony_ci size_t maxStackLevel) 47148f512ceSopenharmony_ci{ 47248f512ceSopenharmony_ci regs_ = regs; 47348f512ceSopenharmony_ci regsNum_ = regsNum; 47448f512ceSopenharmony_ci stack_ = stack; 47548f512ceSopenharmony_ci stackSize_ = stackSize; 47648f512ceSopenharmony_ci 47748f512ceSopenharmony_ci arch_ = GetArchTypeFromABI(abi32); 47848f512ceSopenharmony_ci UpdateRegForABI(arch_, regs_); 47948f512ceSopenharmony_ci if (!RegisterGetSPValue(stackPoint_, arch_, regs_, regsNum_)) { 48048f512ceSopenharmony_ci HLOGE("RegisterGetSPValue failed"); 48148f512ceSopenharmony_ci return false; 48248f512ceSopenharmony_ci } else { 48348f512ceSopenharmony_ci stackEnd_ = stackPoint_ + stackSize_; 48448f512ceSopenharmony_ci } 48548f512ceSopenharmony_ci 48648f512ceSopenharmony_ci uint64_t ip; 48748f512ceSopenharmony_ci uint64_t sp; 48848f512ceSopenharmony_ci if (!GetIpSP(ip, sp, regs_, regsNum_)) { 48948f512ceSopenharmony_ci HLOGW("unable get sp or sp , unable unwind"); 49048f512ceSopenharmony_ci return false; 49148f512ceSopenharmony_ci } else { 49248f512ceSopenharmony_ci if (ip != 0) { 49348f512ceSopenharmony_ci HLOGV("unwind:%zu: ip 0x%" PRIx64 " sp 0x%" PRIx64 "", callStack.size(), ip, sp); 49448f512ceSopenharmony_ci callStack.emplace_back(ip, sp); 49548f512ceSopenharmony_ci } 49648f512ceSopenharmony_ci } 49748f512ceSopenharmony_ci 49848f512ceSopenharmony_ci /* 49948f512ceSopenharmony_ci * If we need more than one entry, do the DWARF 50048f512ceSopenharmony_ci * unwind itself. 50148f512ceSopenharmony_ci */ 50248f512ceSopenharmony_ci if (maxStackLevel - 1 > 0) { 50348f512ceSopenharmony_ci#if HAVE_LIBUNWIND 50448f512ceSopenharmony_ci return DoUnwind(thread, callStack, maxStackLevel); 50548f512ceSopenharmony_ci#else 50648f512ceSopenharmony_ci return DoUnwind2(thread, callStack, maxStackLevel); 50748f512ceSopenharmony_ci#endif 50848f512ceSopenharmony_ci } 50948f512ceSopenharmony_ci return true; 51048f512ceSopenharmony_ci} 51148f512ceSopenharmony_ci 51248f512ceSopenharmony_civoid CallStack::LogFrame(const std::string msg, const std::vector<DfxFrame> &frames) 51348f512ceSopenharmony_ci{ 51448f512ceSopenharmony_ci HLOGM("%s", msg.c_str()); 51548f512ceSopenharmony_ci int level = 0; 51648f512ceSopenharmony_ci for (auto& frame : frames) { 51748f512ceSopenharmony_ci HLOGM("%d:%s", level++, frame.ToString().c_str()); 51848f512ceSopenharmony_ci } 51948f512ceSopenharmony_ci} 52048f512ceSopenharmony_ci 52148f512ceSopenharmony_ci/* 52248f512ceSopenharmony_ciwe should have CallStack cache for each thread 52348f512ceSopenharmony_ciend begin 52448f512ceSopenharmony_ci0. A -> B -> C -> E -> F 52548f512ceSopenharmony_ci1. C -> E -> F 52648f512ceSopenharmony_ci2. B -> C 52748f512ceSopenharmony_ci3. A -> B -> C 52848f512ceSopenharmony_ci4. B -> G -> H 52948f512ceSopenharmony_ci5. J -> C 53048f512ceSopenharmony_ci 53148f512ceSopenharmony_ci0 is our cache 53248f512ceSopenharmony_ci1 2 3... is from record 53348f512ceSopenharmony_ci 53448f512ceSopenharmony_ciuse expandLimit to setup how may frame match is needs 53548f512ceSopenharmony_ci 53648f512ceSopenharmony_ci*/ 53748f512ceSopenharmony_cisize_t CallStack::DoExpandCallStack(std::vector<DfxFrame> &newCallFrames, 53848f512ceSopenharmony_ci const std::vector<DfxFrame> &cachedCallFrames, 53948f512ceSopenharmony_ci size_t expandLimit) 54048f512ceSopenharmony_ci{ 54148f512ceSopenharmony_ci int maxCycle = 0; 54248f512ceSopenharmony_ci 54348f512ceSopenharmony_ci if (expandLimit == 0 or newCallFrames.size() < expandLimit or 54448f512ceSopenharmony_ci cachedCallFrames.size() < expandLimit or 54548f512ceSopenharmony_ci cachedCallFrames.size() >= MAX_CALL_FRAME_UNWIND_SIZE) { 54648f512ceSopenharmony_ci HLOGM("expandLimit %zu not match new %zu cache %zu", expandLimit, newCallFrames.size(), 54748f512ceSopenharmony_ci cachedCallFrames.size()); 54848f512ceSopenharmony_ci return 0; // size not enough 54948f512ceSopenharmony_ci } 55048f512ceSopenharmony_ci 55148f512ceSopenharmony_ci // called (Stack Bottom) , this will NOT change when compare 55248f512ceSopenharmony_ci // in case1 newIt -> C 55348f512ceSopenharmony_ci // in case2 newIt -> B 55448f512ceSopenharmony_ci const auto newIt = newCallFrames.end() - expandLimit; 55548f512ceSopenharmony_ci if (newIt != newCallFrames.end()) { 55648f512ceSopenharmony_ci HLOGM("try find new call chain bottom %s for limit %zu", newIt->ToString().c_str(), 55748f512ceSopenharmony_ci expandLimit); 55848f512ceSopenharmony_ci } 55948f512ceSopenharmony_ci 56048f512ceSopenharmony_ci // first frame search, from called - > caller 56148f512ceSopenharmony_ci // for case 2 it should found B 56248f512ceSopenharmony_ci size_t distances = expandLimit - 1; 56348f512ceSopenharmony_ci auto cachedIt = find(cachedCallFrames.begin(), cachedCallFrames.end(), *newIt); 56448f512ceSopenharmony_ci if (cachedIt == cachedCallFrames.end()) { 56548f512ceSopenharmony_ci HLOGM("not found in first search"); 56648f512ceSopenharmony_ci } 56748f512ceSopenharmony_ci 56848f512ceSopenharmony_ci // cache frame found 56948f512ceSopenharmony_ci while (std::distance(cachedIt, cachedCallFrames.end()) >= signed(expandLimit)) { 57048f512ceSopenharmony_ci HLOG_ASSERT_MESSAGE(maxCycle++ < MAX_CALL_FRAME_EXPAND_CYCLE, "MAX_UNWIND_CYCLE = %d reach", 57148f512ceSopenharmony_ci MAX_CALL_FRAME_EXPAND_CYCLE); 57248f512ceSopenharmony_ci 57348f512ceSopenharmony_ci if (std::equal(newIt, newIt + expandLimit, cachedIt)) { 57448f512ceSopenharmony_ci HLOGM("match %s + %zu", newIt->ToString().c_str(), expandLimit); 57548f512ceSopenharmony_ci cachedIt += expandLimit; // in while we check the boundary safe 57648f512ceSopenharmony_ci if (cachedIt == cachedCallFrames.end()) { 57748f512ceSopenharmony_ci // same but no more need expand 57848f512ceSopenharmony_ci break; 57948f512ceSopenharmony_ci } 58048f512ceSopenharmony_ci 58148f512ceSopenharmony_ci // expand the frame and make some log ? 58248f512ceSopenharmony_ci LogFrame("newCallStack:", newCallFrames); 58348f512ceSopenharmony_ci LogFrame("cachedCallStack:", cachedCallFrames); 58448f512ceSopenharmony_ci 58548f512ceSopenharmony_ci newCallFrames.insert(newCallFrames.end(), cachedIt, cachedCallFrames.end()); 58648f512ceSopenharmony_ci auto expands = std::distance(cachedIt, cachedCallFrames.end()); 58748f512ceSopenharmony_ci HLOGV("merge callstack increse to %zu (+%zd) ", newCallFrames.size(), expands); 58848f512ceSopenharmony_ci // we done the deal 58948f512ceSopenharmony_ci return expands; 59048f512ceSopenharmony_ci } else { 59148f512ceSopenharmony_ci // quick search next same farme again 59248f512ceSopenharmony_ci cachedIt++; 59348f512ceSopenharmony_ci if (cachedIt != cachedCallFrames.end()) { 59448f512ceSopenharmony_ci HLOGM("search next"); 59548f512ceSopenharmony_ci cachedIt = find(cachedIt, cachedCallFrames.end(), *newIt); 59648f512ceSopenharmony_ci } 59748f512ceSopenharmony_ci } 59848f512ceSopenharmony_ci } 59948f512ceSopenharmony_ci HLOGM("cachedIt distance %zd , need %zd", std::distance(cachedCallFrames.begin(), cachedIt), 60048f512ceSopenharmony_ci distances); 60148f512ceSopenharmony_ci return 0u; // nothing expand 60248f512ceSopenharmony_ci} 60348f512ceSopenharmony_ci 60448f512ceSopenharmony_cisize_t CallStack::ExpandCallStack(pid_t tid, std::vector<DfxFrame> &callFrames, size_t expandLimit) 60548f512ceSopenharmony_ci{ 60648f512ceSopenharmony_ci size_t expand = 0u; 60748f512ceSopenharmony_ci if (expandLimit == 0) { 60848f512ceSopenharmony_ci return expand; // nothing need to do 60948f512ceSopenharmony_ci } else if (callFrames.size() < expandLimit) { 61048f512ceSopenharmony_ci HLOGM("new callstack is too small, skip it"); 61148f512ceSopenharmony_ci return expand; 61248f512ceSopenharmony_ci } 61348f512ceSopenharmony_ci if (!cachedCallFramesMap_.count(tid)) { 61448f512ceSopenharmony_ci cachedCallFramesMap_[tid].reserve(MAX_CALL_FRAME_EXPAND_CACHE_SIZE); 61548f512ceSopenharmony_ci } 61648f512ceSopenharmony_ci if (callFrames.size() >= 1u) { 61748f512ceSopenharmony_ci // get top (Earliest caller) 61848f512ceSopenharmony_ci HashList<uint64_t, std::vector<DfxFrame>> &cachedCallFrames = cachedCallFramesMap_[tid]; 61948f512ceSopenharmony_ci HLOGV("find call stack frames in cache size %zu", cachedCallFrames.size()); 62048f512ceSopenharmony_ci // compare 62148f512ceSopenharmony_ci using namespace std::rel_ops; // enable complement comparing operators 62248f512ceSopenharmony_ci for (auto itr = cachedCallFrames.begin(); itr < cachedCallFrames.end(); ++itr) { 62348f512ceSopenharmony_ci // each cached callstack 62448f512ceSopenharmony_ci /* 62548f512ceSopenharmony_ci stack 2 1 0 62648f512ceSopenharmony_ci cache A -> B -> C 62748f512ceSopenharmony_ci new B -> C 62848f512ceSopenharmony_ci check: 62948f512ceSopenharmony_ci 1 if new B == cache C 63048f512ceSopenharmony_ci 2 if new B == cache B 63148f512ceSopenharmony_ci 3 if new C == new C (if limit > 0) 63248f512ceSopenharmony_ci 4 insert A after B in new stack 63348f512ceSopenharmony_ci */ 63448f512ceSopenharmony_ci const std::vector<DfxFrame> &cachedCallStack = *itr; 63548f512ceSopenharmony_ci if (cachedCallStack.size() < expandLimit) { 63648f512ceSopenharmony_ci HLOGM("cache callstack is too small, skip it"); 63748f512ceSopenharmony_ci continue; // check next 63848f512ceSopenharmony_ci } 63948f512ceSopenharmony_ci expand = DoExpandCallStack(callFrames, cachedCallStack, expandLimit); 64048f512ceSopenharmony_ci if (expand > 0) { 64148f512ceSopenharmony_ci break; 64248f512ceSopenharmony_ci } 64348f512ceSopenharmony_ci } 64448f512ceSopenharmony_ci // add new one in to cache cachedCallFrames. 64548f512ceSopenharmony_ci // further optimization can be done by caching pointer which avoids copying 64648f512ceSopenharmony_ci // vector 64748f512ceSopenharmony_ci cachedCallFrames[callFrames[0].pc] = callFrames; 64848f512ceSopenharmony_ci } 64948f512ceSopenharmony_ci HLOGM("expand %zu", expand); 65048f512ceSopenharmony_ci return expand; 65148f512ceSopenharmony_ci} 65248f512ceSopenharmony_ci 65348f512ceSopenharmony_ci#if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER 65448f512ceSopenharmony_cibool CallStack::DoUnwind2(const VirtualThread &thread, std::vector<DfxFrame> &callStack, 65548f512ceSopenharmony_ci size_t maxStackLevel) 65648f512ceSopenharmony_ci{ 65748f512ceSopenharmony_ci#ifdef target_cpu_x86_64 65848f512ceSopenharmony_ci return false; 65948f512ceSopenharmony_ci#else 66048f512ceSopenharmony_ci UnwindInfo unwindInfo = { 66148f512ceSopenharmony_ci .thread = thread, 66248f512ceSopenharmony_ci .callStack = *this, 66348f512ceSopenharmony_ci }; 66448f512ceSopenharmony_ci 66548f512ceSopenharmony_ci if (pidUnwinder_.count(thread.pid_) == 0) { 66648f512ceSopenharmony_ci pidUnwinder_.emplace(thread.pid_, std::make_shared<Unwinder>(accessor_)); 66748f512ceSopenharmony_ci } 66848f512ceSopenharmony_ci auto unwinder = pidUnwinder_[thread.pid_]; 66948f512ceSopenharmony_ci 67048f512ceSopenharmony_ci#ifdef target_cpu_arm 67148f512ceSopenharmony_ci static std::shared_ptr<DfxRegs> regs = std::make_shared<DfxRegsArm>(); 67248f512ceSopenharmony_ci std::vector<uintptr_t> tempRegs; 67348f512ceSopenharmony_ci for (auto i = 0; i < regsNum_; ++i) { 67448f512ceSopenharmony_ci tempRegs.push_back(static_cast<uintptr_t>(regs_[i])); 67548f512ceSopenharmony_ci } 67648f512ceSopenharmony_ci regs->SetRegsData(tempRegs); 67748f512ceSopenharmony_ci#else 67848f512ceSopenharmony_ci static std::shared_ptr<DfxRegs> regs = std::make_shared<DfxRegsArm64>(); 67948f512ceSopenharmony_ci regs->SetRegsData(reinterpret_cast<uintptr_t*>(regs_), regsNum_); 68048f512ceSopenharmony_ci#endif 68148f512ceSopenharmony_ci CHECK_TRUE(unwinder == nullptr, false, 0, ""); 68248f512ceSopenharmony_ci unwinder->SetRegs(regs); 68348f512ceSopenharmony_ci unwinder->Unwind(&unwindInfo); 68448f512ceSopenharmony_ci callStack = unwinder->GetFrames(); 68548f512ceSopenharmony_ci HLOGD("callStack size:%zu", callStack.size()); 68648f512ceSopenharmony_ci for (auto frame: callStack) { 68748f512ceSopenharmony_ci HLOGD("pc 0x%" PRIx64 " sp 0x%" PRIx64 "", frame.pc, frame.sp); 68848f512ceSopenharmony_ci } 68948f512ceSopenharmony_ci auto lastIt = callStack.end() - 1; 69048f512ceSopenharmony_ci auto preIt = lastIt - 1; 69148f512ceSopenharmony_ci if (lastIt != callStack.end() && preIt != callStack.end() && 69248f512ceSopenharmony_ci callStack.size() > 1 && lastIt->pc == preIt->pc && lastIt->sp == preIt->sp) { 69348f512ceSopenharmony_ci callStack.erase(lastIt); 69448f512ceSopenharmony_ci HLOGD("remove last callframe"); 69548f512ceSopenharmony_ci } 69648f512ceSopenharmony_ci return true; 69748f512ceSopenharmony_ci#endif 69848f512ceSopenharmony_ci} 69948f512ceSopenharmony_ci 70048f512ceSopenharmony_civoid CallStack::DumpTableInfo(UnwindTableInfo &outTableInfo) 70148f512ceSopenharmony_ci{ 70248f512ceSopenharmony_ci HLOGV("unwind_table info: "); 70348f512ceSopenharmony_ci HLOGV(" start_ip: 0x%016" UNW_WORD_PFLAG "", outTableInfo.startPc); 70448f512ceSopenharmony_ci HLOGV(" end_ip: 0x%016" UNW_WORD_PFLAG "", outTableInfo.endPc); 70548f512ceSopenharmony_ci HLOGV(" segbase: 0x%016" UNW_WORD_PFLAG "", outTableInfo.segbase); 70648f512ceSopenharmony_ci HLOGV(" table_data: 0x%016" UNW_WORD_PFLAG "", outTableInfo.tableData); 70748f512ceSopenharmony_ci HLOGV(" table_len: 0x%016" UNW_WORD_PFLAG "", outTableInfo.tableLen); 70848f512ceSopenharmony_ci} 70948f512ceSopenharmony_ci 71048f512ceSopenharmony_ciint CallStack::FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr, 71148f512ceSopenharmony_ci uintptr_t pc, UnwindTableInfo& outTableInfo) 71248f512ceSopenharmony_ci{ 71348f512ceSopenharmony_ci HLOGM("try search debug info at %s", symbolsFile->filePath_.c_str()); 71448f512ceSopenharmony_ci CHECK_TRUE(unwindInfoPtr == nullptr, -1, 0, ""); 71548f512ceSopenharmony_ci auto &tableInfoMap = unwindInfoPtr->callStack.unwindTableInfoMap_; 71648f512ceSopenharmony_ci // all the thread in same process have same mmap and symbols 71748f512ceSopenharmony_ci if (tableInfoMap.find(unwindInfoPtr->thread.pid_) == tableInfoMap.end()) { 71848f512ceSopenharmony_ci tableInfoMap.emplace(unwindInfoPtr->thread.pid_, DsoUnwindTableInfoMap {}); 71948f512ceSopenharmony_ci } 72048f512ceSopenharmony_ci DsoUnwindTableInfoMap &unwTabMap = tableInfoMap[unwindInfoPtr->thread.pid_]; 72148f512ceSopenharmony_ci // find use dso name as key 72248f512ceSopenharmony_ci if (unwTabMap.find(symbolsFile->filePath_) == unwTabMap.end()) { 72348f512ceSopenharmony_ci UnwindTableInfo uti; 72448f512ceSopenharmony_ci auto elf = symbolsFile->GetElfFile(); 72548f512ceSopenharmony_ci if (elf == nullptr) { 72648f512ceSopenharmony_ci return -1; 72748f512ceSopenharmony_ci } 72848f512ceSopenharmony_ci if (elf->FindUnwindTableInfo(pc, map, uti) == 0) { 72948f512ceSopenharmony_ci CHECK_TRUE(uti.format == -1, -1, 1, "parse unwind table failed."); 73048f512ceSopenharmony_ci unwTabMap[symbolsFile->filePath_] = uti; 73148f512ceSopenharmony_ci outTableInfo = unwTabMap[symbolsFile->filePath_]; 73248f512ceSopenharmony_ci DumpTableInfo(uti); 73348f512ceSopenharmony_ci return 0; 73448f512ceSopenharmony_ci } else { 73548f512ceSopenharmony_ci HLOGV("FillUnwindTable failed"); 73648f512ceSopenharmony_ci return -1; 73748f512ceSopenharmony_ci } 73848f512ceSopenharmony_ci } else { 73948f512ceSopenharmony_ci outTableInfo = unwTabMap[symbolsFile->filePath_]; 74048f512ceSopenharmony_ci return 0; 74148f512ceSopenharmony_ci } 74248f512ceSopenharmony_ci return -1; 74348f512ceSopenharmony_ci} 74448f512ceSopenharmony_ci 74548f512ceSopenharmony_ciint CallStack::FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg) 74648f512ceSopenharmony_ci{ 74748f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg); 74848f512ceSopenharmony_ci CHECK_TRUE(unwindInfoPtr == nullptr, -1, 0, ""); 74948f512ceSopenharmony_ci int64_t mapIndex = unwindInfoPtr->thread.FindMapIndexByAddr(pc); 75048f512ceSopenharmony_ci if (mapIndex >= 0) { 75148f512ceSopenharmony_ci auto map = unwindInfoPtr->thread.GetMaps()[mapIndex]; 75248f512ceSopenharmony_ci if (map != nullptr) { 75348f512ceSopenharmony_ci SymbolsFile *symbolsFile = unwindInfoPtr->thread.FindSymbolsFileByMap(map); 75448f512ceSopenharmony_ci if (symbolsFile != nullptr) { 75548f512ceSopenharmony_ci return FillUnwindTable(symbolsFile, map, unwindInfoPtr, pc, outTableInfo); 75648f512ceSopenharmony_ci } else { 75748f512ceSopenharmony_ci HLOGD("no symbols file found for thread %d:%s", unwindInfoPtr->thread.tid_, 75848f512ceSopenharmony_ci unwindInfoPtr->thread.name_.c_str()); 75948f512ceSopenharmony_ci } 76048f512ceSopenharmony_ci } else { 76148f512ceSopenharmony_ci HLOGD("pc 0x%016" UNW_WORD_PFLAG " not found in thread %d:%s", pc, 76248f512ceSopenharmony_ci unwindInfoPtr->thread.tid_, unwindInfoPtr->thread.name_.c_str()); 76348f512ceSopenharmony_ci } 76448f512ceSopenharmony_ci } else { 76548f512ceSopenharmony_ci HLOGD("map index is -1"); 76648f512ceSopenharmony_ci } 76748f512ceSopenharmony_ci return -1; 76848f512ceSopenharmony_ci} 76948f512ceSopenharmony_ci 77048f512ceSopenharmony_ciint CallStack::AccessMem2(uintptr_t addr, uintptr_t *val, void *arg) 77148f512ceSopenharmony_ci{ 77248f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg); 77348f512ceSopenharmony_ci *val = 0; 77448f512ceSopenharmony_ci 77548f512ceSopenharmony_ci /* Check overflow. */ 77648f512ceSopenharmony_ci CHECK_TRUE(unwindInfoPtr == nullptr || (addr + sizeof(uintptr_t) < addr), -1, 1, 77748f512ceSopenharmony_ci "unwindInfoPtr is null or address overflow at 0x%" UNW_WORD_PFLAG " increase 0x%zu", 77848f512ceSopenharmony_ci addr, sizeof(uintptr_t)); 77948f512ceSopenharmony_ci 78048f512ceSopenharmony_ci if (addr < unwindInfoPtr->callStack.stackPoint_ or 78148f512ceSopenharmony_ci addr + sizeof(uintptr_t) >= unwindInfoPtr->callStack.stackEnd_) { 78248f512ceSopenharmony_ci if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, val)) { 78348f512ceSopenharmony_ci HLOGM("access_mem addr get val 0x%" UNW_WORD_PFLAG ", from mmap", *val); 78448f512ceSopenharmony_ci } else { 78548f512ceSopenharmony_ci HLOGW("access_mem mmap 0x%" PRIx64 " failed, STACK RANGE 0x%" PRIx64 "- 0x%" PRIx64 "(0x%" PRIx64 ")", 78648f512ceSopenharmony_ci (uint64_t)addr, 78748f512ceSopenharmony_ci unwindInfoPtr->callStack.stackPoint_, unwindInfoPtr->callStack.stackEnd_, 78848f512ceSopenharmony_ci unwindInfoPtr->callStack.stackEnd_ - unwindInfoPtr->callStack.stackPoint_); 78948f512ceSopenharmony_ci return -1; 79048f512ceSopenharmony_ci } 79148f512ceSopenharmony_ci } else { 79248f512ceSopenharmony_ci size_t stackOffset = addr - unwindInfoPtr->callStack.stackPoint_; 79348f512ceSopenharmony_ci *val = *(uintptr_t *)&unwindInfoPtr->callStack.stack_[stackOffset]; 79448f512ceSopenharmony_ci HLOGM("access_mem addr %p val %" UNW_WORD_PFLAG ", from stack offset %zu", 79548f512ceSopenharmony_ci reinterpret_cast<void *>(addr), *val, stackOffset); 79648f512ceSopenharmony_ci } 79748f512ceSopenharmony_ci 79848f512ceSopenharmony_ci return 0; 79948f512ceSopenharmony_ci} 80048f512ceSopenharmony_ciint CallStack::GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg) 80148f512ceSopenharmony_ci{ 80248f512ceSopenharmony_ci UnwindInfo *unwindInfoPtr = static_cast<UnwindInfo *>(arg); 80348f512ceSopenharmony_ci int64_t mapIndex = unwindInfoPtr->thread.FindMapIndexByAddr(pc); 80448f512ceSopenharmony_ci if (mapIndex >= 0) { 80548f512ceSopenharmony_ci map = unwindInfoPtr->thread.GetMaps()[mapIndex]; 80648f512ceSopenharmony_ci if (map != nullptr) { 80748f512ceSopenharmony_ci return 0; 80848f512ceSopenharmony_ci } 80948f512ceSopenharmony_ci } 81048f512ceSopenharmony_ci HLOGD("pc 0x%016" UNW_WORD_PFLAG " not found in thread %d:%s", pc, 81148f512ceSopenharmony_ci unwindInfoPtr->thread.tid_, unwindInfoPtr->thread.name_.c_str()); 81248f512ceSopenharmony_ci return -1; 81348f512ceSopenharmony_ci} 81448f512ceSopenharmony_ci#endif 81548f512ceSopenharmony_ci 81648f512ceSopenharmony_ciCallStack::CallStack() 81748f512ceSopenharmony_ci{ 81848f512ceSopenharmony_ci#if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER 81948f512ceSopenharmony_ci accessor_ = std::make_shared<OHOS::HiviewDFX::UnwindAccessors>(); 82048f512ceSopenharmony_ci accessor_->FindUnwindTable = &CallStack::FindUnwindTable; 82148f512ceSopenharmony_ci accessor_->AccessMem = &CallStack::AccessMem2; 82248f512ceSopenharmony_ci accessor_->AccessReg = nullptr; 82348f512ceSopenharmony_ci accessor_->GetMapByPc = &CallStack::GetMapByPc; 82448f512ceSopenharmony_ci#endif 82548f512ceSopenharmony_ci} 82648f512ceSopenharmony_ci 82748f512ceSopenharmony_ciCallStack::~CallStack() 82848f512ceSopenharmony_ci{ 82948f512ceSopenharmony_ci#if HAVE_LIBUNWIND 83048f512ceSopenharmony_ci for (auto &pair : unwindAddrSpaceMap_) { 83148f512ceSopenharmony_ci unw_destroy_addr_space(pair.second); 83248f512ceSopenharmony_ci } 83348f512ceSopenharmony_ci#endif 83448f512ceSopenharmony_ci} 83548f512ceSopenharmony_ci} // namespace HiPerf 83648f512ceSopenharmony_ci} // namespace Developtools 83748f512ceSopenharmony_ci} // namespace OHOS 838