xref: /aosp_15_r20/system/extras/simpleperf/dso.h (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #ifndef SIMPLE_PERF_DSO_H_
18*288bf522SAndroid Build Coastguard Worker #define SIMPLE_PERF_DSO_H_
19*288bf522SAndroid Build Coastguard Worker 
20*288bf522SAndroid Build Coastguard Worker #include <memory>
21*288bf522SAndroid Build Coastguard Worker #include <optional>
22*288bf522SAndroid Build Coastguard Worker #include <string>
23*288bf522SAndroid Build Coastguard Worker #include <string_view>
24*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
25*288bf522SAndroid Build Coastguard Worker #include <vector>
26*288bf522SAndroid Build Coastguard Worker 
27*288bf522SAndroid Build Coastguard Worker #include <android-base/file.h>
28*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
29*288bf522SAndroid Build Coastguard Worker 
30*288bf522SAndroid Build Coastguard Worker #include "build_id.h"
31*288bf522SAndroid Build Coastguard Worker #include "kallsyms.h"
32*288bf522SAndroid Build Coastguard Worker #include "read_elf.h"
33*288bf522SAndroid Build Coastguard Worker 
34*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
35*288bf522SAndroid Build Coastguard Worker namespace simpleperf_dso_impl {
36*288bf522SAndroid Build Coastguard Worker 
37*288bf522SAndroid Build Coastguard Worker // Find elf files with symbol table and debug information.
38*288bf522SAndroid Build Coastguard Worker class DebugElfFileFinder {
39*288bf522SAndroid Build Coastguard Worker  public:
40*288bf522SAndroid Build Coastguard Worker   void Reset();
AllowMismatchedBuildId()41*288bf522SAndroid Build Coastguard Worker   void AllowMismatchedBuildId() { allow_mismatched_build_id_ = true; }
42*288bf522SAndroid Build Coastguard Worker   bool SetSymFsDir(const std::string& symfs_dir);
43*288bf522SAndroid Build Coastguard Worker   bool AddSymbolDir(const std::string& symbol_dir);
44*288bf522SAndroid Build Coastguard Worker   void SetVdsoFile(const std::string& vdso_file, bool is_64bit);
45*288bf522SAndroid Build Coastguard Worker   std::string FindDebugFile(const std::string& dso_path, bool force_64bit, BuildId& build_id);
46*288bf522SAndroid Build Coastguard Worker   // Only for testing
47*288bf522SAndroid Build Coastguard Worker   std::string GetPathInSymFsDir(const std::string& path);
48*288bf522SAndroid Build Coastguard Worker 
49*288bf522SAndroid Build Coastguard Worker  private:
50*288bf522SAndroid Build Coastguard Worker   void CollectBuildIdInDir(const std::string& dir);
51*288bf522SAndroid Build Coastguard Worker   std::optional<std::string> SearchFileMapByPath(std::string_view path);
52*288bf522SAndroid Build Coastguard Worker   bool CheckDebugFilePath(const std::string& path, BuildId& build_id,
53*288bf522SAndroid Build Coastguard Worker                           bool report_build_id_mismatch);
54*288bf522SAndroid Build Coastguard Worker 
55*288bf522SAndroid Build Coastguard Worker   bool allow_mismatched_build_id_ = false;
56*288bf522SAndroid Build Coastguard Worker   std::string vdso_64bit_;
57*288bf522SAndroid Build Coastguard Worker   std::string vdso_32bit_;
58*288bf522SAndroid Build Coastguard Worker   std::string symfs_dir_;
59*288bf522SAndroid Build Coastguard Worker   std::unordered_map<std::string, std::string> build_id_to_file_map_;
60*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> no_build_id_files_;
61*288bf522SAndroid Build Coastguard Worker };
62*288bf522SAndroid Build Coastguard Worker 
63*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf_dso_impl
64*288bf522SAndroid Build Coastguard Worker 
65*288bf522SAndroid Build Coastguard Worker struct Symbol {
66*288bf522SAndroid Build Coastguard Worker   uint64_t addr;
67*288bf522SAndroid Build Coastguard Worker   // TODO: make len uint32_t.
68*288bf522SAndroid Build Coastguard Worker   uint64_t len;
69*288bf522SAndroid Build Coastguard Worker 
70*288bf522SAndroid Build Coastguard Worker   Symbol(std::string_view name, uint64_t addr, uint64_t len);
NameSymbol71*288bf522SAndroid Build Coastguard Worker   const char* Name() const { return name_; }
72*288bf522SAndroid Build Coastguard Worker 
73*288bf522SAndroid Build Coastguard Worker   const char* DemangledName() const;
74*288bf522SAndroid Build Coastguard Worker   void SetDemangledName(std::string_view name) const;
75*288bf522SAndroid Build Coastguard Worker   // Return function name without signature.
76*288bf522SAndroid Build Coastguard Worker   std::string_view FunctionName() const;
77*288bf522SAndroid Build Coastguard Worker 
HasDumpIdSymbol78*288bf522SAndroid Build Coastguard Worker   bool HasDumpId() const { return dump_id_ != UINT_MAX; }
79*288bf522SAndroid Build Coastguard Worker 
GetDumpIdSymbol80*288bf522SAndroid Build Coastguard Worker   bool GetDumpId(uint32_t* pdump_id) const {
81*288bf522SAndroid Build Coastguard Worker     if (!HasDumpId()) {
82*288bf522SAndroid Build Coastguard Worker       return false;
83*288bf522SAndroid Build Coastguard Worker     }
84*288bf522SAndroid Build Coastguard Worker     *pdump_id = dump_id_;
85*288bf522SAndroid Build Coastguard Worker     return true;
86*288bf522SAndroid Build Coastguard Worker   }
87*288bf522SAndroid Build Coastguard Worker 
CompareByDumpIdSymbol88*288bf522SAndroid Build Coastguard Worker   static bool CompareByDumpId(const Symbol* s1, const Symbol* s2) {
89*288bf522SAndroid Build Coastguard Worker     uint32_t id1 = UINT_MAX;
90*288bf522SAndroid Build Coastguard Worker     s1->GetDumpId(&id1);
91*288bf522SAndroid Build Coastguard Worker     uint32_t id2 = UINT_MAX;
92*288bf522SAndroid Build Coastguard Worker     s2->GetDumpId(&id2);
93*288bf522SAndroid Build Coastguard Worker     return id1 < id2;
94*288bf522SAndroid Build Coastguard Worker   }
95*288bf522SAndroid Build Coastguard Worker 
CompareByAddrSymbol96*288bf522SAndroid Build Coastguard Worker   static bool CompareByAddr(const Symbol* s1, const Symbol* s2) { return s1->addr < s2->addr; }
97*288bf522SAndroid Build Coastguard Worker 
CompareValueByAddrSymbol98*288bf522SAndroid Build Coastguard Worker   static bool CompareValueByAddr(const Symbol& s1, const Symbol& s2) { return s1.addr < s2.addr; }
99*288bf522SAndroid Build Coastguard Worker 
100*288bf522SAndroid Build Coastguard Worker  private:
101*288bf522SAndroid Build Coastguard Worker   const char* name_;
102*288bf522SAndroid Build Coastguard Worker   mutable const char* demangled_name_;
103*288bf522SAndroid Build Coastguard Worker   mutable uint32_t dump_id_;
104*288bf522SAndroid Build Coastguard Worker 
105*288bf522SAndroid Build Coastguard Worker   friend class Dso;
106*288bf522SAndroid Build Coastguard Worker };
107*288bf522SAndroid Build Coastguard Worker 
108*288bf522SAndroid Build Coastguard Worker enum DsoType {
109*288bf522SAndroid Build Coastguard Worker   DSO_KERNEL,
110*288bf522SAndroid Build Coastguard Worker   DSO_KERNEL_MODULE,
111*288bf522SAndroid Build Coastguard Worker   DSO_ELF_FILE,
112*288bf522SAndroid Build Coastguard Worker   DSO_DEX_FILE,  // For files containing dex files, like .vdex files.
113*288bf522SAndroid Build Coastguard Worker   DSO_SYMBOL_MAP_FILE,
114*288bf522SAndroid Build Coastguard Worker   DSO_UNKNOWN_FILE,
115*288bf522SAndroid Build Coastguard Worker   // DSO_UNKNOWN_FILE is written to the file feature section in recording files. Changing its value
116*288bf522SAndroid Build Coastguard Worker   // may cause compatibility issue. So put new DsoTypes below.
117*288bf522SAndroid Build Coastguard Worker };
118*288bf522SAndroid Build Coastguard Worker 
119*288bf522SAndroid Build Coastguard Worker class Dso {
120*288bf522SAndroid Build Coastguard Worker  public:
121*288bf522SAndroid Build Coastguard Worker   static void SetDemangle(bool demangle);
122*288bf522SAndroid Build Coastguard Worker   static std::string Demangle(const std::string& name);
123*288bf522SAndroid Build Coastguard Worker   // SymFsDir is used to provide an alternative root directory looking for files with symbols.
124*288bf522SAndroid Build Coastguard Worker   // For example, if we are searching symbols for /system/lib/libc.so and SymFsDir is /data/symbols,
125*288bf522SAndroid Build Coastguard Worker   // then we will also search file /data/symbols/system/lib/libc.so.
126*288bf522SAndroid Build Coastguard Worker   static bool SetSymFsDir(const std::string& symfs_dir);
127*288bf522SAndroid Build Coastguard Worker   // SymbolDir is used to add a directory containing files with symbols. Each file under it will
128*288bf522SAndroid Build Coastguard Worker   // be searched recursively to build a build_id_map.
129*288bf522SAndroid Build Coastguard Worker   static bool AddSymbolDir(const std::string& symbol_dir);
130*288bf522SAndroid Build Coastguard Worker   static void SetVmlinux(const std::string& vmlinux);
SetKallsyms(std::string kallsyms)131*288bf522SAndroid Build Coastguard Worker   static void SetKallsyms(std::string kallsyms) {
132*288bf522SAndroid Build Coastguard Worker     if (!kallsyms.empty()) {
133*288bf522SAndroid Build Coastguard Worker       kallsyms_ = std::move(kallsyms);
134*288bf522SAndroid Build Coastguard Worker     }
135*288bf522SAndroid Build Coastguard Worker   }
136*288bf522SAndroid Build Coastguard Worker   static void AllowMismatchedBuildId();
137*288bf522SAndroid Build Coastguard Worker   static void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
138*288bf522SAndroid Build Coastguard Worker   static BuildId FindExpectedBuildIdForPath(const std::string& path);
139*288bf522SAndroid Build Coastguard Worker   static void SetVdsoFile(const std::string& vdso_file, bool is_64bit);
140*288bf522SAndroid Build Coastguard Worker 
141*288bf522SAndroid Build Coastguard Worker   static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path,
142*288bf522SAndroid Build Coastguard Worker                                         bool force_64bit = false);
143*288bf522SAndroid Build Coastguard Worker   static std::unique_ptr<Dso> CreateDsoWithBuildId(DsoType dso_type, const std::string& dso_path,
144*288bf522SAndroid Build Coastguard Worker                                                    BuildId& build_id);
145*288bf522SAndroid Build Coastguard Worker   static std::unique_ptr<Dso> CreateKernelModuleDso(const std::string& dso_path,
146*288bf522SAndroid Build Coastguard Worker                                                     uint64_t memory_start, uint64_t memory_end,
147*288bf522SAndroid Build Coastguard Worker                                                     Dso* kernel_dso);
148*288bf522SAndroid Build Coastguard Worker   virtual ~Dso();
149*288bf522SAndroid Build Coastguard Worker 
type()150*288bf522SAndroid Build Coastguard Worker   DsoType type() const { return type_; }
151*288bf522SAndroid Build Coastguard Worker 
152*288bf522SAndroid Build Coastguard Worker   // Return the path recorded in perf.data.
Path()153*288bf522SAndroid Build Coastguard Worker   const std::string& Path() const { return path_; }
154*288bf522SAndroid Build Coastguard Worker   // Return the path containing symbol table and debug information.
GetDebugFilePath()155*288bf522SAndroid Build Coastguard Worker   const std::string& GetDebugFilePath() const {
156*288bf522SAndroid Build Coastguard Worker     if (!debug_file_path_.has_value()) {
157*288bf522SAndroid Build Coastguard Worker       debug_file_path_ = FindDebugFilePath();
158*288bf522SAndroid Build Coastguard Worker     }
159*288bf522SAndroid Build Coastguard Worker     return debug_file_path_.value();
160*288bf522SAndroid Build Coastguard Worker   }
161*288bf522SAndroid Build Coastguard Worker 
162*288bf522SAndroid Build Coastguard Worker   // Return the path beautified for reporting.
GetReportPath()163*288bf522SAndroid Build Coastguard Worker   virtual std::string_view GetReportPath() const { return Path(); }
164*288bf522SAndroid Build Coastguard Worker   // Return the file name without directory info.
FileName()165*288bf522SAndroid Build Coastguard Worker   const std::string& FileName() const { return file_name_; }
166*288bf522SAndroid Build Coastguard Worker 
HasDumpId()167*288bf522SAndroid Build Coastguard Worker   bool HasDumpId() { return dump_id_ != UINT_MAX; }
168*288bf522SAndroid Build Coastguard Worker 
GetDumpId(uint32_t * pdump_id)169*288bf522SAndroid Build Coastguard Worker   bool GetDumpId(uint32_t* pdump_id) {
170*288bf522SAndroid Build Coastguard Worker     if (!HasDumpId()) {
171*288bf522SAndroid Build Coastguard Worker       return false;
172*288bf522SAndroid Build Coastguard Worker     }
173*288bf522SAndroid Build Coastguard Worker     *pdump_id = dump_id_;
174*288bf522SAndroid Build Coastguard Worker     return true;
175*288bf522SAndroid Build Coastguard Worker   }
176*288bf522SAndroid Build Coastguard Worker 
177*288bf522SAndroid Build Coastguard Worker   uint32_t CreateDumpId();
178*288bf522SAndroid Build Coastguard Worker   uint32_t CreateSymbolDumpId(const Symbol* symbol);
179*288bf522SAndroid Build Coastguard Worker 
SetMinExecutableVaddr(uint64_t,uint64_t)180*288bf522SAndroid Build Coastguard Worker   virtual void SetMinExecutableVaddr(uint64_t, uint64_t) {}
GetMinExecutableVaddr(uint64_t * min_vaddr,uint64_t * file_offset)181*288bf522SAndroid Build Coastguard Worker   virtual void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) {
182*288bf522SAndroid Build Coastguard Worker     *min_vaddr = 0;
183*288bf522SAndroid Build Coastguard Worker     *file_offset = 0;
184*288bf522SAndroid Build Coastguard Worker   }
AddDexFileOffset(uint64_t)185*288bf522SAndroid Build Coastguard Worker   virtual void AddDexFileOffset(uint64_t) {}
DexFileOffsets()186*288bf522SAndroid Build Coastguard Worker   virtual const std::vector<uint64_t>* DexFileOffsets() { return nullptr; }
187*288bf522SAndroid Build Coastguard Worker 
188*288bf522SAndroid Build Coastguard Worker   virtual uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) = 0;
189*288bf522SAndroid Build Coastguard Worker   virtual std::optional<uint64_t> IpToFileOffset(uint64_t ip, uint64_t map_start,
190*288bf522SAndroid Build Coastguard Worker                                                  uint64_t map_pgoff);
191*288bf522SAndroid Build Coastguard Worker 
192*288bf522SAndroid Build Coastguard Worker   const Symbol* FindSymbol(uint64_t vaddr_in_dso);
193*288bf522SAndroid Build Coastguard Worker   void LoadSymbols();
GetSymbols()194*288bf522SAndroid Build Coastguard Worker   const std::vector<Symbol>& GetSymbols() const { return symbols_; }
195*288bf522SAndroid Build Coastguard Worker   void SetSymbols(std::vector<Symbol>* symbols);
196*288bf522SAndroid Build Coastguard Worker 
197*288bf522SAndroid Build Coastguard Worker   // Create a symbol for a virtual address which can't find a corresponding
198*288bf522SAndroid Build Coastguard Worker   // symbol in symbol table.
199*288bf522SAndroid Build Coastguard Worker   void AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name);
200*288bf522SAndroid Build Coastguard Worker   bool IsForJavaMethod() const;
201*288bf522SAndroid Build Coastguard Worker 
202*288bf522SAndroid Build Coastguard Worker  protected:
203*288bf522SAndroid Build Coastguard Worker   static bool demangle_;
204*288bf522SAndroid Build Coastguard Worker   static std::string vmlinux_;
205*288bf522SAndroid Build Coastguard Worker   static std::string kallsyms_;
206*288bf522SAndroid Build Coastguard Worker   static std::unordered_map<std::string, BuildId> build_id_map_;
207*288bf522SAndroid Build Coastguard Worker   static size_t dso_count_;
208*288bf522SAndroid Build Coastguard Worker   static uint32_t g_dump_id_;
209*288bf522SAndroid Build Coastguard Worker   static simpleperf_dso_impl::DebugElfFileFinder debug_elf_file_finder_;
210*288bf522SAndroid Build Coastguard Worker 
211*288bf522SAndroid Build Coastguard Worker   Dso(DsoType type, const std::string& path);
212*288bf522SAndroid Build Coastguard Worker   BuildId GetExpectedBuildId() const;
213*288bf522SAndroid Build Coastguard Worker 
FindDebugFilePath()214*288bf522SAndroid Build Coastguard Worker   virtual std::string FindDebugFilePath() const { return path_; }
215*288bf522SAndroid Build Coastguard Worker   virtual std::vector<Symbol> LoadSymbolsImpl() = 0;
216*288bf522SAndroid Build Coastguard Worker 
217*288bf522SAndroid Build Coastguard Worker   DsoType type_;
218*288bf522SAndroid Build Coastguard Worker   // path of the shared library used by the profiled program
219*288bf522SAndroid Build Coastguard Worker   const std::string path_;
220*288bf522SAndroid Build Coastguard Worker   // path of the shared library having symbol table and debug information
221*288bf522SAndroid Build Coastguard Worker   // It is the same as path_, or has the same build id as path_.
222*288bf522SAndroid Build Coastguard Worker   mutable std::optional<std::string> debug_file_path_;
223*288bf522SAndroid Build Coastguard Worker   // File name of the shared library, got by removing directories in path_.
224*288bf522SAndroid Build Coastguard Worker   std::string file_name_;
225*288bf522SAndroid Build Coastguard Worker   std::vector<Symbol> symbols_;
226*288bf522SAndroid Build Coastguard Worker   // unknown symbols are like [libc.so+0x1234].
227*288bf522SAndroid Build Coastguard Worker   std::unordered_map<uint64_t, Symbol> unknown_symbols_;
228*288bf522SAndroid Build Coastguard Worker   bool is_loaded_;
229*288bf522SAndroid Build Coastguard Worker   // Used to identify current dso if it needs to be dumped.
230*288bf522SAndroid Build Coastguard Worker   uint32_t dump_id_;
231*288bf522SAndroid Build Coastguard Worker   // Used to assign dump_id for symbols in current dso.
232*288bf522SAndroid Build Coastguard Worker   uint32_t symbol_dump_id_;
233*288bf522SAndroid Build Coastguard Worker   android::base::LogSeverity symbol_warning_loglevel_;
234*288bf522SAndroid Build Coastguard Worker };
235*288bf522SAndroid Build Coastguard Worker 
236*288bf522SAndroid Build Coastguard Worker const char* DsoTypeToString(DsoType dso_type);
237*288bf522SAndroid Build Coastguard Worker bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id);
238*288bf522SAndroid Build Coastguard Worker bool GetBuildId(const Dso& dso, BuildId& build_id);
239*288bf522SAndroid Build Coastguard Worker 
240*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
241*288bf522SAndroid Build Coastguard Worker 
242*288bf522SAndroid Build Coastguard Worker #endif  // SIMPLE_PERF_DSO_H_
243