106f6ba60Sopenharmony_ci/* 206f6ba60Sopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 306f6ba60Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 406f6ba60Sopenharmony_ci * you may not use this file except in compliance with the License. 506f6ba60Sopenharmony_ci * You may obtain a copy of the License at 606f6ba60Sopenharmony_ci * 706f6ba60Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 806f6ba60Sopenharmony_ci * 906f6ba60Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1006f6ba60Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1106f6ba60Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1206f6ba60Sopenharmony_ci * See the License for the specific language governing permissions and 1306f6ba60Sopenharmony_ci * limitations under the License. 1406f6ba60Sopenharmony_ci */ 1506f6ba60Sopenharmony_ci#ifndef HIPERF_CALLSTACK_H 1606f6ba60Sopenharmony_ci#define HIPERF_CALLSTACK_H 1706f6ba60Sopenharmony_ci 1806f6ba60Sopenharmony_ci#include <map> 1906f6ba60Sopenharmony_ci#include <string> 2006f6ba60Sopenharmony_ci#include <unordered_map> 2106f6ba60Sopenharmony_ci#include <vector> 2206f6ba60Sopenharmony_ci 2306f6ba60Sopenharmony_ci#include "hashlistpp.h" 2406f6ba60Sopenharmony_ci#include "perf_event_record.h" 2506f6ba60Sopenharmony_ci#include "unwinder.h" 2606f6ba60Sopenharmony_ci#include "virtual_thread.h" 2706f6ba60Sopenharmony_ci#include "hook_common.h" 2806f6ba60Sopenharmony_ci#if defined(HAVE_LIBUNWIND) && HAVE_LIBUNWIND 2906f6ba60Sopenharmony_ciusing ADDR_TYPE = unw_word_t; 3006f6ba60Sopenharmony_ci#else 3106f6ba60Sopenharmony_ciusing ADDR_TYPE = uintptr_t; 3206f6ba60Sopenharmony_ci#endif 3306f6ba60Sopenharmony_cinamespace OHOS { 3406f6ba60Sopenharmony_cinamespace Developtools { 3506f6ba60Sopenharmony_cinamespace NativeDaemon { 3606f6ba60Sopenharmony_ciusing namespace OHOS::HiviewDFX; 3706f6ba60Sopenharmony_ci 3806f6ba60Sopenharmony_cistruct UnwindInfo; 3906f6ba60Sopenharmony_ci 4006f6ba60Sopenharmony_ciclass CallStack { 4106f6ba60Sopenharmony_cipublic: 4206f6ba60Sopenharmony_ci CallStack(); 4306f6ba60Sopenharmony_ci ~CallStack(); 4406f6ba60Sopenharmony_ci bool UnwindCallStack(const VirtualThread &thread, u64 *regs, u64 regsNum, 4506f6ba60Sopenharmony_ci const u8 *stack, u64 stackSize, std::vector<CallFrame> &, 4606f6ba60Sopenharmony_ci size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE, int maxjsDepth = 0, 4706f6ba60Sopenharmony_ci bool jsReport = true); 4806f6ba60Sopenharmony_ci size_t ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expendLimit = 1u); 4906f6ba60Sopenharmony_ci 5006f6ba60Sopenharmony_ciprivate: 5106f6ba60Sopenharmony_ci uint64_t stackPoint_ = 0; 5206f6ba60Sopenharmony_ci uint64_t stackEnd_ = 0; 5306f6ba60Sopenharmony_ci u64 *regs_ = nullptr; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI 5406f6ba60Sopenharmony_ci u64 regsNum_ = 0; 5506f6ba60Sopenharmony_ci const u8 *stack_ = nullptr; 5606f6ba60Sopenharmony_ci u64 stackSize_ = 0; 5706f6ba60Sopenharmony_ci 5806f6ba60Sopenharmony_ci void LogFrame(const std::string msg, const std::vector<CallFrame> &frames); 5906f6ba60Sopenharmony_ci size_t ExpendCallStack(std::vector<CallFrame> &newCallFrames, 6006f6ba60Sopenharmony_ci const std::vector<CallFrame> &cachedCallFrames, size_t expendLimit); 6106f6ba60Sopenharmony_ci 6206f6ba60Sopenharmony_ci // we have a cache for all thread 6306f6ba60Sopenharmony_ci std::map<pid_t, HashList<uint64_t, std::vector<CallFrame>>> cachedCallFramesMap_; 6406f6ba60Sopenharmony_ci bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const; 6506f6ba60Sopenharmony_ci ArchType arch_ = ArchType::ARCH_UNKNOWN; 6606f6ba60Sopenharmony_ci using unwMemoryCache = std::unordered_map<ADDR_TYPE, ADDR_TYPE>; 6706f6ba60Sopenharmony_ci std::unordered_map<pid_t, unwMemoryCache> porcessMemoryMap_; 6806f6ba60Sopenharmony_ci static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, ADDR_TYPE addr, 6906f6ba60Sopenharmony_ci ADDR_TYPE *data); 7006f6ba60Sopenharmony_ci#if defined(HAVE_LIBUNWIND) && HAVE_LIBUNWIND 7106f6ba60Sopenharmony_ci static const std::string GetUnwErrorName(int error); 7206f6ba60Sopenharmony_ci static void dumpUDI(unw_dyn_info_t &di); 7306f6ba60Sopenharmony_ci static bool fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, std::shared_ptr<DfxMap> mapmmap, 7406f6ba60Sopenharmony_ci const VirtualThread &thread); 7506f6ba60Sopenharmony_ci static int FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 7606f6ba60Sopenharmony_ci int need_unwind_info, void *arg); 7706f6ba60Sopenharmony_ci static int AccessMem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valuePoint, 7806f6ba60Sopenharmony_ci int writeOperation, void *arg); 7906f6ba60Sopenharmony_ci static int AccessReg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valuePoint, 8006f6ba60Sopenharmony_ci int writeOperation, void *arg); 8106f6ba60Sopenharmony_ci static void PutUnwindInfo(unw_addr_space_t as, unw_proc_info_t *pi, void *arg); 8206f6ba60Sopenharmony_ci static int AccessFpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val, 8306f6ba60Sopenharmony_ci int writeOperation, void *arg); 8406f6ba60Sopenharmony_ci static int GetDynInfoListAaddr(unw_addr_space_t as, unw_word_t *dil_vaddr, void *arg); 8506f6ba60Sopenharmony_ci static int Resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg); 8606f6ba60Sopenharmony_ci static int getProcName(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, 8706f6ba60Sopenharmony_ci unw_word_t *offp, void *arg); 8806f6ba60Sopenharmony_ci static int FindUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> mapmap, 8906f6ba60Sopenharmony_ci UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, 9006f6ba60Sopenharmony_ci unw_proc_info_t *pi, int need_unwind_info, void *arg); 9106f6ba60Sopenharmony_ci void UnwindStep(unw_cursor_t &c, std::vector<CallFrame> &callFrames, size_t maxStackLevel); 9206f6ba60Sopenharmony_ci std::unordered_map<pid_t, unw_addr_space_t> unwindAddrSpaceMap_; 9306f6ba60Sopenharmony_ci 9406f6ba60Sopenharmony_ci using dsoUnwDynInfoMap = std::unordered_map<std::string, std::optional<unw_dyn_info_t>>; 9506f6ba60Sopenharmony_ci std::unordered_map<pid_t, dsoUnwDynInfoMap> unwindTableInfoMap_; 9606f6ba60Sopenharmony_ci unw_accessors_t accessors_ = { 9706f6ba60Sopenharmony_ci .find_proc_info = FindProcInfo, 9806f6ba60Sopenharmony_ci .put_unwind_info = PutUnwindInfo, 9906f6ba60Sopenharmony_ci .get_dyn_info_list_addr = GetDynInfoListAaddr, 10006f6ba60Sopenharmony_ci .access_mem = AccessMem, 10106f6ba60Sopenharmony_ci .access_reg = AccessReg, 10206f6ba60Sopenharmony_ci .access_fpreg = AccessFpreg, 10306f6ba60Sopenharmony_ci .resume = Resume, 10406f6ba60Sopenharmony_ci .get_proc_name = getProcName, 10506f6ba60Sopenharmony_ci }; 10606f6ba60Sopenharmony_ci bool DoUnwind(const VirtualThread &thread, std::vector<CallFrame> &callStack, 10706f6ba60Sopenharmony_ci size_t maxStackLevel); 10806f6ba60Sopenharmony_ci#endif 10906f6ba60Sopenharmony_ci#if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER 11006f6ba60Sopenharmony_ci#ifdef target_cpu_arm64 11106f6ba60Sopenharmony_ci static bool CheckAndStepArkFrame(const VirtualThread &thread, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp); 11206f6ba60Sopenharmony_ci#endif 11306f6ba60Sopenharmony_ci bool DoUnwind2(const VirtualThread &thread, std::vector<CallFrame> &callStack, size_t maxStackLevel, 11406f6ba60Sopenharmony_ci int maxjsDepth = 0, bool jsReport = true); 11506f6ba60Sopenharmony_ci static void DumpTableInfo(UnwindTableInfo &outTableInfo); 11606f6ba60Sopenharmony_ci static int FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr, 11706f6ba60Sopenharmony_ci uintptr_t pc, UnwindTableInfo& outTableInfo); 11806f6ba60Sopenharmony_ci static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg); 11906f6ba60Sopenharmony_ci static int AccessMem2(uintptr_t addr, uintptr_t *val, void *arg); 12006f6ba60Sopenharmony_ci static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg); 12106f6ba60Sopenharmony_ci 12206f6ba60Sopenharmony_ci // pid->unwinder(acc/regs/maps) cache 12306f6ba60Sopenharmony_ci std::unordered_map<pid_t, std::shared_ptr<Unwinder>> pidUnwinder_; 12406f6ba60Sopenharmony_ci // pid->elf->unwindtable cache 12506f6ba60Sopenharmony_ci using DsoUnwindTableInfoMap = std::unordered_map<std::string, UnwindTableInfo>; 12606f6ba60Sopenharmony_ci std::unordered_map<pid_t, DsoUnwindTableInfoMap> unwindTableInfoMap_; 12706f6ba60Sopenharmony_ci 12806f6ba60Sopenharmony_ci std::shared_ptr<UnwindAccessors> accessor_; 12906f6ba60Sopenharmony_ci#endif 13006f6ba60Sopenharmony_ci}; 13106f6ba60Sopenharmony_ci 13206f6ba60Sopenharmony_cistruct UnwindInfo { 13306f6ba60Sopenharmony_ci const VirtualThread &thread; 13406f6ba60Sopenharmony_ci const u64 *regs; 13506f6ba60Sopenharmony_ci size_t regNumber; 13606f6ba60Sopenharmony_ci ArchType arch; 13706f6ba60Sopenharmony_ci CallStack &callStack; 13806f6ba60Sopenharmony_ci}; 13906f6ba60Sopenharmony_ci} // namespace NativeDaemon 14006f6ba60Sopenharmony_ci} // namespace Developtools 14106f6ba60Sopenharmony_ci} // namespace OHOS 14206f6ba60Sopenharmony_ci#endif