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