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