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_DSO_H_
18 #define SIMPLE_PERF_DSO_H_
19 
20 #include <memory>
21 #include <optional>
22 #include <string>
23 #include <string_view>
24 #include <unordered_map>
25 #include <vector>
26 
27 #include <android-base/file.h>
28 #include <android-base/logging.h>
29 
30 #include "build_id.h"
31 #include "kallsyms.h"
32 #include "read_elf.h"
33 
34 namespace simpleperf {
35 namespace simpleperf_dso_impl {
36 
37 // Find elf files with symbol table and debug information.
38 class DebugElfFileFinder {
39  public:
40   void Reset();
41   bool SetSymFsDir(const std::string& symfs_dir);
42   bool AddSymbolDir(const std::string& symbol_dir);
43   void SetVdsoFile(const std::string& vdso_file, bool is_64bit);
44   std::string FindDebugFile(const std::string& dso_path, bool force_64bit, BuildId& build_id);
45   // Only for testing
46   std::string GetPathInSymFsDir(const std::string& path);
47 
48  private:
49   void CollectBuildIdInDir(const std::string& dir);
50 
51   std::string vdso_64bit_;
52   std::string vdso_32bit_;
53   std::string symfs_dir_;
54   std::unordered_map<std::string, std::string> build_id_to_file_map_;
55 };
56 
57 }  // namespace simpleperf_dso_impl
58 
59 struct Symbol {
60   uint64_t addr;
61   // TODO: make len uint32_t.
62   uint64_t len;
63 
64   Symbol(std::string_view name, uint64_t addr, uint64_t len);
NameSymbol65   const char* Name() const { return name_; }
66 
67   const char* DemangledName() const;
68   void SetDemangledName(std::string_view name) const;
69 
HasDumpIdSymbol70   bool HasDumpId() const { return dump_id_ != UINT_MAX; }
71 
GetDumpIdSymbol72   bool GetDumpId(uint32_t* pdump_id) const {
73     if (!HasDumpId()) {
74       return false;
75     }
76     *pdump_id = dump_id_;
77     return true;
78   }
79 
CompareByDumpIdSymbol80   static bool CompareByDumpId(const Symbol* s1, const Symbol* s2) {
81     uint32_t id1 = UINT_MAX;
82     s1->GetDumpId(&id1);
83     uint32_t id2 = UINT_MAX;
84     s2->GetDumpId(&id2);
85     return id1 < id2;
86   }
87 
CompareByAddrSymbol88   static bool CompareByAddr(const Symbol* s1, const Symbol* s2) { return s1->addr < s2->addr; }
89 
CompareValueByAddrSymbol90   static bool CompareValueByAddr(const Symbol& s1, const Symbol& s2) { return s1.addr < s2.addr; }
91 
92  private:
93   const char* name_;
94   mutable const char* demangled_name_;
95   mutable uint32_t dump_id_;
96 
97   friend class Dso;
98 };
99 
100 enum DsoType {
101   DSO_KERNEL,
102   DSO_KERNEL_MODULE,
103   DSO_ELF_FILE,
104   DSO_DEX_FILE,  // For files containing dex files, like .vdex files.
105   DSO_SYMBOL_MAP_FILE,
106   DSO_UNKNOWN_FILE,
107   // DSO_UNKNOWN_FILE is written to the file feature section in recording files. Changing its value
108   // may cause compatibility issue. So put new DsoTypes below.
109 };
110 
111 class Dso {
112  public:
113   static void SetDemangle(bool demangle);
114   static std::string Demangle(const std::string& name);
115   // SymFsDir is used to provide an alternative root directory looking for files with symbols.
116   // For example, if we are searching symbols for /system/lib/libc.so and SymFsDir is /data/symbols,
117   // then we will also search file /data/symbols/system/lib/libc.so.
118   static bool SetSymFsDir(const std::string& symfs_dir);
119   // SymbolDir is used to add a directory containing files with symbols. Each file under it will
120   // be searched recursively to build a build_id_map.
121   static bool AddSymbolDir(const std::string& symbol_dir);
122   static void SetVmlinux(const std::string& vmlinux);
SetKallsyms(std::string kallsyms)123   static void SetKallsyms(std::string kallsyms) {
124     if (!kallsyms.empty()) {
125       kallsyms_ = std::move(kallsyms);
126     }
127   }
128   static void SetBuildIds(const std::vector<std::pair<std::string, BuildId>>& build_ids);
129   static BuildId FindExpectedBuildIdForPath(const std::string& path);
130   static void SetVdsoFile(const std::string& vdso_file, bool is_64bit);
131 
132   static std::unique_ptr<Dso> CreateDso(DsoType dso_type, const std::string& dso_path,
133                                         bool force_64bit = false);
134   static std::unique_ptr<Dso> CreateDsoWithBuildId(DsoType dso_type, const std::string& dso_path,
135                                                    BuildId& build_id);
136   static std::unique_ptr<Dso> CreateKernelModuleDso(const std::string& dso_path,
137                                                     uint64_t memory_start, uint64_t memory_end,
138                                                     Dso* kernel_dso);
139   virtual ~Dso();
140 
type()141   DsoType type() const { return type_; }
142 
143   // Return the path recorded in perf.data.
Path()144   const std::string& Path() const { return path_; }
145   // Return the path containing symbol table and debug information.
GetDebugFilePath()146   const std::string& GetDebugFilePath() const { return debug_file_path_; }
147   // Return the path beautified for reporting.
GetReportPath()148   virtual std::string_view GetReportPath() const { return Path(); }
149   // Return the file name without directory info.
FileName()150   const std::string& FileName() const { return file_name_; }
151 
HasDumpId()152   bool HasDumpId() { return dump_id_ != UINT_MAX; }
153 
GetDumpId(uint32_t * pdump_id)154   bool GetDumpId(uint32_t* pdump_id) {
155     if (!HasDumpId()) {
156       return false;
157     }
158     *pdump_id = dump_id_;
159     return true;
160   }
161 
162   uint32_t CreateDumpId();
163   uint32_t CreateSymbolDumpId(const Symbol* symbol);
164 
SetMinExecutableVaddr(uint64_t,uint64_t)165   virtual void SetMinExecutableVaddr(uint64_t, uint64_t) {}
GetMinExecutableVaddr(uint64_t * min_vaddr,uint64_t * file_offset)166   virtual void GetMinExecutableVaddr(uint64_t* min_vaddr, uint64_t* file_offset) {
167     *min_vaddr = 0;
168     *file_offset = 0;
169   }
AddDexFileOffset(uint64_t)170   virtual void AddDexFileOffset(uint64_t) {}
DexFileOffsets()171   virtual const std::vector<uint64_t>* DexFileOffsets() { return nullptr; }
172 
173   virtual uint64_t IpToVaddrInFile(uint64_t ip, uint64_t map_start, uint64_t map_pgoff) = 0;
174   virtual std::optional<uint64_t> IpToFileOffset(uint64_t ip, uint64_t map_start,
175                                                  uint64_t map_pgoff);
176 
177   const Symbol* FindSymbol(uint64_t vaddr_in_dso);
178   void LoadSymbols();
GetSymbols()179   const std::vector<Symbol>& GetSymbols() const { return symbols_; }
180   void SetSymbols(std::vector<Symbol>* symbols);
181 
182   // Create a symbol for a virtual address which can't find a corresponding
183   // symbol in symbol table.
184   void AddUnknownSymbol(uint64_t vaddr_in_dso, const std::string& name);
185   bool IsForJavaMethod() const;
186 
187  protected:
188   static bool demangle_;
189   static std::string vmlinux_;
190   static std::string kallsyms_;
191   static std::unordered_map<std::string, BuildId> build_id_map_;
192   static size_t dso_count_;
193   static uint32_t g_dump_id_;
194   static simpleperf_dso_impl::DebugElfFileFinder debug_elf_file_finder_;
195 
196   Dso(DsoType type, const std::string& path, const std::string& debug_file_path);
197   BuildId GetExpectedBuildId();
198 
199   virtual std::vector<Symbol> LoadSymbolsImpl() = 0;
200 
201   DsoType type_;
202   // path of the shared library used by the profiled program
203   const std::string path_;
204   // path of the shared library having symbol table and debug information
205   // It is the same as path_, or has the same build id as path_.
206   std::string debug_file_path_;
207   // File name of the shared library, got by removing directories in path_.
208   std::string file_name_;
209   std::vector<Symbol> symbols_;
210   // unknown symbols are like [libc.so+0x1234].
211   std::unordered_map<uint64_t, Symbol> unknown_symbols_;
212   bool is_loaded_;
213   // Used to identify current dso if it needs to be dumped.
214   uint32_t dump_id_;
215   // Used to assign dump_id for symbols in current dso.
216   uint32_t symbol_dump_id_;
217   android::base::LogSeverity symbol_warning_loglevel_;
218 };
219 
220 const char* DsoTypeToString(DsoType dso_type);
221 bool GetBuildIdFromDsoPath(const std::string& dso_path, BuildId* build_id);
222 
223 }  // namespace simpleperf
224 
225 #endif  // SIMPLE_PERF_DSO_H_
226