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