• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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