1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SIMPLE_PERF_OFFLINE_UNWINDER_H_
18 #define SIMPLE_PERF_OFFLINE_UNWINDER_H_
19 
20 #include <memory>
21 #include <vector>
22 
23 #include "perf_regs.h"
24 #include "thread_tree.h"
25 
26 namespace simpleperf {
27 struct ThreadEntry;
28 
29 enum UnwindStackErrorCode : uint8_t {
30   ERROR_NONE,                   // No error.
31   ERROR_MEMORY_INVALID,         // Memory read failed.
32   ERROR_UNWIND_INFO,            // Unable to use unwind information to unwind.
33   ERROR_UNSUPPORTED,            // Encountered unsupported feature.
34   ERROR_INVALID_MAP,            // Unwind in an invalid map.
35   ERROR_MAX_FRAMES_EXCEEDED,    // The number of frames exceed the total allowed.
36   ERROR_REPEATED_FRAME,         // The last frame has the same pc/sp as the next.
37   ERROR_INVALID_ELF,            // Unwind in an invalid elf.
38   ERROR_THREAD_DOES_NOT_EXIST,  // Attempt to unwind a local thread that does
39                                 // not exist.
40   ERROR_THREAD_TIMEOUT,         // Timeout trying to unwind a local thread.
41   ERROR_SYSTEM_CALL,            // System call failed while unwinding.
42   ERROR_MAX = ERROR_SYSTEM_CALL,
43 };
44 
45 struct UnwindingResult {
46   // time used for unwinding, in ns.
47   uint64_t used_time;
48   // unwindstack::LastErrorCode()
49   uint64_t error_code;
50   // unwindstack::LastErrorAddress()
51   uint64_t error_addr;
52   uint64_t stack_start;
53   uint64_t stack_end;
54 };
55 
56 class OfflineUnwinder {
57  public:
58   static constexpr const char* META_KEY_ARM64_PAC_MASK = "arm64_pac_mask";
59 
60   static std::unique_ptr<OfflineUnwinder> Create(bool collect_stat);
~OfflineUnwinder()61   virtual ~OfflineUnwinder() {}
62 
63   virtual bool UnwindCallChain(const ThreadEntry& thread, const RegSet& regs, const char* stack,
64                                size_t stack_size, std::vector<uint64_t>* ips,
65                                std::vector<uint64_t>* sps) = 0;
66 
GetUnwindingResult()67   const UnwindingResult& GetUnwindingResult() const { return unwinding_result_; }
68 
IsCallChainBrokenForIncompleteJITDebugInfo()69   bool IsCallChainBrokenForIncompleteJITDebugInfo() {
70     return is_callchain_broken_for_incomplete_jit_debug_info_;
71   }
72 
73   static void CollectMetaInfo(std::unordered_map<std::string, std::string>* info_map);
LoadMetaInfo(const std::unordered_map<std::string,std::string> &)74   virtual void LoadMetaInfo(const std::unordered_map<std::string, std::string>&) {}
75 
76  protected:
OfflineUnwinder()77   OfflineUnwinder() {}
78 
79   UnwindingResult unwinding_result_;
80   bool is_callchain_broken_for_incomplete_jit_debug_info_ = false;
81 };
82 
83 }  // namespace simpleperf
84 
85 #endif  // SIMPLE_PERF_OFFLINE_UNWINDER_H_
86