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 <optional> 20 #include <string> 21 #include <vector> 22 23 #if !is_mingw 24 #include <sys/mman.h> 25 #endif 26 27 #include "hashlist.h" 28 #include "register.h" 29 #include "utilities.h" 30 #include "unwinder.h" 31 #include "virtual_thread.h" 32 33 using ADDR_TYPE = uintptr_t; 34 35 namespace OHOS { 36 namespace Developtools { 37 namespace HiPerf { 38 using namespace OHOS::HiviewDFX; 39 const int MAX_CALL_FRAME_EXPAND_CYCLE = 10; 40 const size_t MAX_CALL_FRAME_EXPAND_CACHE_SIZE = 10; 41 const size_t MAX_CALL_FRAME_UNWIND_SIZE = 256; 42 43 struct UnwindInfo; 44 45 class CallStack { 46 public: 47 CallStack(); 48 ~CallStack() = default; 49 void ClearCache(); 50 bool UnwindCallStack(const VirtualThread &thread, bool abi32, u64 *regs, u64 regsNum, 51 const u8 *stack, u64 stackSize, std::vector<DfxFrame> &, 52 size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE); 53 size_t ExpandCallStack(pid_t tid, std::vector<DfxFrame> &callFrames, size_t expandLimit = 1u); 54 55 private: 56 pid_t lastPid_ = -1; 57 ADDR_TYPE lastAddr_ = 0; 58 ADDR_TYPE lastData_ = 0; 59 uint64_t stackPoint_ = 0; 60 uint64_t stackEnd_ = 0; 61 u64 *regs_ = nullptr; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI 62 u64 regsNum_ = 0; 63 const u8 *stack_ = nullptr; 64 u64 stackSize_ = 0; 65 66 void LogFrame(const std::string msg, const std::vector<DfxFrame> &frames); 67 size_t DoExpandCallStack(std::vector<DfxFrame> &newCallFrames, 68 const std::vector<DfxFrame> &cachedCallFrames, size_t expandLimit); 69 70 // we have a cache for all thread 71 std::map<pid_t, HashList<uint64_t, std::vector<DfxFrame>>> cachedCallFramesMap_; 72 bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const; 73 ArchType arch_ = ArchType::ARCH_UNKNOWN; 74 75 static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, ADDR_TYPE addr, ADDR_TYPE *data); 76 #if defined(HAVE_LIBUNWINDER) && HAVE_LIBUNWINDER 77 bool DoUnwind2(const VirtualThread &thread, std::vector<DfxFrame> &callStack, size_t maxStackLevel); 78 static void DumpTableInfo(UnwindTableInfo &outTableInfo); 79 static int FillUnwindTable(SymbolsFile *symbolsFile, std::shared_ptr<DfxMap> map, UnwindInfo *unwindInfoPtr, 80 uintptr_t pc, UnwindTableInfo& outTableInfo); 81 static int FindUnwindTable(uintptr_t pc, UnwindTableInfo& outTableInfo, void *arg); 82 static int AccessMem2(uintptr_t addr, uintptr_t *val, void *arg); 83 static int GetMapByPc(uintptr_t pc, std::shared_ptr<DfxMap>& map, void *arg); 84 85 // pid->unwinder(acc/regs/maps) cache 86 std::unordered_map<pid_t, std::shared_ptr<Unwinder>> pidUnwinder_; 87 // pid->elf->unwindtable cache 88 using DsoUnwindTableInfoMap = std::unordered_map<std::string, UnwindTableInfo>; 89 std::unordered_map<pid_t, DsoUnwindTableInfoMap> unwindTableInfoMap_; 90 91 std::shared_ptr<UnwindAccessors> accessor_; 92 #endif 93 }; 94 95 struct UnwindInfo { 96 const VirtualThread &thread; 97 const u64 *regs; 98 size_t regNumber; 99 ArchType arch; 100 CallStack &callStack; 101 }; 102 } // namespace HiPerf 103 } // namespace Developtools 104 } // namespace OHOS 105 #endif // HIPERF_CALLSTACK_H 106