1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 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 "virtual_thread.h" 26 #include "hook_common.h" 27 namespace OHOS { 28 namespace Developtools { 29 namespace NativeDaemon { 30 #if HAVE_LIBUNWIND 31 struct UnwindInfo; 32 #endif 33 34 class CallStack { 35 public: 36 CallStack(); 37 ~CallStack(); 38 bool UnwindCallStack(const VirtualThread &thread, u64 *regs, u64 regsNum, 39 const u8 *stack, u64 stackSize, std::vector<CallFrame> &, 40 size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE); 41 size_t ExpendCallStack(pid_t tid, std::vector<CallFrame> &callFrames, size_t expendLimit = 1u); 42 43 private: 44 uint64_t stackPoint_ = 0; 45 uint64_t stackEnd_ = 0; 46 u64 *regs_ = nullptr; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI 47 u64 regsNum_ = 0; 48 const u8 *stack_ = nullptr; 49 u64 stackSize_ = 0; 50 51 void LogFrame(const std::string msg, const std::vector<CallFrame> &frames); 52 size_t ExpendCallStack(std::vector<CallFrame> &newCallFrames, 53 const std::vector<CallFrame> &cachedCallFrames, size_t expendLimit); 54 55 // we have a cache for all thread 56 std::map<pid_t, HashList<uint64_t, std::vector<CallFrame>>> cachedCallFramesMap_; 57 bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const; 58 ArchType arch_ = ArchType::UNSUPPORT; 59 #if HAVE_LIBUNWIND 60 static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, unw_word_t addr, 61 unw_word_t *data); 62 static const std::string GetUnwErrorName(int error); 63 static void dumpUDI(unw_dyn_info_t &di); 64 static bool fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, const MemMapItem &mmap, 65 const VirtualThread &thread); 66 static int FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, 67 int need_unwind_info, void *arg); 68 static int AccessMem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valuePoint, 69 int writeOperation, void *arg); 70 static int AccessReg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valuePoint, 71 int writeOperation, void *arg); 72 static void PutUnwindInfo(unw_addr_space_t as, unw_proc_info_t *pi, void *arg); 73 static int AccessFpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val, 74 int writeOperation, void *arg); 75 static int GetDynInfoListAaddr(unw_addr_space_t as, unw_word_t *dil_vaddr, void *arg); 76 static int Resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg); 77 static int getProcName(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, 78 unw_word_t *offp, void *arg); 79 static int FindUnwindTable(SymbolsFile *symbolsFile, const MemMapItem &mmap, 80 UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, 81 unw_proc_info_t *pi, int need_unwind_info, void *arg); 82 void UnwindStep(unw_cursor_t &c, std::vector<CallFrame> &callFrames, size_t maxStackLevel); 83 std::unordered_map<pid_t, unw_addr_space_t> unwindAddrSpaceMap_; 84 85 using dsoUnwDynInfoMap = std::unordered_map<std::string, std::optional<unw_dyn_info_t>>; 86 std::unordered_map<pid_t, dsoUnwDynInfoMap> unwindDynInfoMap_; 87 88 using unwMemoryCache = std::unordered_map<unw_word_t, unw_word_t>; 89 std::unordered_map<pid_t, unwMemoryCache> porcessMemoryMap_; 90 91 unw_accessors_t accessors_ = { 92 .find_proc_info = FindProcInfo, 93 .put_unwind_info = PutUnwindInfo, 94 .get_dyn_info_list_addr = GetDynInfoListAaddr, 95 .access_mem = AccessMem, 96 .access_reg = AccessReg, 97 .access_fpreg = AccessFpreg, 98 .resume = Resume, 99 .get_proc_name = getProcName, 100 }; 101 bool DoUnwind(const VirtualThread &thread, std::vector<CallFrame> &callStack, 102 size_t maxStackLevel); 103 #endif 104 105 FRIEND_TEST(CallStackTest, ExpendCallStackFullCache); 106 FRIEND_TEST(CallStackTest, LibUnwindEmptyFunc); 107 FRIEND_TEST(CallStackTest, GetUnwErrorName); 108 }; 109 110 #if HAVE_LIBUNWIND 111 struct UnwindInfo { 112 const VirtualThread &thread; 113 const u64 *regs; 114 size_t regNumber; 115 ArchType arch; 116 CallStack &callStack; 117 }; 118 #endif 119 } // namespace NativeDaemon 120 } // namespace Developtools 121 } // namespace OHOS 122 #endif