xref: /aosp_15_r20/system/extras/simpleperf/thread_tree.h (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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_THREAD_TREE_H_
18 #define SIMPLE_PERF_THREAD_TREE_H_
19 
20 #include <stdint.h>
21 
22 #include <limits>
23 #include <map>
24 #include <memory>
25 #include <unordered_map>
26 
27 #include "dso.h"
28 
29 namespace simpleperf {
30 
31 struct Record;
32 
33 constexpr char DEFAULT_KERNEL_MMAP_NAME[] = "[kernel.kallsyms]";
34 constexpr char DEFAULT_KERNEL_BPF_MMAP_NAME[] = "[bpf]";
35 constexpr char DEFAULT_EXECNAME_FOR_THREAD_MMAP[] = "//anon";
36 
37 namespace map_flags {
38 constexpr uint32_t PROT_JIT_SYMFILE_MAP = 0x4000;
39 }  // namespace map_flags
40 
41 struct MapEntry {
42   uint64_t start_addr;
43   uint64_t len;
44   uint64_t pgoff;
45   Dso* dso;
46   bool in_kernel;
47   uint32_t flags;
48 
49   MapEntry(uint64_t start_addr, uint64_t len, uint64_t pgoff, Dso* dso, bool in_kernel,
50            uint32_t flags = 0)
start_addrMapEntry51       : start_addr(start_addr),
52         len(len),
53         pgoff(pgoff),
54         dso(dso),
55         in_kernel(in_kernel),
56         flags(flags) {}
MapEntryMapEntry57   MapEntry() {}
58 
get_end_addrMapEntry59   uint64_t get_end_addr() const { return start_addr + len; }
60 
ContainsMapEntry61   uint64_t Contains(uint64_t addr) const { return addr >= start_addr && addr < get_end_addr(); }
62 
GetVaddrInFileMapEntry63   uint64_t GetVaddrInFile(uint64_t addr) const {
64     if (Contains(addr)) {
65       return dso->IpToVaddrInFile(addr, start_addr, pgoff);
66     }
67     return 0;
68   }
69 };
70 
71 struct MapSet {
72   std::map<uint64_t, const MapEntry*> maps;  // Map from start_addr to a MapEntry.
73   uint64_t version = 0u;                     // incremented each time changing maps
74 
75   const MapEntry* FindMapByAddr(uint64_t addr) const;
76 };
77 
78 struct ThreadEntry {
79   int pid;
80   int tid;
81   const char* comm;              // It always refers to the latest comm.
82   std::shared_ptr<MapSet> maps;  // maps is shared by threads in the same process.
83 };
84 
85 struct FileFeature;
86 
87 // ThreadTree contains thread information (in ThreadEntry) and mmap information
88 // (in MapEntry) of the monitored threads. It also has interface to access
89 // symbols in executable binaries mapped in the monitored threads.
90 class ThreadTree {
91  public:
ThreadTree()92   ThreadTree()
93       : show_ip_for_unknown_symbol_(false),
94         show_mark_for_unknown_symbol_(false),
95         unknown_symbol_("unknown", 0, std::numeric_limits<unsigned long long>::max()) {
96     unknown_dso_ = Dso::CreateDso(DSO_UNKNOWN_FILE, "unknown");
97     unknown_map_ =
98         MapEntry(0, std::numeric_limits<unsigned long long>::max(), 0, unknown_dso_.get(), false);
99     // We can't dump comm for pid 0 from /proc, so add it's name here.
100     SetThreadName(0, 0, "swapper");
101   }
~ThreadTree()102   virtual ~ThreadTree() {}
103 
DisableThreadExitRecords()104   void DisableThreadExitRecords() { disable_thread_exit_records_ = true; }
105   void SetThreadName(int pid, int tid, const std::string& comm);
106   bool ForkThread(int pid, int tid, int ppid, int ptid);
107   virtual ThreadEntry* FindThread(int tid) const;
108   ThreadEntry* FindThreadOrNew(int pid, int tid);
109   void ExitThread(int pid, int tid);
110   void AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff, const std::string& filename);
GetKernelMaps()111   const MapSet& GetKernelMaps() { return kernel_maps_; }
112   void AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff,
113                     const std::string& filename, uint32_t flags = 0);
114 
115   // Add process symbols that do not correspond to any real dso.
116   // For example, these might be symbols generated by a JIT.
117   void AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols);
118 
119   const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel);
120   // Find map for an ip address when we don't know whether it is in kernel.
121   const MapEntry* FindMap(const ThreadEntry* thread, uint64_t ip);
122   const Symbol* FindSymbol(const MapEntry* map, uint64_t ip, uint64_t* pvaddr_in_file,
123                            Dso** pdso = nullptr);
124   const Symbol* FindKernelSymbol(uint64_t ip);
IsUnknownDso(const Dso * dso)125   bool IsUnknownDso(const Dso* dso) const { return dso == unknown_dso_.get(); }
UnknownSymbol()126   const Symbol* UnknownSymbol() const { return &unknown_symbol_; }
127 
ShowIpForUnknownSymbol()128   void ShowIpForUnknownSymbol() { show_ip_for_unknown_symbol_ = true; }
ShowMarkForUnknownSymbol()129   void ShowMarkForUnknownSymbol() {
130     show_mark_for_unknown_symbol_ = true;
131     unknown_symbol_ = Symbol("*unknown", 0, ULLONG_MAX);
132   }
133   // Clear thread and map information, but keep loaded dso information. It saves
134   // the time to reload dso information.
135   void ClearThreadAndMap();
136   bool AddDsoInfo(FileFeature& file);
137   void AddDexFileOffset(const std::string& file_path, uint64_t dex_file_offset);
138 
139   // Update thread tree with information provided by record.
140   void Update(const Record& record);
141 
142   std::vector<Dso*> GetAllDsos() const;
143   Dso* FindUserDsoOrNew(const std::string& filename, uint64_t start_addr = 0,
144                         DsoType dso_type = DSO_ELF_FILE);
145 
146  private:
147   ThreadEntry* CreateThread(int pid, int tid);
148   Dso* FindKernelDsoOrNew();
149   Dso* FindKernelModuleDsoOrNew(const std::string& filename, uint64_t memory_start,
150                                 uint64_t memory_end);
151 
152   const MapEntry* AllocateMap(const MapEntry& entry);
153   void InsertMap(MapSet& maps, const MapEntry& entry);
154 
155   // Add thread maps to cover symbols in dso.
156   void AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso);
157 
158   std::unordered_map<int, std::unique_ptr<ThreadEntry>> thread_tree_;
159   std::vector<std::unique_ptr<std::string>> thread_comm_storage_;
160 
161   MapSet kernel_maps_;
162   std::vector<std::unique_ptr<MapEntry>> map_storage_;
163   MapEntry unknown_map_;
164 
165   std::unique_ptr<Dso> kernel_dso_;
166   std::unordered_map<std::string, std::unique_ptr<Dso>> module_dso_tree_;
167   std::unordered_map<std::string, std::unique_ptr<Dso>> user_dso_tree_;
168   std::unique_ptr<Dso> unknown_dso_;
169   bool show_ip_for_unknown_symbol_;
170   bool show_mark_for_unknown_symbol_;
171   Symbol unknown_symbol_;
172   bool disable_thread_exit_records_ = false;
173 };
174 
175 }  // namespace simpleperf
176 
177 #endif  // SIMPLE_PERF_THREAD_TREE_H_
178