1 /* 2 * Copyright (c) Huawei Technologies Co., Ltd. 2021. All rights reserved. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef HIPERF_CALLSTACK_H 16 #define HIPERF_CALLSTACK_H 17 18 #include <map> 19 #include <string> 20 #include <unordered_map> 21 #include <vector> 22 23 #include "hashlistpp.h" 24 #include "perf_event_record.h" 25 #include "unwinder.h" 26 #include "virtual_thread.h" 27 #include "hook_common.h" 28 #if defined(HAVE_LIBUNWIND) && HAVE_LIBUNWIND 29 using ADDR_TYPE = unw_word_t; 30 #else 31 using ADDR_TYPE = uintptr_t; 32 #endif 33 namespace OHOS { 34 namespace Developtools { 35 namespace NativeDaemon { 36 using namespace OHOS::HiviewDFX; 37 38 struct UnwindInfo; 39 40 class CallStack { 41 public: 42 CallStack(); 43 ~CallStack(); 44 bool UnwindCallStack(const VirtualThread &thread, u64 *regs, u64 regsNum, 45 const u8 *stack, u64 stackSize, std::vector<CallFrame> &, 46 size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE, int maxjsDepth = 0); 47 size_t ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expendLimit = 1u); 48 49 private: 50 uint64_t stackPoint_ = 0; 51 uint64_t stackEnd_ = 0; 52 u64 *regs_ = nullptr; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI 53 u64 regsNum_ = 0; 54 const u8 *stack_ = nullptr; 55 u64 stackSize_ = 0; 56 57 void LogFrame(const std::string msg, const std::vector<CallFrame> &frames); 58 size_t ExpendCallStack(std::vector<CallFrame> &newCallFrames, 59 const std::vector<CallFrame> &cachedCallFrames, size_t expendLimit); 60 61 // we have a cache for all thread 62 std::map<pid_t, HashList<uint64_t, std::vector<CallFrame>>> cachedCallFramesMap_; 63 bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const; 64 ArchType arch_ = ArchType::ARCH_UNKNOWN; 65 using unwMemoryCache = std::unordered_map<ADDR_TYPE, ADDR_TYPE>; 66 std::unordered_map<pid_t, unwMemoryCache> porcessMemoryMap_; 67 static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, ADDR_TYPE addr, 68 ADDR_TYPE *data); 69 #if defined(HAVE_LIBUNWIND) && HAVE_LIBUNWIND 70 static const std::string GetUnwErrorName(int error); 71 static void dumpUDI(unw_dyn_info_t &di); 72 static bool fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, std::shared_ptr<DfxMap> mapmmap, 73 const VirtualThread &thread); 74 static int FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 75 int need_unwind_info, void *arg); 76 static int AccessMem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valuePoint, 77 int writeOperation, void *arg); 78 static int AccessReg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valuePoint, 79 int writeOperation, void *arg); 80 static void PutUnwindInfo(unw_addr_space_t as, unw_proc_info_t *pi, void *arg); 81 static int AccessFpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val, 82 int writeOperation, void *arg); 83 static int GetDynInfoListAaddr(unw_addr_space_t as, unw_word_t *dil_vaddr, void *arg); 84 static int Resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg); 85 static int getProcName(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, 86 unw_word_t *offp, void *arg); 87 static int FindUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> mapmap, 88 UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, 89 unw_proc_info_t *pi, int need_unwind_info, void *arg); 90 void UnwindStep(unw_cursor_t &c, std::vector<CallFrame> &callFrames, size_t maxStackLevel); 91 std::unordered_map<pid_t, unw_addr_space_t> unwindAddrSpaceMap_; 92 93 using dsoUnwDynInfoMap = std::unordered_map<std::string, std::optional<unw_dyn_info_t>>; 94 std::unordered_map<pid_t, dsoUnwDynInfoMap> unwindTableInfoMap_; 95 unw_accessors_t accessors_ = { 96 .find_proc_info = FindProcInfo, 97 .put_unwind_info = PutUnwindInfo, 98 .get_dyn_info_list_addr = GetDynInfoListAaddr, 99 .access_mem = AccessMem, 100 .access_reg = AccessReg, 101 .access_fpreg = AccessFpreg, 102 .resume = Resume, 103 .get_proc_name = getProcName, 104 }; 105 bool DoUnwind(const VirtualThread &thread, std::vector<CallFrame> &callStack, 106 size_t maxStackLevel); 107 #endif 108 #if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER 109 #ifdef target_cpu_arm64 110 static bool CheckAndStepArkFrame(const VirtualThread &thread, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp); 111 #endif 112 bool DoUnwind2(const VirtualThread &thread, std::vector<CallFrame> &callStack, size_t maxStackLevel, 113 int maxjsDepth = 0); 114 static void DumpTableInfo(UnwindTableInfo &outTableInfo); 115 static int FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr, 116 uintptr_t pc, UnwindTableInfo& outTableInfo); 117 static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg); 118 static int AccessMem2(uintptr_t addr, uintptr_t *val, void *arg); 119 static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg); 120 121 // pid->unwinder(acc/regs/maps) cache 122 std::unordered_map<pid_t, std::shared_ptr<Unwinder>> pidUnwinder_; 123 // pid->elf->unwindtable cache 124 using DsoUnwindTableInfoMap = std::unordered_map<std::string, UnwindTableInfo>; 125 std::unordered_map<pid_t, DsoUnwindTableInfoMap> unwindTableInfoMap_; 126 127 std::shared_ptr<UnwindAccessors> accessor_; 128 #endif 129 FRIEND_TEST(CallStackTest, ExpendCallStackFullCache); 130 FRIEND_TEST(CallStackTest, LibUnwindEmptyFunc); 131 FRIEND_TEST(CallStackTest, GetUnwErrorName); 132 }; 133 134 struct UnwindInfo { 135 const VirtualThread &thread; 136 const u64 *regs; 137 size_t regNumber; 138 ArchType arch; 139 CallStack &callStack; 140 }; 141 } // namespace NativeDaemon 142 } // namespace Developtools 143 } // namespace OHOS 144 #endif