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 bool jsReport = true); 48 size_t ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expendLimit = 1u); 49 50 private: 51 uint64_t stackPoint_ = 0; 52 uint64_t stackEnd_ = 0; 53 u64 *regs_ = nullptr; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI 54 u64 regsNum_ = 0; 55 const u8 *stack_ = nullptr; 56 u64 stackSize_ = 0; 57 58 void LogFrame(const std::string msg, const std::vector<CallFrame> &frames); 59 size_t ExpendCallStack(std::vector<CallFrame> &newCallFrames, 60 const std::vector<CallFrame> &cachedCallFrames, size_t expendLimit); 61 62 // we have a cache for all thread 63 std::map<pid_t, HashList<uint64_t, std::vector<CallFrame>>> cachedCallFramesMap_; 64 bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const; 65 ArchType arch_ = ArchType::ARCH_UNKNOWN; 66 using unwMemoryCache = std::unordered_map<ADDR_TYPE, ADDR_TYPE>; 67 std::unordered_map<pid_t, unwMemoryCache> porcessMemoryMap_; 68 static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, ADDR_TYPE addr, 69 ADDR_TYPE *data); 70 #if defined(HAVE_LIBUNWIND) && HAVE_LIBUNWIND 71 static const std::string GetUnwErrorName(int error); 72 static void dumpUDI(unw_dyn_info_t &di); 73 static bool fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, std::shared_ptr<DfxMap> mapmmap, 74 const VirtualThread &thread); 75 static int FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 76 int need_unwind_info, void *arg); 77 static int AccessMem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valuePoint, 78 int writeOperation, void *arg); 79 static int AccessReg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valuePoint, 80 int writeOperation, void *arg); 81 static void PutUnwindInfo(unw_addr_space_t as, unw_proc_info_t *pi, void *arg); 82 static int AccessFpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val, 83 int writeOperation, void *arg); 84 static int GetDynInfoListAaddr(unw_addr_space_t as, unw_word_t *dil_vaddr, void *arg); 85 static int Resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg); 86 static int getProcName(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, 87 unw_word_t *offp, void *arg); 88 static int FindUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> mapmap, 89 UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, 90 unw_proc_info_t *pi, int need_unwind_info, void *arg); 91 void UnwindStep(unw_cursor_t &c, std::vector<CallFrame> &callFrames, size_t maxStackLevel); 92 std::unordered_map<pid_t, unw_addr_space_t> unwindAddrSpaceMap_; 93 94 using dsoUnwDynInfoMap = std::unordered_map<std::string, std::optional<unw_dyn_info_t>>; 95 std::unordered_map<pid_t, dsoUnwDynInfoMap> unwindTableInfoMap_; 96 unw_accessors_t accessors_ = { 97 .find_proc_info = FindProcInfo, 98 .put_unwind_info = PutUnwindInfo, 99 .get_dyn_info_list_addr = GetDynInfoListAaddr, 100 .access_mem = AccessMem, 101 .access_reg = AccessReg, 102 .access_fpreg = AccessFpreg, 103 .resume = Resume, 104 .get_proc_name = getProcName, 105 }; 106 bool DoUnwind(const VirtualThread &thread, std::vector<CallFrame> &callStack, 107 size_t maxStackLevel); 108 #endif 109 #if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER 110 #ifdef target_cpu_arm64 111 static bool CheckAndStepArkFrame(const VirtualThread &thread, uintptr_t& pc, uintptr_t& fp, uintptr_t& sp); 112 #endif 113 bool DoUnwind2(const VirtualThread &thread, std::vector<CallFrame> &callStack, size_t maxStackLevel, 114 int maxjsDepth = 0, bool jsReport = true); 115 static void DumpTableInfo(UnwindTableInfo &outTableInfo); 116 static int FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr, 117 uintptr_t pc, UnwindTableInfo& outTableInfo); 118 static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg); 119 static int AccessMem2(uintptr_t addr, uintptr_t *val, void *arg); 120 static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg); 121 122 // pid->unwinder(acc/regs/maps) cache 123 std::unordered_map<pid_t, std::shared_ptr<Unwinder>> pidUnwinder_; 124 // pid->elf->unwindtable cache 125 using DsoUnwindTableInfoMap = std::unordered_map<std::string, UnwindTableInfo>; 126 std::unordered_map<pid_t, DsoUnwindTableInfoMap> unwindTableInfoMap_; 127 128 std::shared_ptr<UnwindAccessors> accessor_; 129 #endif 130 }; 131 132 struct UnwindInfo { 133 const VirtualThread &thread; 134 const u64 *regs; 135 size_t regNumber; 136 ArchType arch; 137 CallStack &callStack; 138 }; 139 } // namespace NativeDaemon 140 } // namespace Developtools 141 } // namespace OHOS 142 #endif